滴水逆向笔记系列-win32总结10-63.IAT HOOK-64.Inline HOOK

第六十三课 IAT HOOK

这节课得把前面PE部分的IAT表复习好,再来做就简单多了

1.IAT HOOK是什么

其实就是找到IAT表的位置再换成自己定义的函数,只是我们替换的函数需要和原函数的结构保持一直,比如我们要HOOK Messagebox函数,那么我们需要定义一个MyMessagebox函数,他的结构应该与Messagebox保持一致,只是我们函数的功能可以改变

2.IAT HOOK的用处

比原函数多出一些自己想要的操作,举一个最典型的例子,一些杀毒软件经常会在一些函数上面HOOK,做出一些检测监控的操作,监控函数的返回值,参数

3.IAT HOOK的实现代码

#include <windows.h>
#include <stdio.h>

typedef int (WINAPI* pMyMsg)(
	HWND   hWnd,
	LPCSTR lpText,
	LPCSTR lpCaption,
	UINT   uType
	);

pMyMsg pOldMsg = NULL;

int MyMessageBoxA(_In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText, _In_opt_ LPCSTR lpCaption, _In_ UINT uType)
{
	int result = pOldMsg(NULL, "IAT HOOK成功", "IAT HOOK", MB_OK);
	return result;
}


HMODULE hModImageBase = GetModuleHandle(NULL);
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModImageBase;
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)hModImageBase + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
PIMAGE_OPTIONAL_HEADER pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + 20);
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
PIMAGE_DATA_DIRECTORY pDataDirHeader = (PIMAGE_DATA_DIRECTORY)(pOptionalHeader->DataDirectory + 1);
PIMAGE_IMPORT_DESCRIPTOR pImportTbale = (PIMAGE_IMPORT_DESCRIPTOR)(pDataDirHeader->VirtualAddress + (DWORD)hModImageBase);
PIMAGE_THUNK_DATA32 image_thunk_data = (PIMAGE_THUNK_DATA32)pImportTbale->FirstThunk;

void SetIatHook()
{
	PVOID pHookAddress = nullptr;
	pHookAddress = GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");
	pOldMsg = (pMyMsg)pHookAddress;

	DWORD* pIATaddress;

	while (pImportTbale->FirstThunk != NULL)
	{
		//获取IAT表位置
		pIATaddress = (DWORD*)(pImportTbale->FirstThunk + (DWORD)hModImageBase);
		//pIATaddress = (DWORD*)(hModImageBase + pImportTbale->FirstThunk);
		while (*pIATaddress != NULL)
		{
			if (*pIATaddress == (DWORD)pOldMsg)
			{
				DWORD OldProtected;
				VirtualProtect((LPVOID)pIATaddress, 0x1000, PAGE_EXECUTE_READWRITE, &OldProtected);
				DWORD dwtemp = (DWORD)MyMessageBoxA;
				memcpy((LPVOID)pIATaddress, (DWORD*)&dwtemp, 4);
				VirtualProtect((LPVOID)pIATaddress, 0x1000, OldProtected, &OldProtected);
				
			}
			pIATaddress++;
			
		}
		
		pImportTbale++;
	}

}

int main()
{
	SetIatHook();
	MessageBoxA(NULL, "Hook测试", "标题", MB_OK);
	getchar();
}

注意:

1、pIATaddress = (DWORD)(pImportTbale->FirstThunk + (DWORD)hModImageBase);注意获取IAT表位置时把hModImageBase转换成DWORD类型,虽然编译不会报错但是运行时会报错内存无法访问,gpt说可能是由于指针的类型不匹配,导致了错误的内存地址计算,进而引发了内存访问错误
2、命令行程序没有引入user32,所以使用LoadLibrary
3、MyMessageBoxA的编写,需要使用Oldmessagebox的地址,而不是messagebox
4、memcpy((LPVOID)*pIATaddress, (DWORD*)&dwtemp, 4);
VirtualProtect((LPVOID)*pIATaddress, 0x1000, OldProtected, &OldProtected);这两句我原本写的是这样,其实不应该加

4.课上的两个思考

1、什么时候函数在IAT表里面没有
答:自己手动加载函数loadlibry时
2、定义MyMessagebox时改成这样子可不可以
image.png
答:这时候Messagebox已经换成了MyMessagebox,所以变成了死循环

5.IAT HOOK的局限性

有些不能HOOK,比如一些自己写的函数,或者自己手动load的函数,都不存在IAT表,所以都无法HOOK

第六十四课 Inline HOOK

inline HOOK就可以解决上节课IATHOOK的一些局限性,比如在自己写的函数内HOOK
E8 和 E9 后面4字节地址X的转换公式:X = 真正要跳转的地址 - E8这条指令的下一行地址

1.inline hook的一些细节

  • E9jmp后面的地址是需要根据一条公式来计算的
  • jmp过去后记得把原来两行代码执行了
  • jmp执行我们自己的代码前需要保存一下所有寄存器,以免我们在自己操作的时候改变了寄存器
  • 还要保存标志寄存器
  • jmp执行自己代码时要自己保证堆栈平衡(自己push自己pop),或者使用E8call

image.png

