大家好,又见面了,我是你们的朋友全栈君。
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
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/144951.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...