Windows下64位程序的Inline Hook

有过32位hook的介绍,代码不是主要的,所以贴在最后,首先记述下原理。

主体代码还是参考与那本关于黑客技术的书,部分内容则参考自以下博客。

https://blog.csdn.net/zuishikonghuan/article/details/47979603

原理:
mov rax,地址 push rax ret
64位程序中,jmp 貌似也只能跳转4字节的偏移,而程序的地址都是8字节。所以单独一条jmp指令不足以实现功能。

这也是原理上的不同。
rax是一个64位寄存器,首先把程序地址保存到rax寄存器中。
随后把rax寄存器的内容压入栈中。
最后使用ret返回。
关键之处在于ret指令返回的地址就是栈顶里面的内容。
所以ret后直接跳到了我们指定函数的地址中。

有了32位Inline Hook的经验,我们对照着代码,使用x64dbg调试(功能类似于OD,但是支持64位程序),会比较容易理解。

本次需要12字节:
mov rax,地址 => 0x48 0xb8 + 8字节地址 = 10字节
push rax => 0x50 1字节
ret => 0xc3 1字节

当然了,要实现类似的效果还有很多其实方法,随着学习的深入,以及对指令的熟悉,
举一反三也就有迹可循了。

 

#include <stdio.h>
#include <windows.h>
#include <iostream>
using namespace std;
#define len 12
class MyHook
{
public:
    MyHook()
    {
        funcAddr = NULL;
        ZeroMemory(oldBytes,len);
        ZeroMemory(newBytes,len);
    }
    ~MyHook()
    {
        UnHook();
        funcAddr = NULL;
        ZeroMemory(oldBytes,len);
        ZeroMemory(newBytes,len);
    }
    /*
     *Hook的模块名称,Hook的API函数名称,钩子函数地址
    */
    WINBOOL Hook(LPSTR ModuleName, LPSTR FuncName, PROC HookFunc)
    {
        BOOL bRet = FALSE;
        funcAddr = (PROC)GetProcAddress(GetModuleHandleA(ModuleName),FuncName);
        if(funcAddr!=NULL)
        {
            SIZE_T num = 0;
            ReadProcessMemory(GetCurrentProcess(),(void*)funcAddr,oldBytes,len,&num);
            for (int i = 0; i < len; i++)
            {
                printf("%0x ", oldBytes[i]);
            }
            cout << " finish" << endl;
            newBytes[0] = 0x48;
            newBytes[1] = 0xB8;
            newBytes[10] = 0x50;
            newBytes[11] = 0xC3;
            memcpy(newBytes+2,(void*)&HookFunc,8);
            for(int i=0;i<12;i++)
            {
                printf("%0x ",newBytes[i]);
            }
            cout<<endl;
            WriteProcessMemory(GetCurrentProcess(),(void*)funcAddr,newBytes,len,&num);
            cout<<"mytest"<<endl;
            bRet = TRUE;
        }
        return bRet;
    }
    void UnHook()
    {
        if(funcAddr!=0)
        {
            SIZE_T num = 0;
            WriteProcessMemory(GetCurrentProcess(),(void*)funcAddr,oldBytes,len,&num);
        }
    }
    WINBOOL ReHook()
    {
        BOOL ret = FALSE;
        if(funcAddr!=0)
        {
            SIZE_T num;
            WriteProcessMemory(GetCurrentProcess(),(void*)funcAddr,newBytes,len,&num);
            ret = TRUE;
        }
        return ret;
    }

private:
    PROC funcAddr;
    BYTE oldBytes[len];
    BYTE newBytes[len];
};

MyHook hook;
int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT type)
{
    hook.UnHook();
    MessageBox(hWnd,"Hook流程",lpCaption,type);
    MessageBox(hWnd,lpText,lpCaption,type);
    hook.ReHook();
    return 0;
}
int main()
{

    MessageBox(NULL,"正常流程1","test",MB_OK);
    hook.Hook((LPSTR)"User32.dll",(LPSTR)"MessageBoxA",(PROC)&MyMessageBoxA);
    MessageBox(NULL,"被Hook了1","test",MB_OK);
    MessageBox(NULL,"被Hook了2","test",MB_OK);
    cout<<"finish"<<endl;
    hook.UnHook();
    MessageBox(NULL,"正常流程2","test",MB_OK); 
    cout<<&MyMessageBoxA<<endl;
}

 

上一篇:Base 64 图片解码


下一篇:MongoDB 体系结构与数据模型