挂钩 - 打屁股

 吴款爷 发布于 2023-02-06 13:22

我正在尝试挂钩Windows API函数FindWindowA().我成功地使用下面的代码完成了它而没有"hotpatching"它:我已经覆盖了函数开头的字节.调用myHook()并在调用FindWindowA()时显示一个消息框.

user32.dll启用了hotpatching,我想在实际函数之前覆盖NOP,而不是覆盖函数本身.但是,当我将hotpatching设置为TRUE时,下面的代码将不起作用.FindWindowA()执行时它什么都不做.

#include 
#include 

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

你能告诉我什么是错的吗?

谢谢.

1 个回答
  • 编译器和链接器准备了支持Hotpatching的可执行映像,以允许在使用时替换映像.应用以下两个更改(x86):

      函数入口点设置为2字节无操作mov edi, edi(/ hotpatch).

      每个函数入口点(/ FUNCTIONPADMIN)前面有五个连续的nop .

    为了说明这一点,这里是一个支持hotpaching功能的典型反汇编列表:

    (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字节无操作指定函数入口点.(2)是链接器提供的填充,(3)是非平凡函数实现开始的地方.

    要挂钩函数,您必须(2)通过跳转到钩子函数来覆盖jmp myHook,并通过替换(1)相对跳转来使该代码可达jmp $-5.

    钩子函数必须使堆栈处于一致状态.它应该被声明为__declspec(naked)阻止编译器生成函数prolog和epilog代码.最后一条指令必须按照钩子函数的调用约定执行堆栈清理,或者跳转到指定地址的钩子函数(3).

    2023-02-06 13:24 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有