Hook技术简单介绍

Hook技术简单介绍Hook主要就是通过一定手段在程序执行过程中进行干预。IATHook篡改MessageBox借用accills的例子#include<windows.h>#include<stdio.h>#include<imagehlp.h>#pragmacomment(lib,"imagehlp.lib")//以MessageBoxA的…

大家好,又见面了,我是你们的朋友全栈君。

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函数执行后

Hook技术简单介绍

Hook技术简单介绍

 这个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消息

Hook技术简单介绍

esi值向User32.MessageBoxA 

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

Hook技术简单介绍

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

 

 

 

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/144951.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 公务员叫停年终奖_100个月年终奖

    公务员叫停年终奖_100个月年终奖年底红包,多少羡慕嫉妒恨  时光荏苒,岁月蹉跎。不知不觉间,2011年即将走过。忙碌了一年的人们,自进入12月便开始了年终奖的各种讨论及猜测。在贴吧,微博网友们纷纷以晒年终奖的方式品味着所有快乐以及忧愁。  2011年,通胀压力下物价节节攀高,进入下半年CPI指数有所下降,但消费支出压力丝毫没有得到缓解,特别是集中到年底流水似的花销更叫人隐隐作痛。在现实的生存压力之下,上班族对年终

  • 翻译软件市场分析_it软件开发 2019年小结

    翻译软件市场分析_it软件开发 2019年小结「译」软件开发趋势 2019 调查报告

  • haxm device is not found

    haxm device is not foundandriodstudio刚装完,都会忍不住跑一个helloworld~但是AVDManager里的虚拟设备会提示错误:haxmdeviceisnotfound.androidstudio–>Tools–>AVDManager–>+CreateVirtualDevice…–>VirtualDeviceConfiguration–>Phone–>随便点一个–>Next。出现这个问题:EnableVT-xin

  • 遍历map的几种方法?_hashmap如何遍历

    遍历map的几种方法?_hashmap如何遍历#先往map加入几个数据Map<Integer,String>map=newHashMap<>();map.put(1,”美好的周一”);map.put(2,”美好的周二”);map.put(3,”美好的周三”);方法一:普通的foreach循环,使用keySet()方法,遍历keyfor(Integerkey:map.keySet()){System.out.println(“key:”+key+

  • 12个MySQL慢查询的原因分析「建议收藏」

    12个MySQL慢查询的原因分析「建议收藏」12个MySQL慢查询的原因分析

    2022年10月14日
  • linux 刷流量ip,程序员同事问shell脚本刷流量,不讨巧帮他填了一个巨坑

    linux 刷流量ip,程序员同事问shell脚本刷流量,不讨巧帮他填了一个巨坑程序员同事闲来无事问我可以用shell脚本写个刷微博访问量的没。于是脑海里想起了病毒营销或者fork×××这些词。依稀操刀稀松吧啦的写了起来。并测试了下,脚本内容是下面这样的:脚本跑起来的样子当然仅仅是为了展示shell脚本威力。当然还是希望大家靠实际的阅读量。拿微信公众号来说,刷量增粉的很多。同样笔者手里也有些软件。但一次都没有使用过。以来防止被中马,二来做人如果都急功近利.光追求虚妄的东西而没…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号