【逆向学习】Inline Hook学习
浏览 52 | 评论 0 | 字数 3844
Xunflash
2023年03月09日
  • inline hook

    主要思想:

    1、构造跳转指令。

    2、在内存中找到欲HOOK函数地址,并保存欲HOOK位置处的原本字节。

    3、将构造的跳转指令写入需HOOK的位置处。

    4、当被HOOK位置被执行时会转到我们的流程执行。

    5、如果要执行原来的流程,那么恢复HOOK,也就是还原被修改的字节。

    6、执行函数原来的流程。

    hook方式

    这部分其实参考了网上很多文章,自己感觉这些文章光写文字还是缺少一些对比,所以自己思考然后patch出来一些代码,自己理解与展示的更方便

    1、call跳转后修改系统函数

    众所周知,ms的库函数是从一条MOV EDI, EDI指令开始的,这是因为在运行时,如果需要一个填充字节,则会填充一条NOP指令,如果需要两个字节来填充,则会填充一条MOV EDI, EDI指令。

    这样当hook时就有了五个字节给我们进行操作,可以对MessageBoxW的前五个字节(固定的mov edi,edi push ebp mov ebp,esp)进行修改,将其替换为一个五字节近距离地址跳转的jmp指令跳转到我们自行构造的函数中。

    至于修改字节,有几种方式,《加密与解密》中记录了jmp xxxxxxxx;push xxxxxxxx/retn;mov eax,xxxxxxxx/jmp eax;这几种方式。

    image-20230308190458298

    image-20230308190545893

    代码实现:

    #include <windows.h>
    #include <stdio.h>
    #include <iostream>
    #include <tchar.h>
    
    //修改API入口为 jmp xxx 使得程序能跳转到自己的函数
    BYTE __NewCode[7] = { 0xE9, 0x0, 0x0, 0x0, 0x0 };
    BYTE __OldCode[7] = { 0 };
    
    FARPROC Messagebox_FARPROC;
    
    int WINAPI MyMessageBoxA(
        HWND hWnd,          // handle to owner window
        LPCTSTR lpText,     // text in message box
        LPCTSTR lpCaption,  // message box title
        UINT uType          // message box style
    );
    
    void InlineHook();
    
    void main()
    {
    
        InlineHook();
        //调用MessageBoxA
        MessageBoxA(NULL, "Hello World", "Title", MB_OK);
    }
    
    void InlineHook()
    {
        DWORD dwOldProtect = 0;
        //首先获取user32.dll的模块句柄
        HMODULE user32_HMODULE = LoadLibraryA("user32.dll");
        //利用GetProcAddress获取MessageBoxA导出函数的地址
        Messagebox_FARPROC = GetProcAddress(user32_HMODULE, "MessageBoxA");
        //利用ReadProcessMemory读取内存中MessageBoxA的前5字节
        if (!ReadProcessMemory(GetCurrentProcess(), Messagebox_FARPROC, __OldCode, 6, NULL)) {
            printf("[!] ReadProcessMemory Failed");
        }
        printf("%x%x%x%x%x\n", __OldCode[0], __OldCode[1], __OldCode[2], __OldCode[3], __OldCode[4]);
        //E9跳转为jmp地址到目标地址的间隔,地址需要进行计算,计算出来后赋值给newcode的后4位
        *((ULONG*)(__NewCode + 1)) = (ULONG)&MyMessageBoxA - ((ULONG)Messagebox_FARPROC + 5);
    
        //memcpy(&__NewCode[1], &JmpAddress, 4);
    
        printf("JmpAddress : %x\n", *((ULONG*)(__NewCode + 1)));
        //将权限替换为可读写执行
        VirtualProtect(Messagebox_FARPROC, 6, PAGE_EXECUTE_READWRITE, &dwOldProtect);
        //直接写入内存
        WriteProcessMemory(GetCurrentProcess(), Messagebox_FARPROC, __NewCode, 5, NULL);
        //恢复之前的权限
        VirtualProtect(Messagebox_FARPROC, 6, dwOldProtect, &dwOldProtect);
    
    }
    
    int WINAPI MyMessageBoxA(
        HWND hWnd,          // handle to owner window
        LPCTSTR lpText,     // text in message box
        LPCTSTR lpCaption,  // message box title
        UINT uType          // message box style
    )
    {
        printf("Hook Successful\n");
        //恢复原本的MessageBoxA,否则不能调用
        WriteProcessMemory(GetCurrentProcess(), Messagebox_FARPROC,__OldCode, 5, NULL);
        //可以使用参数进行调用
        MessageBoxA(NULL, (const char*)lpText, (const char*)lpCaption, MB_OK);
        MessageBoxA(NULL, "Xunflash", "Hook successful", MB_OK);
        //恢复hook
        WriteProcessMemory(GetCurrentProcess(), Messagebox_FARPROC, __NewCode, 5, NULL);
        return 0;
    }

    2、call跳转前替换函数地址

    假如在call跳转之前直接将程序hook的地址替换了那就更加方便了,可以直接将call跳转的地址替换成我们自己的函数地址,从而实现hook效果

    感觉缺点也很明显,假如有很多次调用的话,需要反复修改不同位置的call(也可能是我理解错了)

    image-20230308190710851

    image-20230308190645876

    3、热补丁

    利用函数上方的空间,将mov edi,edi和前面的nop/int 3进行替换,先使用一个向上的小跳转替换mov edi,edi。再用一个大跳转替换掉函数前面留空的nop/int 3,从而实现热补丁hook

    这种方式可以避免多次hook后恢复原程序流程的时候的反复的卸载hook,提高效率。要恢复原流程只需要重新跳转到短跳转下方的push ebp即可

    image-20230308185637484

    image-20230308190009834

    本文作者:Xunflash
    本文链接:http://xunflash.top/index.php/archives/Inline_Hook.html
    最后修改时间:2023-03-09 19:37:56
    本站未注明转载的文章均为原创,并采用 CC BY-NC-SA 4.0 授权协议,转载请注明来源,谢谢!
    评论
    114514
    textsms
    支持 Markdown 语法
    email
    link
    评论列表
    暂无评论