伪任意地址HOOK类
2015-10-10 21:02
656 查看
前言:
代码HOOK技术不管在安全领域还是在木马病毒方面都运用很广泛,因为他可以改变程序执行流程,悄无声息执行我们自己的代码。
之前我也用过一些hook类,如mhook等,但很多都局限于API HOOK,有的时候无法满足实际应用。也因此,我自己的hook类就诞生了。
先贴核心代码(完整代码下载地址见本文结尾):
使用方法
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:使用示例如下
(其他编译选项可能会有问题,同样,使用其他编译器编译也可能有问题。)
理论上存在的问题(也因为这点所以叫伪任意地址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
完整源代码(VS2010编译)下载地址:
http://download.csdn.net/detail/sunflover454/9170633
代码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核心代码:
// dllmain.cpp : 定义 DLL 应用程序的入口点。 #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; }关于编译器和编译选项,我在这里也有必要提一下。我使用的VS2010,编译选项如下:
(其他编译选项可能会有问题,同样,使用其他编译器编译也可能有问题。)
理论上存在的问题(也因为这点所以叫伪任意地址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
完整源代码(VS2010编译)下载地址:
http://download.csdn.net/detail/sunflover454/9170633
相关文章推荐
- 1036. Boys vs Girls
- Monkey测试问题及解决方法
- iOS开发中的字典转模型应用
- 287款 图形和图像工具开源软件
- lintcode 容易题:Remove Element 删除元素
- 测试用例设计
- Android笔记--实现广播的使用
- bat批处理写法
- TCP/IP协议原理与应用笔记14:电路交换 和 分组交换
- 木马捆绑器设计思路和源码
- ios数据存储NSString,NSArray,NSDictionary
- 计算机视觉、机器学习相关领域论文和源代码大集合--持续更新……
- Json转为Map
- Install Caffe on CentOS 6.5
- UVA-1149 Bin Packing (贪心)
- 动手学习TCP:数据传输
- 二分——无序数组快速查找第K小的数
- iOS雨笙 NSTimer(计时器)和NSUserDefaults(最轻量级的持久化)的简单应用
- VMware虚拟机克隆Linux系统后找不到eth0网卡的问题
- 2014年去哪儿网笔试题--给定一个整型数组,对这个整型素组排序,使得按序拼接数组各元素得到的值最小