-
-
Save S3cur3Th1sSh1t/8294ec59d1ef38cba661697edcfacb9b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <stdio.h> | |
#include <tlhelp32.h> | |
#include <psapi.h> | |
typedef struct _MEMORY_SEARCH { | |
MEMORY_BASIC_INFORMATION mbi; | |
SIZE_T size; | |
} MEMORY_SEARCH, *PMEMORY_SEARCH; | |
typedef struct _PATCH_PATTERN { | |
DWORD Length; | |
BYTE *Pattern; | |
} PATCH_PATTERN, *PPATCH_PATTERN; | |
typedef struct _PATCH_OFFSETS { | |
LONG off0; | |
} PATCH_OFFSETS, *PPATCH_OFFSETS; | |
typedef struct _PATCH_GENERIC { | |
DWORD MinBuildNumber; | |
PATCH_PATTERN Search; | |
PATCH_PATTERN Patch; | |
PATCH_OFFSETS Offsets; | |
} PATCH_GENERIC, *PPATCH_GENERIC; | |
typedef struct _dll_info | |
{ | |
int pid; | |
byte * dll_addr; | |
int dll_size; | |
} dll_info; | |
BYTE PTRN_WN60_Query__CDefPolicy[] = {0x8b, 0x81, 0x38, 0x06, 0x00, 0x00, 0x39, 0x81, 0x3c, 0x06, 0x00, 0x00, 0x75}; | |
BYTE PTRN_WN6x_Query__CDefPolicy[] = {0x39, 0x87, 0x3c, 0x06, 0x00, 0x00, 0x0f, 0x84}; | |
BYTE PTRN_WN81_Query__CDefPolicy[] = {0x39, 0x81, 0x3c, 0x06, 0x00, 0x00, 0x0f, 0x84}; | |
BYTE PTRN_W10_1803_Query__CDefPolicy[] = {0x8b, 0x99, 0x3c, 0x06, 0x00, 0x00, 0x8b, 0xb9, 0x38, 0x06, 0x00, 0x00, 0x3b, 0xdf, 0x0f, 0x84}; | |
BYTE PTRN_W10_1809_Query__CDefPolicy[] = {0x8b, 0x81, 0x38, 0x06, 0x00, 0x00, 0x39, 0x81, 0x3c, 0x06, 0x00, 0x00, 0x0f, 0x84}; | |
BYTE PTRN_W11_24H2[] = {0x8B, 0x81, 0x38, 0x06, 0x00, 0x00, 0x39, 0x81, 0x3C, 0x06, 0x00, 0x00, 0x75}; | |
BYTE PATC_WN60_Query__CDefPolicy[] = {0xc7, 0x81, 0x3c, 0x06, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x90, 0x90, 0xeb}; | |
BYTE PATC_WN6x_Query__CDefPolicy[] = {0xc7, 0x87, 0x3c, 0x06, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x90, 0x90}; | |
BYTE PATC_WN81_Query__CDefPolicy[] = {0xc7, 0x81, 0x3c, 0x06, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x90, 0x90}; | |
BYTE PATC_W10_1803_Query__CDefPolicy[] = {0xc7, 0x81, 0x3c, 0x06, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x90, 0x90, 0x90, 0x90, 0x90, 0xe9}; | |
BYTE PATC_W10_1809_Query__CDefPolicy[] = {0xc7, 0x81, 0x3c, 0x06, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; | |
BYTE PATC_W11_23H2[] = {0xB8, 0x00, 0x01, 0x00, 0x00, 0x89, 0x81, 0x38, 0x06, 0x00, 0x00, 0x90}; | |
BYTE PATC_W11_24H2[] = {0xB8, 0x00, 0x01, 0x00, 0x00, 0x89, 0x81, 0x38, 0x06, 0x00, 0x00, 0x90, 0xEB}; | |
BYTE PTRN_WIN5_TestLicence[] = {0x83, 0xf8, 0x02, 0x7f}; | |
BYTE PATC_WIN5_TestLicence[] = {0x90, 0x90}; | |
PATCH_GENERIC TermSrvMultiRdpReferences[] = { | |
{2600/*Win XP*/, {sizeof(PTRN_WIN5_TestLicence),PTRN_WIN5_TestLicence},{sizeof(PATC_WIN5_TestLicence), PATC_WIN5_TestLicence},{3}}, | |
{6000/*VISTA*/, {sizeof(PTRN_WN60_Query__CDefPolicy), PTRN_WN60_Query__CDefPolicy}, {sizeof(PATC_WN60_Query__CDefPolicy), PATC_WN60_Query__CDefPolicy}, {0}}, | |
{7600/*Win_7*/, {sizeof(PTRN_WN6x_Query__CDefPolicy), PTRN_WN6x_Query__CDefPolicy}, {sizeof(PATC_WN6x_Query__CDefPolicy), PATC_WN6x_Query__CDefPolicy}, {0}}, | |
{9600/*Win8*/, {sizeof(PTRN_WN81_Query__CDefPolicy), PTRN_WN81_Query__CDefPolicy}, {sizeof(PATC_WN81_Query__CDefPolicy), PATC_WN81_Query__CDefPolicy}, {0}}, | |
{17134/*Win_10_1803*/, {sizeof(PTRN_W10_1803_Query__CDefPolicy), PTRN_W10_1803_Query__CDefPolicy}, {sizeof(PATC_W10_1803_Query__CDefPolicy), PATC_W10_1803_Query__CDefPolicy}, {0}}, | |
{17763/*Win_10_1803*/, {sizeof(PTRN_W10_1809_Query__CDefPolicy), PTRN_W10_1809_Query__CDefPolicy}, {sizeof(PATC_W10_1809_Query__CDefPolicy), PATC_W10_1809_Query__CDefPolicy}, {0}}, | |
{22631/*Win_11_23H2*/, {sizeof(PTRN_W11_24H2), PTRN_W11_24H2}, {sizeof(PATC_W11_23H2), PATC_W11_23H2}, {0}}, | |
{26100/*Win_11_24H2*/, {sizeof(PTRN_W11_24H2), PTRN_W11_24H2}, {sizeof(PATC_W11_24H2), PATC_W11_24H2}, {0}}, | |
}; | |
BOOL PatchMemory(HANDLE hProcess, LPVOID lpBaseAddress, SIZE_T region_size, BYTE *pattern, SIZE_T patternSize, BYTE *patch, SIZE_T patchSize, LONG offset) { | |
BYTE *buffer = (BYTE *)malloc(region_size); | |
SIZE_T bytesRead; | |
BOOL result = FALSE; | |
// print pattern to search for | |
printf("[*] Pattern to search for: "); | |
for (int i = 0; i < patternSize; i++) | |
{ | |
printf("%02x ", pattern[i]); | |
} | |
printf("\r\n"); | |
if (ReadProcessMemory(hProcess, lpBaseAddress, buffer, region_size, &bytesRead) && bytesRead == region_size) { | |
printf("[+] Read %zu bytes from process\n", bytesRead); | |
// write buffer into file C:\temp\buffer.dmp, just for debugging/Checking new offsets | |
/* | |
FILE *f = fopen("C:\\temp\\buffer.dmp", "wb"); | |
if (f) { | |
fwrite(buffer, 1, bytesRead, f); | |
fclose(f); | |
printf("Wrote process memory to C:\\temp\\buffer.dmp\n"); | |
} else { | |
printf("Failed to write process memory to C:\\temp\\buffer.dmp\n"); | |
} | |
*/ | |
for (SIZE_T i = 0; i <= region_size - patternSize; i++) { | |
if (memcmp(buffer + i, pattern, patternSize) == 0) { | |
printf("[+] Found pattern in process memory at offset %zu\n", i); | |
DWORD oldProtect; | |
if (VirtualProtectEx(hProcess, (LPVOID)((BYTE *)lpBaseAddress + i + offset), patchSize, PAGE_EXECUTE_READWRITE, &oldProtect)) { | |
printf("[+] Patched memory permissions\n"); | |
SIZE_T bytesWritten; | |
if (WriteProcessMemory(hProcess, (LPVOID)((BYTE *)lpBaseAddress + i + offset), patch, patchSize, &bytesWritten) && bytesWritten == patchSize) { | |
printf("[+] Patched process memory\n"); | |
result = TRUE; | |
} | |
VirtualProtectEx(hProcess, (LPVOID)((BYTE *)lpBaseAddress + i + offset), patchSize, oldProtect, &oldProtect); | |
printf("[+] Restored memory permissions\n"); | |
} | |
break; // Exit the loop after patching | |
} | |
} | |
} | |
free(buffer); | |
return result; | |
} | |
PATCH_GENERIC *GetPatchGenericFromBuild(PATCH_GENERIC *generics, SIZE_T cbGenerics, DWORD buildNumber) { | |
PATCH_GENERIC *bestMatch = NULL; | |
for (SIZE_T i = 0; i < cbGenerics; i++) { | |
if (generics[i].MinBuildNumber <= buildNumber) { | |
if (bestMatch == NULL || generics[i].MinBuildNumber > bestMatch->MinBuildNumber) { | |
bestMatch = &generics[i]; | |
} | |
} | |
} | |
return bestMatch; | |
} | |
dll_info * get_dll_info(char * dll_name, BOOL verbose) | |
{ | |
dll_info * dll; | |
dll = malloc(sizeof(dll_info)); | |
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); | |
if( hProcessSnap == INVALID_HANDLE_VALUE ) | |
{ | |
printf("[-] error CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, ...)\n"); | |
return; | |
} | |
PROCESSENTRY32 pe32; | |
pe32.dwSize = sizeof(PROCESSENTRY32); | |
if(! Process32First(hProcessSnap, &pe32) ) | |
{ | |
printf("[-] error Process32First()\n"); | |
return; | |
} | |
do | |
{ | |
if(! strcmp("svchost.exe", pe32.szExeFile) ) | |
{ | |
if(verbose) | |
printf("%s [%d]\n", pe32.szExeFile, pe32.th32ProcessID); | |
HANDLE hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pe32.th32ProcessID ); | |
if( hModuleSnap == INVALID_HANDLE_VALUE ) | |
{ | |
printf("[-] error CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, %d)\n", pe32.th32ProcessID); | |
continue; | |
} | |
MODULEENTRY32 me32; | |
me32.dwSize = sizeof(MODULEENTRY32); | |
if(! Module32First(hModuleSnap, &me32) ) | |
{ | |
printf("[-] error Module32First()\n"); | |
continue; | |
} | |
do | |
{ | |
if(verbose) | |
printf(" [0x%08x]\t%s (%d B)\n", me32.modBaseAddr, me32.szModule, me32.modBaseSize); | |
if(! strcmp( dll_name, me32.szModule ) ) | |
{ | |
dll->pid = pe32.th32ProcessID; | |
dll->dll_addr = me32.modBaseAddr; | |
dll->dll_size = me32.modBaseSize; | |
CloseHandle(hModuleSnap); | |
return dll; | |
} | |
} | |
while( Module32Next(hModuleSnap, &me32) ); | |
CloseHandle(hModuleSnap); | |
} | |
} | |
while( Process32Next(hProcessSnap, &pe32) ); | |
return 0; | |
} | |
typedef LONG (WINAPI *RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); | |
int GetWindowsBuildNumber() { | |
HMODULE hMod = GetModuleHandleW(L"ntdll.dll"); | |
if (hMod) { | |
RtlGetVersionPtr pRtlGetVersion = (RtlGetVersionPtr)GetProcAddress(hMod, "RtlGetVersion"); | |
if (pRtlGetVersion) { | |
RTL_OSVERSIONINFOW rovi = {0}; | |
rovi.dwOSVersionInfoSize = sizeof(rovi); | |
if (pRtlGetVersion(&rovi) == 0) { | |
return rovi.dwBuildNumber; | |
} | |
} | |
} | |
return -1; // Return -1 if retrieval fails | |
} | |
BOOL PatchTermService(PATCH_GENERIC *generics, SIZE_T cbGenerics, PCWSTR moduleName) { | |
BOOL result = FALSE; | |
DWORD buildNumber = GetWindowsBuildNumber(); // Example build number, replace with actual build number retrieval | |
printf("[*] Windows build number: %lu\n", buildNumber); | |
PATCH_GENERIC *currentReferences = GetPatchGenericFromBuild(generics, cbGenerics, buildNumber); | |
if (currentReferences) { | |
printf("[*] Found patch references for build number %lu\n", buildNumber); | |
SERVICE_STATUS_PROCESS serviceStatusProcess; | |
dll_info * termsrv = get_dll_info( "termsrv.dll", FALSE ); | |
DWORD processId = termsrv->pid; | |
printf("[+] Found TermService with PID %lu\n", processId); | |
HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION, FALSE, processId); | |
if (hProcess) { | |
printf("[+] Opened process with PID %lu\n", processId); | |
LPVOID baseAddress = termsrv->dll_addr; | |
SIZE_T imageSize = termsrv->dll_size; | |
printf("[*] Module base address: %p, size: %zu\n", baseAddress, imageSize); | |
MEMORY_BASIC_INFORMATION mbi; | |
for (LPBYTE address = (LPBYTE)baseAddress; address < (LPBYTE)baseAddress + imageSize; address += mbi.RegionSize) { | |
if (VirtualQueryEx(hProcess, address, &mbi, sizeof(mbi)) == sizeof(mbi)) { | |
if (mbi.State == MEM_COMMIT && (mbi.Protect == PAGE_EXECUTE_READ || mbi.Protect == PAGE_EXECUTE_READWRITE)) { | |
printf("[*] Checking memory region at address %p, size: %zu\n", address, mbi.RegionSize); | |
if (PatchMemory(hProcess, address,mbi.RegionSize, currentReferences->Search.Pattern, currentReferences->Search.Length, currentReferences->Patch.Pattern, currentReferences->Patch.Length, currentReferences->Offsets.off0)) { | |
printf("[+] \"%ls\" service patched at address %p\n", moduleName, address); | |
result = TRUE; | |
break; | |
} | |
} | |
} else { | |
printf("[-] VirtualQueryEx failed at address %p with error %lu\n", address, GetLastError()); | |
} | |
} | |
CloseHandle(hProcess); | |
} else { | |
printf("OpenProcess failed with error %lu\n", GetLastError()); | |
} | |
} else { | |
printf("No patch references found for build number %lu\n", buildNumber); | |
} | |
return result; | |
} | |
void get_privileges() | |
{ | |
HANDLE hProcessToken; | |
LUID luid; | |
TOKEN_PRIVILEGES priv; | |
OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken); | |
LookupPrivilegeValue(NULL, "SeDebugPrivilege", &luid); | |
priv.PrivilegeCount = 1; | |
priv.Privileges[0].Luid = luid; | |
priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; | |
AdjustTokenPrivileges( hProcessToken, FALSE, &priv, sizeof(TOKEN_PRIVILEGES), 0, 0 ); | |
} | |
// main function | |
int main() { | |
get_privileges(); | |
if (!PatchTermService(TermSrvMultiRdpReferences, ARRAYSIZE(TermSrvMultiRdpReferences), L"termsrv.dll")) { | |
printf("[-] Failed to patch service\n"); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment