• x64 Inline Hook 代码封装


    Hook 技术常被叫做挂钩技术,挂钩技术其实早在DOS时代就已经存在了,该技术是Windows系统用于替代DOS中断机制的具体实现,钩子的含义就是在程序还没有调用系统函数之前,钩子捕获调用消息并获得控制权,在执行系统调用之前执行自身程序,简单来说就是函数劫持.

    接着来研究一下64位程序的Hook,64位与32位系统之间无论从寻址方式,还是语法规则都与x32架构有着本质的不同,所以上面的使用技巧只适用于32位程序,注入32位进程使用,下面的内容则是64位下手动完成Hook挂钩的一些操作手法,由于64位编译器无法直接内嵌汇编代码,导致我们只能调用C库函数来实现Hook的中转.

    该笔记是针对64位Hook的简易封装,自己留着也没什么意思,还是分享出来吧,转载请加出处,谢谢!


    简单实现64位Hook去弹窗: 由于64位编译器无法直接内嵌汇编代码,所以在我们需要Hook时只能将跳转机器码以二进制字节方式写死在程序里,如下代码是一段简单的演示案例,主要实现了去弹窗的功能.

    #include <stdio.h>
    #include <Windows.h>
    
    BYTE OldCode[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    BYTE HookCode[12] = { 0x48, 0xB8, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xFF, 0xE0 };
    DWORD_PTR base;
    
    int WINAPI MyMessageBoxW(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
    {
    	return 1;
    }
    
    int main(int argc,char * argv[])
    {
    	HMODULE hwnd = GetModuleHandle(TEXT("user32.dll"));
    	DWORD_PTR base = (DWORD_PTR)GetProcAddress(hwnd, "MessageBoxW");
    	DWORD OldProtect;
    
    	if (VirtualProtect((LPVOID)base, 12, PAGE_EXECUTE_READWRITE, &OldProtect))
    	{
    		memcpy(OldCode, (LPVOID)base, 12);                  // 拷贝原始机器码指令
    		*(PINT64)(HookCode + 2) = (INT64)&MyMessageBoxW;    // 填充90为指定跳转地址
    	}
    	memcpy((LPVOID)base, &HookCode, sizeof(HookCode));      // 拷贝Hook机器指令
    
    	MessageBoxW(NULL, L"hello lyshark", NULL, NULL);
    
    	return 0;
    }
    

    64位Hook代码完整版: 接着我们在上面代码的基础上,继续进行完善,添加恢复钩子的功能,该功能时必须要有的,因为我们还是需要调用原始的弹窗代码,所以要在调用时进行暂时恢复,调用结束后再继续Hook挂钩.

    #include <stdio.h>
    #include <Windows.h>
    
    void Hook();
    void UnHook();
    
    BYTE Ori_Code[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    BYTE HookCode[12] = { 0x48, 0xB8, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xFF, 0xE0 };
    
    /* Hook 机器码的原理如下所示
    MOV RAX, 0x9090909090909090
    JMP RAX
    */
    
    static int (WINAPI *OldMessageBoxW)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) = MessageBoxW;
    
    int WINAPI MyMessageBoxW(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
    {
    	UnHook();                                                                  // 恢复Hook
    	int ret = OldMessageBoxW(hWnd, TEXT("Hook Inject"), lpCaption, uType);     // 调用原函数
    	Hook();                                                                    // 继续hook
    	return ret;
    }
    
    void Hook()
    {
    	DWORD OldProtect;
    	if (VirtualProtect(OldMessageBoxW, 12, PAGE_EXECUTE_READWRITE, &OldProtect))
    	{
    		memcpy(Ori_Code, OldMessageBoxW, 12);               // 拷贝原始机器码指令
    		*(PINT64)(HookCode + 2) = (INT64)&MyMessageBoxW;    // 填充90为指定跳转地址
    	}
    	memcpy(OldMessageBoxW, &HookCode, sizeof(HookCode));    // 拷贝Hook机器指令
    }
    
    void UnHook()
    {
    	memcpy(OldMessageBoxW, &Ori_Code, sizeof(Ori_Code));    // 恢复hook原始代码
    }
    
    int main(int argc, char *argv [])
    {
    	Hook();
    	MessageBoxW(NULL, TEXT("hello lyshark"), TEXT("MsgBox"), MB_OK);
    	UnHook();
    	MessageBoxW(NULL, TEXT("hello lyshark"), TEXT("MsgBox"), MB_OK);
    
    	return 0;
    }
    

    完整版DLL注入钩子: 最后将上面所写的代码进行封装,实现一个完整的钩子处理程序,代码如下.

    #include <stdio.h>
    #include <Windows.h>
    
    BYTE OldCode[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    BYTE HookCode[12] = { 0x48, 0xB8, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xFF, 0xE0 };
    
    void Hook(LPCWSTR lpModule, LPCSTR lpFuncName, LPVOID lpFunction)
    {
    	DWORD_PTR FuncAddress = (UINT64)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
    	DWORD OldProtect = 0;
    
    	if (VirtualProtect((LPVOID)FuncAddress, 12, PAGE_EXECUTE_READWRITE, &OldProtect))
    	{
    		memcpy(OldCode, (LPVOID)FuncAddress, 12);                   // 拷贝原始机器码指令
    		*(PINT64)(HookCode + 2) = (UINT64)lpFunction;               // 填充90为指定跳转地址
    	}
    	memcpy((LPVOID)FuncAddress, &HookCode, sizeof(HookCode));       // 拷贝Hook机器指令
    	VirtualProtect((LPVOID)FuncAddress, 12, OldProtect, &OldProtect);
    }
    
    void UnHook(LPCWSTR lpModule, LPCSTR lpFuncName)
    {
    	DWORD OldProtect = 0;
    	UINT64 FuncAddress = (UINT64)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
    	if (VirtualProtect((LPVOID)FuncAddress, 12, PAGE_EXECUTE_READWRITE, &OldProtect))
    	{
    		memcpy((LPVOID)FuncAddress, OldCode, sizeof(OldCode));
    	}
    	VirtualProtect((LPVOID)FuncAddress, 12, OldProtect, &OldProtect);
    }
    
    int WINAPI MyMessageBoxW(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
    {
    	// 首先恢复Hook代码
    	UnHook(L"user32.dll", "MessageBoxW");
    	int ret = MessageBoxW(0, L"hello lyshark", lpCaption, uType);
    
    	// 调用结束后,再次挂钩
    	Hook(L"user32.dll", "MessageBoxW", (PROC)MyMessageBoxW);
    	return ret;
    }
    
    bool APIENTRY DllMain(HANDLE handle, DWORD dword, LPVOID lpvoid)
    {
    	switch (dword)
    	{
    	case DLL_PROCESS_ATTACH:
    		Hook(L"user32.dll", "MessageBoxW", (PROC)MyMessageBoxW);
    		break;
    	case DLL_PROCESS_DETACH:
    		UnHook(L"user32.dll", "MessageBoxW");
    		break;
    	}
    	return true;
    }
    

    针对Hook代码的封装: 上方的代码还是基于过程化的案例,为了能更加通用,我们将其封装成类,这样后期可以直接调用了.

    // hook.h
    #pragma once
    #include <Windows.h>
    
    #ifdef __cplusplus
    extern "C"{
    #endif
    
    	class MyHook
    	{
    	public:
    		FARPROC m_pfnOrig;       // 保存函数地址
    		BYTE m_bOldBytes[12];  // 保存函数入口代码
    		BYTE m_bNewBytes[12];  // 保存Inlie Hook代码
    	public:
    		MyHook();
    		~MyHook();
    		BOOL Hook(LPCWSTR lpModule, LPCSTR lpFuncName, LPVOID lpFunction);
    		BOOL UnHook(LPCWSTR lpModule, LPCSTR lpFuncName);
    	};
    #ifdef __cplusplus
    }
    #endif
    
    // hook.cpp
    #include "hook.h"
    
    MyHook::MyHook()
    {
    	BYTE OldCode[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    	BYTE NewCode[12] = { 0x48, 0xB8, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xFF, 0xE0 };
    
    	RtlMoveMemory(MyHook::m_bNewBytes, NewCode, 12);
    	memset(MyHook::m_bOldBytes, 0, 12);
    	m_pfnOrig = NULL;
    }
    
    MyHook::~MyHook()
    {
    	m_pfnOrig = NULL;
    	ZeroMemory(MyHook::m_bNewBytes, 12);
    	ZeroMemory(MyHook::m_bOldBytes, 12);
    }
    
    BOOL MyHook::Hook(LPCWSTR lpModule, LPCSTR lpFuncName, LPVOID lpFunction)
    {
    	DWORD_PTR FuncAddress = (UINT64)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
    	DWORD OldProtect = 0;
    
    	if (VirtualProtect((LPVOID)FuncAddress, 12, PAGE_EXECUTE_READWRITE, &OldProtect))
    	{
    		memcpy(m_bOldBytes, (LPVOID)FuncAddress, 12);                           // 拷贝原始机器码指令
    		*(PINT64)(MyHook::m_bNewBytes + 2) = (UINT64)lpFunction;                // 填充90为指定跳转地址
    	}
    	memcpy((LPVOID)FuncAddress, &m_bNewBytes, sizeof(m_bNewBytes));             // 拷贝Hook机器指令
    	VirtualProtect((LPVOID)FuncAddress, 12, OldProtect, &OldProtect);
    	return TRUE;
    }
    
    BOOL MyHook::UnHook(LPCWSTR lpModule, LPCSTR lpFuncName)
    {
    	DWORD OldProtect = 0;
    	UINT64 FuncAddress = (UINT64)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
    	if (VirtualProtect((LPVOID)FuncAddress, 12, PAGE_EXECUTE_READWRITE, &OldProtect))
    	{
    		memcpy((LPVOID)FuncAddress, m_bOldBytes, sizeof(m_bOldBytes));
    	}
    	VirtualProtect((LPVOID)FuncAddress, 12, OldProtect, &OldProtect);
    	return TRUE;
    }
    
    // main.cpp
    #include <Windows.h>
    #include "hook.h"
    
    MyHook MsgHook;
    
    int WINAPI MyMessageBoxW(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
    {
    	// 首先恢复Hook代码
    	MsgHook.UnHook(L"user32.dll", "MessageBoxW");
    	int ret = MessageBoxW(0, L"Hook Inject", lpCaption, uType);
    
    	// 调用结束后,再次挂钩
    	MsgHook.Hook(L"user32.dll", "MessageBoxW", (PROC)MyMessageBoxW);
    	return ret;
    }
    
    int main(int argc, char * argv[])
    {
    	// 开始Hook
    	MsgHook.Hook(L"user32.dll", "MessageBoxW", (PROC)MyMessageBoxW);
    
    	MessageBoxW(NULL, L"hello lyshark", L"Msg", MB_OK);
    
    	// 结束Hook
    	MsgHook.UnHook(L"user32.dll", "MessageBoxW");
    	return 0;
    }
    

    第二种封装方式: 接着我们将代码声明与实现合在一起,实现第二种封装方式.

    // hook.h
    #include <Windows.h>
    
    class MyHook
    {
    public:
    	static UINT64 Hook(LPCWSTR lpModule, LPCSTR lpFuncName, LPVOID lpFunction)
    	{
    		UINT64 dwAddr = (UINT64)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
    		BYTE jmp[] =
    		{
    			0x48, 0xb8,               // jmp
    			0x00, 0x00, 0x00, 0x00,
    			0x00, 0x00, 0x00, 0x00,   // address
    			0x50, 0xc3                // retn
    		};
    
    		ReadProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, MemoryAddress(), 12, 0);
    		UINT64 dwCalc = (UINT64)lpFunction;
    		memcpy(&jmp[2], &dwCalc, 8);
    
    		WriteProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, jmp, 12, nullptr);
    		return dwAddr;
    	}
    
    	static BOOL UnHook(LPCWSTR lpModule, LPCSTR lpFuncName)
    	{
    		UINT64 dwAddr = (UINT64)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
    
    		if (WriteProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, MemoryAddress(), 12, 0))
    			return TRUE;
    		return FALSE;
    	}
    
    	static BYTE* MemoryAddress()
    	{
    		static BYTE backup[12];
    		return backup;
    	}
    };
    
    // main.cpp
    #include <windows.h>
    #include "hook.h"
    
    MyHook MsgHook;
    
    static int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
    {
    	MsgHook.UnHook(L"user32.dll", "MessageBoxW");
    	int ret = MessageBox(hWnd, L"Hook Inject", lpCaption, uType);
    	MsgHook.Hook(L"user32.dll", "MessageBoxW", (PROC)MyMessageBoxW);
    	return ret;
    }
    
    int main(int argc, char * argv[])
    {
    	MsgHook.Hook(L"user32.dll", "MessageBoxW", (PROC)MyMessageBoxW);
    	MessageBoxW(NULL, L"hello lyshark", L"MsgBox", MB_OK);
    
    	MsgHook.UnHook(L"user32.dll", "MessageBoxW");
    	MessageBoxW(NULL, L"hello lyshark", L"MsgBox", MB_OK);
    
    	return 0;
    }
    

    版权声明: 本博客,文章与代码均为学习时整理的笔记,博客中除去明确标注有参考文献的文章,其他文章【均为原创】作品,转载请务必【添加出处】,您添加出处是我创作的动力!

    警告:如果您恶意转载本人文章,则您的整站文章,将会变为我的原创作品,请相互尊重!
  • 相关阅读:
    C# Socket TcpClient 无法从传输连接中读取数据: 远程主机强迫关闭了一个现有的连接。。
    C#编程使用Managed Wifi API连接无线SSID
    中国最精确的电子地图,可以找到你家哦
    利用mysql数据库中的TMD表修复“is marked as crashed and last (automatic?) repair failed”的错误 Database query error
    Google Directions API 中路线编码解析
    c语言 nmealib-0.5.3 学习 简单代码 ,供参考
    【转】IT管理人才必备的十大能力
    【转】10个让人受益的管理原理
    【转】耐心看
    【转】对于移动APP测试的一个小技巧
  • 原文地址:https://www.cnblogs.com/LyShark/p/13653394.html
Copyright © 2020-2023  润新知