易语言教程_易语言源码_易语言写挂_易语言论坛_看流星社区

 找回密码
 注册
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
赞助广告位 请点击这里联系站长 QQ20209081
赞助广告位 请点击这里联系站长 QQ20209081
赞助广告位 请点击这里联系站长 QQ20209081
查看: 519|回复: 0

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

[复制链接]
发表于 2018-3-14 08:52:56 | 显示全部楼层 |阅读模式

前言:

代码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

点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
*滑动验证:
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|看流星社区  |网站地图

GMT+8, 2018-12-17 18:23 易语言论坛 易语言导航

Powered by 看流星社区 X3.2

©2011-2016 最好的辅助编程技术论坛

快速回复 返回顶部 返回列表