Chinaunix首页 | 论坛 | 博客

=.=

  • 博客访问: 140383
  • 博文数量: 50
  • 博客积分: 3000
  • 博客等级: 中校
  • 技术积分: 550
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-25 17:22
文章分类

全部博文(50)

文章存档

2010年(7)

2009年(43)

我的朋友

分类: 网络与安全

2009-11-05 16:16:48

KeServiceDescriptorTable:是由内核(Ntoskrnl.exe)导出的一个表,这个表是访问SSDT的关键,具体结构是
   typedef struct ServiceDescriptorTable {
   PVOID ServiceTableBase;
   PVOID ServiceCounterTable(0);
   unsigned int NumberOfServices;
   PVOID ParamTableBase;
   }
  
   其中,
   ServiceTableBase :System Service Dispatch Table 的基地址。
   NumberOfServices 由 ServiceTableBase 描述的服务的数目。
   ServiceCounterTable 此域用于操作系统的 checked builds,包含着 SSDT 中每个服务被调用次数的计数器。这个计数器由 INT 2Eh 处理程序 (KiSystemService)更新。
   ParamTableBase 包含每个系统服务参数字节数表的基地址。
   System Service Dispath Table(SSDT):系统服务分发表,给出了服务函数的地址,每个地址4子节长。
   System Service Parameter Table(SSPT):系统服务参数表,定义了对应函数的参数字节,每个函数对应一个字节。如在0x804AB3BF处的函数需0x18字节的参数。


Hook前的准备-改变SSDT内存的保护
我们要修改SSDT表,首先这个表必须是可写的,但在xp以后的系统中他都是只读的,三个办法来修改内存保护机制。
(1) 更改注册表

HKLM\SYSTEM\CurrentControlset\Control\Session Manger\

Memory Management\EnforceWriteProtection=0

HKLM\SYSTEM\CurrentControlset\Control\Session Manger\

Memory Management\DisablePagingExecutive=1


(2)改变CR0寄存器的第1位
   Windows对内存的分配,是采用的分页管理。其中有个CR0寄存器,如下图:
31             12  11 9  8  7  6  5  4  3  2  1  0
PageBaseAdress           0  0  D  A  P  P  U  W  P
                                     C  W
                                     D  T  


其中第1位叫做保护属性位,控制着页的读或写属性。如果为1,则可以读/写/执行;如果为0,则只可以读/执行。SSDT,IDT的页属性在默认下都是只读,可执行的,但不能写。所以现在要把这一位设置成1。
其中第1位叫做保护属性位,控制着页的读或写属性。如果为1,则可以读/写/执行;如果为0,则只可以读/执行。SSDT,IDT的页属性在默认下都是只读,可执行的,但不能写。所以现在要把这一位设置成1。

wp位设置为0

__asm

{

push eax

mov eax,CR0

and eax,0FFFEFFFFh

mov CR0,eax

pop eax

}

如果恢复可以

__asm

{

push eax

move eax,CR0

or eax, NOT 0FFFEFFFFh

mov CR0,eax

pop eax

}

   (3)通过Memory Descriptor List(MDL)
   也就是把原来SSDT的区域映射到我们自己的MDL区域中,并把这个区域设置成可写。MDL的结构:
   typedef struct _MDL {
   struct _MDL *Next;   
   CSHORT Size;       
   CSHORT MdlFlags;   //关键在这里,将来设置成MDL_MAPPED_TO_SYSTEM_VA ,这样一来,这块区域就可写
   struct _EPROCESS *Process;
   PVOID MappedSystemVa;
   PVOID StartVa;
   ULONG ByteCount;
   ULONG ByteOffset;
   } MDL, *PMDL;
   首先需要知道KeServiceDscriptorTable的基址和入口数,这样就可以用MmCreateMdl创建一个有起始地址和大小的内存区域。然后把这个MDL结构的flag改成
   MDL_MAPPED_TO_SYSTEM_VA ,那么这个区域就可以写了。最后把这个内存区域调用MmMapLockedPages锁定在内存中。大体框架如下:
   //先声明一个System Service Descriptor Table,我们知道SSDT及SSPT都从这个表中指向
   #pragma pack(1)
   typedef struct ServiceDescriptorEntry {
  
           unsigned int *ServiceTableBase;
  
           unsigned int *ServiceCounterTableBase;
  
           unsigned int NumberOfServices;
  
           unsigned char *ParamTableBase;
  
   } SSDT_Entry;
  
   #pragma pack()
  
   __declspec(dllimport) SSDT_Entry KeServiceDescriptorTable;
  
  
   /
   PMDL   g_pmdlSystemCall;
  
   PVOID *MappedSystemCallTable;
   // 代码
   // 保存原系统调用位置
  
  
  
   // 映射我们的区域
  
   g_pmdlSystemCall = MmCreateMdl(NULL,
  
                      KeServiceDescriptorTable.ServiceTableBase,
  
                      KeServiceDescriptorTable.NumberOfServices*4);
  
   if(!g_pmdlSystemCall)
  
      return STATUS_UNSUCCESSFUL;
  
   MmBuildMdlForNonPagedPool(g_pmdlSystemCall);
  
   // 改变MDL的flags
  
   g_pmdlSystemCall->MdlFlags = g_pmdlSystemCall->MdlFlags |
  
                                MDL_MAPPED_TO_SYSTEM_VA;
  
  
   //在内存中索定,不让换出
   MappedSystemCallTable = MmMapLockedPages(g_pmdlSystemCall, KernelMode);


  
   现在遇到的第一个问题解决了,但接着面临另外一个问题,如何获得SSDT中函数的地址呢?
   3.四个有用的宏
   SYSTEMSERVICE macro:可以获得由ntoskrnl.exe导出函数,以Zw*开头函数的地址,这个函数的返回值就是Nt*函数,Nt*函数的地址就在SSDT中
   SYSCALL_INDEX macro:获得Zw*函数的地址并返回与之通信的函数在SSDT中的索引。
   这两个宏之所以能工作,是因为所有的Zw*函数都开始于opcode:MOV eax, ULONG,这里的ULONG就是系统调用函数在SSDT中的索引。
   HOOK_SYSCALL和UNHOOK_SYSCALL macros:获得Zw*函数的地址,取得他的索引,自动的交换SSDT中索引所对应的函数地址和我们hook函数的地址。
   这四个宏具体是:
   #define SYSTEMSERVICE(_func) \
           KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_func+1)]
  
   #define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)
  
   #define HOOK_SYSCALL(_Function, _Hook, _Orig )        \
  
           _Orig = (PVOID) InterlockedExchange( (PLONG) \
  
           &MappedSystemCallTable[SYSCALL_INDEX(_Function)], (LONG) _Hook)
  
   #define UNHOOK_SYSCALL(_Func, _Hook, _Orig )   \
  
           InterlockedExchange((PLONG)            \
  
           &MappedSystemCallTable[SYSCALL_INDEX(_Func)], (LONG) _Hook)
阅读(1443) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~