1、
读出SSDT表当前函数地址
A、引用KeServiceDescriptorTable表
B、通过ServiceTableBase+偏移读出当前函数地址
C、用windbg测试读取的值
【100】把第16课代码复制过来(第17课 没有写代码)
【155】上节课的公式
[[KeServiceDescriptorTable]+0x7A*4]
【210】如何读出"当前地址"
方法一:用汇编 相当简单
定义:extern PServiceDescriptorTable KeServiceDescriptorTable; 【320】最简便的方式,当然 不是正规的做法 "extern long KeServiceDescriptorTable;"
【395】∵ KeServiceDescriptorTable表 是导出的,用 extern 默认定义成什么类型都是可以的,只要它用了 extern,它理论上都会取得这个表的地址
ZC: 结合这里的讲解 和 下面的代码,意思就是说 一个结构体(或者别的什么类型?) 只要它是导出的,就能这样直接得到它的地址?这里所说的"导出"到底是什么样的导出?而且它是被exe(ntoskrnl.exe)导出的...
ZC: (1)、查一下,DLL导出 结构体 (2)、ntoskrnl.exe 其实是当做DLL来用的?看一下PE头吧 看能不能看得出来到底是啥?(网上查到“if((pNtHeader->FileHeader.Characteristics & IMAGE_FILE_DLL) == IMAGE_FILE_DLL)”)
【470】
NTSTATUS DriverEntry(PDRIVER_OBJECT _pDrvierObject, PUNICODE_STRING B)
{
ULONG SSDT_NtOpenProcess_Cur_Addr;
KdPrint(("驱动成功被加载...OK+++++++++\n\n"));
// 读取SSDT表中 NtOpenProcess的 当前地址
__asm
{
int 3 // 【1545】加一个断点,便于测试
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] // [[KeServiceDescriptorTable]+0x7A*4]
mov SSDT_NtOpenProcess_Cur_Addr,ebx
ppo eax
pop ebx
}
KdPrint(("SSDT_NtOpenProcess_Cur_Addr : 0x%08X\n\n", SSDT_NtOpenProcess_Cur_Addr));
// 注册派遣函数
_pDrvierObject->MajorFunction[IRP_MJ_CREATE] = ddk_DispatchRiutine_CONTROL;
// ...
CreateMyDevice(_pDrvierObject);
_pDrvierObject->DriverUnload = DDK_Unload;
return 1;
}
【830】再用一个寄存器 eax来表示偏移(ZC: 不能直接"mov ebx,[ebx+7A*4]"么?)
【975】"shl eax,2" 和 "imul eax,eax,4" 相比,只有一个操作数,速度会快一些,更效率一些
【1820】【1825】ZC: 这个时候的源码界面是怎么调出来的?
【1855】最好我们不用 源码的调试模式,用汇编的调试模式 更方便跟踪
【1955】看寄存器的值,WinDBG命令"r eax"
【2560】检验 我们得到的值 SSDT_NtOpenProcess_Cur_Addr(0x8058270a) 是否正确
【2600】用 KernelDetective 来看一下
【2720】方法二:用指针来读取 "当前地址"
【2735】必须定义 结构_ServiceDescriptorTable
【2929】讲解一下... ... 编译测试
ZC: 不太好理解的点:
extern PServiceDescriptorTable KeServiceDescriptorTable;
extern long KeServiceDescriptorTable;
ntoskrnl.exe导出
2、