【原创】导出表钩子------EAT HOOK

看了combojiang大侠的rootkit专题,发现少了一个导出表钩子,既EAT;HOOK,刚好前几天自己搞了个IAT HOOK,然后就把其中的代码稍做修改,于是有这篇文章,

偶学的东西不久,很多东西还不知道,请多指教,呵呵

导出表钩子比导入表钩子感觉好用多,先说下原理吧,函数导入的函数的地址是再运行时候才确定的,比如我们的一个驱动程序导入了PsGetCurrentProcessId这个ntkrnlpa.exe

导出的函数,那在我们驱动程序加载运行的时候,装载程序会确定ntkrnlpa.exe在内存的基地址,接着遍历它的导出表,在AddressOfNames指向的"函数名字表"中找到

PsGetCurrentProcessId的位置,也就是如果在AddressOfNames[i]中找到PsGetCurrentProcessId,那就用i在AddressOfNameOrdinals中索引,假使得到是X,那么

AddressOfFunctions[index]的值就是PsGetCurrentProcessId的RVA了,最后就可以知道PsGetCurrentProcessId在内存的值是MM=ntkrnlpa.exe在内存的基地址

+PsGetCurrentProcessId的RVA,然后转载程序就把这个值写到我们驱动程序的IAT中,好了知道这些后,EAT HOOK就是修改PsGetCurrentProcessId的RVA,使得

PsGetCurrentProcessId的RVA(修改后的)+ntkrnlpa.exe在内存的基地址=我们自己函数的值,这样装载程序会把我们的函数的地址写入那些调用PsGetCurrentProcessId

的驱动程序的IAT,那么当那些驱动程序调用PsGetCurrentProcessId时,实际上是执行了我们自己的函数...呵呵.是不是比IAT HOOK更好用呢

EAT HOOK可以用来监控系统函数的调用情况,比如我们EAT HOOK了

PsGetCurrentProcessId,那谁调用该函数我们就知道了,你也可以HOOK KeInitializeApc等热门函数,其实知道了EAT HOOK原理后,我们

可以修改函数名字表,比如把PsGetCurrentProcessId改成其它名字,这样装载程序遍历"函

数名字表"就找不到匹对的名字,那驱动程序就宣告装载失败,详细代码请看
<<利用导出表来禁止一些驱动程序的加载>>http://bbs.pediy.com/showthread.php?t=62531


那怎么防止EAT HOOK,一个方法是自己定位函数在内存地址,请看下面的代码,用于枚举

ntkrnlpa.exe导出函数在内存的地址
VOID ListKernelFunctionAndAddress() 
{
HANDLE hMod;
PVOID BaseAddress = NULL;
IMAGE_DOS_HEADER * dosheader;
IMAGE_OPTIONAL_HEADER * opthdr;
PIMAGE_EXPORT_DIRECTORY exports;

USHORT index=0 ; 
ULONG addr, i;

PVOID FuncNameRVA;
PUCHAR pFuncName = NULL;
PULONG pAddressOfFunctions,pAddressOfNames,pAddressOfNameOrdinals;

BaseAddress= GetDriverBaseAdress("ntkrnlpa.exe");
DbgPrint("Map BaseAddress is:%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("the function: %s is at: 0x%x\n",pFuncName,addr+(BYTE*)hMod);

}

}
运行后:

12982
--------------------
--------------
-----------------
---------------------
好了,讲了这么多时候进去正题,怎样EAT HOOK,这里我们以HOOK ntkrnlpa.exe导出的

