源程序程序破解之 API HOOK技术
// 2012-12-28 10:00:00
lpSystemTime->wYear = 2012;
lpSystemTime->wMonth = 12;
lpSystemTime->wDayOfWeek = 0;
lpSystemTime->wDay = 28;
lpSystemTime->wHour = 10;
WriteDataToFile(formatstring(L"1\\%d.in", gCallCounter).c_str(), lpInBuffer, nInBufferSize);
gCallCounter ++;
}
#else
{
// 拔掉后狗直接从已保存的文件中返回数据,实现狗数据的模拟
int nRet = 0;
mov eax, pNewAddr[/size][size=3] jmp eax
读写进程内存方法:
1.读进程内存:
2.VirtualProtect(lpAddress, nSize, PAGE_READONLY, &dwOldProtect);
3.ReadProcessMemory(hProcess, lpAddress, lpBuffer, nSize, &dwRead);
string hexData1 = toHexString((const char *)pbData, strlen((const char *)pbData));
int ret = sub_4026B0(pbData);
string hexData2 = toHexString((const char *)pbData, strlen((const char *)pbData));
void *addr = (void *)0x004026B0;
if(gHooks.Add(addr, my_sub_4026B0, verifyData, sizeof(verifyData), 0) != NULL)
{
logOutput(formatString("ApiDebugger - hook sub_4026B0 ok.\r\n"));
*lpBytesReturned = ReadDataFromFile(formatstring(L"1\\%d.in", gCallCounter).c_str(), lpOutBuffer, nOutBufferSize);
gCallCounter ++;
}
#endif
return ret;
}
2)使用刚才提到的方法进行DLL导入
logOutput(formatString("ApiDebugger - sub_4026B0(%s=>%s)",
hexData1.c_str(), hexData2.c_str()));
return ret;
}
const BYTE verifyData[] = { 0x55, 0x8B, 0xEC, 0x81, 0xEC, 0x2C, 0x01, 0x00, 0x00 };
VirtualProtect(lpAddress, nSize, dwOldProtect, &dwOldProtect);
在很多年前这种技术非常的流行,有各种各样的工具和SDK,我自己也实现了一个C++ class,名为 CAdHookApi, 主要几个函数是:
class CAdHookApi
{
public:
BOOL Remove(HANDLE hHook);
BOOL Begin(HANDLE hHook);
BOOL End(HANDLE hHook);
BOOL Begin2(void *pNewAddr);
BOOL End2(void *pNewAddr);
int BeginAll();
int EndAll();
};
举例说明使用方法:
假设一个软件是试用软件,试用7天,最笨的办法就是改本机时间,但如果用API HOOK技术就可以很容易做到,可以先用CFF Explorer或者Dependency查看一下该软件是调用哪个函数来获取系统当前时间的,假如是GetLocalTime函数(当然获取时间的函数还有很多API),那么我就可以截获GetLocalTime,返回一个永不过期的时间.
lpSystemTime->wMinute = 0;
lpSystemTime->wSecond = 0;
lpSystemTime->wMilliseconds = 0;
#endif
}
3.直接HOOK已知的函数地址:
如果已知函数地址和函数定义,可以直接对地址进行HOOK,在HOOK之前还可以先对内存数据进行检验,只有数据一致才HOOK.
// 开始HOOK所有的
gHooks.BeginAll();
}
break ;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break ;
case DLL_PROCESS_DETACH:
{
gHooks.EndAll();
}
break;
}
return TRUE;
gHooks.Add(_T("KERNEL32.DLL"), "DeviceIoControl", my_DeviceIoControl);
static int gCallCounter = 0;
BOOL WINAPI my_DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
// 指定DLL的某个函数进行HOOK
HANDLE Add(LPCTSTR lpszModule, LPCSTR lpcFuncName, void *pNewAddr, DWORD dwData = 0);
// 给定一个函数地址进行HOOK
HANDLE Add(void *pOldAddr, void *pNewAddr, const BYTE *verifyData = NULL, DWORD verifySize = 0, DWORD dwData = 0);
#if 1
ret = DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize,
lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped);
if(ret)
{
// 带狗时记录ss, nSize, dwOldProtect, &dwOldProtect);
2.写进程内存:
VirtualProtect(lpAddress, nSize, PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(hProcess, lpAddress, lpBuffer, nSize, &dwWrite);
在原程序运行之后,通过API CreateRemoteThread 把自己的DLL注入到另一个进程.使用DLL注入工具,这个工具是我多年前写的:
这种方式最大的好处是不需要对原程序进行修改,可以躲避程序CRC校验.
最后例举一些应用场景:
1.加密狗的通用破解方法,仅针对固定数据读取的有效(有算法的加密狗无效):
只要Rebuild Import Table,然后再Save/Save As就可以保存新的文件,这样你的dll就自动的被加载了,DLL加载的时候也就实现了API HOOK。
这种方式因为对原程序进行了修改,如果程序有CRC校验,运行肯定就不正确了,就需要通过破解去除CRC校验部分的判断.
2.动态DLL加载:
3)带狗保存数据,数据记录完成后,用保存的数据进行狗的模拟
2. 360 CrackMe加密API的截获,
下图是用给的提示用户名:360和正确的密码输入,返回API HOOK的Log output:
解密的结果:
5375636365737300000000000000000000000000000000000000000000000000
}
else
{
logOutput(formatString("ApiDebugger - hook sub_4026B0 failed.\r\n"));
}
4.函数首次HOOK是在DLL加载时完成的,DLL入口增加代码:
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
1)HOOK几个API,加密狗一般最终都是使用CreateFile打开设备,调用API DeviceIoControl与加密狗进行数据交互:
gHooks.Add(_T("KERNEL32.DLL"), "CreateFileA", my_CreateFileA);
gHooks.Add(_T("KERNEL32.DLL"), "CreateFileW", my_CreateFileW);
1.首先,声明一个全局变量:
static CAdHookApi gHooks;
2.确定要截获API的参数,API GetLocalTime对应的DLL是KERNEL32.DLL, API定义为:
通过DLL劫持技术HookAPI
DLL劫持技术当一个可执行文件运行时,Windows加载器将可执行模块映射到进程的地址空间中,加载器分析可执行模块的输入表,并设法找出任何需要的DLL,并将它们映射到进程的地址空间中。
由于输入表中只包含DLL名而没有它的路径名,因此加载程序必须在磁盘上搜索DLL文件。
首先会尝试从当前程序所在的目录加载DLL,如果没找到,则在Windows系统目录中查找,最后是在环境变量中列出的各个目录下查找。
利用这个特点,先伪造一个系统同名的DLL,提供同样的输出表,每个输出函数转向真正的系统DLL。
程序调用系统DLL时会先调用当前目录下伪造的DLL,完成相关功能后,再跳到系统DLL同名函数里执行,如图18.3所示。
这个过程用个形象的词来描述就是系统DLL被劫持(hijack)了。
图18.3 DLL劫持技术演示利用这种方法取得控制权后,可以对主程序进行补丁。
此种方法只对除kernel32.dll、ntdll.dll等核心系统库以外的DLL有效,如网络应用程序的ws2_32.dll、游戏程序中的d3d8.dll,还有大部分应用程序都调用的lpk.dll,这些DLL都可被劫持。
利用第5章5.6.2节提供的CrackMeNet.exe来演示一下如何利用劫持技术制作补丁,目标文件用Themida v1.9.2.0加壳保护。
1.补丁地址去除这个CrackMe网络验证方法参考第5章5.6.2节,将相关补丁代码存放到函数PatchProcess()里。
例如将401496h改成:00401496 EB 29 jmp short 004014C1补丁编程实现就是:unsigned char p401496[2] = {0xEB, 0x29};WriteProcessMemory(hProcess,(LPVOID)0x401496, p401496, 2, NULL);p401496这个数组的数据格式,可以用OllyDbg插件获得,或十六进制工具转换。
APIHOOK的实现原理
APIHOOK的实现原理API Hooking(API挂钩)是一种常见的软件技术,用于修改或者扩展应用程序的行为,它通过“操纵”应用程序的API调用过程来实现这一目标。
API Hooking通常用于各种目的,例如:监视应用程序的行为、修复漏洞、收集数据等。
本文将介绍API Hook的实现原理及其相关概念。
1. API Hook概述API Hooking通过劫持和修改应用程序对动态链接库(DLL)中导出函数的调用来实现目标功能。
在Windows操作系统中,每个可执行文件都会使用一些API函数,这些函数由系统提供并存储在动态链接库中。
当应用程序调用这些函数时,操作系统会在库文件中查找并执行相应的函数代码。
API Hooking就是在应用程序和DLL之间插入一个中间层,通过改变函数调用的目标,来控制和改变应用程序的行为。
API Hooking的实现原理可以归纳为以下几个步骤:(1)定位目标函数:首先,需要确定要Hook的目标函数。
可以通过静态分析程序源代码、反汇编可执行文件、监视应用程序行为等方法来获取目标函数的地址或名称。
(2)获取目标函数的原始地址:通过动态链接库(DLL)中的导入表,可以获取到目标函数的原始地址。
导入表中保存了DLL中导出函数地址的引用。
(3)Hook目标函数:Hook目标函数的方式有多种,这里介绍两种常见的方式。
a. 钩子函数(Hook Function):通过将Hook函数替换为目标函数的调用,可以劫持目标函数的执行。
Hook函数在执行之前、中间或者之后可以执行额外的逻辑操作,并返回结果给应用程序。
b. IAT Hooking(Import Address Table Hooking):IAT是动态链接库中的导入表,包含了动态链接库中导出函数的地址。
通过修改IAT中目标函数的地址,将其指向Hook函数,即可实现Hook效果。
(4)重定向函数调用:Hook目标函数后,需要将应用程序中对目标函数的调用重定向到Hook函数。
hook技术--代码hook
hook技术--代码hook1.简介:对于IAT hook ⽅法,它只能hook掉在iat中的API,如果是通过动态加载的就不⾏了因为动态加载的dll的API不在iat中,⽽是动态⽣成的.这时可以预先加载该dll和API,并对API前⼏个字节进⾏保存然后修改成跳转到⾃⼰的某函数中,然后进⾏⼀些操作后可以再跳回到原来的API.这就是所谓的API修改hook.2.以hook掉任务管理器的进程遍历功能,为例,⽤此来隐藏calc.exe这个进程windows上ring3层的遍历进程API底层都调⽤了ZwQuerySystemInformation 函数该函数在ntdll中,但没有公开在⽹上寻找该API的参数和返回值信息,在代码中体现代码思路是: 先获取ZwQuerySystemInformation的地址,保存前5个字节的代码. 再覆盖为⼀个跳转到我们实现的⼀个伪ZwQuerySystemInformation函数地址的jmp指令的机器代码.在我们的函数中找到calc.exe的进程名,然后再跳过这个节点即可.#include "stdafx.h"#include <Windows.h>#include <wchar.h>#include <malloc.h>#include<stdio.h>#define funcName "ZwQuerySystemInformation"#define dllName "ntdll.dll"#define processName L"calc.exe"typedef LONG NTSTATUS;typedef enum _SYSTEM_INFORMATION_CLASS {SystemBasicInformation = 0,SystemPerformanceInformation = 2,SystemTimeOfDayInformation = 3,SystemProcessInformation = 5,SystemProcessorPerformanceInformation = 8,SystemInterruptInformation = 23,SystemExceptionInformation = 33,SystemRegistryQuotaInformation = 37,SystemLookasideInformation = 45} SYSTEM_INFORMATION_CLASS;typedef struct _SYSTEM_PROCESS_INFORMATION {ULONG NextEntryOffset;ULONG NumberOfThreads;BYTE Reserved1[48];PVOID Reserved2[3];HANDLE UniqueProcessId;PVOID Reserved3;ULONG HandleCount;BYTE Reserved4[4];PVOID Reserved5[11];SIZE_T PeakPagefileUsage;SIZE_T PrivatePageCount;LARGE_INTEGER Reserved6[6];} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;typedef NTSTATUS(WINAPI *PFZWQUERYSYSTEMINFORMATION)(SYSTEM_INFORMATION_CLASS SystemInformationClass,PVOID SystemInformation,ULONG SystemInformationLength,PULONG ReturnLength);BYTE orgCode[5];//原始指令BYTE fakeCode[5]; //伪造的jmp指令DWORD funcBase; //我们的函数基址// char debug[100]={0};DWORD WINAPI myZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass,PVOID SystemInformation,ULONG SystemInformationLength,PULONG ReturnLength);DWORD hook(DWORD funcbase, DWORD fakeFunc);DWORD unhook(DWORD funcbase);BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved){ //获取⽬标函数基址和伪造函数基址DWORD fakeFunc;funcBase = (DWORD)GetProcAddress(GetModuleHandleA(dllName), funcName);fakeFunc = (DWORD)myZwQuerySystemInformation;switch (ul_reason_for_call){case DLL_PROCESS_ATTACH: //加载时就hook掉hook(funcBase, fakeFunc);break;case DLL_PROCESS_DETACH:unhook(funcBase);break;}return TRUE;}DWORD hook(DWORD funcbase, DWORD fakeFunc){DWORD page;//如果已经被hook了就不再继续if(*(BYTE*)funcbase==0xe9){return0;}VirtualProtect((LPVOID)funcbase, 5, PAGE_EXECUTE_READWRITE, &page);memcpy(orgCode, (LPVOID)funcbase, 5);fakeCode[0] = 0xe9;DWORD opCode = fakeFunc -funcBase - 5;//jmp指令的操作码计算公式为:⽬标地址-当前指令地址-5 // sprintf(debug,"hook fakeFunc is %p, funcbase is %p",fakeFunc,funcbase);memcpy(fakeCode + 1, &opCode, 4);//填充为指令memcpy((LPVOID)funcBase, fakeCode, 5); //修改代码VirtualProtect((LPVOID)funcbase, 5, page, &page);return1;}DWORD unhook(DWORD funcbase){DWORD page;if(*(BYTE*)funcbase!=0xe9){return0;}VirtualProtect((LPVOID)funcbase, 5, PAGE_EXECUTE_READWRITE, &page);memcpy((LPVOID)funcBase, orgCode, 4); //恢复代码VirtualProtect((LPVOID)funcbase, 5, page, &page);return1;}DWORD WINAPI myZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass,PVOID SystemInformation,ULONG SystemInformationLength,PULONG ReturnLength)/*这个函数的hook和⼀般的函数不同,这种函数属于查询类的函数,真正有⽤的信息在该函数调⽤完了后才会写到缓冲区类的参数,⽽调⽤前的参数信息基本没⽤,因此我们要对该函数进⾏正常调⽤,完后了再截取信息*/{DWORD fakeFunc;funcBase = (DWORD)GetProcAddress(GetModuleHandleA(dllName), funcName);fakeFunc = (DWORD)myZwQuerySystemInformation;PSYSTEM_PROCESS_INFORMATION p, pPre;unhook(funcBase); //取消hook以正常调⽤DWORD status=4;status=((PFZWQUERYSYSTEMINFORMATION)funcBase)(SystemInformationClass,SystemInformation,SystemInformationLength,ReturnLength);//正常调⽤该函数if(status!=0){hook(funcBase, fakeFunc); //hook住return0;}if (SystemInformationClass== SystemProcessInformation) //只对查询进程的信息感兴趣 {p = ((PSYSTEM_PROCESS_INFORMATION)SystemInformation);while (1){if(p->Reserved2[1]!=0){if (lstrcmpiW((WCHAR*)p->Reserved2[1], processName)==0){if (p->NextEntryOffset==0)//说明是最后⼀个了{pPre->NextEntryOffset = 0; //将后⾯⼀个节点的next指针置0即可}else{//跳过本节点 NextEntryOffset字段是相对于本节点的偏移,⽽不是绝对地址 //当当前节点是第⼀个节点时这个式⼦也成⽴pPre->NextEntryOffset += p->NextEntryOffset;}}else{pPre = p;}}if(p->NextEntryOffset==0){break;}p =((PSYSTEM_PROCESS_INFORMATION)((DWORD)p + p->NextEntryOffset)); }}hook(funcBase, fakeFunc); //hook住return1;}。
API_HOOK讲解1
第6章APIHOOKAPIHOOK始终是系统程序员关心的热门话题。
通过APIHOOK,可以对Win32API函数进行拦截,从而改变函数乃至程序的固有行为。
通过APIHOOK拦截可以解决十分棘手的难题。
本章主要介绍Win32API拦截、驱动程序服务函数的拦截、BrowserHelpObject实现、SPI接口的应用,并利用Detours库实现对DLL的绑定。
6.1 APIHOOK综述APIHOOK尽管能够提供非常强大的功能,但是遗憾的是,无论是DDK还是SDK都没有提供这方面的任何文档和例子。
使用APIHOOK前,用户首先应该弄清楚,究竟是拦截一个应用程序还是系统范围内的拦截。
系统的拦截往往需要实现对创建的新的进程进行监视。
对系统底层服务进行拦截,能够打破进程边界。
最简单的实现拦截的方法是实现一个代理的动态链接库。
这个动态链接库实现了目标拦截动态链接库的全部输出函数,但是它只是一个函数转发器,其函数功能还是通过间接地调用原来的目标动态链接库函数实现。
当程序或者系统调用目标动态链接库的时候,真正调用的是代理动态链接库。
代理动态链接库的输出函数会首先检查调用函数的入口参数,决定直接返回一个值,还是调用原来的函数。
可以把这个函数的返回结果作为返回值返回,也可以对调用结果进行二次处理。
由于这种方法需要对所有的函数进行处理,这个过程十分繁琐,而且并非所有的函数都提供了足够的文档,因此这种方法在某些情况下几乎是无法实现的。
这方面应用的例子有关于WinInet实现的程序,发表在1994年12月份的MSJ杂志上,网址是/MSJ/0997/hood0997.htm。
对API函数的拦截不外乎两种方式,要么在磁盘文件上实现,要么在内存中实现。
前者拦截在可执行程序加载以前,后者则是在程序加载之后。
两种方法基本上都是通过打补丁的方法实现的。
如果用户以前曾经研究过APIHOOK,也许听说过导入地址表补丁的概念。
它的很多优点使得这种WindowsAPIHOOK的方法成为最体面、最常见的方法之一。
hook技术原理
Hook技术是一种用于拦截API函数调用的技术,它通过修改系统API函数的内存地址,从而拦截系统函数的调用,实现对系统API函数的拦截和修改。
Hook技术的基本原理是将系统API函数的内存地址指向一个用户定义的函数,而不是指向实际的API函数。
当调用系统API函数时,系统将调用用户定义的函数,而不是原来的函数。
这样就可以实现对系统API函数的拦截和修改。
Hook技术的实现步骤如下:
1、首先,程序员需要查找和定位需要拦截的API函数的内存地址。
2、然后,程序员需要编写用户定义的函数,用来拦截和修改系统API函数的调用。
3、接着,程序员需要将系统API函数的内存地址指向用户定义的函数,从而实现API函数的拦截。
4、最后,程序员需要将系统API函数的原始内存地址保存起来,以便在不再需要拦截时,可以恢复原来的API函数调用行为。
Hook技术是一种强大的技术,可以用来实现各种功能,比如拦截软件的调用,拦截软件的输入输出,拦截系统函数的调用等。
Hook技术也可以用来实现防病毒,反垃圾邮件,防恶意程序,实现软件保护以及实现自定义控件等功能。
hook api
实现HOOK API两种方法
改引入表式 陷阱式
用改引入表式方法来实现,这种方法易 于实现,但要求你熟悉PE文件结构。主 要是定位到Kernel32.dll模块的 OpenProcess函数地址,并用 WriteProcessMemory函数改写函数地址。
进程的定义
通常被定义为一个正在运行的程序的实 例,是一个程序在其自身的地址空间中 的一次执行活动。 的一次执行活动。
Hook的应用模式 的应用模式
观察模式 最为常用,像Windows提供的SetWindowHook 就是典型地为这类应用准备的。而且这也是最 普遍的用法。 这个模式的特点是,在事情发生 的时候,发出一个通知信息。观察者只可以查 看过程中的信息,根据自己关心的内容处理自 己的业务,但是不可以更改原来的流程。 如全 局钩子中,经常使用的鼠标消息、键盘消息的 监视等应用。金山词霸屏幕取词的功能是一个 典型的应用
HOOKAPI的原则
被HOOK的API的原有功能不能受到任何 影响。就像医生救人,如果把病人身体里 的病毒杀死了,病人也死了,那么这个 “救人”就没有任何意义了。如果你 HOOK API之后,你的目的达到了,但 API的原有功能失效了,这样不是HOOK, 而是REPLACE,操作系统的正常功能就 会受到影响,甚至会崩溃。
HOOK API
Hook API是一种拦截应用程序API函 数调用的通用机制,通过建立API Hook 可以监视和改变应用程序的行为。 HookAPI 技术常用于屏幕取词、网络防 火墙、病毒木马等领域。
Hook就是钩子的意思,而API是指 Windows开放给程序员的编程接口,使 得在用户级别下可以对操作系统进行控 制,也就是一般的应用程序都需要调用 API来完成某些功能,Hook API就是在这 些应用程序调用真正的系统API前可以先 被截获,从而进行一些处理再调用真正 的API来完成功能。
源程序程序破解之 API HOOK技术
gCallCounter ++;
}
#endif
return ret;
}
2)使用刚才提到的方法进行DLL导入
string hexData1 = toHexString((const char *)pbData, strlen((const char *)pbData));
int ret = sub_4026B0(pbData);
string hexData2 = toHexString((const char *)pbData, strlen((const char *)pbData));
gHooks.Add(_T("KERNEL32.DLL"), "DeviceIoControl", my_DeviceIoControl);
static int gCallCounter = 0;
BOOL WINAPI my_DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
// 指定DLL的某个函数进行HOOK
HANDLE Add(LPCTSTR lpszModule, LPCSTR lpcFuncName, void *pNewAddr, DWORD dwData = 0);
// 给定一个函数地址进行HOOK
hook api几种方法
:71A21B72 8B4508 mov eax, dword ptr [ebp+08]
:71A21B75 5F pop edi
:71A21B76 5E pop esi
:71A21B77 C9 leave
:71A21B78 C21000 ret 0010
下面用4种方法来HOOK这个API:
:71A21B62 8BD8 mov ebx, eax
:71A21B64 E8C7F6FFFF call 71A21230 //将被HOOK的机器码(第3种方法)
:71A21B69 3BDF cmp ebx, edi
:71A21B6B 5B pop ebx
:71A21B6C 0F855F940000 jne 71A2AFD1
假设我们的HOOK代码在71A20400处,那么我们把71A21B64处的CALL指令改为CALL 71A20400(原指令是这样的:CALL 71A21230)
而71A20400处的HOOK代码是这样的:
71A20400:
pushad
//在这里做你想做的事情
:71A21B42 57 push edi
:71A21B43 57 push edi
:71A21B44 FF7514 push [ebp+14]
:71A21B47 8945F0 mov dword ptr [ebp-10], eax
:71A21B4A 8B450C mov eax, dword ptr [ebp+0C]
4,上下文的问题,有些HOOK代码不能执行某些操作,否则会破坏原API的上下文,原API就失效了;
5,同步问题,在HOOK代码里尽量不使用全局变量,而使用局部变量,这样也是模块化程序的需要;
APIHook的几种实现
APIHook的⼏种实现所谓的API Hook,就是利⽤某种技术将API的调⽤转为我们⾃⼰定义的函数的调⽤。
这种技术在实际项⽬⾥⾯的应⽤也是很⼴泛的。
最近,我在做关于我们项⽬的⾃动化测试的时候,就遇到了这种情况。
在写测试代码之前,我们对测试代码有⼀些要求。
1. 不能因为测试代码⽽修改原代码。
2. 原有的模块是以dll格式输出的,在做测试的时候,要测的类和函数也只能使⽤dll的导出类或者函数,⽽不能将源⽂件重新编译。
由于这些限制,导致测试⽤例往往不能在普通的机器上运⾏。
⽐如这样⼀个函数:int func(){//Some initializing codesint hardware_code = get_hardware_code();if (is_valid_code(hardware_code)){//}//return ret;}此处,函数get_hardware_code()是与特定平台相关的,在普通PC上运⾏肯定⽆法获得正确的结果。
如果拿不到正确的结果,也就不能对函数func()进⾏测试了。
于是,我们就可以利⽤API Hook技术,在测试代码⾥⾯,把所有对get_hardware_code()的调⽤换成我们⾃定义的函数mock_get_hardware_code()的调⽤,这样,在我们⾃⼰定义的函数⾥⾯,可以返回⼀个有效的代码以保证原代码能够正确的往下执⾏。
经过研究,API Hook有这么⼏种⽅法。
1. 改写函数的⾸地址。
这个是在《Windows核⼼编程》⾥⾯⼤师提到的API Hook的⽅法之⼀。
原理就是,⾸先获得要被Hook的函数的地址(⽐如get_hardware_code()),然后将其⾸地址之后的若⼲字节(通常是5个字节)改成⼀条jmp指令,⽽jmp的⽬标地址就是⾃定义函数的地址(此处为mock_get_hardware_code())。
这样,当函数每次执⾏⽬标函数的时候,就会跳转到我们⾃定义的函数⾥⾯去。
Windows中Hook API技术
Windows下Hook API技术 inline hook分类: WINDOWS什么叫Hook API?所谓Hook就是钩子的意思,而API是指 Windows开放给程序员的编程接口,使得在用户级别下可以对操作系统进行控制,也就是一般的应用程序都需要调用API来完成某些功能, Hook API的意思就是在这些应用程序调用真正的系统API前可以先被截获,从而进行一些处理再调用真正的API来完成功能。
在讲Hook API之前先来看一下如何Hook消息,例如Hook全局键盘消息,从而可以知道用户按了哪些键,这种Hook消息的功能可以由以下函数来完成,该函数将一个新的 Hook加入到原来的Hook链中,当某一消息到达后会依次经过它的Hook链再交给应用程序。
HHOOK SetWindowsHookEx(int idHook, //Hook类型,例如WH_KEYBOARD,WH_MOUSEHOOKPROC lpfn, //Hook处理过程函数的地址HINSTANCE hMod, //包含Hook处理过程函数的dll句柄(若在本进程可以为NULL)DWORD dwThreadId, //要Hook的线程ID,若为0,表示全局Hook所有);这里需要提一下的就是如果是Hook全局的而不是某个特定的进程则需要将Hook过程编写为一个DLL,以便让任何程序都可以加载它来获取Hook过程函数。
而对于Hook API微软并没有提供直接的接口函数,也许它并不想让我们这样做,不过有2种方法可以完成该功能。
第一种,修改可执行文件的IAT表(即输入表),因为在该表中记录了所有调用API的函数地址,则只需将这些地址改为自己函数的地址即可,但是这样有一个局限,因为有的程序会加壳,这样会隐藏真实的IAT表,从而使该方法失效。
第二种方法是直接跳转,改变API函数的头几个字节,使程序跳转到自己的函数,然后恢复API开头的几个字节,在调用AP完成功能后再改回来又能继续Hook了,但是这种方法也有一个问题就是同步的问题,当然这是可以克服的,并且该方法不受程序加壳的限制。
