1、
第19课、读出原函数地址-
A、集成上一课代码至GetNt_CurAddr函数
B、MmGetSystemRoutineAddress
C、书写GetNt_OldAddr函数
D、测试结果
【120】第18课的代码
【215】集成上一课代码至GetNt_CurAddr函数
ULONG GetNt_CurAddr() //获取当前SSDT_NtOpenProcess的当前地址
{
LONG *SSDT_Adr,SSDT_NtOpenProcess_Cur_Addr,t_addr;
KdPrint(("驱动成功被加载中.............................\n"));
//读取SSDT表中索引值为0x7A的函数
//poi(poi(KeServiceDescriptorTable)+0x7a*4)
t_addr=(LONG)KeServiceDescriptorTable->ServiceTableBase;
KdPrint(("当前ServiceTableBase地址为%x \n",t_addr));
SSDT_Adr=(PLONG)(t_addr+0x7A*4);
KdPrint(("当前t_addr+0x7A*4=%x \n",SSDT_Adr));
SSDT_NtOpenProcess_Cur_Addr=*SSDT_Adr;
KdPrint(("当前SSDT_NtOpenProcess_Cur_Addr地址为%x \n",SSDT_NtOpenProcess_Cur_Addr));
return SSDT_NtOpenProcess_Cur_Addr;
}
【520】本节课 需要另外构建一个函数
ULONG GetNt_OldAddr();
【590】先看 函数MmGetSystemRoutineAddress
PVOID MmGetSystemRoutineAddress
(
__in PUNICODE_STRING SystemRoutineName
);
ZC: 应该就是 根据 内核函数名 得到 内核函数的地址
【855】
ULONG GetNt_OldAddr()
{
UNICODE_STRING Old_NtOpenProcess;
ULONG Old_Addr;
RtlInitUnicodeString(&Old_NtOpenProcess,L"NtOpenProcess"); //【1005】这里"NtOpenProcess"填入的是导出函数的名字
Old_Addr=(ULONG)MmGetSystemRoutineAddress(&Old_NtOpenProcess); // 取得NtOpenProcess的地址
KdPrint(("取得原函数NtOpenProcess的值为 %x",Old_Addr));
return Old_Addr;
}
【920】这里就 不使用PUNICODE_STRING了 直接使用UNICODE_STRING,这样就不用动态分配内存了。(ZC: 忘了内核中如何动态分配内存了...本教程会讲到吗?看了下标题,可能第33讲会讲到)
【1005】这里"NtOpenProcess"填入的是导出函数的名字。若传入的 函数名,不是一个导出函数 的话,MmGetSystemRoutineAddress就返回NULL了(ZC: 记得以前看过代码,有人使用 未公开的API函数,这应该也是 导出函数,只是 ms没有公开 文档上查不到而已吧?)
ZC: 这里的一直讲到的"导出函数",指的是 内核导出给应用层使用的函数?还是指 DLL的导出函数?
【1220】ZC: MmGetSystemRoutineAddress 本来返回的是void*,他却强转为 ULONG。我的思考是 Windows下,void* 能兼容x86/x64,而ULONG就不一定了...(参看:"http://blog.chinaunix.net/uid-25513153-id-182196.html")
【1730】
NTSTATUS DriverEntry(PDRIVER_OBJECT _pDrvierObject, PUNICODE_STRING B)
{
ULONG cur, old;
cur = GetNt_CurAddr() ;
old = GetNt_OldAddr();
if (cur != old)
{
// 【2830】写入 我们的 JMP指令
KdPrint(("NtOpenProcess被Hook了"));
}
else
KdPrint(("NtOpenProcess没有被Hook"));
_pDrvierObject->DriverUnload = DDK_Unload;
return 1;
}
【2015】编译测试
【2195】打开KernelDetective看一下,∵他的机器 已经加载过 hook NtOpenProcess的驱动 了,∴ KernelDetective显示的信息是 NtOpenProcess 已经是被hook的状态了
【2300】加载一下我们的驱动
【2450】对比一下 KernelDetective 和 DebugView 中的信息 是一致的
【2605】ZC: 看到,hook NtOpenProcess 的 那个驱动 还是 sx.sys
【2648】如果 sx.sys 对 hook NtOpenProcess 的那个函数 做了一些措施的话(如 循环的监测/修复 或者 检测到函数被改动就直接蓝屏),那么 我们修改首指令为JMP的方案将会行不通(如被 修复/还原 或者 机子蓝屏),那我们采取的措施是:
(1)、避开 sx.sys 监测的指令,就是 在下面一点的指令中 选择一条指令改为 我们的JMP,但是 要注意堆栈平衡
(2)、或者 如果 sx.sys搜索的字串是0xE8(也就是JMP指令),那我们就不使用JMP指令 改用 jne之类的指令、je(0x74)之类的指令
ZC: 改为 jne/je 值了IDE指令的话,还要注意 那几个寄存器的状态(zero寄存器 等)
ZC: 个人感觉 还有一种修改方案 : ∵ hook NtOpenProcess 的那个函数,肯定最后还是要调用 NtOpenProcess的,于是分析 hook NtOpenProcess 的那个函数 修改其中的指令 使之直接跳转到 执行NtOpenProcess 的地方。
后面再详细的讲解
2、