PsGetCurrentProcessId
首先我们是定位ntkrnlpa.exe被加载在内存中的什么地方,那就写一个函数吧,
PVOID GetModlueBaseAdress(char* ModlueName)
{
ULONG size,index;
PULONG buf;
NTSTATUS status;
PSYSTEM_MODULE_INFORMATION module;
PVOID driverAddress=0;

ZwQuerySystemInformation(SystemModuleInformation,&size, 0, &size);
if(NULL==(buf = (PULONG)ExAllocatePool(PagedPool, size)))
{
DbgPrint("failed alloc memory failed \n");
return 0;
}
status=ZwQuerySystemInformation(SystemModuleInformation,buf, size , 0);
if(!NT_SUCCESS( status ))
{
DbgPrint("failed query\n");
return 0;
}
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("Module found at:%x\n",driverAddress);
}
ExFreePool(buf);
return driverAddress;
}
自己添加点测试代码编译下,没什么问题,这样我们就完成了第一个问题

接着是写自己的函数了,就是替换PsGetCurrentProcessId的函数,这里我们很简单的输

出点内容就可以了
ULONG g_OriginalPsGetCurrentProcessId;
typedef HANDLE (*PSGETCURRENTPROCESSID)();

HANDLE
MyPsGetCurrentProcessId()

