Hook技术简单介绍

Hook主要就是通过一定手段在程序执行过程中进行干预。

IAT Hook 篡改MessageBox

借用accills的例子

#include <windows.h>
#include <stdio.h>
#include <imagehlp.h>
#pragma comment(lib,"imagehlp.lib")


//以MessageBoxA的原型定义一个函数指针类型
typedef int 
(WINAPI *PFN_MessageBoxA)(
	HWND hWnd,          // handle of owner window
	LPCTSTR lpText,     // address of text in message box
	LPCTSTR lpCaption,  // address of title of message box
	UINT uType          // style of message box
	);

//以MessageBoxA的原型定义一个函数来替代原始的MessageBoxA
int WINAPI My_MessageBoxA(
	HWND hWnd,          // handle of owner window
	LPCTSTR lpText,     // address of text in message box
	LPCTSTR lpCaption,  // address of title of message box
	UINT uType          // style of message box
	);

//存在以下关系
//*(*pThunkPointer) == *pOriginalFuncAddr ;
BOOL InstallModuleIATHook(
	HMODULE hModToHook,
	char *szModuleName, 
	char *szFuncName,
	PVOID ProxyFunc,
	PULONG_PTR *pThunkPointer,
	ULONG_PTR *pOriginalFuncAddr
	);

VOID ShowMsgBox(char *szMsg);
BOOL IAT_InstallHook();
VOID IAT_UnInstallHook();
BOOL IsWow64();
//保存原始MessageBoxA的地址
PFN_MessageBoxA OldMessageBox=NULL;
//指向IAT中pThunk的地址
PULONG_PTR g_PointerToIATThunk = NULL;

int main(int argc, char *argv[ ])
{
	BOOL bIsWow64 = IsWow64();
	printf("IsWow64 = %d\n",bIsWow64);
	ShowMsgBox("Before IAT Hook");
	IAT_InstallHook();
	ShowMsgBox("After  IAT Hook");
	IAT_UnInstallHook();
	ShowMsgBox("After  IAT Hook UnHooked");
	return 0;
}

//之所以把这个调用单独放在一个函数中,是因为Release模式下对调用进行了优化,第二次调用时直接采用了寄存器寻址而不是导入表
//因此,单独放在一个函数中可以避免这个情况。

VOID ShowMsgBox(char *szMsg)
{
	MessageBoxA(NULL,szMsg,"Test",MB_OK);
}


int WINAPI My_MessageBoxA(
	HWND hWnd,          // handle of owner window
	LPCTSTR lpText,     // address of text in message box
	LPCTSTR lpCaption,  // address of title of message box
	UINT uType          // style of message box
	)
{	
	//在这里,你可以对原始参数进行任意操作
	int ret;
	char newText[1024]={0};
	char newCaption[256]="pediy.com";
	printf("有人调用MessageBox!\n");
	//在调用原函数之前,可以对IN(输入类)参数进行干涉
	lstrcpy(newText,lpText);//为防止原函数提供的缓冲区不够,这里复制到我们自己的一个缓冲区中再进行操作
	lstrcat(newText,"\n\tMessageBox Hacked by pediy.com!");//篡改消息框内容
	uType|=MB_ICONERROR;//增加一个错误图标
	ret = OldMessageBox(hWnd,newText,newCaption,uType);//调用原MessageBox,并保存返回值
	//调用原函数之后,可以继续对OUT(输出类)参数进行干涉,比如网络函数的recv,可以干涉返回的内容
	return ret;//这里你还可以干涉原始函数的返回值
	
}

BOOL IAT_InstallHook()
{
	BOOL bResult = FALSE ;
	HMODULE hCurExe = GetModuleHandle(NULL);
	PULONG_PTR pt ;
	ULONG_PTR OrginalAddr;
	bResult = InstallModuleIATHook(hCurExe,"user32.dll","MessageBoxA",(PVOID)My_MessageBoxA,&pt,&OrginalAddr);
	if (bResult)
	{
		printf("[*]Hook安装完毕! pThunk=0x%p  OriginalAddr = 0x%p\n",pt,OrginalAddr);
		g_PointerToIATThunk = pt ;
		OldMessageBox = (PFN_MessageBoxA)OrginalAddr ;
	}
	return bResult;
	
}

