zoukankan      html  css  js  c++  java
  • Ring 0 Inline Hook

    本文讲 用inline hook的方式修改NtOpenKey函数的一个例子

    hook 计算机里面一般是指 挂钩某函数,也可以是替换掉原来的函数。

    inline hook 是直接在以前的函数替里面修改指令,用一个跳转或者其他指令来达到挂钩的目的。 这是相对普通的hook来说,因为普通的hook只是修改函数的调用地址,而不是在原来的函数体里面做修改。
    一般来说 普通的hook比较稳定使用。 inline hook 更加高级一点,一般也跟难以被发现。所以很多人比如病毒制作者都比较推崇inline hook。

    SSDT的全称是System Services Descriptor Table,系统服务描述符表
    一般来说此表与链接系统内核的API密切相关,对此有一项应用就是杀毒软件的主动防御,当然病毒也可以通过修改主动防御的SSDT来绕过杀软的主动防御。SSDT hook一般是用来隐藏进程运行程序的,前面已经讲了。

    在函数头部inline hook太容易被发现, 在函数中间inline 不容易被发现, 下面demo实现在函数中间inline
    hook NtOpenFile函数, 使用PCHunter查看, 发现NtOpenFile已经被QQ的QQFrmMgr.sys hook了
    取ssdt表NtOpenFile的当前地址(QFrmMgr.sys hook地址), 在函数头+48的地方替换5个字节的 机器码 来跳转, 在QFrmMgr.sys里面加了一个inline hook
    模块执行流程 ntkrnlpa.exe ---> QQFrmMgr.sys ---> myinline.sys

    先用PCHunter查看下NtOpenKey的序号

     

    完整代码

     1 #include "ntddk.h"
     2 
     3 
     4 extern "C"    
     5 {
     6 #pragma pack(1)
     7     typedef struct ServiceDescriptorEntry {
     8         unsigned int *ServiceTableBase;
     9         unsigned int *ServiceCounterTableBase; //仅适用于checked build版本
    10         unsigned int NumberOfServices;
    11         unsigned char *ParamTableBase;
    12     } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
    13 #pragma pack()
    14     __declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
    15     void PageProtectOn()//恢复内存保护  
    16     {
    17         __asm
    18         {
    19             mov  eax,cr0
    20             or   eax,10000h
    21             mov  cr0,eax
    22             sti
    23         }
    24     }
    25 
    26     void PageProtectOff()//去掉内存保护
    27     { 
    28         __asm{
    29             cli
    30                 mov  eax,cr0
    31                 and  eax,not 10000h
    32                 mov  cr0,eax
    33         }
    34     }
    35     ULONG    g_ntopenkey;
    36     ULONG    g_jmp_orig_ntopenkey;
    37     UCHAR    g_orig_funcode[5];
    38 
    39     char *pp="my de inline hook";
    40     void FilterNtOpenFile(char* p1)
    41     {
    42         KdPrint(("kk:%s",pp));
    43         KdPrint(("kk:%s",(char*)PsGetCurrentProcess()+0x16c));
    44     }
    45     
    46     //__declspec(naked) 告诉编译器函数代码的汇编语言为自己的所写,不需要编译器添加任何汇编代码
    47     __declspec(naked) void NewNtOpenFile()
    48     {
    49         __asm{
    50                     PUSHAD//保存所有寄存器
    51                     push pp
    52                     call    FilterNtOpenFile
    53                     POPAD//还原所有寄存器
    54                     xor        ecx,ecx
    55                     mov     eax,esi
    56                     inc     ecx
    57                     jmp        g_jmp_orig_ntopenkey
    58             }
    59     }
    60 
    61     void HookNtOpenKey()
    62     {
    63         UCHAR    jmp_code[5]="";//存放修改指令的数组
    64         ULONG changeva=48;//相对于函数入口偏移48的位置hook
    65         g_ntopenkey = KeServiceDescriptorTable.ServiceTableBase[179];//NtOpenKey的入口地址
    66         g_jmp_orig_ntopenkey = g_ntopenkey + changeva+ 5;//调回的地址, 29从入口地址偏移29的地方改写指令, 指令长度5
    67         ULONG u_jmp_temp = (ULONG)NewNtOpenFile - g_ntopenkey - changeva - 5;//计算 newNtOpenKey相对于NtOpenKey的偏移量
    68         jmp_code[0] = 0xE9;//0xE9对应jmp指令。  (上一篇使用E8(call)指令跳转, 需要在pop eax, jmp不需要)
    69         *(ULONG*)&jmp_code[1] = u_jmp_temp;//生成完整的修改指令
    70         PageProtectOff();//解锁内存
    71         RtlCopyMemory(g_orig_funcode,(PVOID)(g_ntopenkey+changeva), 5);//备份 原始指令, 已便还原
    72         RtlCopyMemory((PVOID)(g_ntopenkey+changeva), jmp_code, 5);//修改指令
    73         PageProtectOn();//锁定内存
    74     }
    75 
    76     void UnHookOpenFile()
    77     {
    78         PageProtectOff();
    79         RtlCopyMemory((PVOID)(g_ntopenkey+48),g_orig_funcode,5);//还原指令, 卸载hook
    80         PageProtectOn();
    81     }
    82 
    83     VOID MyUnload(PDRIVER_OBJECT pDriverObject)
    84     {
    85         UnHookOpenFile();//卸载
    86     }
    87 
    88     NTSTATUS DriverEntry(PDRIVER_OBJECT    pDriverObject,PUNICODE_STRING Reg_Path)
    89     {
    90         HookNtOpenKey();
    91         g_ntopenkey = KeServiceDescriptorTable.ServiceTableBase[179];//179==NtOpenFile 函数的 ssdt表的数组下标
    92         pDriverObject->DriverUnload = MyUnload;
    93         return STATUS_SUCCESS;
    94     }
    95 }
  • 相关阅读:
    【Python学习笔记之三】lambda表达式用法小结
    Cisco Packet Tracer 6.0 实验笔记
    Kali Linux 下安装中文版输入法
    kali 2018.1安装教程
    Kali Linux菜单中各工具功能大全
    互联网电商购物车架构演变案例
    互联网业务场景下消息队列架构
    物流系统高可用架构案例
    高并发下海量容器案例一
    客服系统微服务架构的演化
  • 原文地址:https://www.cnblogs.com/mayingkun/p/5151539.html
Copyright © 2011-2022 走看看