加密与解密之hook函数

描述

  • 拦截messagebox函数,调用自己的MyMessageBox,然后再调用原函数

原理

  • 本文进行了针对程序输入表的address hook,通过GetProcAddress获取原messagebox的地址,通过比对IAT内的地址,找到存放messagebox的项,将其替换为MyMessageBox的地址
  • 将MyMessageBox实现的代码放到dll中,注入到目标程序中使用,在MyMessageBox函数的最后调用了原messagebox,实现Detour

步骤

  • 编写dll,这里随便加了一个导出函数MyTestFunc,用于注入
#include <windows.h>
#include <cstdio>

//创建相同函数指针.
typedef int (WINAPI* PfnMsgA)(
	_In_opt_ HWND hWnd,
	_In_opt_ LPCSTR lpText,
	_In_opt_ LPCSTR lpCaption,
	_In_ UINT uType);

PfnMsgA g_OldPfnMsgA = nullptr;


int WINAPI MyMessageBox(_In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText, _In_opt_ LPCSTR lpCaption, _In_ UINT uType)
{

	char sz1[] = "检测到原来的输出为:";
	char sz2[] = "\n将输出修改为:进入游戏失败哈哈!";
	strcat(sz1, (char*)lpText);
	strcat(sz1, sz2);
	if (g_OldPfnMsgA != nullptr)
	{
		return g_OldPfnMsgA(hWnd, sz1, lpCaption, uType);//调用以前的
	}
	return 0;
}
void SetIatHook()
{
	MessageBoxA(NULL, "开始进行HOOK", "提示", NULL);
	PVOID pHookAddress = nullptr;
	pHookAddress = GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA"); //你要HOOK的函数.
	if (nullptr == pHookAddress)
	{
		OutputDebugString(TEXT("获取函数地址失败"));
		MessageBoxA(NULL, "获取函数地址失败HOOK", NULL, NULL);

		return;
	}
	printf("msgbox函数地址为:%llx", pHookAddress);

	g_OldPfnMsgA = (PfnMsgA)pHookAddress; //保存旧的函数指针.
	//解析PE头.寻找IAT.

	HMODULE hModImageBase = GetModuleHandle(NULL);//获取当前的ImagBase
	PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)(DWORD_PTR)hModImageBase; //获取DOS头
	DWORD_PTR dwTemp = (DWORD_PTR)pDosHead + (DWORD_PTR)pDosHead->e_lfanew;
	PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)dwTemp;
	PIMAGE_FILE_HEADER pFileHead = (PIMAGE_FILE_HEADER)&pNtHead->FileHeader;
	PIMAGE_OPTIONAL_HEADER pOptHead = (PIMAGE_OPTIONAL_HEADER)&pNtHead->OptionalHeader;

	//寻找导出表的位置.
	DWORD_PTR dwExportLocal = pOptHead->DataDirectory[1].VirtualAddress; //找到导出表偏移.
	//定位到导出表
	dwTemp = (DWORD_PTR)GetModuleHandle(NULL) + dwExportLocal;
	PIMAGE_IMPORT_DESCRIPTOR   pImport = (PIMAGE_IMPORT_DESCRIPTOR)dwTemp;
	PIMAGE_IMPORT_DESCRIPTOR   pCurrent = pImport;
	DWORD_PTR* pFirstThunk; //导入表子表,也就是IAT存储函数地址的表.
	//遍历导入表

	while (pCurrent->Characteristics && pCurrent->FirstThunk != NULL)
	{
		dwTemp = pCurrent->FirstThunk + (DWORD_PTR)GetModuleHandle(NULL);//找到导入表
		pFirstThunk = (DWORD_PTR*)dwTemp; //加上偏移才是真正的导入表.
		while (*(DWORD_PTR*)pFirstThunk != NULL)
		{
			//遍历子表
			if (*(DWORD_PTR*)pFirstThunk == (DWORD_PTR)g_OldPfnMsgA)
			{
				//找到要修改的导入表了//修改内存保护属性.写入我们新的函数地址.
				DWORD oldProtected;
				VirtualProtect(pFirstThunk, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected);
				dwTemp = (DWORD_PTR)MyMessageBox;
				memcpy(pFirstThunk, (DWORD_PTR*)&dwTemp, 8); //将变量中保存的函数地址拷贝到导入表中.
				VirtualProtect(pFirstThunk, 0x1000, oldProtected, &oldProtected);
				MessageBoxA(NULL, "修改函数完毕!", "提示", NULL);
			}
			pFirstThunk++; //继续遍历.
		}
		pCurrent++; //每次是加一个导入表结构.
	}

}


