- 注册时间
- 2021-4-16
- 最后登录
- 2024-3-23
- 在线时间
- 2 小时
编程入门
- 龙马币
- 22
|
C++ 伪任意地址HOOK类源码
前言:
代码HOOK技术不管在安全领域还是在木马病毒方面都运用很广泛,因为他可以改变程序执行流程,悄无声息执行我们自己的代码。
之前我也用过一些hook类,如mhook等,但很多都局限于API HOOK,有的时候无法满足实际应用。也因此,我自己的hook类就诞生了。
先贴核心代码:
- /
- /Hook.h
- #pragma once
-
- struct t_Context
- {
- DWORD EDI;
- DWORD ESI;
- DWORD EBP;
- DWORD ESP;
- DWORD EBX;
- DWORD EDX;
- DWORD ECX;
- DWORD EAX;
- };
-
- class CHook
- {
- public:
- CHook(void);
- ~CHook(void);
- // 添加Hook
- bool AddHook(__in DWORD dwHookAddr, __in void *pfnHookProc);
- // 移除Hook
- bool RemoveHook();
- // 寄存器结构体
- t_Context m_Context;
- // 返回地址,没有特殊需求不要修改这里
- DWORD m_dwRetAddr;
- private:
- // 保存Hook地址,用于RemoveHook
- DWORD m_dwHookAddr;
- // 保存原始字节,用于RemoveHook
- BYTE m_OldCode[5];
- };
复制代码
- //Hook.cpp
- #include "StdAfx.h"
- #include "Hook.h"
- #include "MyOutputDebugString.h"
-
- //BeaEngine 反汇编引擎
- #define BEA_ENGINE_STATIC
- #define BEA_USE_STDCALL
- #include "bea/headers/BeaEngine.h"
- #pragma comment(lib, "bea/win32/lib/BeaEngine.lib")
- #pragma comment(linker,"/nodefaultlib:crt.lib")
- //BeaEngine end
-
- //XEDParse 汇编引擎
- #include "XEDParse/XEDParse.h"
- #pragma comment(lib,"XEDParse/XEDParse.lib")
-
- CHook::CHook(void)
- {
- memset(&m_Context, 0, sizeof(m_Context));
- memset(m_OldCode, 0x90, 5);
- m_dwRetAddr = 0;
- m_dwHookAddr = 0;
- }
-
-
- CHook::~CHook(void)
- {
- }
-
-
- // 添加Hook
- bool CHook::AddHook(__in DWORD dwHookAddr, __in void *lpHookProc)
- {
- //00240000 60 PUSHAD
- //00240001 9C PUSHFD
- //00240002 BF 00012400 MOV EDI,0x240100
- //00240007 8BF4 MOV ESI,ESP
- //00240009 83C6 04 ADD ESI,0x4
- //0024000C B9 20000000 MOV ECX,0x20
- //00240011 F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] ; 保存寄存器结构体,备用
- //00240013 B8 90909090 MOV EAX,0x90909090
- //00240018 FFD0 CALL EAX ; 调用HookPro
- //0024001A 9D POPFD
- //0024001B 61 POPAD
- //0024001C 90 NOP ; 个数等于被毁掉的指令总长度
- //0024001D 68 90909090 PUSH 0x90909090 ; jmp back
- //00240022 C3 RETN
- //00240023 90 NOP
- BYTE Shell[0x100] = {0x60, 0x9C, 0xBF, 0x90, 0x90, 0x90, 0x90, 0x8B, 0xF4, 0x83, 0xC6, 0x04, 0xB9, 0x20, 0x00, 0x00, 0x00, 0xF3, 0xA4, 0xB8, 0x90, 0x90, 0x90, 0x90, 0xFF, 0xD0, 0x9D, 0x61, 0x90, 0x90};
- int pContext = (int)&m_Context;
- memcpy(&Shell[3], &pContext, 4);
- int pHookProc = (int)lpHookProc;
- memcpy(&Shell[0x14], &pHookProc, 4);
-
- //保存原始机器码
- DWORD dwOldProtect = 0;
- BOOL bRet = VirtualProtect((LPVOID)dwHookAddr, 0x20, PAGE_EXECUTE_READWRITE, &dwOldProtect);
- if (!bRet)
- {
- MyOutputDebugStringA("VirtualProtect(0x%p) Error!!!", dwHookAddr);
- MyOutputDebugStringA("AddHook Failed:0x%p", dwHookAddr);
- return false;
- }
- memcpy(m_OldCode, (LPVOID)dwHookAddr, 5);//用于hook还原
-
- DWORD dwStart = (DWORD)VirtualAlloc(NULL, 0x100, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
- if (dwStart == 0)
- {
- OutputDebugStringA("VirtualAlloc Error!!!");
- MyOutputDebugStringA("AddHook Failed:0x%p", dwHookAddr);
- return false;
- }
-
- //开始解析原始指令,通过反汇编引擎,识别要Hook的地址处的指令,以及破坏的指令长度
- int nSize = 0;//毁掉的指令的总字节数
- DWORD dwASM = dwStart + 30;//30为前面shell前面部分代码长度
-
- DISASM MyDisasm;
- memset (&MyDisasm, 0, sizeof(DISASM));
- MyDisasm.EIP = (UIntPtr)dwHookAddr;
- MyDisasm.Options = PrefixedNumeral + ShowSegmentRegs;
-
- while (1)
- {
- //反汇编
- int nInstLen = Disasm(&MyDisasm);
- if (nInstLen < 1)
- {
- MyOutputDebugStringA("Disasm(%p) Error!!!", MyDisasm.EIP);
- MyOutputDebugStringA("AddHook Failed:0x%p", dwHookAddr);
- return false;
- }
- MyOutputDebugStringA("Addr = 0x%p nInstLen = %d %s", MyDisasm.EIP, nInstLen, MyDisasm.CompleteInstr);
- if (MyDisasm.Instruction.BranchType == RetType)
- {
- MyOutputDebugStringA("要hook的地址开始,后面5个字节对应的指令,不能有ret");
- MyOutputDebugStringA("AddHook Failed:0x%p", dwHookAddr);
- return false;
- }
- nSize += nInstLen;
- //汇编,先反汇编再汇编的好处在于不用修正相对偏移地址
- XEDPARSE parse;
- memset(&parse, 0, sizeof(parse));
- parse.x64 = false;
- parse.cip = dwASM;
- memset(parse.instr, 0, 256);
- memcpy(parse.instr, MyDisasm.CompleteInstr, 64);
- XEDPARSE_STATUS status = XEDParseAssemble(&parse);
- if (status == XEDPARSE_ERROR)
- {
- MyOutputDebugStringA("Parse Error:%s", parse.error);
- MyOutputDebugStringA("AddHook Failed:0x%p", dwHookAddr);
- return false;
- }
- memcpy(&Shell[dwASM - dwStart], &parse.dest[0], parse.dest_size);
-
- dwASM += parse.dest_size;
- MyDisasm.EIP += nInstLen;
- if (nSize >= 5)
- {
- m_dwRetAddr = MyDisasm.EIP;
- m_dwHookAddr = dwHookAddr;
- break;
- }
- }
- BYTE PushRet[6] = {0x68, 0x90, 0x90, 0x90, 0x90, 0xC3};
- memcpy(&PushRet[1], &m_dwRetAddr, 4);
- memcpy(&Shell[dwASM - dwStart], &PushRet[0], 6);
- //Shell整理好了 写过去
- memcpy((LPVOID)dwStart, Shell, 0x100);
-
- BYTE jmpcode[] = {0xE9, 0xFF, 0xFF, 0xFF, 0xFF}; //jmp Start
- DWORD VA = dwStart - dwHookAddr - 5;
- memcpy(&jmpcode[1], &VA, 4);
- //hook jmp Start;
- memcpy((LPVOID)dwHookAddr, jmpcode, sizeof(jmpcode) / sizeof(jmpcode[0]));
- VirtualProtect((LPVOID)dwHookAddr, 5, dwOldProtect, &dwOldProtect);
-
- MyOutputDebugStringA("AddHook Success:0x%p", dwHookAddr);
- return true;
- }
-
-
- // 移除Hook
- bool CHook::RemoveHook(void)
- {
- //还原原始机器码
- if (m_dwHookAddr == 0)
- {
- return false;
- }
- DWORD dwOldProtect = 0;
- VirtualProtect((LPVOID)m_dwHookAddr, 0x20, PAGE_EXECUTE_READWRITE, &dwOldProtect);
- memcpy((LPVOID)m_dwHookAddr, m_OldCode, 5);
- VirtualProtect((LPVOID)m_dwHookAddr, 5, dwOldProtect, &dwOldProtect);
-
- return true;
- }
复制代码
核心代码就这些了,由于使用反汇编,汇编库,实现起来代码非常简单,连注释一起也就150行代码哈,下面讲一下如何使用。
使用方法
0x00:将MyOutputDebugString.h,MyOutputDebugString.cpp,Hook.h,Hook.cpp,bea文件夹,XEDParse文件夹复制到自己项目的代码目录。
0x01:将MyOutputDebugString.h,MyOutputDebugString.cpp,Hook.h,Hook.cpp添加到项目中。
0x02:在需要使用hook的地方,#include "Hook.h",然后就可以使用了。
0x03:使用示例如下
- CHook hook1;
-
- void MyHookPro()
- {
- //hook回调函数,这里写自己的代码
- }
-
- hook1.AddHook(dwHookAddr,MyHookPro);
复制代码
HookDll Demo核心代码:
- #include "stdafx.h"
- #include "Hook.h"
- #include "MyOutputDebugString.h"
-
- CHook hook1;
- CHook hook2;
- CHook hook3;
- CHook hook4;
-
- wchar_t szTitle[] = L"Tip:Modify by sunflover";
- void Hook1Proc(void)
- {
- //在这里添加你的代码
- MyOutputDebugStringA("Hook1Proc EAX = 0x%.8X ECX = 0x%.8X EDX = 0x%.8X EBX = 0x%.8X ESP = 0x%.8X EBP = 0x%.8X ESI = 0x%.8X EDI = 0x%.8X",
- hook1.m_Context.EAX,hook1.m_Context.ECX,hook1.m_Context.EDX,hook1.m_Context.EBX,
- hook1.m_Context.ESP,hook1.m_Context.EBP,hook1.m_Context.ESI,hook1.m_Context.EDI);
-
- //$ ==> > 00405AAE /CALL 到 MessageBoxW 来自 HookTest.00405AA8
- //$+4 > 00120A06 |hOwner = 00120A06 ('HookDemo',class='#32770')
- //$+8 > 00550BB8 |Text = "www.jmpoep.com"
- //$+C > 02607D40 |Title = "HookTest"
- //$+10 > 00000000 \Style = MB_OK|MB_APPLMODAL
- //这里我们改变消息框的标题吧。
- LPVOID ppTitle= (LPVOID)(hook1.m_Context.ESP +0xC);
- DWORD pszTitle = (DWORD)&szTitle[0];
- memcpy(ppTitle,&pszTitle,4);
- }
-
- void Hook2Proc(void)
- {
- //在这里添加你的代码
- MyOutputDebugStringA("Hook2Proc EAX = 0x%.8X ECX = 0x%.8X EDX = 0x%.8X EBX = 0x%.8X ESP = 0x%.8X EBP = 0x%.8X ESI = 0x%.8X EDI = 0x%.8X",
- hook2.m_Context.EAX,hook2.m_Context.ECX,hook2.m_Context.EDX,hook2.m_Context.EBX,
- hook2.m_Context.ESP,hook2.m_Context.EBP,hook2.m_Context.ESI,hook2.m_Context.EDI);
- }
-
- void Hook3Proc(void)
- {
- //在这里添加你的代码
- MyOutputDebugStringA("Hook3Proc EAX = 0x%.8X ECX = 0x%.8X EDX = 0x%.8X EBX = 0x%.8X ESP = 0x%.8X EBP = 0x%.8X ESI = 0x%.8X EDI = 0x%.8X",
- hook3.m_Context.EAX,hook3.m_Context.ECX,hook3.m_Context.EDX,hook3.m_Context.EBX,
- hook3.m_Context.ESP,hook3.m_Context.EBP,hook3.m_Context.ESI,hook3.m_Context.EDI);
- //这里就简单的弹出个消息框
- MessageBoxA(NULL, "Hook3Proc\tBy sunflover","www.jmpoep.com",MB_ICONINFORMATION);
- }
-
- void Hook4Proc(void)
- {
- //在这里添加你的代码
- MyOutputDebugStringA("Hook3Proc EAX = 0x%.8X ECX = 0x%.8X EDX = 0x%.8X EBX = 0x%.8X ESP = 0x%.8X EBP = 0x%.8X ESI = 0x%.8X EDI = 0x%.8X",
- hook4.m_Context.EAX,hook4.m_Context.ECX,hook4.m_Context.EDX,hook4.m_Context.EBX,
- hook4.m_Context.ESP,hook4.m_Context.EBP,hook4.m_Context.ESI,hook4.m_Context.EDI);
- }
-
- //bug1:要hook的地址开始后5个字节,不会retn,如下hook 00405AC5 处会失败,hook 00405AC0成功
- //00405ABD |. 8B45 E4 mov eax,[local.7]
- //00405AC0 |> E8 C0CB0F00 call HookDemo.00502685
- //00405AC5 \. C3 retn
- //00405AC6 /$ 33C0 xor eax,eax
- //00405AC8 |. 3945 E4 cmp [local.7],eax
-
-
- //请使用Release目录的HookTest.exe测试hook
-
- BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
- {
- switch (ul_reason_for_call)
- {
- case DLL_PROCESS_ATTACH:
- {
- DWORD dwAddrMSGBOX = (DWORD)GetProcAddress(GetModuleHandle("user32.dll"), "MessageBoxW");
- hook1.AddHook(dwAddrMSGBOX, Hook1Proc);
- hook2.AddHook(0x00405AB1, Hook2Proc);
- hook3.AddHook(0x00405AC0, Hook3Proc);
- hook4.AddHook(0x00405AC5, Hook4Proc);//ret处hook会失败
- }
- case DLL_THREAD_ATTACH:
- case DLL_THREAD_DETACH:
- case DLL_PROCESS_DETACH:
- break;
- }
- return TRUE;
- }
复制代码
理论上存在的问题(也因为这点所以叫伪任意地址Hook):
0x00:要hook的地址开始后5个字节,不能有retn,如下hook 00405AC5 处会失败,hook 00405AC0成功
//00405ABD |. 8B45 E4 mov eax,[local.7]
//00405AC0 |> E8 C0CB0F00 call HookDemo.00502685
//00405AC5 \. C3 retn
//00405AC6 /$ 33C0 xor eax,eax
//00405AC8 |. 3945 E4 cmp [local.7],eax
|
|