• 内核驱动


      1 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //   驱动编程: HOOK SSDT
      4 //
      5 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      6 #include "ntddk.h"
      7 
      8 // 全局变量
      9 // 声明NtOpenProcess 函数指针
     10 typedef NTSTATUS (_stdcall *NTOPENPROCESS ) ( __out  PHANDLE ProcessHandle,
     11                                    __in     ACCESS_MASK DesiredAccess,
     12                                    __in     POBJECT_ATTRIBUTES ObjectAttributes ,
     13                                    __in_opt PCLIENT_ID ClientId );
     14 
     15 ULONG g_nOldNtOpenProcessAddr ; // 存储NtOpenProcess原地址
     16 
     17 // 内存字节对齐
     18 #pragma pack(1)
     19 
     20 //struct: ServiceDescriptorEntry_t
     21 typedef struct ServiceDescriptorEntry
     22 {
     23     unsigned int    * ServiceTableBase;        // SSDT 基址+偏移 (索引 )定位内核函数
     24     unsigned int    * ServiceCounterTableBase;   // checked build
     25     unsigned int     nNumberOfServices;       // SSDT 中函数个数
     26     unsigned char   * ParamTableBase;         // SSDT中函数的参数
     27 }ServiceDescriptorEntry_t, * PServiceDescriptorTableEntry_t;
     28 
     29 #pragma pack()
     30 
     31 // 导出( 微软未公开,需导出 )
     32 _declspec(dllimport ) ServiceDescriptorEntry_t     KeServiceDescriptorTable;
     33 
     34 
     35 // 恢复内存页保护
     36 void fnPageProtectOn ()
     37 {                         // 【 or】 : 按位“或”运算 ,当且仅当两操作数对应位都为“”时                 
     38     _asm                  //       结果相应位为“”,否则结果相应位为“”。
     39     {                    
     40          mov  eax, cr0         // cr0寄存器内核保护标志位当前为
     41          or    eax,10000h      // 将 h通过 or汇编指令按位 "或" 运算,cr0寄存器标志位
     42          mov  cr0, eax         // 从变为 ,从而达到恢复内存保护页的目的
     43          sti                // sti汇编指令: 允许中断发生
     44     }
     45 }
     46 
     47 // 清除内存页保护
     48 void fnPageProtectOff ()
     49 {                         // 【 and】 : 按位“与”操作 ,当且仅当两操作数对应位都为“”时
     50     _asm                  //        结果的相应位为“”,否则结果相应位为“”。
     51     {
     52          cli                // cli汇编指令: 禁用中断发生 ;当修改中断向量或堆栈指针时 ,
     53                          // 必须先禁用 ,否则产生中断会破坏当前的环境 ,造成程序崩溃
     54          mov  eax, cr0         // cr0寄存器保存了内核保护的标志位 :保护状态 ,否则为 ;
     55          and   eax, not 10000h   // 将 h取反并通过 and指令按位 "与" 运算,cr0寄存器标志
     56          mov  cr0, eax         // 位从变成 ,从而达到了取消内存页保护的目的
     57     }
     58 }
     59 
     60 
     61 // 实际执行NtOpenProcess 函数的函数
     62 NTSTATUS fnNewNtOpenProcess (  __out  PHANDLE ProcessHandle,
     63                          __in  ACCESS_MASK DesiredAccess,
     64                          __in  POBJECT_ATTRIBUTES ObjectAttributes,
     65                          __in_opt PCLIENT_ID ClientId)
     66 {
     67     // PEPROCESS结构体偏移 x16c即 :ImageFileName 存放的是当前进程的名称
     68     KdPrint(( "当前调用fnNewNtOpenProcess 函数的进程: %s", (UCHAR*)PsGetCurrentProcess ()+0x16c));
     69 
     70     // g_nOldNtOpenProcessAddr中存储原 NtOpenProcess地址, 强制转换成原函数指针类型后下发
     71     return ((NTOPENPROCESS)g_nOldNtOpenProcessAddr )(ProcessHandle , DesiredAccess,ObjectAttributes , ClientId );
     72 }
     73 
     74 NTSTATUS fnHookNtOpenProcess (void )
     75 {
     76     /**************************************************************************************
     77     //ULONG  nIndex;
     78     // 遍历SSDT 中函数的内存地址
     79     for ( nIndex=0; nIndex<KeServiceDescriptorTable.nNumberOfServices; ++nIndex)
     80     {
     81         KdPrint(("ServiceTable[%d]:%X",nIndex, KeServiceDescriptorTable.pnServiceTableBase[nIndex]));
     82     }
     83     **************************************************************************************/
     84     
     85     // 关闭页保护
     86     fnPageProtectOff();
     87 
     88     // 替换目标函数地址前 ,先保存原地址
     89     g_nOldNtOpenProcessAddr = KeServiceDescriptorTable.ServiceTableBase [190];
     90 
     91     // NtOpenProcess内存地址保存在 pnServiceTableBase索引第位,
     92     // 将 NtOpenProcess内存地址替换为目标函数内存地址 (fnNewNtOpenProcess)
     93     KeServiceDescriptorTable. ServiceTableBase[190] = (unsigned int)fnNewNtOpenProcess ;
     94     // 恢复页保护
     95     fnPageProtectOn();
     96     return STATUS_SUCCESS;
     97 }
     98 
     99 // 卸载hook
    100 void fnUnHookNtOpenProcess ()
    101 {
    102     // 先关闭内存页保护
    103     fnPageProtectOff();
    104     // 再恢复 NtOpenProcess
    105     KeServiceDescriptorTable. ServiceTableBase[190] = (unsigned int)g_nOldNtOpenProcessAddr ;
    106     // 最后恢复页保护
    107     fnPageProtectOn();
    108 }
    109 
    110 // 卸载驱动
    111 void fnUnLoadDriver (PDRIVER_OBJECT pDriverObj )
    112 {
    113     fnUnHookNtOpenProcess();    // 卸载 Hook
    114     KdPrint(( "驱动卸载成功!" ));
    115 }
    116 // 驱动入口
    117 NTSTATUS DriverEntry (PDRIVER_OBJECT pDriverObj , PUNICODE_STRING pszRegisterPath )
    118 {
    119     KdPrint(( "驱动加载成功!" ));
    120     fnHookNtOpenProcess();      // 开始 Hook
    121     pDriverObj-> DriverUnload = fnUnLoadDriver;
    122     return STATUS_SUCCESS;
    123 }
  • 相关阅读:
    Chapter01_前言、入门程序、常量、变量
    面向对象知识点总结
    Java快捷键
    上线
    docker
    分页,过滤,搜索,排序
    Celery
    django-redis 缓存使用
    前台登录注册修订
    短信注册接口
  • 原文地址:https://www.cnblogs.com/DuanLaoYe/p/5454092.html
Copyright © 2020-2023  润新知