分享
 
 
 

Windows下的函数hook技术

王朝vc·作者佚名  2006-01-10
窄屏简体版  字體: |||超大  

都是很成熟的东西了,这几天看了看,总结一下而已。

讨论了Windows下hook函数的几种方法。提供了一个hook TextOutA的完整例子。通过CreateRemoteThread的方法把hook dll注入到一个普通的应用程序中。Hooking Imported Functions by name调用

imported functions'时的步骤/实现

在程序中调用从其它模块引入的函数的方法和普通的函数调用有所不同。对于普通的函数调用,直接使用

call address来调用即可,但是对于

imported functions

,在编译的时候

compiler/link

并不知道实际的函数实现会被加载到那个地址,函数实现在那个地址在运行的时候才会确定。对于

imported functions

,首先是

call

引入表中的一个函数,在运行时再初始化引入表,使用

jmp

跳转到真实的函数实现。

引入表:

The PE file

IMAGE_IMPORT_DESCRipTOR

strUCture, which holds all the information about functions imported from a specific DLL, has pointers to two arrays in the executable. These arrays are called import address tables (IATs), or sometimes thunk data arrays. The first pointer references the real IAT, which the PRogram loader fixes up when the executable is loaded. The second pointer references the original IAT, which is untouched by the loader and lists the imported functions.

实现原理

找到

PE

文件的

Image_Import_Descriptor

结构

找到

Original LAT

Real LAT.

通过要

hook

的函数的名字在

Original LAT

找到要

hook

imported function

在数组中的

index.

保存并修改

Real LAT

在相应

index

function address

(refer to John Robbins, BugsLayerUtil.dll)

Hooking Imported Functions by ordinal

原理和

Hook Imported functions by name

一样,只是是通过要

hook

的函数的

ordinal

original LAT

中找到

index.

Hooking a function in this dll

当一个

DLL

是通过

LoadLibrary

载入的时候,我们无法通过

hook imported function

的方法的

hook

它中的

function

。有两种可能的办法处理这种情况:

第一种方法,遍历进程空间,发现

call

指定函数的地方替换为

call hookFunction.

太麻烦,而且不安全。

第二种方法,改写要

hook

的函数

FuncA

。比较好的方法

实现

HookFuncA

,最后的实现垫入

n

nop.

找到要

hook

的函数

FuncA

的绝对地址,改写前

5

个字节为

jmp hookFuncA(

假定前

5

个字节为

n

个完整的指令

)

FuncA

的前

5

个字节拷贝到

hookFuncA

的后面,在加上一条指令

jmp funcA+5.

----Code of HookDLL.dll, 可以通过CreateRemoteThread的方法把hook dll注入到一个普通的应用程序中。

// HookDLL.cpp : Defines the entry point for the DLL application.

//

#include "stdafx.h"

#include "HookDLL.h"

#include "Log.h"

//forward declare.

LRESULT WINAPI InstallTextoutHook();

LRESULT WINAPI UninstallTextoutHook();

BOOL APIENTRY DllMain( HANDLE hModule,

DWord ul_reason_for_call,

LPVOID lpReserved

)

{

switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

if (InstallTextoutHook())

{

WriteLog("Install hook success.\n");

}else

{

WriteLog("Intall hook failed.\n");

}

break;

case DLL_THREAD_ATTACH:

break;

case DLL_THREAD_DETACH:

break;

case DLL_PROCESS_DETACH:

if (UninstallTextoutHook())

{

WriteLog("Uninstall hook success.\n");

}else

{

WriteLog("Unintall hook failed.\n");

}

break;

}

return TRUE;

}

#define DWORD_PTR DWORD*

#define __LOCAL_SIZE 40h

#define NAKED_PROLOG() \

DWORD_PTR dwRet ; \

DWORD_PTR dwESI ; \

{ \

__asm PUSH EBP /* Set up the standard frame.*/\

__asm MOV EBP , ESP \

__asm SUB ESP , __LOCAL_SIZE /* Save room for the local */\

/* variables. */\

__asm MOV EAX , EBP /* EBP has the stack coming */\

/* into the fn. in it. */\

__asm ADD EAX , 4 /* Account for PUSH EBP */\

__asm MOV EAX , [EAX] /* Get return address. */\

__asm MOV [dwRet] , EAX /* Save return address. */\

__asm MOV [dwESI] , ESI /* Save ESI so chkesp in dbg */\

/* builds works. */\

}// The common epilog part that can be shared between the stdcall and

// cdecl hook functions.

#define EPILOG_COMMON() \

{ \

__asm MOV ESI , [dwESI] /* Restore ESI. */\

__asm ADD ESP , __LOCAL_SIZE /* Take away local var space */\

__asm MOV ESP, EBP /* Restore standard frame. */\

__asm POP EBP \

}

#define COPY_CODE_LENGTH 5

BYTE g_abOriCode[COPY_CODE_LENGTH];