VOID IAT_UnInstallHook()
{
	
	DWORD dwOLD;
	MEMORY_BASIC_INFORMATION  mbi;
	if (g_PointerToIATThunk)
	{
		//查询并修改内存页的属性
		VirtualQuery((LPCVOID)g_PointerToIATThunk,&mbi,sizeof(mbi));
		VirtualProtect(mbi.BaseAddress,mbi.RegionSize,PAGE_EXECUTE_READWRITE,&dwOLD);
		//将原始的MessageBoxA地址填入IAT中
		*g_PointerToIATThunk = (ULONG)OldMessageBox;
		//恢复内存页的属性
		VirtualProtect(mbi.BaseAddress,mbi.RegionSize,dwOLD,0);
	}

}

//************************************
// FullName:    InstallModuleIATHook
// Description: 为指定模块安装IAT Hook
// Access:      public 
// Returns:     BOOL
// Parameter:   HMODULE hModToHook , 待Hook的模块基址
// Parameter:   char * szModuleName , 目标函数所在模块的名字
// Parameter:   char * szFuncName , 目标函数的名字
// Parameter:   PVOID DetourFunc , Detour函数地址
// Parameter:   PULONG * pThunkPointer , 用以接收指向修改的位置的指针
// Parameter:   ULONG * pOriginalFuncAddr , 用以接收原始函数地址
//************************************
BOOL InstallModuleIATHook(
	HMODULE hModToHook,// IN
	char *szModuleName,// IN
	char *szFuncName,// IN
	PVOID DetourFunc,// IN
	PULONG_PTR *pThunkPointer,//OUT
	ULONG_PTR *pOriginalFuncAddr//OUT
	)
{
	PIMAGE_IMPORT_DESCRIPTOR  pImportDescriptor;
	PIMAGE_THUNK_DATA         pThunkData;
	ULONG ulSize;
	HMODULE hModule=0;
	ULONG_PTR TargetFunAddr;
	PULONG_PTR lpAddr;
	char *szModName;
	BOOL result = FALSE ;
	BOOL bRetn = FALSE;

	hModule = LoadLibrary(szModuleName);
	TargetFunAddr = (ULONG_PTR)GetProcAddress(hModule,szFuncName);
	printf("[*]Address of %s:0x%p\n",szFuncName,TargetFunAddr);
	printf("[*]Module To Hook at Base:0x%p\n",hModToHook);
	pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(hModToHook, TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);;
	printf("[*]Find ImportTable,Address:0x%p\n",pImportDescriptor);
	while (pImportDescriptor->FirstThunk)
	{
		szModName = (char*)((PBYTE)hModToHook+pImportDescriptor->Name) ;
		printf("[*]Cur Module Name:%s\n",szModName);
		if (stricmp(szModName,szModuleName) != 0)
		{
			printf("[*]Module Name does not match, search next...\n");
			pImportDescriptor++;
			continue;
		}
		//程序的导入表处理完毕后OriginalFirstThunk可能是无效的,不能再根据名称来查找,而是遍历FirstThunk直接根据地址判断
		pThunkData = (PIMAGE_THUNK_DATA)((BYTE *)hModToHook + pImportDescriptor->FirstThunk);
		while(pThunkData->u1.Function)
		{
			lpAddr = (ULONG_PTR*)pThunkData;
			//找到了地址
			if((*lpAddr) == TargetFunAddr)
			{
				printf("[*]Find target address!\n");
				//通常情况下导入表所在内存页都是只读的,因此需要先修改内存页的属性为可写
				DWORD dwOldProtect;
				MEMORY_BASIC_INFORMATION  mbi;
				VirtualQuery(lpAddr,&mbi,sizeof(mbi));
				bRetn = VirtualProtect(mbi.BaseAddress,mbi.RegionSize,PAGE_EXECUTE_READWRITE,&dwOldProtect);
				if (bRetn)
				{
					//内存页属性修改成功,继续下一步操作,先保存原始数据
					if (pThunkPointer != NULL)
					{
						*pThunkPointer = lpAddr ;
					}
					if (pOriginalFuncAddr != NULL)
					{
						*pOriginalFuncAddr = *lpAddr ;
					}
					//修改地址
					*lpAddr = (ULONG_PTR)DetourFunc;
					result = TRUE ;
					//恢复内存页的属性
					VirtualProtect(mbi.BaseAddress,mbi.RegionSize,dwOldProtect,0);
					printf("[*]Hook ok.\n");
				}
				
				break;	
			}
			//---------
			pThunkData++;
		}
		pImportDescriptor++;
	}
	
	FreeLibrary(hModule);
	return result;
}
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);