2.代码实现

参考了这位大佬的new函数编写https://github.com/LoveCppp/dishuinixiang/blob/main/win32/win32%E8%BF%9B%E7%A8%8B%E7%9B%91%E6%8E%A7%E9%A1%B9%E7%9B%AE/processmonitoring/processmon/InlineHOOK.cpp
第一版代码:有两处错误

#include <Windows.h>
#include <stdio.h>


typedef int (WINAPI* pMyMsg)(
	HWND   hWnd,
	LPCSTR lpText,
	LPCSTR lpCaption,
	UINT   uType
	);

pMyMsg pOldMsg = NULL;
PVOID pHookAddress = nullptr;


//定义newmessagebox函数
int WINAPI NewMessagebox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
	
	printf("HOOK成功");
	pOldMsg( hWnd,"HOOK成功", "HOOK", MB_OK);

	return 0;
}


//定义unhook函数



//定义hook函数
void SetHook()
{
	

	BYTE code[5] = { 0xe9, };
	BYTE OldCode[5];
	DWORD JmpAddress = (DWORD)NewMessagebox - ((DWORD)pOldMsg + 5);

	memcpy(&code[1],&JmpAddress,0x4);

	DWORD OldProtected;
	VirtualProtect((LPVOID)pOldMsg, 0x1000, PAGE_EXECUTE_READWRITE, &OldProtected);
	
	memcpy(OldCode, (LPVOID)pOldMsg,0x4);
	memcpy((LPVOID)pOldMsg,code, 0x5);
	VirtualProtect((LPVOID)pOldMsg, 0x1000, OldProtected, &OldProtected);
}

int main()
{
	pHookAddress = GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");
	pOldMsg = (pMyMsg)pHookAddress;
	SetHook();
	MessageBoxA(NULL, "after hook", "tips", MB_OK);


}

1、memcpy(OldCode, (LPVOID)pOldMsg,0x4);需要注意我们想要把pOldMsg老函数地址放到一个字符串数组里面,但是我们这样子的代码就是把函数地址里面的前4个值放到字符串数组OldCode里面,应该改成memcpy(OldCode, (LPVOID)&pOldMsg,0x4);
2、第二我发现这样写NewMessagebox会进入死循环,他没办法执行旧的Messagebox函数

3.最终代码实现

#include <Windows.h>
#include <stdio.h>


typedef int (WINAPI* pMyMsg)(
	HWND   hWnd,
	LPCSTR lpText,
	LPCSTR lpCaption,
	UINT   uType
	);

//pMyMsg pHookMsg = NULL;
pMyMsg pOldMsg = NULL;
PVOID pHookAddress = nullptr;


//定义newmessagebox函数
//int WINAPI NewMessagebox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
//{
//	
//	printf("HOOK成功");
//	pOldMsg( hWnd,"HOOK成功", "HOOK", MB_OK);
//
//	return 0;
//}

typedef struct _regeist
{
	DWORD EAX;
	DWORD EBX;
	DWORD ECX;
	DWORD EDX;
	DWORD EBP;
	DWORD ESP;
	DWORD ESI;
	DWORD EDI;
}regeist;

regeist reg = { 0 };

DWORD x, y, z;
DWORD RetWriteHookAddr;
_declspec(naked) void NewMessagebox()
{
	_asm
	{
		pushad;     //保留寄存器
		pushfd;     //保留标志寄存器
	}

	printf("123");

	_asm
	{
		popfd;      //还原标志寄存器
		popad;      //还原寄存器
	}

	//执行之前覆盖的代码
	_asm
	{
		//77D507EA 8B FF                mov         edi,edi
		//77D507EC 55                   push        ebp
		//77D507ED 8B EC                mov         ebp,esp
		//77D507EF 83 3D BC 14 D7 77 00 cmp         dword ptr ds:[77D714BCh],0
		//77D507F6 74 24                je          77D5081C

		mov         edi, edi
		push        ebp
		mov         ebp, esp
		//执行完后跳转回hook地址
		jmp RetWriteHookAddr;
	}
}

//定义unhook函数



//定义hook函数
void SetHook()
{
	

	BYTE code[5] = { 0xe9, };
	BYTE OldCode[5];
	DWORD JmpAddress = (DWORD)NewMessagebox - ((DWORD)pOldMsg + 5);
	RetWriteHookAddr = ((DWORD)pOldMsg + 5) ;
	

	memcpy(&code[1],&JmpAddress,0x4);

	DWORD OldProtected;
	VirtualProtect((LPVOID)pOldMsg, 0x1000, PAGE_EXECUTE_READWRITE, &OldProtected);
	
	memcpy(OldCode, (LPVOID)&pOldMsg,0x4);
	memcpy((LPVOID)pOldMsg,code, 0x5);
	VirtualProtect((LPVOID)pOldMsg, 0x1000, OldProtected, &OldProtected);


}

int main()
{
	
	pHookAddress = GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");
	pOldMsg = (pMyMsg)pHookAddress;
	SetHook();
	MessageBoxA(NULL, "after hook", "tips", MB_OK);


}

posted @ 2024-03-17 17:30  小新07  阅读(192)  评论(0编辑  收藏  举报