龙马谷

 找回密码
 立即注册

QQ登录

只需一步,快速开始

龙马谷VIP会员办理客服QQ:82926983(如果临时会话没有收到回复,请先加QQ好友再发。)
1 [已完结] GG修改器新手入门与实战教程 31课 2 [已完结] GG修改器美化修改教程 6课 3 [已完结] GG修改器Lua脚本新手入门教程 12课
4 [已完结] 触动精灵脚本新手入门必学教程 22课 5 [已完结] 手游自动化脚本入门实战教程 9课 6 [已完结] C++射击游戏方框骨骼透视与自瞄教程 27课
7 [已完结] C++零基础UE4逆向开发FPS透视自瞄教程 29课 8 [已完结] C++零基础大漠模拟器手游自动化辅助教程 22课 9 [已完结] C++零基础开发DXF内存脚本辅助教程 32课
以下是天马阁VIP教程,本站与天马阁合作,赞助VIP可以获得天马阁对应VIP会员,名额有限! 点击进入天马阁论坛
1 [已完结] x64CE与x64dbg入门基础教程 7课 2 [已完结] x64汇编语言基础教程 16课 3 [已完结] x64辅助入门基础教程 9课
4 [已完结] C++x64内存辅助实战技术教程 149课 5 [已完结] C++x64内存检测与过检测技术教程 10课 6 [已完结] C+x64二叉树分析遍历与LUA自动登陆教程 19课
7 [已完结] C++BT功能原理与x64实战教程 29课 8 [已完结] C+FPS框透视与自瞄x64实现原理及防护思路
查看: 5715|回复: 0

C++ 伪任意地址HOOK类源码

[复制链接]

6

主题

10

回帖

18

积分

编程入门

Rank: 1

龙马币
22

C++ 伪任意地址HOOK类源码

前言:

代码HOOK技术不管在安全领域还是在木马病毒方面都运用很广泛,因为他可以改变程序执行流程,悄无声息执行我们自己的代码。

之前我也用过一些hook类,如mhook等,但很多都局限于API HOOK,有的时候无法满足实际应用。也因此,我自己的hook类就诞生了。

先贴核心代码:

  1. /
  2. /Hook.h
  3. #pragma once

  4. struct t_Context
  5. {
  6.         DWORD EDI;
  7.         DWORD ESI;
  8.         DWORD EBP;
  9.         DWORD ESP;
  10.         DWORD EBX;
  11.         DWORD EDX;
  12.         DWORD ECX;
  13.         DWORD EAX;
  14. };

  15. class CHook
  16. {
  17. public:
  18.         CHook(void);
  19.         ~CHook(void);
  20.         // 添加Hook
  21.         bool AddHook(__in DWORD dwHookAddr, __in void *pfnHookProc);
  22.         // 移除Hook
  23.         bool RemoveHook();
  24.         // 寄存器结构体
  25.         t_Context m_Context;
  26.         // 返回地址,没有特殊需求不要修改这里
  27.         DWORD m_dwRetAddr;
  28. private:
  29.         // 保存Hook地址,用于RemoveHook
  30.         DWORD m_dwHookAddr;
  31.         // 保存原始字节,用于RemoveHook
  32.         BYTE m_OldCode[5];
  33. };