LPFN_ISWOW64PROCESS fnIsWow64Process;

BOOL IsWow64()
{
	BOOL bIsWow64 = FALSE;

	fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
		GetModuleHandle(TEXT("kernel32")),"IsWow64Process");

	if (NULL != fnIsWow64Process)
	{
		if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
		{
			// handle error
		}
	}
	return bIsWow64;
}

 

00DA8845  |.  C745 A4 01000>||mov [local.23],0x1
00DA884C  |.  8BF4          ||mov esi,esp
00DA884E  |.  6A 00         ||push 0x0                                       ; /pOldProtect = NULL
00DA8850  |.  8B45 8C       ||mov eax,[local.29]                             ; |
00DA8853  |.  50            ||push eax                                       ; |NewProtect = PAGE_READWRITE|PAGE_WRITECOPY
00DA8854  |.  8B8D 74FFFFFF ||mov ecx,[local.35]                             ; |
00DA885A  |.  51            ||push ecx                                       ; |Size = 501EBA15 (1344190997.)
00DA885B  |.  8B95 68FFFFFF ||mov edx,[local.38]                             ; |IATHookM._IMPORT_DESCRIPTOR_KERNEL32:NativeDll::ProcessAttach)'0,64)'4)'64)'
00DA8861  |.  52            ||push edx                                       ; |Address = IATHookM.00E04038
00DA8862  |.  FF15 8882E000 ||call dword ptr ds:[<&KERNEL32.VirtualProtect>] ; \VirtualProtect
00DA8868  |.  3BF4          ||cmp esi,esp
00DA886A  |.  E8 80E3FFFF   ||call IATHookM.00DA6BEF
00DA886F  |.  68 7C4DDF00   ||push IATHookM.00DF4D7C                         ;  [*]Hook ok.\n
00DA8874  |.  E8 F5E6FFFF   ||call IATHookM.00DA6F6E
00DA8879  |.  83C4 04       ||add esp,0x4
00DA887C  |>  EB 0E         ||jmp short IATHookM.00DA888C
00DA887E  |>  8B45 EC       ||mov eax,[local.5]                              ;  <&USER32.MessageBoxA>
00DA8881  |.  83C0 04       ||add eax,0x4
00DA8884  |.  8945 EC       ||mov [local.5],eax
00DA8887  |.^ E9 1EFFFFFF   |\jmp IATHookM.00DA87AA
00DA888C  |>  8B45 F8       |mov eax,[local.2]                               ;  IATHookM._IMPORT_DESCRIPTOR_USER32t Hierarchy Descriptor'r',-1,0,64)'4)'64)'
00DA888F  |.  83C0 14       |add eax,0x14
00DA8892  |.  8945 F8       |mov [local.2],eax
00DA8895  |.^ E9 AEFEFFFF   \jmp IATHookM.00DA8748

