首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >钩-热修补

钩-热修补
EN

Stack Overflow用户
提问于 2014-01-05 21:41:05
回答 1查看 2K关注 0票数 4

我正在尝试连接Windows函数FindWindowA()。我在没有“热修补”的情况下成功地完成了下面的代码:我已经在函数的开头覆盖了字节。调用myHook(),调用FindWindowA()时会显示一个消息框。

user32.dll启用了热补丁,我希望在实际函数之前覆盖NOPs,而不是覆盖函数本身。但是,当我将热补丁设置为TRUE时,下面的代码将无法工作。当FindWindowA()被执行时,它什么也不做。

代码语言:javascript
复制
#include <stdio.h>
#include <windows.h>

void myHook()
{
    MessageBoxA(NULL, "Hooked", "Hook", MB_ICONINFORMATION);
}

int main(int argc, char *argv[])
{
    BOOLEAN hotpatching = FALSE;

    LPVOID fwAddress = GetProcAddress(GetModuleHandleA("user32.dll"), "FindWindowA");
    LPVOID fwHotpatchingAddress = (LPVOID)((DWORD)fwAddress - 5);
    LPVOID myHookAddress = &myHook;

    DWORD jmpOffset = (DWORD)&myHook - (DWORD)(!hotpatching ? fwAddress : fwHotpatchingAddress) - 5; // -5 because "JMP offset" = 5 bytes (1 + 4)

    printf("fwAddress: %X\n", fwAddress);
    printf("fwHotpatchingAddress: %X\n", fwHotpatchingAddress);
    printf("myHookAddress: %X\n", myHookAddress);
    printf("jmpOffset: %X\n", jmpOffset);
    printf("Ready?\n\n");
    getchar();


    char JMP[1] = {0xE9};
    char RETN[1] = {0xC3};

    LPVOID offset0 = NULL;
    LPVOID offset1 = NULL;
    LPVOID offset2 = NULL;

    if (!hotpatching)
        offset0 = fwAddress;
    else
        offset0 = fwHotpatchingAddress;

    offset1 = (LPVOID)((DWORD)offset0 + 1);
    offset2 = (LPVOID)((DWORD)offset1 + 4);


    DWORD oldProtect = 0;
    VirtualProtect(offset0, 6, PAGE_EXECUTE_READWRITE, &oldProtect);

    memcpy(fwAddress, JMP, 1);
    memcpy(offset1, &jmpOffset, 4);
    memcpy(offset2, RETN, 1);

    VirtualProtect(offset0, 6, oldProtect, &oldProtect);


    printf("FindWindowA() Patched");
    getchar();


    FindWindowA(NULL, "Test");
    getchar();


    return 0;
}

你能告诉我怎么回事吗?

谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-01-06 09:08:09

启用热修补功能的可执行映像由编译器和链接器准备,以便在使用时替换映像。应用以下两个更改(x86):

  1. 函数入口点设置为2字节的非op mov edi, edi (/hotpatch).
  2. 每个功能入口点(/FUNCTIONPADMIN)都有五个连续的nop。

为了说明这一点,下面是启用热播功能的一个典型的反汇编清单:

代码语言:javascript
复制
(2) 768C8D66 90                   nop  
    768C8D67 90                   nop  
    768C8D68 90                   nop  
    768C8D69 90                   nop  
    768C8D6A 90                   nop  
(1) 768C8D6B 8B FF                mov         edi,edi
(3) 768C8D6D 55                   push        ebp  
    768C8D6E 8B EC                mov         ebp,esp  

(1)用2字节的no指定函数入口点.(2)是链接器提供的填充,而(3)是重要的函数实现的起点。

要连接到函数,必须用跳转到钩子函数jmp myHook来覆盖jmp myHook,并通过用相对跳转jmp $-5替换(1)来实现这段代码的可达性。

钩子函数必须使堆栈处于一致状态。应该将其声明为__declspec(naked),以防止编译器生成函数prolog和epilog代码。最后的指令必须按照挂钩函数的调用约定执行堆栈清理,或者在(3)指定的地址跳回挂钩函数。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20939554

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档