消息钩子

  1. 我们创建DLL
  2. 我们在DLLmain函数中劫持了我们指定线程的窗口消息
  3. 我们利用另一个程序,在原程序中注入我们自定义的DLL
  4. DLL加载后就完成了劫持

实例

  1. 注意窗口句柄分为 宽字节 窄字节
  2. 通过IsWindowUnicode 来判断 宽字节 窄字节
  3. 区别使用 SetWindowsHookExASetWindowsHookExW
  4. 释放DLL的时候 要把回掉函数恢复
  5. 释放DLL的时候 别再DLL主线程中 FreeLibrary

    1. FreeLibrary 会返回调用他的地址,但是这时候DLL已经被释放了所以会崩溃
    2. 最好的做法是在第三方线程中施放 DLL
    3. 我们可以在DLL主线程中创建一个子线程 FreeLibrary

      1. 巧合编程

创建消息劫持DLL

//全局变量保存我们创建的钩子
HHOOK myhook_COMMAND;

//自定义我们的消息函数
LRESULT CALLBACK COMMANDProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    const CWPSTRUCT& cwps = *(CWPSTRUCT*)lParam;
    int wmId = LOWORD(cwps.wParam);

    char msg[128] = { 0 };


    switch (cwps.message) {

        case WM_COMMAND: {

            if (HIWORD(cwps.wParam) == BN_CLICKED) {

                char sz[128] = { 0 };

                sprintf_s(sz, "触发 COMMAND nCode=%d id= %d  lParam=%d", nCode , LOWORD(cwps.wParam), lParam);
                OutputDebugStringA(sz);
            }

        }

    }


    return CallNextHookEx(myhook_COMMAND, nCode, wParam, lParam);
}

//劫持 原程序的消息
void dll_accach() {

    //锁定劫持的线程id
    DWORD dw_hack = 0;
    HWND hCalc = FindWindowW(NULL, L"计算器");
    dw_hack = GetWindowThreadProcessId(hCalc, NULL);
    
    //劫持
    myhook_COMMAND = SetWindowsHookEx(
        WH_CALLWNDPROC,   // 监听类型
        COMMANDProc,      // 处理函数
        NULL,             // 当前实例句柄
        dw_hack           // 监听窗口句柄
    );

    if (myhook_COMMAND == NULL)
    {
        char text[128] = { 0 };
        sprintf_s(text, "COMMAND监听失败!error : %d n", GetLastError());
        MessageBoxA(NULL, text, "错误", MB_OK);
    }
    //MessageBoxA(NULL, "绑定成功", "ok", MB_OK);
    OutputDebugStringA("dll_accach");

}

BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,  // handle to DLL module
    DWORD fdwReason,     // reason for calling function
    LPVOID lpReserved)  // reserved
{
    // Perform actions based on the reason for calling.
    switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:
        // Initialize once for each new process.
        // Return FALSE to fail DLL load.
        OutputDebugStringA("DLL_PROCESS_ATTACH");
        dll_accach();//注入
        break;

    case DLL_THREAD_ATTACH:
        // Do thread-specific initialization.
        OutputDebugStringA("DLL_THREAD_ATTACH");
        dll_accach();//注入
        break;

    case DLL_THREAD_DETACH:
        // Do thread-specific cleanup.
        OutputDebugStringA("DLL_THREAD_DETACH");
        break;

    case DLL_PROCESS_DETACH:
        // Perform any necessary cleanup.
        OutputDebugStringA("DLL_PROCESS_DETACH");
        break;
    }
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

创建DLL注入程序

void Inject() {

    //1. 获取目标进程句柄
    DWORD dwPID = 0;
    HWND hGame = FindWindowA(NULL, "计算器");

    if (hGame == NULL) {
        return;
    }

    GetWindowThreadProcessId(hGame, &dwPID);

    HANDLE hGameProcess = OpenProcess(PROCESS_ALL_ACCESS,
        TRUE,
        dwPID);
    if (hGameProcess == NULL || hGameProcess == INVALID_HANDLE_VALUE) {
        return;
    }

    //2 在目标进程空间中,开辟一块内存,存放待注入的dll路径
    LPVOID lpAddr = VirtualAllocEx(hGameProcess,
        NULL,
        0x1000,
        MEM_COMMIT,
        PAGE_EXECUTE_READWRITE);

    if (lpAddr == NULL) {
        return;
    }

    SIZE_T dwWritedBytes = 0;
    //3 向目标进程的写入注入dll路径
    BOOL bRet = WriteProcessMemory(hGameProcess,
        lpAddr,
        "劫持窗口消息.dll",
        sizeof("劫持窗口消息.dll"),
        &dwWritedBytes);

    //4 调用远程线程,使用LoadLibraryA,加载目标dll.
    HANDLE hRemoteThread = CreateRemoteThread(hGameProcess,
        NULL,
        0,
        (LPTHREAD_START_ROUTINE)LoadLibraryA,
        lpAddr,
        0,
        NULL);

    //5 等待DLL 结束运行
    WaitForSingleObject(hRemoteThread, INFINITE);

    DWORD dwExitCode = 0;

    //6 获取DLL句柄
    GetExitCodeThread(hRemoteThread, &dwExitCode);
    
    //释放目标进程的注入dll FreeLibrary
    CreateRemoteThread(hGameProcess,
        NULL,
        0,
        (LPTHREAD_START_ROUTINE)FreeLibrary,
        (LPVOID)dwExitCode,
        0,
        NULL);
}
Last modification:October 26, 2018
如果觉得我的文章对你有用,请随意赞赏