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
總結
以上是生活随笔為你收集整理的Hook技术简单介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: adobe audition cs6 能
- 下一篇: matlab中的colorbar用法(显