第一次写文章,希望各位大侠,牛人体谅,呵。
API HOOK 是个好古老的话题了,但作为一个不懂算入门没有的新手,也只能从这些基本的学起。HOOK API的作用主要是在原程序调用API是首先进入自己的处理过程,对调用结果进程一定处理后再按自己意愿返回。如比较经典的封包助手,就是HOOK了系统的SOCKET的recv函数,把包显示出来再调用返回给应用处理。
OK,下面我要HOOK的是EnumProcesses ,钩API有几种方式:
1.API实现函数内钩,起作用范围广,对进程内所有位置内包括远程注入线程调用均有效。但钩的位置要比较猥琐才行,一般的会选择头几字节来钩,但说实在的,做一个简单的内存校验就可以发现被钩了。一般是选择中间位置来钩,或钩更下层的API,如GetProcAddress这个,它会调用LdrGetProcedureAddress这个API,所以可以选择钩这个,但要注意处理堆栈。当然,原应用做内存检测的话,还是逃不过被检测的命运的。
2.可以在API调用位置上下钩,作用范围仅在于当前调用处有效,假如程序在另一地方有调用API则是钩不到的。严格来说这不算是钩API了,和一般的内联hook差不多。但在某些场合还是比较有用的。
3.可以修改IAT表,作用范围仅在当前模块,这种方式比较常用,当然要小心原程序调用GetProcAddress来检查:
if [IATBase] != GetProcAddress(APIName)
{
cout<<" 你的钩子被发现了 你的计算机即在10s内发生'砰'......................";
}
下面说下HOOK EnumProcesses过程,选用IAT HOOK,操作系统为win server03.先查MSDN,实现语言是Delphi。先看函数的原型:
BOOL WINAPI EnumProcesses(
__out DWORD* pProcessIds,
__in DWORD cb,
__out DWORD* pBytesReturned
);看解释可以知道,第一个参数是一个进程ID数组指针,即返回当前系统的所有进程的ID,第二个参数是这个数组的长度,注意它是按字节算的,这个参数一般可以用SizeOf(array)来传入,因为SizeOf获取的是数组的字节长度。第三个参数是返回的数据长度,也是按字节计算,即获取的进程个数实际上是(pBytesReturned*)/SizeOf(DWORD);好了,下面再看看实际调用的汇编代码:
压栈顺序是从右至左,然后跟进这个CALL:
这个就是它的输入表的位置了,看看它的基址是:0x00B2C700 .这个地址下面的值就是EnumProcesses的真正地址了:
为什么要有IAT表呢?因为DLL载入内存需要重定位的,会把真正的API地址放入这个基址下面。嗯,接下来的工作就简单了,我们把0x00B2C700这个地址下一值改成我们自己的处理函数就行了。我们要先写一个函数过程,注意参数要和原API一致。至于类型,一般来说WIN下的API都是指针操作,所以一般用DWORD就可以了,你自己的函数内使用时要记住它是指针就行。先复制代码:
///
/// EnumProcesses的过滤处理过程
/// 可以修改输出的结果
///
/// 输出参数:进程ID数组指针
/// 进程ID数组的初始化长度,以byte为单位
/// 输出参数:返回的数据大小,以byte为单位
/// 原API的处理结果,也压入,通过这个过程返回给原应用调用者
///
function MYEnumProcessesFilter(pProcessIds: DWORD; cb: DWORD; pBytesReturned: DWORD; res: DWORD): DWORD; stdcall;
begin
Result:=res;
end;
///
/// 自己的EnumProcesses处理过程
///
/// 输出参数:进程ID数组指针
/// 进程ID数组的初始化长度,以byte为单位
/// 输出参数:返回的数据大小,以byte为单位
///
function MyEnumProcesses(pProcessIds: DWORD; cb: DWORD; pBytesReturned: DWORD): Integer; stdcall;
asm
push pBytesReturned
push cb
push pProcessIds
mov eax,EnumProcesseApiAddr
call eax
[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!
上传的附件: