飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 2878|回复: 0

KeServiceDescriptorTable 结构

[复制链接]
  • TA的每日心情
    慵懒
    2019-3-12 17:25
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2010-9-24 10:30:01 | 显示全部楼层 |阅读模式
    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寄存器,如下图:



    其中第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)
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表