Windows驱动开发学习笔记(六)—— Inline HOOK

  • SSDT HOOK
  • Inline Hook
    • 挂钩
    • 执行流程
    • 脱钩
  • 实验一:3环 Inline Hook
  • 实验二:0环 Inline Hook

SSDT HOOK

缺点

  1. 容易发现,容易绕过
  2. 只能HOOK系统服务表里的函数

Inline Hook

JMP的偏移 = 跳转地址 - 补丁地址 -5

挂钩

执行流程

脱钩

实验一:3环 Inline Hook

#include <stdio.h>
#include <windows.h>BYTE* ProcAddr = 0;          //原函数地址
DWORD OldProtect = 0;      //保存旧的内存保护
BYTE  OldCmd[20] = {0};        //存储原函数头部原始指令 在最后面构造返回到原函数的指令BYTE* HookProcAddr  = 0;  //钩子函数的地址//函数指针 将数据作为指令执行
typedef void (*POLDCMD)();
POLDCMD pOldCmd = (POLDCMD)(char*)OldCmd;
//printf的格式
char *format = "%x";DWORD add(DWORD a, DWORD b)
{return a + b;
}void __declspec(naked) HookProc()
{//保存现场__asm{pushadpushfd}//获得参数1printf("a = ");__asm{mov eax, espadd eax, 40push [eax]push formatcall printfadd esp, 8}//获得参数2printf("\nb = ");__asm{mov eax, espadd eax, 44push [eax]push formatcall printfadd esp, 8}printf("\n");//还原现场__asm{popfdpopad//执行原函数头部指令 并返回到原函数下一行继续执行jmp pOldCmd}
}void InlineHook()
{//获得需要挂钩的函数地址ProcAddr  =   (BYTE*)add + 1;ProcAddr += *(DWORD*)ProcAddr + 4;//修改内存保护VirtualProtect(ProcAddr, 6, PAGE_EXECUTE_READWRITE, &OldProtect);//将被覆盖的指令复制到数组中strncpy((char*)OldCmd, (char*)ProcAddr, 6);//数组末尾添上跳转指令 用于返回到被挂钩的函数OldCmd[6] = 0xE9;*(DWORD*)&OldCmd[7] = (DWORD)(ProcAddr+6) - (DWORD)&OldCmd[6] - 5;//获得钩子函数的地址HookProcAddr  =   (BYTE*)HookProc + 1;HookProcAddr += *(DWORD*)HookProcAddr + 4;//修改原函数的头部 跳转到钩子函数ProcAddr[0] = 0xE9;*(DWORD*)&ProcAddr[1] = HookProcAddr - ProcAddr - 5;//跳转指令只占五个字节 原函数头部三行指令占六个字节 因此将多余字节填充为nopProcAddr[5] = 0x90;}void UnInlineHook()
{//判断函数是否被挂钩if(ProcAddr[0] == 0xE9){strncpy((char*)ProcAddr, (char*)OldCmd, 6);}
}int main()
{DWORD sum;//挂钩InlineHook();sum = add(1, 2);printf("sum = %x\n", sum);//脱钩UnInlineHook();sum = add(3, 4);printf("sum = %x\n", sum);return 0;
}

执行结果

实验二:0环 Inline Hook

#include <ntddk.h>
#include <ntstatus.h>PUCHAR pNtOpenProcess;
UCHAR  OldCmd[20] = {0};
//函数指针 用于将数据作为指令执行
typedef VOID (*POLDCMD)();
POLDCMD pOldCmd = (POLDCMD)(PUCHAR)OldCmd;PCHAR format = "%x %x %x %x \r\n";typedef NTSTATUS (*NTOPENPROCESS)(PHANDLE ProcessHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,PCLIENT_ID ClientId);typedef struct _KSYSTEM_SERVICE_TABLE
{  PULONG  ServiceTableBase;            // 服务函数地址表基址  PULONG  ServiceCounterTableBase;  // SSDT函数被调用的次数ULONG   NumberOfService;         // 服务函数的个数  PULONG   ParamTableBase;            // 服务函数参数表基址
} KSYSTEM_SERVICE_TABLE, *PKSYSTEM_SERVICE_TABLE;  typedef struct _KSERVICE_TABLE_DESCRIPTOR
{  KSYSTEM_SERVICE_TABLE   ntoskrnl;        // ntoskrnl.exe 的服务函数  KSYSTEM_SERVICE_TABLE   win32k;          // win32k.sys 的服务函数(GDI32.dll/User32.dll 的内核支持)  KSYSTEM_SERVICE_TABLE   notUsed1;  KSYSTEM_SERVICE_TABLE   notUsed2;
}KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;// KeServiceDescriptorTable 是 ntoskrnl.exe 所导出的全局变量 申明一下就可以直接使用了
extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;VOID PageProtectOn()
{__asm{//开启内存保护mov  eax,cr0or   eax,10000hmov  cr0,eaxsti}
}VOID PageProtectOff()
{__asm{//关闭内存保护cli                  mov  eax,cr0and  eax,not 10000hmov  cr0,eax}
}VOID __declspec(naked) HookProc(){__asm{//保存现场pushadpushfdmov eax, espadd eax, 40      //eflags + 8个通用寄存器 + 返回地址add eax, 12      //定位到最后一个参数push [eax]       //ClientIdpush [eax-0x4]    //ObjectAttributespush [eax-0x8]    //DesiredAccesspush [eax-0xC]   //ProcessHandlepush formatcall DbgPrintadd esp, 20//还原现场popfdpopad//调用原本的指令,然后返回到原函数jmp pOldCmd}
}NTSTATUS InlineHook()
{NTSTATUS status;status = STATUS_SUCCESS;PageProtectOff();//保存原来的指令pNtOpenProcess = (PUCHAR)KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[0x7A];RtlMoveMemory(OldCmd, pNtOpenProcess, 5);//构造回去的指令,用于返回到原函数OldCmd[5] = 0xE9;*(PULONG)&OldCmd[6] = ((ULONG)pNtOpenProcess+5) - (ULONG)&OldCmd[5] - 5;//内核函数不存在中间人(call后通过jmp跳转),函数地址为实际地址pNtOpenProcess[0] = 0xE9;*(PULONG)&pNtOpenProcess[1] = (ULONG)HookProc - (ULONG)pNtOpenProcess - 5;PageProtectOn();return status;
}NTSTATUS UnInlineHook()
{NTSTATUS status;status = STATUS_SUCCESS;if(pNtOpenProcess[0] == 0xE9){PageProtectOff();RtlMoveMemory(pNtOpenProcess, OldCmd, 5);PageProtectOn();}return status;
}//卸载函数
VOID DriverUnload(PDRIVER_OBJECT driver)
{//卸载驱动时脱钩UnInlineHook();DbgPrint("驱动程序已停止.\r\n");
}//驱动程序入口函数,相当于控制台的main函数
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
{DbgPrint("驱动程序已运行.\r\n");//运行驱动时挂钩InlineHook();//设置一个卸载函数  便于退出DriverObject->DriverUnload = DriverUnload;return STATUS_SUCCESS;
}

执行结果

Windows驱动开发学习笔记(六)—— Inline HOOK相关推荐

  1. Windows驱动开发学习笔记(五)—— SSDT HOOK

    Windows驱动开发学习笔记(五)-- SSDT HOOK 系统服务表 系统服务描述符表 实验一:通过代码获取SSDT表地址 通过页表基址修改页属性 方法1:修改页属性 方法2:修改CR0寄存器 实 ...

  2. Windows驱动开发学习笔记(七)—— 多核同步内核重载

    Windows驱动开发学习笔记(七)-- 多核同步 基础知识 并发与同步 分析 InterlockedIncrement 原子操作相关API 内核文件 多核同步 临界区 示例一:错误的临界区 示例二: ...

  3. Windows驱动开发学习笔记(四)—— 3环与0环通信(常规方式)

    Windows驱动开发学习笔记(四)-- 3环与0环通信(常规方式) 设备对象 创建设备对象 设置数据交互方式 创建符号链接 IRP与派遣函数 IRP的类型 其它类型的IRP 派遣函数 派遣函数注册位 ...

  4. Windows驱动开发学习笔记(三)—— 内核空间内核模块

    Windows驱动开发学习笔记(三)-- 内核空间&内核模块 内核空间 实验 第一步:编译如下代码 第二步:将 .sys 文件拷贝到虚拟机中 第三步:部署 .sys 文件并运行 第四步:创建一 ...

  5. Windows驱动开发学习笔记(二)—— 驱动调试内核编程基础

    Windows驱动开发学习笔记(二)-- 驱动调试&内核编程基础 基础知识 驱动调试 PDB(Program Debug Database) WinDbg 加载 PDB 实验:调试 .sys ...

  6. Windows驱动开发学习笔记(一)—— 环境配置第一个驱动程序

    Windows驱动开发学习笔记(一)-- 环境配置&第一个驱动程序 环境配置 第一个驱动程序 环境配置 安装VS2010:https://pan.baidu.com/s/1uZWWxCtB60 ...

  7. windows内核开发学习笔记十七:IRP 和 IO_STACK_LOCATION 的交互

    windows内核开发学习笔记十七:IRP 和 IO_STACK_LOCATION 的交互 前面两篇学习笔记分别介绍了IRP和IO_STACK_LOCATION,整个设备栈来处理这个IRP,但是每个设 ...

  8. windows内核开发学习笔记十五:IRP结构

    windows内核开发学习笔记十五:IRP结构   IRP(I/O Request Package)在windows内核中,有一种系统组件--IRP,即输入输出请求包.当上层应用程序需要访问底层输入输 ...

  9. Android深度探索(卷1)HAL与驱动开发学习笔记(8)

    Android深度探索(卷1)HAL与驱动开发学习笔记(8) 第八章 蜂鸣器驱动   L i n u x驱动的代码重用有很多种方法.可以采用标准C程序的方式.将要重用的代码放在其他的文件(在头文件中声 ...

最新文章

  1. java devexpress_Coolite与DevExpress比较
  2. C之 #pragma(二十二)
  3. 996+GPA+500
  4. 【docker脚本收藏】docker-compose部署hadoop、spark等大数据各组件
  5. 消费者广播模式和负载均衡模式
  6. 转一个网络软件开发的广告
  7. chrome浏览器崩溃_不只是您:Chrome浏览器在Windows 10的2018年4月更新中崩溃
  8. 前端学习(2193):vuex概念和作用分析
  9. linux CentOS7最小化安装环境静默安装Oracle11GR2数据库(安装常用工具_02)
  10. java 二叉树特点_二叉树的Java实现及特点总结
  11. Mac Apache ZooKeeper 配置
  12. C语言如何动态分配空间:malloc
  13. JavaScript 实现Map效果
  14. 单机俄罗斯方块游戏制作心得(四)
  15. 看完这篇就够了,mac版本最新Camera Raw 15.1 新功能HDR详解
  16. Long类型的数据转换
  17. stm32零基础怎么两周入门,应该怎么安排?
  18. 攻防世界逆向高手题之re2-cpp-is-awesome
  19. 延迟执行与不可变,系统讲解JavaStream数据处理
  20. 共享丢失、找不到网络名、访问拒绝等问题的解决

热门文章

  1. 成功解决 ValueError: feature_names mismatch training data did not have the following fields
  2. Graphviz之DT:手把手教你使用可视化工具Graphviz将dot文件转为结构图的png文件
  3. BlockChain:区块链/加密数字货币落地技术应用高质量相关文章
  4. Anaconda:Anaconda安装图文教程及其tensorflow安装、运行、测试之最强详细攻略
  5. php websocket
  6. 44.更多replace案例
  7. JavaScript 表单编程
  8. Java容器类和包装类
  9. border-radius的使用 css样式
  10. oracle更改字段名顺序的方法