YJX_Driver_021_绕过驱动保护

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、

 

posted @ 2016-04-02 17:43  DebugSkill  阅读(331)  评论(0编辑  收藏  举报