1、
绕过SSDT驱动保护
A、去掉页面保护
B、写入In Line HOOK代码
C、用OD附加测试效果
D、反HOOK代码
【190】复制 第20课 的代码
【315】涉及到 页面的保护 ==> 涉及到 一个特殊的寄存器
cr0,32位寄存器 ==> 其中的第17位(从第0位开始) ==> CW位
【480】CW位: 置1 --> 开启 页面保护
置0 --> 去掉 页面保护
【530】这只是一种方法(修改cr0的CW位),还有一种是修改内存描述符(MDL)(相关函数前面也说了,也可以更改页面保护的属性,那个更详细一些 更专业一点)
【580】用 CR0(CW位) 去掉页面保护,更方便一些
【660】方法:
(not (1 shl 16)) & cr0
【935】指令"cli" ==> 关掉相应的 中断,避免在执行我们的指令的时候被打扰
#pragma pack(1)
#pragma pack()
__asm // 去掉页面保护
{
cli
mov eax,cr0
and eax,not 10000h //and eax,0FFFEFFFFh
mov cr0,eax
}
__asm // 恢复页保护
{
mov eax,cr0
or eax,10000h //or eax,not 0FFFEFFFFh
mov cr0,eax
sti // 【1145】恢复中断
}
【1160】加cli/sti指令 增加稳定性
【1235】
【1270】中间这一段,进行我们的写入操作
上一节课,讲的是纯汇编的指令书写方式,还有一种更直接的方式,但是需要改一下对齐
标志。预编译指令:
“
#pragma pack(1)
#pragma pack()
”
【1380】
#pragma pack(1) // 设置对齐标识为1
typedef struct _JMPCODE
{
BYTE E9;
ULONG JMPADDR;
} JMPCODE,*PJMPCODE;
#pragma pack() // 恢复对齐标识
为什么设置对齐标识为1?默认对齐是4...(ZC: 相关解释)
“
JMPCODE oldCode; // 【1960】用来保存 前5个字节,以便恢复
PJMPCODE pcur;
NTSTATUS DriverEntry(PDRIVER_OBJECT _pDrvierObject, PUNICODE_STRING B)
{
ULONG cur, old, ulOffset;
JMPCODE JmpCode;
cur = GetNt_CurAddr() ;
old = GetNt_OldAddr();
if (cur != old)
{
// 【2040】保存 前5个字节
pcur = (PJMPCODE)(cur); // 【2500】初始化指针
oldCode.E9 = pcur->E9; // 【2205】1字节
oldCode.JMPADDR = pcur->JMPADDR; // 【2210】4字节
ulOffset = old - (cur + 5);
JmpCode.E9 = 0xE9;
JmpCode.JMPADDR = ulOffset;
KdPrint(("要写入的地址 : 0x%08X", JmpCode.JMPADDR));
__asm // 去掉页面保护
{
cli
mov eax,cr0
and eax,not 10000h //and eax,0FFFEFFFFh
mov cr0,eax
}
pcur->E9 = 0xE9;
pcur->JMPADDR = JmpCode.JMPADDR; // 【1790】要跳转到的地址
__asm // 恢复页保护
{
mov eax,cr0
or eax,10000h //or eax,not 0FFFEFFFFh
mov cr0,eax
sti // 【1145】恢复中断
}
KdPrint(("NtOpenProcess被Hook了"));
}
else
KdPrint(("NtOpenProcess没有被Hook"));
_pDrvierObject->DriverUnload = DDK_Unload;
return 1;
}
”
【2240】我们保存原来的信息之后,在卸载例程中 反过来写,就实现了恢复了
VOID DDK_Unload(IN PDRIVER_OBJECT _pDrvierObject)
{
PDEVICE_OBJECT pDev; // 用来取得要删除的设备对象
UNICODE_STRING symLinkName;
__asm // 去掉页面保护
{
cli
mov eax,cr0
and eax,not 10000h //and eax,0FFFEFFFFh
mov cr0,eax
}
pcur->E9 = oldCode.E9;
pcur->JMPADDR = oldCode.JMPADDR;
__asm // 恢复页保护
{
mov eax,cr0
or eax,10000h //or eax,not 0FFFEFFFFh
mov cr0,eax
sti // 【1145】恢复中断
}
pDev = _pDrvierObject->DeviceObject;
IoDeleteDevice(pDev); // 删除设备
// 取得符号链接的名字
RtlInitUnicodeString(&symLinkName, L"\\??\\yjx888");
IoDeleteSymbolicLink(&symLinkName);
KdPrint(("驱动成功被卸载...OK----------"));
}
【2745】测试驱动,sx.sys(ZC: 是这个吗?)已经提前加载了(ZC: 貌似还没有 用 DDK来编译啊)
【2810】DriverMonitor 加载驱动
【2860】用DDK编译我们的驱动
【2980】DriverMonitor 加载驱动
【2995】代码写错的话 肯定会蓝屏蓝掉
【3000】KernelDetective 中没有刷新功能,看不到改变
我们重新从 标签"系统服务描述表" 再次跳转到 标签"反汇编"
【3045】现在我们看到,"当前地址"指向的函数 的首指令已经是 我们的JMP指令了
【3135】卸载驱动 --> DriverMonitor 点击"STOP"
【3150】KernelDetective 中,重新从 标签"系统服务描述表" 跳转到 标签"反汇编"
"当前地址"指向的函数 的指令又恢复了
2、