void UnIatHook()
{
	/*
	  1.遍历导入表.恢复导入表即可.
	*/

	MessageBoxA(NULL, "开始进行HOOK", NULL, NULL);
	PVOID64 pHookAddress = nullptr;
	pHookAddress = MyMessageBox;
	if (nullptr == pHookAddress)
	{
		OutputDebugString(TEXT("获取函数地址失败"));
		MessageBoxA(NULL, "恢复函数地址失败HOOK", NULL, NULL);
		return;
	}
	//解析PE头.寻找IAT.

	HMODULE hModImageBase = GetModuleHandle(NULL);//获取当前的ImagBase
	PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)(DWORD)hModImageBase; //获取DOS头
	DWORD dwTemp = (DWORD)pDosHead + (DWORD)pDosHead->e_lfanew;
	PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)dwTemp;
	PIMAGE_FILE_HEADER pFileHead = (PIMAGE_FILE_HEADER)&pNtHead->FileHeader;
	PIMAGE_OPTIONAL_HEADER pOptHead = (PIMAGE_OPTIONAL_HEADER)&pNtHead->OptionalHeader;

	//寻找导出表的位置.
	DWORD dwExportLocal = pOptHead->DataDirectory[1].VirtualAddress; //找到导出表偏移.
	//定位到导出表
	dwTemp = (DWORD)GetModuleHandle(NULL) + dwExportLocal;
	PIMAGE_IMPORT_DESCRIPTOR   pImport = (PIMAGE_IMPORT_DESCRIPTOR)dwTemp;
	PIMAGE_IMPORT_DESCRIPTOR   pCurrent = pImport;
	DWORD* pFirstThunk; //导入表子表
	//遍历导入表

	while (pCurrent->Characteristics && pCurrent->FirstThunk != NULL)
	{
		dwTemp = pCurrent->FirstThunk + (DWORD)GetModuleHandle(NULL);
		pFirstThunk = (DWORD*)dwTemp; //加上偏移才是真正的导入表.
		while (*(DWORD*)pFirstThunk != NULL)
		{
			//遍历子表
			if (*(DWORD*)pFirstThunk == (DWORD)MyMessageBox) //如果是我们的函数地址.则进行恢复.
			{
				//找到要修改的导入表了//修改内存保护属性.写入我们新的函数地址.
				DWORD oldProtected;
				VirtualProtect(pFirstThunk, 0x1000, PAGE_EXECUTE_READWRITE, &oldProtected);
				dwTemp = (DWORD)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");
				memcpy(pFirstThunk, (DWORD*)&dwTemp, 4); //将变量中保存的函数地址拷贝到导入表中.
				VirtualProtect(pFirstThunk, 0x1000, oldProtected, &oldProtected);
			}
			pFirstThunk++; //继续遍历.
		}
		pCurrent++; //每次是加一个导入表结构.
	}
}

extern "C" __declspec(dllexport) int MyTestFunc(int a, int b)
{
	return a + b;
}

BOOL APIENTRY DllMain(HMODULE hModule,
	DWORD  ul_reason_for_call,
	LPVOID lpReserved
)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		SetIatHook();
		break;
	case DLL_THREAD_ATTACH:
		break;
	case DLL_THREAD_DETACH:

		break;
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}
  • 通过PE Tools修改原程序输入表,注入dll

效果

  • 将HookMsg.dll放到原程序目录下,运行原程序,成功拦截原messagebox调用
posted @ 2023-04-04 17:00  z5onk0  阅读(150)  评论(0编辑  收藏  举报