修改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;
}
 

你可能感兴趣的:(c,api,struct,service,table,hook)