跟踪到这一步已经实现了HOOK,在IAT——InstallHook函数执行后

 这个MessageBox的地址已经被修改

之前的是

00DA832C  |.  F3:AB         rep stos dword ptr es:[edi]
00DA832E  |.  8BF4          mov esi,esp
00DA8330  |.  6A 00         push 0x0                                         ; /Style = MB_OK|MB_APPLMODAL
00DA8332  |.  68 C44CDF00   push IATHookM.00DF4CC4                           ; |Test
00DA8337  |.  8B45 08       mov eax,[arg.1]                                  ; |
00DA833A  |.  50            push eax                                         ; |Text = B0ADE667 ???
00DA833B  |.  6A 00         push 0x0                                         ; |hOwner = NULL
00DA833D  |.  FF15 4884E000 call dword ptr ds:[<&USER32.MessageBoxA>]        ; \MessageBoxA
00DA8343  |.  3BF4          cmp esi,esp
00DA8345  |.  E8 A5E8FFFF   call IATHookM.00DA6BEF

   所以现在调用的是My——MessageBox函数

 

说明第二次条用ShowMsgBox之前执行的IAT_InstallHook函数。因为这个函数以修改IAT方式拦截了对API的调用。

第二个Inline Hook 篡改指定MessageBox消息

esi值向User32.MessageBoxA 

而MessageBoxA 函数内部被篡改了(在开头直接通过一个跳转指令到了MY—— MessageBoxA函数里)

