• 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字节

    当然了,要实现类似的效果还有很多其实方法,随着学习的深入,以及对指令的熟悉,
    举一反三也就有迹可循了。
    以下为另一篇关于64位Hook的博客,这里记录以下,方便日后参考
    https://www.cnblogs.com/iBinary/p/11334793.html
    #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;
    }
  • 相关阅读:
    Python OpenCV 常用操作
    Conda Cheatsheet | 速查表
    Loadrunner解决启动浏览器后页面显示空白
    26个ASP.NET常用性能优化方法
    C# Foreach用法
    体验ASP.NET MVC3 表单令牌功能!
    基于.Net(C#开发)平台的三层框架架构软件的设计与实现
    去掉浏览器中a标签的虚线
    Microsoft Dynamics CRM 4.0 序列号
    编写 Cookie
  • 原文地址:https://www.cnblogs.com/dayq/p/15808873.html
Copyright © 2020-2023  润新知