目前大多数项目都在64位系统下开发,很多时候不知道是否malloc溢出,所以我专门花了些时间,写了一个如何拦截malloc的示例程序。
注意:该程序必须在64位Release版本下运行,如果是DeBug版本的话,因为编译器没做优化和加了一些debug代码,所以会内存读写报错
// 说明:此test.cpp文件为win7下,对msvcr100.dll动态库中的maollc函数的hook测试文件,
// 即拦截win7平台下Release版本的malloc函数
//
// 作者:过客
// 邮箱:386520874@qq.com
// 日期:2017.04.17
#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
typedef HANDLE (__stdcall * PFN_GETCURRENTPROCESS)(void);
typedef BOOL (__stdcall * PFN_WRITEPROCESSMEMORY)(HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T *);
typedef DWORD (__stdcall * PFN_GETCURRENTTHREADID)(void);
typedef void * (__cdecl * PFN_MALLOC)(size_t _Size);
typedef int (__cdecl * PFN_PRINTF)(const char * _Format, ...);
//------------------------------------------------
#pragma pack(1) //#pragma pack(push, 4) 说明:可以1字节对齐也可以4字节对齐,此处非常重要
typedef struct HOOK_PARAM
{
DWORD pGetCurrentProcess;
DWORD pWriteProcessMemory;
DWORD pGetCurrentThreadId;
DWORD pMalloc;
DWORD pPrintf;
long long malloc_param_1; //用于保存malloc的输入参数值
long long nextIpAddr; //64位地址
void * pMallocReturn; //用于保存malloc的返回值
DWORD currentThreadId; //用于保存GetCurrentThreadId的返回值
char oldCode[20];
char newCode[20];
char str[100];
char str_format[100]; //printf的参数
}HOOK_PARAM;
#pragma pack() //#pragma pack(pop)
//------------------------------------------------
void * my_hook_malloc(void *lParam)
{
HOOK_PARAM * p = (HOOK_PARAM *)lParam;
PFN_GETCURRENTPROCESS pfnGetCurrentProcess = (PFN_GETCURRENTPROCESS)(p->pGetCurrentProcess);
PFN_WRITEPROCESSMEMORY pfnWriteProcessMemory = (PFN_WRITEPROCESSMEMORY)(p->pWriteProcessMemory);
PFN_GETCURRENTTHREADID pfnGetCurrentThreadId = (PFN_GETCURRENTTHREADID)(p->pGetCurrentThreadId);
PFN_MALLOC pfnMalloc = (PFN_MALLOC)(p->pMalloc);
PFN_PRINTF pfnPrintf = (PFN_PRINTF)(p->pPrintf);
//恢复API原来的样子,即摘掉API钩子
pfnWriteProcessMemory(pfnGetCurrentProcess(), (LPVOID)pfnMalloc, (LPCVOID)(p->oldCode), 20, NULL);
//调用正常的malloc
p->pMallocReturn = pfnMalloc(p->malloc_param_1);
//调用win32 API GetCurrentThreadId()
p->currentThreadId = pfnGetCurrentThreadId();
//-------------------------------------------------
pfnPrintf(p->str_format, p->currentThreadId, p->currentThreadId, p->malloc_param_1, p->malloc_param_1); //将hook到的信息打印出来
return p->pMallocReturn; //将malloc申请的内存地址返回
}
//---------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
//--------------------------
HOOK_PARAM hook_param = {0};
::GetCurrentThreadId();
HMODULE hKernel32 = LoadLibraryA("kernel32.dll");
HMODULE hMsvcr100 = LoadLibraryA("msvcr100.dll");
hook_param.pGetCurrentProcess = (DWORD)GetProcAddress(hKernel32, "GetCurrentProcess");
hook_param.pWriteProcessMemory = (DWORD)GetProcAddress(hKernel32, "WriteProcessMemory");
hook_param.pGetCurrentThreadId = (DWORD)GetProcAddress(hKernel32, "GetCurrentThreadId");
hook_param.pMalloc = (DWORD)GetProcAddress(hMsvcr100, "malloc");
hook_param.pPrintf = (DWORD)GetProcAddress(hMsvcr100, "printf");
hook_param.malloc_param_1 = 0x12345678;
// sprintf(hook_param.str, "malloc(): size = ");
sprintf(hook_param.str_format, "GetCurrentThreadId() = %%ld = 0x%%X; malloc(): size = %%ld = 0x%%X;\n");
//---------------------------------------------
HANDLE hProcess = GetCurrentProcess();
int size_Func = 1024 * 1;
DWORD dwFunAddr = (DWORD)VirtualAllocEx(hProcess, NULL, size_Func, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); //在进程空间申请内存
memset((void *)dwFunAddr, 0, size_Func);
int size_Param = sizeof(HOOK_PARAM);
DWORD dwParmaAddr = (DWORD)VirtualAllocEx(hProcess, NULL, size_Param, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); //在进程空间申请内存
//---------------------------------------------
hook_param.newCode[0] = 0x51; //push rcx //将 char * p = (char *)malloc(0x0637); 的参数 0x0637 入栈
hook_param.newCode[1] = 0x68; //0x68: push newcode[2..5],参数先压栈
hook_param.newCode[2] = (dwParmaAddr << 24) >> 24;
hook_param.newCode[3] = (dwParmaAddr << 16) >> 24;
hook_param.newCode[4] = (dwParmaAddr << 8 ) >> 24;
hook_param.newCode[5] = (dwParmaAddr << 0 ) >> 24;
hook_param.newCode[6] = 0x59; //pop ecx
hook_param.newCode[7] = 0x67; //pop qword ptr [ecx + 14h] // hook_param.malloc_param_1 = 0x0637; 将malloc(size);的size参数偷偷保存起来
hook_param.newCode[8] = 0x8F;
hook_param.newCode[9] = 0x41;
hook_param.newCode[10] = 0x14;
hook_param.newCode[11] = 0x48; //sub rsp, 20h //目的是平衡栈
hook_param.newCode[12] = 0x83;
hook_param.newCode[13] = 0xEC;
hook_param.newCode[14] = 0x18;
int offsetaddr = dwFunAddr - (int)hook_param.pMalloc - 20;
hook_param.newCode[15] = 0xE8; //0xE8: call newcode[16..19],然后调用函数 my_hook_malloc
hook_param.newCode[16] = (offsetaddr << 24) >> 24;
hook_param.newCode[17] = (offsetaddr << 16) >> 24;
hook_param.newCode[18] = (offsetaddr << 8 ) >> 24;
hook_param.newCode[19] = (offsetaddr << 0 ) >> 24;
char add_rsp[5] = {0};
add_rsp[0] = 0x48; //add rsp, 20h //目的是平衡栈
add_rsp[1] = 0x83;
add_rsp[2] = 0xC4;
add_rsp[3] = 0x20;
add_rsp[4] = 0xC3; //ret
//---------------------------------------------
SIZE_T dwNumberOfBytesRead = 0;
BOOL ret4 = ::ReadProcessMemory(hProcess, (LPCVOID)hook_param.pMalloc, hook_param.oldCode, 20, &dwNumberOfBytesRead); //将malloc函数体原始的前20个字节保存起来,以便hook后恢复
BOOL ret5 = ::WriteProcessMemory(hProcess, (LPVOID)hook_param.pMalloc, &hook_param.newCode, 20, &dwNumberOfBytesRead); //在新申请的进程地址空间,写函数my_hook_malloc的参数
BOOL ret6 = ::WriteProcessMemory(hProcess, (LPVOID)dwFunAddr, &my_hook_malloc, size_Func, &dwNumberOfBytesRead); //将编译后的函数体写到新申请的进程地址空间
BOOL ret7 = ::WriteProcessMemory(hProcess, (LPVOID)(dwFunAddr + 0x8A), &add_rsp, 5, &dwNumberOfBytesRead); //此处目的是为了能正常返回main函数领空, 0x8A是原始函数体的大小
BOOL ret8 = ::WriteProcessMemory(hProcess, (LPVOID)dwParmaAddr, &hook_param, size_Param, &dwNumberOfBytesRead);
char * p = (char *)malloc(0x0637);
sprintf(p, "dddddddd 6666666666: 我hook malloc成功啦! 嚯嚯嚯!");
printf("%s\n", p);
free(p);
CloseHandle(hProcess);
return 0;
}