BYTE g_abJmpCode[COPY_CODE_LENGTH];

PROC g_oriTextout;

BOOL g_blHooked = FALSE;

LRESULT WINAPI InstallTextoutHook()

{

if (g_blHooked)

return TRUE;

//Get TextOutA's address.

HMODULE hGdi32 = ::LoadLibrary(_T("Gdi32.dll"));

g_oriTextout = GetProcAddress(hGdi32, _T("TextOutA"));

if (NULL == g_oriTextout)

return FALSE;

//Get the hook'a address.

HMODULE hModule = GetModuleHandle(_T("HookDLL.dll"));

if (NULL == hModule)

return FALSE;

DWORD dwHookAddr = NULL;

__asm

{

mov esi, offset HookLabel;

mov edi, 0x10000000;//0x10000000 is the dll's base address.

sub esi, edi;

add esi, hModule;

mov [dwHookAddr], esi;

}

//Get the NOP's address.

DWORD dwNOPAddr = NULL;

__asm

{

mov esi, offset NOPLabel;

mov edi, 0x10000000;//0x10000000 is the dll's base address.

sub esi, edi;

add esi, hModule;

mov [dwNOPAddr], esi;

}

//Save the first 5 byte of TextOutA to g_abOriCode

__asm

{

mov esi, g_oriTextout;

lea edi, g_abOriCode;

cld;

movsd;

movsb;

}

//Generate the jmp Hook function.

g_abJmpCode[0] = 0xe9;

__asm

{

mov eax, dwHookAddr;

mov ebx, g_oriTextout;

add ebx, 5;

sub eax, ebx;

mov dword ptr[g_abJmpCode+1], eax;

}

//Write the jump instruction to the textoutA.

DWORD dwProcessId = GetCurrentProcessId();

HANDLE hProcess = OpenProcess (PROCESS_ALL_access,

FALSE, dwProcessId);

if (NULL == hProcess)

return FALSE;

DWORD dwOldFlag;

VirtualProtectEx(hProcess, g_oriTextout, 5, PAGE_READWRITE, &dwOldFlag);

WriteProcessMemory(hProcess, g_oriTextout, g_abJmpCode, sizeof(g_abJmpCode), NULL);

VirtualProtectEx(hProcess, g_oriTextout, 5, dwOldFlag, NULL);

//Write g_abOriTextout to the end of Hook function(NOP addr), then write the jmp instruction.

VirtualProtectEx(hProcess, (LPVOID)dwNOPAddr, 10, PAGE_READWRITE, &dwOldFlag);

WriteProcessMemory(hProcess, (LPVOID)dwNOPAddr, g_abOriCode, sizeof(g_abOriCode), NULL);

//Generate the jmp TextoutA + 5

__asm

{

mov eax, g_oriTextout;

mov ebx, dwNOPAddr;

add ebx, 5;

sub eax, ebx;

mov dword ptr[g_abJmpCode+1], eax;

}

WriteProcessMemory(hProcess, (LPVOID)(dwNOPAddr+5), g_abJmpCode, sizeof(g_abJmpCode), NULL);

VirtualProtectEx(hProcess, (LPVOID)dwNOPAddr, 10, dwOldFlag, NULL);

g_blHooked = TRUE;

if(TRUE)

return TRUE;

HookLabel:

NAKED_PROLOG ( ) ;

int nx, ny;

LPCSTR lp;

lp = NULL;

_asm

{

mov esi, ebp;

add esi, 0Ch;

lea edi, nx;

movsd;

lea edi, ny;

movsd;

lea edi, lp;

movsd;

}

WriteLog_F("Try to ouput \"%s\" at (%d,%d)\n", lp, nx, ny);

// Do the common epilog.

EPILOG_COMMON ( ) ;

NOPLabel:

_asm NOP

_asm NOP

_asm NOP

_asm NOP

_asm NOP

_asm NOP

_asm NOP

_asm NOP

_asm NOP

_asm NOP

_asm NOP

}

LRESULT WINAPI UninstallTextoutHook()

{

if (!g_blHooked)

return FALSE;

//Restore the first 5 bytes code of TextOutA

DWORD dwProcessId = GetCurrentProcessId();

HANDLE hProcess = OpenProcess (PROCESS_ALL_ACCESS,

FALSE, dwProcessId);

if (NULL == hProcess)

return FALSE;

DWORD dwOldFlag;

VirtualProtectEx(hProcess, g_oriTextout, 5, PAGE_READWRITE, &dwOldFlag);

WriteProcessMemory(hProcess, g_oriTextout, g_abOriCode, sizeof(g_abOriCode), NULL);

VirtualProtectEx(hProcess, g_oriTextout, 5, dwOldFlag, NULL);

g_blHooked = FALSE;

return TRUE;

}

更多内容请看Windows操作系统安全集 Windows操作系统安装 Windows频道专题,或

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有