{
HANDLE handle;
DbgPrint("HOOK_PsGetCurrentProcessId called!\n");
handle =((PSGETCURRENTPROCESSID)(g_OriginalPsGetCurrentProcessId))();
return handle;



好了,那就开始写安装钩子程序吧,因为在卸在钩子时需要用到一些变量,这里我们就把安

装和卸载写成一个函数就可以了,注意IN unsigned int test,传入1表示安装钩子,否则表

示卸载,IN PCSTR funName这里我们传入PsGetCurrentProcessId,好了请看代码

VOID StartHook_And_Unhook(IN PCSTR funName, IN unsigned int test) 
{
HANDLE hMod;
PUCHAR BaseAddress = NULL;
IMAGE_DOS_HEADER * dosheader;
IMAGE_OPTIONAL_HEADER * opthdr;
PIMAGE_EXPORT_DIRECTORY exports;

USHORT index=0 ; 
ULONG addr ,i;
PUCHAR pFuncName = NULL;
PULONG pAddressOfFunctions,pAddressOfNames;
PUSHORT pAddressOfNameOrdinals;

BaseAddress= GetModlueBaseAdress("ntkrnlpa.exe");
DbgPrint("Map BaseAddress is:%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 
AND EAX, NOT 10000H 
MOV CR0, EAX 


DbgPrint("PsGetCurrentProcessId is:%x\n",(PUCHAR)hMod + pAddressOfFunctions[index]);
pAddressOfFunctions[index] = ( PCHAR )MyPsGetCurrentProcessId - BaseAddress;
DbgPrint("g_OriginalPsGetCurrentProcessId is:%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 
AND EAX, NOT 10000H 
MOV CR0, EAX 


pAddressOfFunctions[index] = ( PCHAR )g_OriginalPsGetCurrentProcessId - BaseAddress;

_asm 
{
MOV EAX, CR0 
OR EAX, 10000H 
MOV CR0, EAX 
STI 


}


好了,基本框架就差不多了,接着就是一些结构的声明,我们把它放在hookiat.h这个头文件

里,因为很长就不帖了,可以在附件里看,上面的代码很多地方不是很好,需要自己修改,不

保证在你机器不蓝,呵呵,学习靠思考,在代码里我修改了一处地方

12983
lly鹅
2008-04-05, 18:31:53
Windows的运行机制 复杂的很


从哪开始进去啊。。。会把人搞晕不?

有没有比较入门的 大众话点 系统的点资料啊
lOOp
2008-04-06, 00:48:10
shoucang....
combojiang
2008-04-06, 14:35:53
不错,收录到专题中了。
Sysnap
2008-04-06, 17:43:35
哇.....谢谢combojiang 的鼓励
winnip
2008-04-06, 17:59:23
讲的很复杂..:):
metalqiang
2008-04-06, 20:22:49
好文章,学习了
linyboy
2008-04-06, 20:59:04
:eek: 蓝屏
HSQ
2008-04-18, 09:39:37
楼上的BSOD了:p: 
只要是关于钩子的,都顶之:p:
nuke
2008-05-02, 00:52:33
不错,
MmGetSystemRoutineAddress取的是挂了服务表后的,
可能不干净了。
这个表是不是在inline hook之后呢,
inline hook里直接jmp处理,会绕过这个表不
icqking
2008-05-11, 19:26:20
很好.谢谢.


最好把
PULONG pAddressOfNameOrdinals;
改成
PUSHORT pAddressOfNameOrdinals;
不然有可能会蓝屏.

在VM中测试,函数地址确实改了,但测试时,没有调用自定的函数(没看到dbgprint输出的信息)

不知是怎么回事?
classfree
2008-05-31, 19:01:50
还是要BSOD
Sysnap
2008-06-01, 08:10:38
很好.谢谢.


最好把
PULONG pAddressOfNameOrdinals;
改成
PUSHORT pAddressOfNameOrdinals;
不然有可能会蓝屏.

在VM中测试,函数地址确实改了,但测试时,没有调用自定的函数(没看到dbgprint输出的信息...
EAT HOOK有一个时间的问题...对那些已经加载运行的程序无效.....你可以打开ICESWORD就可以看到输出了
Sysnap
2008-06-01, 08:11:24
还是要BSOD

参考11楼的....如果蓝的话自己再改改...
loien
2008-06-01, 10:34:03
啊,我要疯了,各种蓝,蓝各种,各种加各种。
调试你的驱动蓝屏。编译成功后依然蓝屏.
另外问一下楼主,为什么GetModlueBaseAdress在我的机器上得到的ntkrnlpa.exe基址为0????:eek:
Sysnap
2008-06-01, 11:16:19
你先运行我附件里的驱动看看....如果可以的话再说
Sysnap
2008-06-01, 11:20:56
BaseAddress= GetModlueBaseAdress("ntkrnlpa.exe");//-----这句可能有问题....当时是在我机器里试的...用了硬编码...事实上ZwQuerySystemInformation返回的第一个模块就是我们要的.....所以你可以改下代码....或者
BaseAddress= GetModlueBaseAdress("ntkrnlpa.exe");改为
BaseAddress= GetModlueBaseAdress("ntoskrnl.exe");看看
loien
2008-06-01, 11:34:13
恩好我试一下:p: 
你附加里的驱动我运行了,还是蓝屏(我的机器直接重启):confused:
loien
2008-06-02, 08:07:14
Sysnap正如你所说的
BaseAddress=&nbsp;&nbsp;GetModlueBaseAdress("ntoskrnl.exe");确实可以得到基址,
:D: 另外还有几个小问题:
ULONG g_OriginalPsGetCurrentProcessId;是保存原函数的的地址

MOV CR0, EAX
}

DbgPrint("PsGetCurrentProcessId is:%x\n",(PUCHAR)hMod + pAddressOfFunctions[index]);
pAddressOfFunctions[index] = ( PCHAR )MyPsGetCurrentProcessId - BaseAddress;
DbgPrint("g_OriginalPsGetCurrentProcessId is:%x\n",g_OriginalPsGetCurrentProcessId);
g_OriginalPsGetCurrentProcessId= (ULONG)hMod + pAddressOfFunctions[index] ;
_asm 
{
MOV EAX, CR0

g_OriginalPsGetCurrentProcessId= (ULONG)hMod + pAddressOfFunctions[index] ;是不是应该放在pAddressOfFunctions[index] = ( PCHAR )MyPsGetCurrentProcessId - BaseAddress;前面啊,不然g_OriginalPsGetCurrentProcessId得到的是( PCHAR )MyPsGetCurrentProcessId - BaseAddress;

Byw
Sysnap你有没有什么QQ的啊~~给个号呗,研究下问题
loien
2008-06-02, 08:10:36
另外你有没有出现过这样的问题
g_OriginalPsGetCurrentProcessId=0了
:eek:
Sysnap
2008-06-02, 08:17:07
嗯...看你图片就知道你成功了..呵呵....
loien
2008-06-02, 09:01:05
帮我回答下19楼的问题呀:):
Sysnap
2008-06-02, 09:15:27
嗯....的确是你所说的...当时俺的代码可能改糊涂了...
g_OriginalPsGetCurrentProcessId=0这个问题不会出现
loien
2008-06-02, 09:26:47
哦,好的明白:cool:
classfree
2008-06-03, 12:49:18
我用冰刃看了,获取的ntoskrnl.exe的地址没有错,
但是好像并没有HOOK到样, 运行其他的程序,并没有调用我的My函数
cvcvxk
2008-09-08, 13:46:36
DbgPrint("PsGetCurrentProcessId is:%x\n",(PUCHAR)hMod + pAddressOfFunctions[index]);
pAddressOfFunctions[index] = ( PCHAR )MyPsGetCurrentProcessId - BaseAddress;
DbgPrint("g_OriginalPsGetCurrentProcessId is:%x\n",g_OriginalPsGetCurrentProcessId);
g_OriginalPsGetCurrentProcessId= (PUCHAR)hMod + pAddressOfFunctions[index] ;

要改成
g_OriginalPsGetCurrentProcessId= (PUCHAR)hMod + pAddressOfFunctions[index] ;
DbgPrint("PsGetCurrentProcessId is:%x\n",(PUCHAR)hMod + pAddressOfFunctions[index]);
pAddressOfFunctions[index] = ( PCHAR )MyPsGetCurrentProcessId - BaseAddress;
DbgPrint("g_OriginalPsGetCurrentProcessId is:%x\n",g_OriginalPsGetCurrentProcessId);
sflyhm
2008-10-25, 16:35:26
对更改内核导出表的操作,代码略作修改,如下:

if(test==1)
{
g_OriginalPsGetCurrentProcessId=(ULONG)((PUCHAR)hMod + pAddressOfFunctions[index]);
DbgPrint("PsGetCurrentProcessId is:%x\n",g_OriginalPsGetCurrentProcessId);

_asm
{
CLI
MOV EAX, CR0
AND EAX, NOT 10000H 
MOV CR0, EAX
}

pAddressOfFunctions[index] = (PCHAR)MyPsGetCurrentProcessId - BaseAddress; 

_asm 
{
MOV EAX, CR0
OR EAX, 10000H
MOV CR0, EAX
STI
}


DbgPrint("g_OriginalPsGetCurrentProcessId is:%x\n",g_OriginalPsGetCurrentProcessId);
}

否则容易蓝屏。
yaolibing
2009-03-01, 18:57:49
PVOID GetModlueBaseAdress(char* ModlueName)
{
ULONG size,index;
PULONG buf;
NTSTATUS status;
PSYSTEM_MODULE_INFORMATION module;
PVOID driverAddress=0;

ZwQuerySystemInformation(SystemModuleInformation,&size, 0, &size);
if(NULL==(buf = (PULONG)ExAllocatePool(PagedPool, size)))
{
DbgPrint("failed alloc memory failed \n");
return 0;
}
status=ZwQuerySystemInformation(SystemModuleInformation,buf, size , 0);
if(!NT_SUCCESS( status ))
{
DbgPrint("failed query\n");
return 0;
}
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("Module found at:%x\n",driverAddress);
}
ExFreePool(buf);
return driverAddress;
}

哪位大哥告诉我下
(_stricmp(module[index].ImageName + module[index].ModuleNameOffset, ModlueName) == 0这句的module[index].ImageName + module[index].ModuleNameOffset是什么意思啊?弄不明白
yindubao
2009-04-28, 16:34:41
#include "ntddk.h"
#include "hookiat.h"
#pragma comment(lib,"ntdll.lib")

ULONG g_OriginalPsGetCurrentProcessId;
typedef HANDLE (*PSGETCURRENTPROCESSID)();

HANDLE
MyPsGetCurrentProcessId()

{
HANDLE handle;
DbgPrint("HOOK_PsGetCurrentProcessId called!\n");
handle =((PSGETCURRENTPROCESSID)(g_OriginalPsGetCurrentProcessId))();
return handle;



PVOID GetModlueBaseAdress(char* ModlueName)
{
ULONG size,index;
PULONG buf;
NTSTATUS status;
PSYSTEM_MODULE_INFORMATION module;
PVOID driverAddress=0;

ZwQuerySystemInformation(SystemModuleInformation,&size, 0, &size);
if(NULL==(buf = (PULONG)ExAllocatePool(PagedPool, size)))
{
DbgPrint("failed alloc memory failed \n");
return 0;
}
status=ZwQuerySystemInformation(SystemModuleInformation,buf, size , 0);
if(!NT_SUCCESS( status ))
{
DbgPrint("failed query\n");
return 0;
}
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("Module found at:%x\n",driverAddress);
}
ExFreePool(buf);
return driverAddress;
}

//StartHook_And_Unhook是安装钩子和卸载钩子,如果 test==1表示安装,否则表示卸载
VOID StartHook_And_Unhook(IN PCSTR funName, IN unsigned int test) 
{
HANDLE hMod;//JK:不指向任何类型的指针
PUCHAR BaseAddress = NULL;//JK:这个变量保存了一个32BTI地址,而这个地址指向了一个内存单元的内容
IMAGE_DOS_HEADER * dosheader;//JK:DOS文件头指针
IMAGE_OPTIONAL_HEADER * opthdr;//JK:结构
PIMAGE_EXPORT_DIRECTORY exports;//JK:用于保存一个IMAGE_EXPORT_DIRECTORY结构地址的指针变量

USHORT index=0 ; 
ULONG addr ,i;


PUCHAR pFuncName = NULL;
PULONG pAddressOfFunctions,pAddressOfNames;//这个变量保存了一个32BTI地址,而这个地址指向了四个内存单元的内容
PUSHORT pAddressOfNameOrdinals;//这个变量保存了一个32BTI地址,而这个地址指向了两个内存单元的内容

BaseAddress= GetModlueBaseAdress("ntoskrnl.exe");//JK:获取要HOOK模块的导入表的模块地址
DbgPrint("Map BaseAddress is:%x\n",BaseAddress);
hMod = BaseAddress;



dosheader = (IMAGE_DOS_HEADER *)hMod;//JK:dosheader保存了描述DOS头的结构变量的地址
opthdr =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hMod+dosheader->e_lfanew+24);//JK:dosheader->e_lfanew会输出PE文件头的位置+24是因为IMAGE_FILE_HEADER结构占20个字节,而加4是因为Signature所占4个字节,这样就指向了IMAGE_OPTIONAL_HEADER的位置
exports = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)dosheader+ opthdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);//JK:exports保存了IMAGE_EXPORT_DIRECTORY结构变量的地址

pAddressOfFunctions=(ULONG*)((BYTE*)hMod+exports->AddressOfFunctions); //JK:获得EAT的入口地址,EAT又双字的数组组成
pAddressOfNames=(ULONG*)((BYTE*)hMod+exports->AddressOfNames);//JK:函数名字符串的地址表,根据这个地址表(由双字的数组组成)可获得函数名称的字符串
pAddressOfNameOrdinals=(USHORT*)((BYTE*)hMod+exports->AddressOfNameOrdinals); //JK:保存用于去pAddressOfFunctions指向的EAT中取函数地址的索引值(这个索引值还与函数名字符串的地址表对应,这样就可通过函数名称返回函数的地址了)



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];//JK:addr变量保存了PsGetCurrentProcessId函数的地址
break;
}

}


