64位的Win7下拦截malloc函数

目前大多数项目都在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;
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值