复制代码


  1. //Hook.cpp
  2. #include "StdAfx.h"
  3. #include "Hook.h"
  4. #include "MyOutputDebugString.h"

  5. //BeaEngine 反汇编引擎
  6. #define BEA_ENGINE_STATIC
  7. #define BEA_USE_STDCALL
  8. #include "bea/headers/BeaEngine.h"
  9. #pragma comment(lib, "bea/win32/lib/BeaEngine.lib")
  10. #pragma comment(linker,"/nodefaultlib:crt.lib")
  11. //BeaEngine end

  12. //XEDParse 汇编引擎
  13. #include "XEDParse/XEDParse.h"
  14. #pragma comment(lib,"XEDParse/XEDParse.lib")

  15. CHook::CHook(void)
  16. {
  17.         memset(&m_Context, 0, sizeof(m_Context));
  18.         memset(m_OldCode, 0x90, 5);
  19.         m_dwRetAddr = 0;
  20.         m_dwHookAddr = 0;
  21. }


  22. CHook::~CHook(void)
  23. {
  24. }


  25. // 添加Hook
  26. bool CHook::AddHook(__in DWORD dwHookAddr, __in void *lpHookProc)
  27. {
  28.         //00240000    60              PUSHAD
  29.         //00240001    9C              PUSHFD
  30.         //00240002    BF 00012400     MOV EDI,0x240100
  31.         //00240007    8BF4            MOV ESI,ESP
  32.         //00240009    83C6 04         ADD ESI,0x4
  33.         //0024000C    B9 20000000     MOV ECX,0x20
  34.         //00240011    F3:A4           REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]     ; 保存寄存器结构体,备用
  35.         //00240013    B8 90909090     MOV EAX,0x90909090
  36.         //00240018    FFD0            CALL EAX                                         ; 调用HookPro
  37.         //0024001A    9D              POPFD
  38.         //0024001B    61              POPAD
  39.         //0024001C    90              NOP                                              ; 个数等于被毁掉的指令总长度
  40.         //0024001D    68 90909090     PUSH 0x90909090                                  ; jmp back
  41.         //00240022    C3              RETN
  42.         //00240023    90              NOP
  43.         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};
  44.         int pContext = (int)&m_Context;
  45.         memcpy(&Shell[3], &pContext, 4);
  46.         int pHookProc = (int)lpHookProc;
  47.         memcpy(&Shell[0x14], &pHookProc, 4);

  48.         //保存原始机器码
  49.         DWORD dwOldProtect = 0;
  50.         BOOL bRet = VirtualProtect((LPVOID)dwHookAddr, 0x20, PAGE_EXECUTE_READWRITE, &dwOldProtect);
  51.         if (!bRet)
  52.         {
  53.                 MyOutputDebugStringA("VirtualProtect(0x%p) Error!!!", dwHookAddr);
  54.                 MyOutputDebugStringA("AddHook Failed:0x%p", dwHookAddr);
  55.                 return false;
  56.         }
  57.         memcpy(m_OldCode, (LPVOID)dwHookAddr, 5);//用于hook还原

  58.         DWORD dwStart = (DWORD)VirtualAlloc(NULL, 0x100, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  59.         if (dwStart == 0)
  60.         {
  61.                 OutputDebugStringA("VirtualAlloc Error!!!");
  62.                 MyOutputDebugStringA("AddHook Failed:0x%p", dwHookAddr);
  63.                 return false;
  64.         }

  65.         //开始解析原始指令,通过反汇编引擎,识别要Hook的地址处的指令,以及破坏的指令长度
  66.         int nSize = 0;//毁掉的指令的总字节数
  67.         DWORD dwASM = dwStart + 30;//30为前面shell前面部分代码长度

  68.         DISASM MyDisasm;
  69.         memset (&MyDisasm, 0, sizeof(DISASM));
  70.         MyDisasm.EIP = (UIntPtr)dwHookAddr;
  71.         MyDisasm.Options = PrefixedNumeral + ShowSegmentRegs;

  72.         while (1)
  73.         {
  74.                 //反汇编
  75.                 int nInstLen = Disasm(&MyDisasm);
  76.                 if (nInstLen < 1)
  77.                 {
  78.                         MyOutputDebugStringA("Disasm(%p) Error!!!", MyDisasm.EIP);
  79.                         MyOutputDebugStringA("AddHook Failed:0x%p", dwHookAddr);
  80.                         return false;
  81.                 }
  82.                 MyOutputDebugStringA("Addr = 0x%p nInstLen = %d %s", MyDisasm.EIP, nInstLen, MyDisasm.CompleteInstr);
  83.                 if (MyDisasm.Instruction.BranchType == RetType)
  84.                 {
  85.                         MyOutputDebugStringA("要hook的地址开始,后面5个字节对应的指令,不能有ret");
  86.                         MyOutputDebugStringA("AddHook Failed:0x%p", dwHookAddr);
  87.                         return false;
  88.                 }
  89.                 nSize += nInstLen;
  90.                 //汇编,先反汇编再汇编的好处在于不用修正相对偏移地址
  91.                 XEDPARSE parse;
  92.                 memset(&parse, 0, sizeof(parse));
  93.                 parse.x64 = false;
  94.                 parse.cip = dwASM;
  95.                 memset(parse.instr, 0, 256);
  96.                 memcpy(parse.instr, MyDisasm.CompleteInstr, 64);
  97.                 XEDPARSE_STATUS status = XEDParseAssemble(&parse);
  98.                 if (status == XEDPARSE_ERROR)
  99.                 {
  100.                         MyOutputDebugStringA("Parse Error:%s", parse.error);
  101.                         MyOutputDebugStringA("AddHook Failed:0x%p", dwHookAddr);
  102.                         return false;
  103.                 }
  104.                 memcpy(&Shell[dwASM - dwStart], &parse.dest[0], parse.dest_size);

  105.                 dwASM += parse.dest_size;
  106.                 MyDisasm.EIP  += nInstLen;
  107.                 if (nSize >= 5)
  108.                 {
  109.                         m_dwRetAddr = MyDisasm.EIP;
  110.                         m_dwHookAddr = dwHookAddr;
  111.                         break;
  112.                 }
  113.         }
  114.         BYTE PushRet[6] = {0x68, 0x90, 0x90, 0x90, 0x90, 0xC3};
  115.         memcpy(&PushRet[1], &m_dwRetAddr, 4);
  116.         memcpy(&Shell[dwASM - dwStart], &PushRet[0], 6);
  117.         //Shell整理好了 写过去
  118.         memcpy((LPVOID)dwStart, Shell, 0x100);

  119.         BYTE jmpcode[] = {0xE9, 0xFF, 0xFF, 0xFF, 0xFF}; //jmp Start
  120.         DWORD VA =  dwStart - dwHookAddr - 5;
  121.         memcpy(&jmpcode[1], &VA, 4);
  122.         //hook jmp Start;
  123.         memcpy((LPVOID)dwHookAddr, jmpcode, sizeof(jmpcode) / sizeof(jmpcode[0]));
  124.         VirtualProtect((LPVOID)dwHookAddr, 5, dwOldProtect, &dwOldProtect);

  125.         MyOutputDebugStringA("AddHook Success:0x%p", dwHookAddr);
  126.         return true;
  127. }


  128. // 移除Hook
  129. bool CHook::RemoveHook(void)
  130. {
  131.         //还原原始机器码
  132.         if (m_dwHookAddr == 0)
  133.         {
  134.                 return false;
  135.         }        
  136.         DWORD dwOldProtect = 0;
  137.         VirtualProtect((LPVOID)m_dwHookAddr, 0x20, PAGE_EXECUTE_READWRITE, &dwOldProtect);
  138.         memcpy((LPVOID)m_dwHookAddr, m_OldCode, 5);
  139.         VirtualProtect((LPVOID)m_dwHookAddr, 5, dwOldProtect, &dwOldProtect);

  140.         return true;
  141. }