if(test==1) {

_asm
{
CLI
MOV EAX, CR0
AND EAX, NOT 10000H 
MOV CR0, EAX
}

//DbgPrint("PsGetCurrentProcessId is:%x\n",(ULONG)hMod + addr);//JK:输出PsGetCurrentProcessId这个函数的地址,基地址加RVA JK:用addr代替了pAddressOfFunctions[index]
g_OriginalPsGetCurrentProcessId= (ULONG)hMod + pAddressOfFunctions[index] ;//JK:g_OriginalPsGetCurrentProcessId保存了原先PsGetCurrentProcessId的地址

//DbgPrint("g_OriginalPsGetCurrentProcessId is:%x\n",g_OriginalPsGetCurrentProcessId);


pAddressOfFunctions[index] = ( PCHAR )MyPsGetCurrentProcessId - BaseAddress;//求出MyPsGetCurrentProcessId的RVA




_asm 
{
MOV EAX, CR0
OR EAX, 10000H
MOV CR0, EAX
STI
}
}

else
{
_asm
{
CLI
MOV EAX, CR0
AND EAX, NOT 10000H 
MOV CR0, EAX
}

pAddressOfFunctions[index] = ( PCHAR )g_OriginalPsGetCurrentProcessId - BaseAddress;//JK 恢复以前的PsGetCurrentProcessId的地址


_asm 
{
MOV EAX, CR0
OR EAX, 10000H
MOV CR0, EAX
STI
}



}







