Hook技术简单介绍
Hook主要就是通過一定手段在程序執(zhí)行過程中進(jìn)行干預(yù)。
IAT Hook 篡改MessageBox
借用accills的例子
#include <windows.h>
#include <stdio.h>
#include <imagehlp.h>
#pragma comment(lib,"imagehlp.lib")
//以MessageBoxA的原型定義一個(gè)函數(shù)指針類型
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的原型定義一個(gè)函數(shù)來替代原始的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
);
//存在以下關(guān)系
//*(*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;
}
//之所以把這個(gè)調(diào)用單獨(dú)放在一個(gè)函數(shù)中,是因?yàn)镽elease模式下對(duì)調(diào)用進(jìn)行了優(yōu)化,第二次調(diào)用時(shí)直接采用了寄存器尋址而不是導(dǎo)入表
//因此,單獨(dú)放在一個(gè)函數(shù)中可以避免這個(gè)情況。
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
)
{
//在這里,你可以對(duì)原始參數(shù)進(jìn)行任意操作
int ret;
char newText[1024]={0};
char newCaption[256]="pediy.com";
printf("有人調(diào)用MessageBox!\n");
//在調(diào)用原函數(shù)之前,可以對(duì)IN(輸入類)參數(shù)進(jìn)行干涉
lstrcpy(newText,lpText);//為防止原函數(shù)提供的緩沖區(qū)不夠,這里復(fù)制到我們自己的一個(gè)緩沖區(qū)中再進(jìn)行操作
lstrcat(newText,"\n\tMessageBox Hacked by pediy.com!");//篡改消息框內(nèi)容
uType|=MB_ICONERROR;//增加一個(gè)錯(cuò)誤圖標(biāo)
ret = OldMessageBox(hWnd,newText,newCaption,uType);//調(diào)用原MessageBox,并保存返回值
//調(diào)用原函數(shù)之后,可以繼續(xù)對(duì)OUT(輸出類)參數(shù)進(jìn)行干涉,比如網(wǎng)絡(luò)函數(shù)的recv,可以干涉返回的內(nèi)容
return ret;//這里你還可以干涉原始函數(shù)的返回值
}
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)
{
//查詢并修改內(nèi)存頁(yè)的屬性
VirtualQuery((LPCVOID)g_PointerToIATThunk,&mbi,sizeof(mbi));
VirtualProtect(mbi.BaseAddress,mbi.RegionSize,PAGE_EXECUTE_READWRITE,&dwOLD);
//將原始的MessageBoxA地址填入IAT中
*g_PointerToIATThunk = (ULONG)OldMessageBox;
//恢復(fù)內(nèi)存頁(yè)的屬性
VirtualProtect(mbi.BaseAddress,mbi.RegionSize,dwOLD,0);
}
}
//************************************
// FullName: InstallModuleIATHook
// Description: 為指定模塊安裝IAT Hook
// Access: public
// Returns: BOOL
// Parameter: HMODULE hModToHook , 待Hook的模塊基址
// Parameter: char * szModuleName , 目標(biāo)函數(shù)所在模塊的名字
// Parameter: char * szFuncName , 目標(biāo)函數(shù)的名字
// Parameter: PVOID DetourFunc , Detour函數(shù)地址
// Parameter: PULONG * pThunkPointer , 用以接收指向修改的位置的指針
// Parameter: ULONG * pOriginalFuncAddr , 用以接收原始函數(shù)地址
//************************************
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;
}
//程序的導(dǎo)入表處理完畢后OriginalFirstThunk可能是無效的,不能再根據(jù)名稱來查找,而是遍歷FirstThunk直接根據(jù)地址判斷
pThunkData = (PIMAGE_THUNK_DATA)((BYTE *)hModToHook + pImportDescriptor->FirstThunk);
while(pThunkData->u1.Function)
{
lpAddr = (ULONG_PTR*)pThunkData;
//找到了地址
if((*lpAddr) == TargetFunAddr)
{
printf("[*]Find target address!\n");
//通常情況下導(dǎo)入表所在內(nèi)存頁(yè)都是只讀的,因此需要先修改內(nèi)存頁(yè)的屬性為可寫
DWORD dwOldProtect;
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(lpAddr,&mbi,sizeof(mbi));
bRetn = VirtualProtect(mbi.BaseAddress,mbi.RegionSize,PAGE_EXECUTE_READWRITE,&dwOldProtect);
if (bRetn)
{
//內(nèi)存頁(yè)屬性修改成功,繼續(xù)下一步操作,先保存原始數(shù)據(jù)
if (pThunkPointer != NULL)
{
*pThunkPointer = lpAddr ;
}
if (pOriginalFuncAddr != NULL)
{
*pOriginalFuncAddr = *lpAddr ;
}
//修改地址
*lpAddr = (ULONG_PTR)DetourFunc;
result = TRUE ;
//恢復(fù)內(nèi)存頁(yè)的屬性
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
跟蹤到這一步已經(jīng)實(shí)現(xiàn)了HOOK,在IAT——InstallHook函數(shù)執(zhí)行后
這個(gè)MessageBox的地址已經(jīng)被修改
之前的是
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
所以現(xiàn)在調(diào)用的是My——MessageBox函數(shù)
說明第二次條用ShowMsgBox之前執(zhí)行的IAT_InstallHook函數(shù)。因?yàn)檫@個(gè)函數(shù)以修改IAT方式攔截了對(duì)API的調(diào)用。
第二個(gè)Inline Hook 篡改指定MessageBox消息
esi值向User32.MessageBoxA
而MessageBoxA 函數(shù)內(nèi)部被篡改了(在開頭直接通過一個(gè)跳轉(zhuǎn)指令到了MY—— MessageBoxA函數(shù)里)
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>; 有人調(diào)用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]
總結(jié):通過在執(zhí)行真正的目標(biāo)函數(shù)之前執(zhí)行事先插入的代碼,獲得了程序執(zhí)行過程的決定權(quán)(Hook終極奧義)。
AddressHook 是指通過修改數(shù)據(jù)(指一些函數(shù)的地址也可能是偏移量)進(jìn)行Hook方法。
Hook的典型過程
不管是哪種Hook都需要自定義的函數(shù)來代替被Hook的函數(shù)。稱之為Detour函數(shù)。其原型、調(diào)用約定、返回值都與原函數(shù)一模一樣。
對(duì)函數(shù)調(diào)用的約定為_cdecl,WindowAPI通常是stdcall調(diào)用。
AddressHook 是指通過修改數(shù)據(jù)(指一些函數(shù)的地址也可能是偏移量)進(jìn)行Hook方法。
以messageBox原型定義一個(gè)函數(shù)指針類型
實(shí)現(xiàn)IATHook的函數(shù)見上
虛函數(shù)Hook
(1)確定TargetFun在TargetClass虛函數(shù)表中的位置及函數(shù)原型
(2)定義DetourClass和TrampolineClass
(3)修改虛函數(shù)表,實(shí)現(xiàn)Hook
InlineHook的實(shí)施過程中要明確的3個(gè)概念
TargetFun : 要被Hook的目標(biāo)函數(shù);
DetourFun:用于代替TargetFun的自定義函數(shù);
TargetpolineFun:該函數(shù)不是一個(gè)完成的函數(shù),而是調(diào)用用原函數(shù)的入口。在該函數(shù)中要執(zhí)行TargetFun中被替換的前幾條指令,也就是說,TrampolinentFun和TargetFun中被Hook位置之后的部分構(gòu)成了一個(gè)完成的函數(shù)。
實(shí)現(xiàn)Inline Hook 時(shí)需要解決兩個(gè)問題:一是確定要采用的Hook方式。這樣才能確定要寫入何種機(jī)器碼來完成執(zhí)行的轉(zhuǎn)移。
1、確定Hook方式及需要Trampoline中執(zhí)行的指令
2、準(zhǔn)備TrampolineFun函數(shù)
3、準(zhǔn)備JMP指令并寫入
4、call Hook
總結(jié)
以上是生活随笔為你收集整理的Hook技术简单介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: adobe audition cs6 能
- 下一篇: matlab中的colorbar用法(显