复制代码



核心代码就这些了,由于使用反汇编,汇编库,实现起来代码非常简单,连注释一起也就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:使用示例如下
  1. CHook hook1;

  2. void MyHookPro()
  3. {
  4.         //hook回调函数,这里写自己的代码
  5. }

  6. hook1.AddHook(dwHookAddr,MyHookPro);
复制代码



HookDll Demo核心代码:

  1. #include "stdafx.h"
  2. #include "Hook.h"
  3. #include "MyOutputDebugString.h"

  4. CHook hook1;
  5. CHook hook2;
  6. CHook hook3;
  7. CHook hook4;

  8. wchar_t szTitle[] = L"Tip:Modify by sunflover";
  9. void Hook1Proc(void)
  10. {
  11.         //在这里添加你的代码
  12.         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",
  13.                 hook1.m_Context.EAX,hook1.m_Context.ECX,hook1.m_Context.EDX,hook1.m_Context.EBX,
  14.                 hook1.m_Context.ESP,hook1.m_Context.EBP,hook1.m_Context.ESI,hook1.m_Context.EDI);

  15.         //$ ==>    > 00405AAE  /CALL 到 MessageBoxW 来自 HookTest.00405AA8
  16.         //$+4      > 00120A06  |hOwner = 00120A06 ('HookDemo',class='#32770')
  17.         //$+8      > 00550BB8  |Text = "www.jmpoep.com"
  18.         //$+C      > 02607D40  |Title = "HookTest"
  19.         //$+10     > 00000000  \Style = MB_OK|MB_APPLMODAL
  20.         //这里我们改变消息框的标题吧。
  21.         LPVOID ppTitle= (LPVOID)(hook1.m_Context.ESP +0xC);
  22.         DWORD pszTitle = (DWORD)&szTitle[0];
  23.         memcpy(ppTitle,&pszTitle,4);
  24. }

  25. void Hook2Proc(void)
  26. {
  27.         //在这里添加你的代码
  28.         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",
  29.                 hook2.m_Context.EAX,hook2.m_Context.ECX,hook2.m_Context.EDX,hook2.m_Context.EBX,
  30.                 hook2.m_Context.ESP,hook2.m_Context.EBP,hook2.m_Context.ESI,hook2.m_Context.EDI);
  31. }

  32. void Hook3Proc(void)
  33. {
  34.         //在这里添加你的代码
  35.         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",
  36.                 hook3.m_Context.EAX,hook3.m_Context.ECX,hook3.m_Context.EDX,hook3.m_Context.EBX,
  37.                 hook3.m_Context.ESP,hook3.m_Context.EBP,hook3.m_Context.ESI,hook3.m_Context.EDI);
  38.         //这里就简单的弹出个消息框
  39.         MessageBoxA(NULL, "Hook3Proc\tBy sunflover","www.jmpoep.com",MB_ICONINFORMATION);
  40. }

  41. void Hook4Proc(void)
  42. {
  43.         //在这里添加你的代码
  44.         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",
  45.                 hook4.m_Context.EAX,hook4.m_Context.ECX,hook4.m_Context.EDX,hook4.m_Context.EBX,
  46.                 hook4.m_Context.ESP,hook4.m_Context.EBP,hook4.m_Context.ESI,hook4.m_Context.EDI);
  47. }

  48. //bug1:要hook的地址开始后5个字节,不会retn,如下hook 00405AC5 处会失败,hook 00405AC0成功
  49. //00405ABD  |.  8B45 E4       mov eax,[local.7]
  50. //00405AC0  |>  E8 C0CB0F00   call HookDemo.00502685
  51. //00405AC5  \.  C3            retn
  52. //00405AC6  /$  33C0          xor eax,eax
  53. //00405AC8  |.  3945 E4       cmp [local.7],eax


  54. //请使用Release目录的HookTest.exe测试hook

  55. BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
  56. {
  57.         switch (ul_reason_for_call)
  58.         {
  59.         case DLL_PROCESS_ATTACH:
  60.                 {
  61.                         DWORD dwAddrMSGBOX = (DWORD)GetProcAddress(GetModuleHandle("user32.dll"), "MessageBoxW");
  62.                         hook1.AddHook(dwAddrMSGBOX, Hook1Proc);
  63.                         hook2.AddHook(0x00405AB1, Hook2Proc);
  64.                         hook3.AddHook(0x00405AC0, Hook3Proc);
  65.                         hook4.AddHook(0x00405AC5, Hook4Proc);//ret处hook会失败         
  66.                 }
  67.         case DLL_THREAD_ATTACH:
  68.         case DLL_THREAD_DETACH:
  69.         case DLL_PROCESS_DETACH:
  70.                 break;
  71.         }
  72.         return TRUE;
  73. }
复制代码



理论上存在的问题(也因为这点所以叫伪任意地址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

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

龙马谷| C/C++辅助教程| 安卓逆向安全| 论坛导航| 免责申明|Archiver|
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表龙马谷立场!
任何人不得以任何方式翻录、盗版或出售本站视频,一经发现我们将追究其相关责任!
我们一直在努力成为最好的编程论坛!
Copyright© 2018-2021 All Right Reserved.
在线客服
快速回复 返回顶部 返回列表