YJX_Driver_019_读出原函数地址

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、

 

posted @ 2016-04-01 21:41  DebugSkill  阅读(297)  评论(0编辑  收藏  举报