首页 > 其他分享 >滴水逆向笔记系列-win32总结10-63.IAT HOOK-64.Inline HOOK

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

时间:2024-03-17 17:34:10浏览次数:44  
标签:pOldMsg 10 LPVOID win32 HOOK IAT PIMAGE DWORD

第六十三课 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);


}

标签:pOldMsg,10,LPVOID,win32,HOOK,IAT,PIMAGE,DWORD
From: https://www.cnblogs.com/xiaoxin07/p/18078853

相关文章

  • Win11-鼠标右键菜单恢复为win10显示样式
    先看下win11默认的鼠标右键菜单显示情况看起来没有win10舒服解决方法:cmd命令行执行以下命令reg add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve 执行后重启Windows资源管理器 执行完以上操作后,效果如下......
  • 滴水逆向笔记系列-win32总结7-57.进程创建-58.挂起方式创建进程
    第五十七课win32进程创建1.进程创建的过程父进程创建子进程,父进程挂了子进程不会挂0x00程序、imagebuffer、进程的关系程序就是一个普通的二进制文件;imagebuffer就是程序拉伸到内存后的二进制文件,但是没有线程去执行他,进程则是有线程去运行这个imagebuffer0x01过程......
  • win10-我的电脑隐藏不需要的文件夹
    我的电脑默认会像下面显示红框内的内容使用频率很低,故想隐藏掉。方法如下:新建一个文本文件,内容如下WindowsRegistryEditorVersion5.00 [-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\{088e3905-0323-4b02-9826-5d99......
  • 代码随想录 第23天 | 669. 修剪二叉搜索树 ● 108.将有序数组转换为二叉搜索树 ● 5
    leetcode:669.修剪二叉搜索树-力扣(LeetCode)classSolution{publicTreeNodetrimBST(TreeNoderoot,intlow,inthigh){//和删除差不多,怕删除的节点的左右孩子节点有符合范围的,所以要每次判断一下,如果有不符合要求的就直接返回上一个节点。if(roo......
  • ARC108 vp记录
    运气好又是简单场,打算下周开一场AGC。赛时通过了ABCDEF(6/6)A.SumandProduct题意:给出两个正整数\(s,p\),求是否存在一组正整数\(n,m\)满足:\(n+m=s\)\(n\timesm=p\)\(1\les,p\le10^{12}\)考虑直接枚举\(n\),范围是\(O(\sqrtp)\)的,时间\(O(\sqrtp)\)。......
  • 开发 3 年拥有 100 万用户,这个操作系统开源了
    开发3年拥有100万用户,这个操作系统开源了!macrozheng 2024-03-1710:32 江苏 听全文mall学习教程官网:macrozheng.com来源:OSC开源社区Puter是近日在GitHub上最受欢迎的一款开源项目,正式开源还没到一周——star数就已接近7k。作者表示这个项目已开发3年,......
  • LeetCode精选101刷题必备(C++)-附详细分类及解体说明
    分享一本leetcode刷题必备,互联网就业必备的免费书,非常好,值得推荐。感谢作者高畅无私整理和免费分享。本书介绍    本书分为算法和数据结构两大部分,又细分了十五个章节,详细讲解了刷LeetCode时常用的技巧。我把题目精简到了101道,一是呼应了本书的标题,二是不想让读......
  • lc2104 子数组的范围和
    给定数组nums[n],子数组的范围指子数组中最大元素与最小元素的差值,返回nums中所有子数组的范围之和。子数组是数组的连续非空序列。1<=n<=1000;-1e9<=nums[i]<=1e9分别考虑每个元素作为最小和最大值的情况,统计作为最小值的次数,作为最大值的次数,这个可以用单调栈求出,然后统计各位......
  • UVA10829 L-Gap Substrings
    我永远喜欢数据结构。貌似是此题中第一个使用SA+分治+二维数点做法的题解?题目传送门给出字符串\(s\)和常数\(g\),求出有多少四元组\((l_1,r_1,l_2,r_2)\),满足\(s[l_1,r_1]=s[l_2,r_2]\)且\(r_1+g+1=l_2\)。\(T\)组数据,\(1\leT,g\le10\),\(|s|\le5\times10......
  • Android开发笔记[10]-关于页
    摘要构建关于页、最终用户许可页(EULA)页和隐私协议页;Compose页面中嵌入xml布局;Compose页面中添加markdown文本.关键信息AndroidStudio:Iguana|2023.2.1Gradle:distributionUrl=https://services.gradle.org/distributions/gradle-8.4-bin.zipjvmTarget='1.8'minSdk......