VOID Unload(PDRIVER_OBJECT DriverObject)
{

PCSTR myfunName="PsGetCurrentProcessId";
StartHook_And_Unhook(myfunName,0);
DbgPrint("Unload Callled\n");
}


NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING str)
{

PCSTR myfunName="PsGetCurrentProcessId";
StartHook_And_Unhook(myfunName,1);

DriverObject->DriverUnload = Unload;
return STATUS_SUCCESS;
}
wangzheye
2009-04-28, 17:51:45
别做这傻事了,eat是危险的,因为call指令在作怪。call指令有长跳河短跳之分,系统函数中call指令一般都跳的距离不太远。
wangzheye
2009-04-28, 17:54:37
别光顾着发帖,得试试你的方法可靠不?你的方法我可以是说不可靠,除非你的驱动基地址离系统基地址很近
yindubao
2009-04-29, 09:14:01
不是CALL的事,我调试时发现时进入了KeStackAttachProcess这个函数,好像是保护系统了。。。。 请高手指点,因为上面有贴图,所以我觉得是可行了。。。。。。。。
yindubao
2009-04-30, 09:03:16
怎么没人跟帖呢?
jerrynpc
2009-09-07, 09:37:20
好东西,才发现。膜拜
yspwch
2010-01-13, 14:33:19
应该多加学习学习
mistkx
2010-01-14, 13:02:09
侃侃:p:,不懂
zyyuser
2010-06-13, 13:52:29
这个能钩住用GetProcAddress得到的函数地址吗?我要钩的是普通DLL的函数,应该不会蓝吧!
我又来了
2010-06-19, 10:17:50
看看再说。。。
笑熬浆糊
2010-08-02, 11:08:48
两年之后 再看这个贴子 果然很强大 楼主太无敌了
yindubao
2010-11-19, 17:05:46
我搞定这个了,是因为没有正确返回基地址的问题。我用WINDBG一步步追踪发现问题存于此

