简单的内存监视实现

简单的内存监视实现

 

前言:

 

  前段时间学习了API HOOK,对这技术也略知一二,决定利用这技术实现个小功能。

 

以前有用过某工具,可以偷取别人外挂的功能地址,当时想想觉得挺不可思议的,如今了解API HOOK后,觉得这功能也就那样。

 

废话不多说,进入正题。

 

一、    HOOK WriteProcessMemory

 

首先看看WriteProcessMemory()原型:

BOOL WriteProcessMemory(
  HANDLEhProcess,               // handle to process
  LPVOIDlpBaseAddress,          // base of memory area
  LPVOIDlpBuffer,               // data buffer
  DWORDnSize,                   // number of bytes to write
  LPDWORDlpNumberOfBytesWritten // number of bytes written
);

如何实现呢?其实很简单,我们只需是获取hProcess/ lpBaseAddress/ nSize/ lpBuffer这四个参数。

 

我们定义一个结构体:

typedef struct HookData

     {

         HANDLE hProcess,               // handle to process

         LPVOID lpBaseAddress,          // base of memory area

         LPVOID lpBuffer,               // data buffer

         DWORD nSize,                   // number of bytes to write

 

     }HookData,*pHookData;

并定义一个全局变量HookData g_hookdata;

 

在我们自己的函数体里保存四个参数,然后返回原函数:

BOOL MyWriteProcessMemory(

                            HANDLE hProcess,               // handle to process

                            LPVOID lpBaseAddress,          // base of memory area

                            LPVOID lpBuffer,               // data buffer

                            DWORD nSize,                   // number of bytes to write

                            LPDWORD lpNumberOfBytesWritten // number of bytes written

                            )

{

     g_hookdata.hProcess = hProcess;

     g_hookdata.lpBaseAddress = lpBaseAddress;

     g_hookdata.lpBuffer = lpBuffer;

     g_hookdata.nSize =nSize;

     return WriteProcessMemory(hProcess,lpBaseAddress,lpBuffer,nSize,lpNumberOfBytesWritten);

}

 

获取这四个参数后,如何将这些数据取出来,我这里抛砖引玉,用一种笨方法,把数据以文件方式保存,然后外部程序读取:

BOOL SaveHookData(HANDLE hpro,pHookData phd)

{

     if (g_hookdata.hProcess != hpro)//判断是否对目标进程HOOK成功

         return FALSE;

 

     FILE *fp = fopen("hookdata","r+");

     if (!fp)

         return FALSE;      //打开文件失败

 

     if (!fwrite(phd,sizeof(HookData),sizeof(phd),fp))

     {

         fclose(fp);

         return FALSE;

     }

     fclose(fp);

     return TRUE;

}

 

BOOL TakeHookData(pHookData phd)

{

     FILE *fp = fopen("c:\\hookdata","r+");

     if (!fp)

         return FALSE;      //打开文件失败

 

     if (!fread(phd,sizeof(HookData),1,fp))

     {

         fclose(fp);

         return FALSE;

     }

     fclose(fp);

     return TRUE;

}

 

 

二、HOOK ReadProcessMemory

 

         ReadProcessMemory()原型:

BOOL ReadProcessMemory(

  HANDLE hProcess,             // handle to the process

  LPCVOID lpBaseAddress,       // base of memory area

  LPVOID lpBuffer,             // data buffer

  DWORD nSize,                 // number of bytes to read

  LPDWORD lpNumberOfBytesRead  // number of bytes read

);

 

  同HOOK WriteProcessMemory()类似,需要获取 hProcess/ lpBaseAddress/ nSize/ lpBuffer这四个参数,不过有一点不同,ReadProcessMemory()的lpBuffer参数不是在一开始就有数据。我们先看看ReadProcessMemory 的反汇编代码:

 

751A9982 >    8BFF          mov     edi, edi                                    ; 

751A9984   .  55            push    ebp

751A9985   .  8BEC          mov     ebp, esp

751A9987   .  8D45 14       lea     eax, dword ptr [ebp+14]

751A998A   . 50            push    eax                                         ;

751A998B   .  FF75 14       push    dword ptr [ebp+14]                          ;  地址

751A998E   .  FF75 10       push    dword ptr [ebp+10]                          ;  data buffer

751A9991   .  FF75 0C       push    dword ptr [ebp+C]                           ;  nSize

751A9994   .  FF75 08       push    dword ptr [ebp+8]                           ; 

751A9997   .  FF15 B4111A75 call    dword ptr [<&ntdll.NtReadVirtualMemory>]    ;  ntdll.ZwReadVirtualMemory

751A999D   .  8B4D 18       mov     ecx, dword ptr [ebp+18]

751A99A0   .  85C9          test    ecx, ecx

751A99A2   .  75 0F         jnz     short 751A99B3

751A99A4   >  85C0          test    eax, eax

751A99A6   .  0F8C 789E0100 jl      751C3824

751A99AC   .  33C0          xor     eax, eax

751A99AE   .  40            inc     eax

751A99AF   >  5D            pop     ebp

751A99B0   .  C2 1400       retn    14

751A99B3   >  8B55 14       mov     edx, dword ptr [ebp+14]                     ;  LPCVOID lpBaseAddress,       // base of memory area

751A99B6   .  8911          mov     dword ptr [ecx], edx                        ;  lpBuffer,             // data buffer

751A99B8   .^ EB EA         jmp     short 751A99A4

 

 

  我们可以得出当程序执行到751A99B3才开始读取lpBaseAddress的值到lpBuffer,所以如果HOOK函数头,那么截取到的内容肯定为空。

那到底如何实现呢?其实有个很取巧的方法,我们同样HOOK函数头,截取lpBaseAddress参数后再自己手动将该地址的内容读取出来,用memcpy()函数就能实现。

实现方法与上面的HOOK WriteProcessMemory类似,没必要重复写了。

 

 

三、总结

 

  相信看完篇文章,你可以揭开“偷取外挂功能地址”的神秘面纱。由于本人也是菜鸟,只能完成这些,代码没有经过测试,有什么地方有错误,可以给我留言,大家一起探讨,大神们看完可以指点指点。

  本文所实现的方法对做了反监视、非远程内存读写式外挂无效,对于后者,只要弄清楚外挂的实现方式,理论上按照本方法,HOOK关键函数,是可以完成的。

 

 

 

JJHUANG

2013/8/28

你可能感兴趣的:(内存)