SSDT 表的初步学习、、

 1 理论知识、、

大概思路和理论知识、、

首先明白应用层到 内核层 会通过一张SSDT 表、、我们要根据SSDT结构和索引号来获取函数的当前地址 

 如果检测一下这个函数有木有被HOOK我们要在获取这个函数的起源地址   对比一下即可知道、、

 

1 读取SSDT表函数当前地址、、

了解SSDT结构

系统服务描述符表 在ntoskrnl.exe导出  KeServiceDescriptorTable   这个表

typedef struct _ServiceDescriptorTable {

    PVOID ServiceTableBase; //System Service Dispatch Table 的基地址  

    PVOID ServiceCounterTable;

    //包含着SSDT 中每个服务被调用次数的计数器。这个计数器一般由sysenter 更新。 

    unsigned int NumberOfServices;//由ServiceTableBase 描述的服务的数目。  

    PVOID ParamTableBase; //包含每个系统服务参数字节数表的基地址-系统服务参数表 

}*PServiceDescriptorTable;  

//由SSDT索引号获取当前函数地址  

extern PServiceDescriptorTable KeServiceDescriptorTable;

用KeServiceDescriptorTable   这张表 可以获取SSDT的基地址 再使用索引号 即可得到函数的地址、、

  这里是NTOpenProcess 索引号是7A(122) 、、所以

NTOpenProcess 的地址是保存在KeServiceDescriptorTable  + 7A*4的位置、、

使用汇编得到这个地址 这么写、、

首先加一句

extern long KeServiceDescriptorTable;// 这里使用long不太准确

ULONG  SSDT_NtOpenProcess_Cur_Addr; //定义一个全局变量 打印出这个值

    __asm

    {   

int 3  //为了调试方便 下一个int 3断点

        push ebx

        push eax

            mov ebx,KeServiceDescriptorTable  //直接使用这个表

            mov ebx,[ebx]

            mov eax,0x7A

            shl eax,2 // imul eax,eax,4   //左移两位

            add ebx,eax  // 地址  [KeServiceDescriptorTable]+0x7A*4

            mov ebx,[ebx]//取上边地址的内容

            mov SSDT_NtOpenProcess_Cur_Addr,ebx//赋予全局变量

        pop eax   

        pop ebx

    }
使用指针这样写、

先定义一个

typedef struct _ServiceDescriptorTable {

    PVOID ServiceTableBase; //System Service Dispatch Table 的基地址  

    PVOID ServiceCounterTable;

    //包含着SSDT 中每个服务被调用次数的计数器。这个计数器一般由sysenter 更新。 

    unsigned int NumberOfServices;//由ServiceTableBase 描述的服务的数目。  

    PVOID ParamTableBase; //包含每个系统服务参数字节数表的基地址-系统服务参数表 

}*PServiceDescriptorTable;  

然后

extern PServiceDescriptorTable KeServiceDescriptorTable; //这个是准确的、

LONG *SSDT_Adr;

LONG SSDT_NtOpenProcess_Cur_Addr; //最终结果

LONG t_addr; //基地址

t_addr=(LONG)KeServiceDescriptorTable->ServiceTableBase;

SSDT_Adr=(PLONG)(t_addr+0x7A*4);//得到存放  NTOpenProcess的地址  的地址、、

SSDT_NtOpenProcess_Cur_Addr = *SSDT_Adr;    //得到NTOpenProcess的地址

KdPrint(("SSDT_NtOpenProcess_Cur_Addr =%x\n",SSDT_NtOpenProcess_Cur_Addr));

 

可以双机调试一下、使用Kernel Detective 软件对照分析、、

 

2 读取SSDT函数表的真正地址、、即原始地址、

上边获取的是SSDT 当前地址 不一定为函数的原始地址(该函数若有HOOK行为、)

这个有固定的函数、、

PVOID MmGetSystemRoutineAddress

(

  __in  PUNICODE_STRING SystemRoutineName

 //参数是 保存要得到的函数名字的 缓冲区、、

);

实现

ULONG GetSSDT_Old_ADDR()

UNICODE_STRING Old_NtOpenProcess;

ULONG Old_Addr;

RtlInitUnicodeString(&Old_NtOpenProcess,L"NtOpenProcess");//初始化字符串

Old_Addr=(ULONG)MmGetSystemRoutineAddress(&Old_NtOpenProcess)NtOpenProcess地址

KdPrint(("取得原函数NtOpenProcess的值为%x",Old_Addr));

return Old_Addr;

 

完、