BaseAddress= GetModlueBaseAdress("\\WINDOWS\\system32\\ntkrnlpa.exe");
。。。。
if (_stricmp( (char*)pFuncName,funName) == 0)

修改后的源码:


#include "ntddk.h"
#include "hookiat.h"
#pragma comment(lib,"ntdll.lib")

ULONG g_OriginalPsGetCurrentProcessId;
typedef HANDLE (*PSGETCURRENTPROCESSID)();

HANDLE
MyPsGetCurrentProcessId()

{
HANDLE handle=NULL;
DbgPrint("HOOK_PsGetCurrentProcessId called!\n");
// handle =((PSGETCURRENTPROCESSID)(g_OriginalPsGetCurrentProcessId))();
return handle;



PVOID GetModlueBaseAdress(char* ModlueName)
{
ULONG size,index;
PULONG buf;
NTSTATUS status;
PSYSTEM_MODULE_INFORMATION module;
PVOID driverAddress=0;
//利用ZwQuerySystemInformation依据SystemModuleInformation获取Ntoskerl.exe基址和镜像大小
ZwQuerySystemInformation(SystemModuleInformation,&size, 0, &size); //返回需要size大小
if(NULL==(buf = (PULONG)ExAllocatePool(PagedPool, size)))
{
DbgPrint("failed alloc memory failed \n");
return 0;
}
status=ZwQuerySystemInformation(SystemModuleInformation,buf, size , 0);//系统模块信息存入buf
if(!NT_SUCCESS( status ))
{
DbgPrint("failed query\n");
return 0;
}
/*
typedef struct _SYSTEM_MODULE_INFORMATION {//Information Class 11
ULONG Reserved[2];
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName[256];
}SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION;
*/
module = (PSYSTEM_MODULE_INFORMATION)(( PULONG )buf + 1);//+1代表加了4个字节,可能4个字节里存了MODULE的总数。通过下面的FOR循环中看出
for (index = 0; index < *buf; index++)
//if (_stricmp(module[index].ImageName + module[index].ModuleNameOffset, ModlueName) == 0)
if (_stricmp(module[index].ImageName, ModlueName) == 0) 
{
driverAddress = module[index].Base;//找到模块的基地址
DbgPrint("Module found at:%x\n",driverAddress);
}
ExFreePool(buf);
return driverAddress;
}

//StartHook_And_Unhook是安装钩子和卸载钩子,如果 test==1表示安装,否则表示卸载
VOID StartHook_And_Unhook(IN PCSTR funName, IN unsigned int test) 
{
HANDLE hMod;//JK:不指向任何类型的指针
PUCHAR BaseAddress = NULL;//JK:这个变量保存了一个32BTI地址,而这个地址指向了一个内存单元的内容
IMAGE_DOS_HEADER * dosheader;//JK:DOS文件头指针
IMAGE_OPTIONAL_HEADER * opthdr;//JK:结构
PIMAGE_EXPORT_DIRECTORY exports;//JK:用于保存一个IMAGE_EXPORT_DIRECTORY结构地址的指针变量

USHORT index=0 ; 
ULONG addr ,i;


PUCHAR pFuncName = NULL;
PULONG pAddressOfFunctions,pAddressOfNames;//这个变量保存了一个32BTI地址,而这个地址指向了四个内存单元的内容
PUSHORT pAddressOfNameOrdinals;//这个变量保存了一个32BTI地址,而这个地址指向了两个内存单元的内容

BaseAddress= GetModlueBaseAdress("\\WINDOWS\\system32\\ntkrnlpa.exe");//JK:获取要HOOK模块的导入表的模块地址 ntoskrnl.exe
DbgPrint("Map BaseAddress is:%x\n",BaseAddress);
hMod = BaseAddress;



dosheader = (IMAGE_DOS_HEADER *)hMod;//JK:dosheader保存了描述DOS头的结构变量的地址
opthdr =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hMod+dosheader->e_lfanew+24);//JK:dosheader->e_lfanew会输出PE文件头的位置+24是因为IMAGE_FILE_HEADER结构占20个字节,而加4是因为Signature所占4个字节,这样就指向了IMAGE_OPTIONAL_HEADER的位置
exports = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)dosheader+ opthdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);//JK:exports保存了IMAGE_EXPORT_DIRECTORY结构变量的地址

