修改SSDT来挂钩API的代码

/
//函数用途:修改SSDT表         //
/
//输入:服务ID, 新地址         //
//返回值:原始地址             //
/

ULONG SetSSDTAddress(ULONG ulServiceID, ULONG procNewAddress)

QUOTE:

// 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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值