00401050 > .  81EC 00050000 sub esp,0x500                                    ;  ?My_MessageBoxA@@YGHPAUHWND__@@PBD1I@Z
00401056   .  57            push edi                                         ;  InlineHo.<ModuleEntryPoint>
00401057   .  B9 FF000000   mov ecx,0xFF
0040105C   .  33C0          xor eax,eax
0040105E   .  8DBC24 050100>lea edi,dword ptr ss:[esp+0x105]
00401065   .  C68424 040100>mov byte ptr ss:[esp+0x104],0x0
0040106D   .  66:8B15 C0804>mov dx,word ptr ds:[0x4080C0]                    ;  m
00401074   .  F3:AB         rep stos dword ptr es:[edi]
00401076   .  8B0D BC804000 mov ecx,dword ptr ds:[0x4080BC]                  ;  y.com
0040107C   .  66:895424 0C  mov word ptr ss:[esp+0xC],dx
00401081   .  66:AB         stos word ptr es:[edi]
00401083   .  AA            stos byte ptr es:[edi]
00401084   .  A1 B8804000   mov eax,dword ptr ds:[<??_C@_09HIDC@pediy?4com?$>;  pediy.com
00401089   .  894C24 08     mov dword ptr ss:[esp+0x8],ecx
0040108D   .  894424 04     mov dword ptr ss:[esp+0x4],eax
00401091   .  B9 3D000000   mov ecx,0x3D
00401096   .  33C0          xor eax,eax
00401098   .  8D7C24 0E     lea edi,dword ptr ss:[esp+0xE]
0040109C   .  F3:AB         rep stos dword ptr es:[edi]
0040109E   .  68 A0804000   push offset <InlineHo.??_C@_0BF@ODOO@?S?P?H?K?$L>;  有人调用MessageBox!\n
004010A3   .  66:AB         stos word ptr es:[edi]
004010A5   .  E8 4C030000   call InlineHo.printfsbh_decommit_pagesem_page
004010AA   .  8B8424 100500>mov eax,dword ptr ss:[esp+0x510]
004010B1   .  83C4 04       add esp,0x4
004010B4   .  8D8C24 040100>lea ecx,dword ptr ss:[esp+0x104]
004010BB   .  50            push eax                                         ; /String2 = 00000001 ???
004010BC   .  51            push ecx                                         ; |String1 = 00000005
004010BD   .  FF15 04704000 call dword ptr ds:[<&KERNEL32.lstrcpyA>]         ; \lstrcpyA
004010C3   .  8D9424 040100>lea edx,dword ptr ss:[esp+0x104]
004010CA   .  68 7C804000   push offset <InlineHo.??_C@_0CC@ELLF@?6?7Message>; /\n\tMessageBox Hacked by pediy.com!
004010CF   .  52            push edx                                         ; |ConcatString = ""
004010D0   .  FF15 00704000 call dword ptr ds:[<&KERNEL32.lstrcatA>]         ; \lstrcatA
004010D6   .  8D4C24 04     lea ecx,dword ptr ss:[esp+0x4]

总结:通过在执行真正的目标函数之前执行事先插入的代码,获得了程序执行过程的决定权(Hook终极奥义)。

 

 

AddressHook 是指通过修改数据(指一些函数的地址也可能是偏移量)进行Hook方法。

 Hook的典型过程

不管是哪种Hook都需要自定义的函数来代替被Hook的函数。称之为Detour函数。其原型、调用约定、返回值都与原函数一模一样。

对函数调用的约定为_cdecl,WindowAPI通常是stdcall调用。

AddressHook 是指通过修改数据(指一些函数的地址也可能是偏移量)进行Hook方法。

以messageBox原型定义一个函数指针类型

实现IATHook的函数见上

虚函数Hook

(1)确定TargetFun在TargetClass虚函数表中的位置及函数原型

(2)定义DetourClass和TrampolineClass

(3)修改虚函数表,实现Hook

 

InlineHook的实施过程中要明确的3个概念

TargetFun : 要被Hook的目标函数;

DetourFun:用于代替TargetFun的自定义函数;

TargetpolineFun:该函数不是一个完成的函数,而是调用用原函数的入口。在该函数中要执行TargetFun中被替换的前几条指令,也就是说,TrampolinentFun和TargetFun中被Hook位置之后的部分构成了一个完成的函数。

 

 

实现Inline Hook 时需要解决两个问题:一是确定要采用的Hook方式。这样才能确定要写入何种机器码来完成执行的转移。

1、确定Hook方式及需要Trampoline中执行的指令

2、准备TrampolineFun函数

3、准备JMP指令并写入

4、call Hook

 

 

 

 

 

 

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Hook是React 16.8版本引入的一种新的特性,它可以让你在无需编写类组件的情况下使用状态和其他React特性。TypeScript是一种静态类型检查的JavaScript超集,可以帮助我们在开发过程中发现并修复潜在的错误。 要深入学习React Hook和TypeScript技术栈,你可以按照以下步骤进行: 1. 学习React基础知识:在学习React Hook之前,确保你对React的基础知识有一定的了解。理解React组件、生命周期、状态管理等概念是很重要的。 2. 学习TypeScript基础知识:如果你还不熟悉TypeScript,可以先学习一些基础知识,比如类型注解、接口、泛型等。掌握这些概念可以帮助你更好地使用TypeScript进行开发。 3. 学习React Hook:阅读React官方文档中关于React Hook的内容,并尝试编写一些简单Hook。掌握useState、useEffect、useContext等常用的Hook函数,并理解它们的使用方法和原理。 4. 使用TypeScript编写React Hook:在掌握了React Hook的基本知识后,你可以开始使用TypeScript编写React Hook。使用TypeScript可以为你的代码提供类型检查和智能提示,减少潜在的错误。 5. 实践项目:选择一个小型的项目或者练习,使用React Hook和TypeScript进行开发。通过实践项目可以帮助你更好地理解和掌握这两个技术栈。 6. 深入学习进阶内容:一旦你对React Hook和TypeScript有了基本的了解,你可以进一步学习一些进阶内容,比如自定义Hook、使用第三方库、使用Context API等。 记住,深入学习任何技术栈都需要时间和实践。通过不断地阅读文档、编写代码和解决问题,你会逐渐掌握React Hook和TypeScript技术栈。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值