pAddressOfFunctions=(ULONG*)((BYTE*)hMod+exports->AddressOfFunctions/*指向了一个双字数组*/); //JK:获得EAT的入口地址,EAT又双字的数组组成
pAddressOfNames=(ULONG*)((BYTE*)hMod+exports->AddressOfNames);//JK:函数名字符串的地址表,根据这个地址表(由双字的数组组成)可获得函数名称的字符串
pAddressOfNameOrdinals=(USHORT*)((BYTE*)hMod+exports->AddressOfNameOrdinals); //JK:保存用于去pAddressOfFunctions指向的EAT中取函数地址的索引值(这个索引值还与函数名字符串的地址表对应,这样就可通过函数名称返回函数的地址了)



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];//JK:addr变量保存了PsGetCurrentProcessId函数的地址
DbgPrint("fount !! %x\n",addr);
break;
}

}


if(test==1) {

_asm
{
push eax
mov eax,CR0
and eax,0FFFEFFFFh
mov CR0,eax
pop eax

/*
//DbgPrint("PsGetCurrentProcessId is:%x\n",(ULONG)hMod + addr);//JK:输出PsGetCurrentProcessId这个函数的地址,基地址加RVA JK:用addr代替了pAddressOfFunctions[index]
g_OriginalPsGetCurrentProcessId= (ULONG)hMod + pAddressOfFunctions[index] ;//JK:g_OriginalPsGetCurrentProcessId保存了原先PsGetCurrentProcessId的地址

DbgPrint("original is:%x\n",(ULONG)hMod + pAddressOfFunctions[index]);
//DbgPrint("g_OriginalPsGetCurrentProcessId is:%x\n",g_OriginalPsGetCurrentProcessId);


pAddressOfFunctions[index] = ( PCHAR )MyPsGetCurrentProcessId;- BaseAddress;//求出MyPsGetCurrentProcessId的RVA
DbgPrint("Current is:%x\n",(ULONG)hMod + pAddressOfFunctions[index]);
*/

DbgPrint("hMod is:%x\n",(ULONG)hMod);
DbgPrint("pAddressOfFunctions[index] is:%x\n",pAddressOfFunctions[index]);
DbgPrint("PsGetCurrentProcessId is:%x\n",(ULONG)hMod + (ULONG)pAddressOfFunctions[index]);


DbgPrint("BaseAddress is:%x\n",(ULONG)BaseAddress);
DbgPrint("MyPsGetCurrentProcessId is:%x\n",(ULONG)MyPsGetCurrentProcessId);

pAddressOfFunctions[index] = ( PCHAR )MyPsGetCurrentProcessId - (PCHAR)BaseAddress;
DbgPrint("pAddressOfFunctions[index] is:%x\n",pAddressOfFunctions[index]);



g_OriginalPsGetCurrentProcessId= (ULONG)hMod + pAddressOfFunctions[index] ;



_asm 
{
push eax
mov eax,CR0
or eax,NOT 0FFFEFFFFh
mov CR0,eax
pop eax

}

else
{

_asm
{
push eax
mov eax,CR0
and eax,0FFFEFFFFh
mov CR0,eax
pop eax


pAddressOfFunctions[index] = ( PCHAR )g_OriginalPsGetCurrentProcessId - BaseAddress;//JK 恢复以前的PsGetCurrentProcessId的地址



_asm 
{
push eax
mov eax,CR0
or eax,NOT 0FFFEFFFFh
mov CR0,eax
pop eax




}







VOID Unload(PDRIVER_OBJECT DriverObject)
{

PCSTR myfunName="PsGetCurrentProcessId";
StartHook_And_Unhook(myfunName,0);
DbgPrint("Unload Callled\n");
}


NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING str)
{
PCSTR myfunName="PsGetCurrentProcessId";

// MyPsGetCurrentProcessId();
DbgPrint("MyPsGetCurrentProcessId is:%x\n", MyPsGetCurrentProcessId);
DbgPrint("unmodify PsGetCurrentProcessId is:%x\n", PsGetCurrentProcessId);


DbgPrint("original is:%x\n", PsGetCurrentProcessId());

StartHook_And_Unhook(myfunName,1);
DbgPrint("Modify is:%x\n", PsGetCurrentProcessId());

DbgPrint("modify PsGetCurrentProcessId is:%x\n", PsGetCurrentProcessId);
//PsGetCurrentProcessId();
DriverObject->DriverUnload = Unload;
return STATUS_SUCCESS;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值