C++ 修改SSDT来挂钩API的代码 2/13
///////////////////////////////
//函数用途:修改SSDT表 //
///////////////////////////////
//输入:服务ID, 新地址 //
//返回值:原始地址 //
///////////////////////////////
ULONG SetSSDTAddress(ULONG ulServiceID, ULONG procNewAddress)
// SSDT_Hook.c: SSDT Hook API.
//
//////////////////////////////////////////////////////////////////////
/*
代码最初来源于网络,原作者未知,表示歉意,代码经由at.Least(炉子)
*/
#include <ntddk.h>
typedef struct _SERVICE_DEscrīptOR_TABLE
{
PVOID ServiceTableBase;
PULONG ServiceCounterTableBase;
ULONG NumberOfService;
ULONG ParamTableBase;
}SERVICE_DEscrīptOR_TABLE,*PSERVICE_DEscrīptOR_TABLE; //由于KeServiceDescrīptorTable只有一项,这里就简单点了
extern PSERVICE_DEscrīptOR_TABLE KeServiceDescrīptorTable;//KeServiceDescrīptorTable为导出函数
static ULONG JmpAddress;//跳转到的地址
static ULONG OldServiceAddress;//原来的服务地址
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
/////////////////////////////////
//函数用途:修改SSDT表 //
/////////////////////////////////
//输入:服务ID, 新地址 //
//返回值:原始地址 //
/////////////////////////////////
ULONG SetSSDTAddress(ULONG ulServiceID, ULONG procNewAddress)
{
ULONG Address;
Address = (ULONG)KeServiceDescrīptorTable->ServiceTableBase + ulServiceID * 4;//服务ID
/*
炉子(at_Least) 注解 1(Address变量):
其实这个 Address 并不是真正的原始地址,从下文的
“OldServiceAddress = *(ULONG*)Address;”就可看
出其实这个 Address 是指向地址变量的指针(可能我
说的很复杂或者是很难懂,你可以把这个Address理解
为一个 *Address 变量 (ULONG *Address),并且被
赋值为:
Address = &服务函数地址(就是0x8XXXXXXX那东西)
*/
///////////////////////////////////////////////
/*
炉子(at_Least) 注解 2(如何获得Address的值):
SSDT 中数据的存放方式实际是:
------------------理论譬如说------------------>
lkd> dd KeServiceDescrīptorTable
8055ab80 804e3d20 00000000 0000011c 804d9f48
8055ab90 00000000 00000000 00000000 00000000
8055aba0 00000000 00000000 00000000 00000000
8055abb0 00000000 00000000 00000000 00000000
在windbg.exe中我们就看得比较清楚,KeServiceD-
escrīptorTable中就只有第一项有数据,其他都是0
。其中804e3d20就是KeServiceDescrīptorTable.n-
toskrnel.ServiceTableBase,服务函数个数为0x1-
1c个。我们再看看804e3d20地址里是什么东西:
lkd> dd 804e3d20
804e3d20 80587691 805716ef 8057ab71 80581b5c
804e3d30 80599ff7 80637b80 80639d05 80639d4e
804e3d40 8057741c 8064855b 80637347 80599539
804e3d50 8062f4ec 8057a98c 8059155e 8062661f
如上,80587691 805716ef 8057ab71 80581b5c 这些
就是系统服务函数的地址了。
<------------------理论譬如说------------------
(【理论譬如说】中的内容为引用——懒得打字- -)
相信大家也看明白了,每个地址占用4个字节( 1个字
节可以表示两位数字 ——不明白的自己换算。)所以
当我们获取地址的指针时,需要用服务 ID * 4(地址
是连续存放的, 不存在两个地址之间的间隔符之类的
情况)来获取相对于起始地址(在引用部分是【804e-
3d20】)的差值,然后再加上起始地址(就是Servic-
eTableBase)
*/
DbgPrint("Address:0x%08X",Address);
OldServiceAddress = *(ULONG*)Address;//保存原来的地址
DbgPrint("OldServiceAddress:0x%08X",OldServiceAddress);
DbgPrint("procNewFunAddress:0x%08X",procNewAddress);
JmpAddress = (ULONG)NtOpenProcess + 10; //跳转到函数头+10的地方,这样在其前面写的JMP都失效了
DbgPrint("JmpAddress:0x%08X",JmpAddress);
__asm{//去掉内存保护
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
*((ULONG*)Address) = (ULONG)
procNewAddress;//HOOK SSDT
__asm{//恢复内存保护
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
return OldServiceAddress;
}
目前有0条回应
Comment
Trackback