eat hook原来eat hook原来
作 者: Sysnap时 间: 2008-04-05,17:13链 接: ?t=62574看了combojiang大侠的rootkit专题,发现少了一个导出表钩子,既EAT;HOOK,刚好前几天自己搞了个IATHOOK,然后就把其中的代码稍做修改,于是有这篇文章,偶学的东西不久,很多东西还不知道,请多指教,呵呵导出表钩子比导入表钩子感觉好用多,先说下原理吧,函数导入的函数的地址是再运行时候才确定的,比如我们的一个驱动程序导入了PsGetCurrentProcessId这个ntkrnlpa.exe导出的函数,那在我们驱动程序加载运行的时候,装载程序会确定ntkrnlpa.exe在内存的基地址,接着遍历它的导出表,在AddressOfNames指向的"函数名字表"中找到PsGetCurrentProcessId的位置,也就是如果在AddressOfNames[i]中找到PsGetCurrentProcessId,那就用i在AddressOfNameOrdinals中索引,假使得到是X,那么AddressOfFunctions[index]的值就是PsGetCurrentProcessId的RVA了,最后就可以知道PsGetCurrentProcessId在内存的值是MM=ntkrnlpa.exe在内存的基地址+PsGetCurrentProcessId的RVA,然后转载程序就把这个值写到我们驱动程序的IAT中,好了知道这些后,EATHOOK就是修改PsGetCurrentProcessId的RVA,使得PsGetCurrentProcessId的RVA(修改后的)+ntkrnlpa.exe在内存的基地址=我们自己函数的值,这样装载程序会把我们的函数的地址写入那些调用PsGetCurrentProcessId的驱动程序的IAT,那么当那些驱动程序调用PsGetCurrentProcessId时,实际上是执行了我们自己的函数...呵呵.是不是比IATHOOK更好用呢
EATHOOK可以用来监控系统函数的调用情况,比如我们EATHOOK了PsGetCurrentProcessId,那谁调用该函数我们就知道了,你也可以HOOKKeInitializeApc等热门函数,其实知道了EATHOOK原理后,我们可以修改函数名字表,比如把PsGetCurrentProcessId改成其它名字,这样装载程序遍历"函数名字表"就找不到匹对的名字,那驱动程序就宣告装载失败,详细代码请看<<利用导出表来禁止一些驱动程序的加载>>?t=62531
那怎么防止EATHOOK,一个方法是自己定位函数在内存地址,请看下面的代码,用于枚举ntkrnlpa.exe导出函数在内存的地址VOIDListKernelFunctionAndAddress(){
HANDLEhMod;
PVOIDBaseAddress=NULL;
IMAGE_DOS_HEADER*dosheader;
IMAGE_OPTIONAL_HEADER*opthdr;
PIMAGE_EXPORT_DIRECTORYexports;
USHORTindex=0;
ULONGaddr,i;
PVOIDFuncNameRVA;
PUCHARpFuncName=NULL;
PULONGpAddressOfFunctions,pAddressOfNames,pAddressOfNameOrdinals;
BaseAddress=GetDriverBaseAdress("ntkrnlpa.exe");
DbgPrint("MapBaseAddressis:%x/n",BaseAddress);
hMod=BaseAddress;
dosheader=(IMAGE_DOS_HEADER*)hMod;
opthdr=(IMAGE_OPTIONAL_HEADER*)((BYTE*)hMod+dosheader->e_lfanew+24);
exports=(PIMAGE_EXPORT_DIRECTORY)((BYTE*)dosheader+opthdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
pAddressOfFunctions=(ULONG*)((BYTE*)hMod+exports->AddressOfFunctions);
pAddressOfNames=(ULONG*)((BYTE*)hMod+exports->AddressOfNames);
pAddressOfNameOrdinals=(USHORT*)((BYTE*)hMod+exports->AddressOfNameOrdinals);
for(i=0;i<exports->NumberOfNames;i++){
index=pAddressOfNameOrdinals[i];
addr=pAddressOfFunctions[index];
pFuncName=(PUCHAR)((BYTE*)hMod+pAddressOfNames[i]);
addr=pAddressOfFunctions[index];
DbgPrint("thefunction:%sisat:0x%x/n",pFuncName,addr+(BYTE*)hMod);}}运行后:------------------------------------------------------------------------
好了,讲了这么多时候进去正题,怎样EATHOOK,这里我们以HOOKntkrnlpa.exe导出的PsGetCurrentProcessId
首先我们是定位ntkrnlpa.exe被加载在内存中的什么地方,那就写一个函数吧,PVOIDGetModlueBaseAdress(char*ModlueName){
ULONGsize,index;
PULONGbuf;NTSTATUSstatus;
PSYSTEM_MODULE_INFORMATIONmodule;
PVOIDdriverAddress=0;
ZwQuerySystemInformation(SystemModuleInformation,&size,0,&size);if(NULL==(buf=(PULONG)ExAllocatePool(PagedPool,size)))
{
DbgPrint("failedallocmemoryfailed/n");
return0;
}status=ZwQuerySystemInformation(SystemModuleInformation,buf,size,0);
if(!NT_SUCCESS(status))
{DbgPrint("failedquery/n");
return0;
}module=(PSYSTEM_MODULE_INFORMATION)((PULONG)buf+1);
for(index=0;index<*buf;index++)
if(_stricmp(module[index].ImageName+module[index].ModuleNameOffset,ModlueName)==0)
{driverAddress=module[index].Base;DbgPrint("Modulefoundat:%x/n",driverAddress);
}
ExFreePool(buf);
returndriverAddress;}自己添加点测试代码编译下,没什么问题,这样我们就完成了第一个问题
接着是写自己的函数了,就是替换PsGetCurrentProcessId的函数,这里我们很简单的输出点内容就可以了ULONGg_OriginalPsGetCurrentProcessId;typedefHANDLE(*PSGETCURRENTPROCESSID)();HANDLEMyPsGetCurrentProcessId(){
HANDLEhandle;
DbgPrint("HOOK_PsGetCurrentProcessIdcalled!/n");handle=((PSGETCURRENTPROCESSID)(g_OriginalPsGetCurrentProcessId))();returnhandle;}
好了,那就开始写安装钩子程序吧,因为在卸在钩子时需要用到一些变量,这里我们就把安装和卸载写成一个函数就可以了,注意INunsignedinttest,传入1表示安装钩子,否则表示卸载,INPCSTRfunName这里我们传入PsGetCurrentProcessId,好了请看代码VOIDStartHook_And_Unhook(INPCSTRfunName,INunsignedinttest){
HANDLEhMod;
PUCHARBaseAddress=NULL;
IMAGE_DOS_HEADER*dosheader;
IMAGE_OPTIONAL_HEADER*opthdr;
PIMAGE_EXPORT_DIRECTORYexports;
USHORTindex=0;
ULONGaddr,i;
PUCHARpFuncName=NULL;
PULONGpAddressOfFunctions,pAddressOfNames;
PUSHORTpAddressOfNameOrdinals;
BaseAddress=GetModlueBaseAdress("ntkrnlpa.exe");
DbgPrint("MapBaseAddressis:%x/n",BaseAddress);
hMod=BaseAddress;
dosheader=(IMAGE_DOS_HEADER*)hMod;
opthdr=(IMAGE_OPTIONAL_HEADER*)((BYTE*)hMod+dosheader->e_lfanew+24);
exports=(PIMAGE_EXPORT_DIRECTORY)((BYTE*)dosheader+opthdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
pAddressOfFunctions=(ULONG*)((BYTE*)hMod+exports->AddressOfFunctions);
pAddressOfNames=(ULONG*)((BYTE*)hMod+exports->AddressOfNames);
pAddressOfNameOrdinals=(USHORT*)((BYTE*)hMod+exports->AddressOfNameOrdinals);
for(i=0;i<exports->NumberOfNames;i++){
index=pAddressOfNameOrdinals[i];
pFuncName=(PUCHAR)((BYTE*)hMod+pAddressOfNames[i]);
if(_stricmp((char*)pFuncName,funName)==0){
addr=pAddressOfFunctions[index];
break;}}
if(test==1)
{
_asm
{
CLI
MOV
EAX,CR0
ANDEAX,NOT10000H
MOV
CR0,EAX
}
DbgPrint("PsGetCurrentProcessIdis:%x/n",(PUCHAR)hMod+pAddressOfFunctions[index]);
pAddressOfFunctions[index]=(PCHAR)MyPsGetCurrentProcessId-BaseAddress;
DbgPrint("g_OriginalPsGetCurrentProcessIdis:%x/n",g_OriginalPsGetCurrentProcessId);
g_OriginalPsGetCurrentProcessId=(PUCHAR)hMod+pAddressOfFunctions[index];_asm
{
MOV
EAX,CR0
OR
EAX,10000H
MOV
CR0,EAX
STI
}
}
else
{_asm
{
CLI
MOV
EAX,CR0
ANDEAX,NOT10000H
MOV
CR0,EAX
}
pAddressOfFunctions[index]=(PCHAR)g_OriginalPsGetCurrentProcessId-BaseAddress;
_asm
{
MOV
EAX,CR0
OR
EAX,10000H
MOV
CR0,EAX
STI
}
}}好了,基本框架就差不多了,接着就是一些结构的声明,我们把它放在hookiat.h这个头文件里,因为很长就不帖了,可以在附件里看,上面的代码很多地方不是很好,需要自己修改,不保证在你机器不蓝,呵呵,学习靠思考,在代码里我修改了一处地方
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/tongxinshuyu/article-43685-1.html
你那是WiFi热点吧
一旦开战吃亏的还是自己