关于Hook,有一本书讲的比较清楚,最近刚刚看完,《Rootkits: Subverting the Windows Kernel》

http://www.amazon.com/Rootkits-Subverting-Windows-Greg-Hoglund/dp/0321294319

总结下来,Hook的方法有以下几种:

1.修改各种table,IAT/IDT/SSDT

涉及到函数调用的原理,OS,每个bin文件都会维护各种Table,函数调用,系统调用,中断响应都会reference这些table来确定跳转的目的地址。

所以,通过修改这些table的信息,可以达到一些hook的目的

2.修改函数入口的汇编

特别是win32,函数的入口前几个Byte的汇编都是蛮规律的,修改函数入口的几个Byte,用一个jump指令来替换,jump到hook的函数,执行完了再jump回来。

这个办法是下面会详细讲到的。

3.安装filter Driver.

自己create一个driver,通过IoAttachDevice/IoDetachDevice来附加到对应的设备,以后每次发给设备的信息都会先送到我们的driver里面。

会涉及到windows driver,IRP, IRP stack等知识。

4.修改Kernel object。

当我们进入kernel mode的时候,我们就可以修改很多kernel的结构,譬如process list。Processs list是一个LIST_ENTRY的双链表。

通过回去当前的process,可以遍历到所有的process。

对于每个Process的LIST_ENRTY,我们可以修改对应的FLINK,BLINK,来remove一个节点。

所以那些通过遍历process LIST_ENTRY来遍历Process的办法,我们就可以隐藏相应的Process.

/******** 下面会具体讨论Solution 2 *******/

Mark:SetWindowsHookEx,好像可以修改文件的IAT表来Hook...

这两天在想怎么port到x64上去,发现有一些的一些难点:

1. compiler for X64 don't support inline assemble了,所以不能用汇编来修改a.写保护,b.添加jmp指令

2. x64版本函数入栈的方式不像x86那么规律了,每个函数入口指令都不一样

为了hook正常运行,需要保证在调回到函数执行时,ebp,esp,堆栈内容都要保持不变

想到的办法:

函数入口直接改写成call xxx,并保存原来的指令,在ret之前修改stack里面的返回地址为原函数入口,并且恢复 for NdisRegisterxxx

么啥好办法yet...强制该汇编....

Helps:

windows提供一下函数_disable(), __writecr0(ULONG)等来替代一些原本需要汇编来做的操作。(注册表可以cancel写保护)

单独写.asm文件,这个貌似没什么帮助

=================

原理蛮好理解的,就是替换了windows api函数入口的汇编代码,用一个5个byte的长跳转jmp指令跳转到自己写的函数,执行完之后再jmp回来。

先来看一段windows x86函数入口前后的汇编指令(平台有别):

(Ps: 5byte的nop指令一般都是compiler预留,可用于patch一个长跳转, move edi,edi: 2byte可替换成一个段跳转)

  1. -: nop
  2. -: nop
  3. -: nop
  4. -: nop
  5. -: nop
  6. function:
  7. -: move edi, edi
  8. -: push ebp
  9. -: move ebp, esp
  10. -: sub esp, xxxx

不过有几个地方我还是蛮困惑的:

1.因为函数调用的时候有很多register是上下文相关的,compiler帮忙都配置好了用哪些register。怎么保证跳转过去的函数使用的register跟先前的能够匹配呢。

[Answer]: function call的时候,会把需要保存的register保存到stack, Jmp过去之后,不从register里面拿信息,所以也不会影响。当然platform dependent,不同的调用规范行为不一样,这里讨论windows 32bit,linux函数调用的时候会把一些参数放在register里,以提高速度。

2.hook函数执行完之后,在jmp回到先前函数+5的地方开始执行,这时候register context也可能都改变了啊。

[Answer]:不依赖register的值,只要stack没有破坏,ebp没被改坏就没事,一般都是ebp+xx, ebp-xx来拿参数的,其实就算esp变了也不要紧,函数结束一般都有mov esp, ebp 恢复esp的值。

3.先前函数那5个byte对应的指令怎么办,略过了?要是先前函数+5的地址不是一个完整的指令起始地址呢?

[Answer]:本代码刚好在jmp到hook_func的时候,执行了同样的5byte指令,而且本代码hook的函数入口+5byte都刚好是完整的指令地址,这些都是tricky的地方,不通用。

http://www.cnblogs.com/StudyRush/archive/2011/03/06/1966553.html 这篇文章对于函数调用写的比较清楚。

粗略的先post一些code.

  1. VOID DisableIntChangeRight( PULONG pOldAttr){
  2. ULONG uAttr;
  3. _asm{
  4. cli;
  5. push eax;
  6. mov eax, cr0;
  7. mov uAttr, eax;
  8. and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
  9. mov cr0, eax;
  10. pop eax;
  11. };
  12. *pOldAttr = uAttr;
  13. }
  14. VOID EnableIntRestoreRight( ULONG uOldAttr ){
  15. _asm{
  16. push eax;
  17. mov eax, uOldAttr;
  18. mov cr0, eax;
  19. pop eax;
  20. sti;
  21. };
  22. }
  23. VOID InterceptFunction( PDEVICE_EXTENSION deviceExtension, HOOKINDEX Index, PVOID pOriginalFunc, PVOID pDestFunc){
  24. UINT uAttrib;
  25. UINT OffsetJump;
  26. UCHAR JumpCode[] = { 0xe9, 0x01, 0x02, 0x03, 0x04}; // Code inserted to pOriginalFunc to jump to pDestFunc
  27. PCHAR pString = NULL;
  28.  
  29. if (deviceExtension->CodeHooked[Index] == TRUE){
  30. DebugPrint((ERROR, "Function %s already hooked.\n", pString));
  31. return;
  32. }else {
  33. DebugPrint((INFO, "Function %s hooked.\n", pString));
  34. DisableIntChangeRight(&uAttrib);

  35. // First backup to be overwritten code.
  36. RtlCopyMemory((PCHAR)(deviceExtension->BackupCode[Index]), (PCHAR)pOriginalFunc, \
    sizeof(deviceExtension->BackupCode[Index]));
  37.  
  38. // Second calculate jmp pDestFunc and overwrite
  39. OffsetJump = (UINT)pDestFunc - (UINT)pOriginalFunc - 5;
  40.  
  41. *(PUINT)&JumpCode[1] = OffsetJump;
  42. RtlCopyMemory((PCHAR)pOriginalFunc, JumpCode, sizeof(JumpCode));
  43. deviceExtension->BackAddress[Index] = (ULONG_PTR)pOriginalFunc + 5;
  44. deviceExtension->CodeHooked[Index] = TRUE;
  45. EnableIntRestoreRight(uAttrib);
  46. }
  47. return;
  48. }
  49.  
  50. VOID RestoreFunction( PDEVICE_EXTENSION deviceExtension, HOOKINDEX Index){
  51. UINT uAttrib;
  52. PCHAR pString = NULL;
  53.  
  54. if (deviceExtension->CodeHooked[Index]){
  55. DebugPrint((TRACE, "Function %s restored.\n", pString));
  56.  
  57. DisableIntChangeRight(&uAttrib);
  58. deviceExtension->CodeHooked[Index] = FALSE;
  59.  
  60. RtlCopyMemory((PCHAR)(deviceExtension->BackAddress[Index] - 5),(PCHAR)(deviceExtension->BackupCode[Index]), sizeof(deviceExtension->BackupCode[Index]));
  61. EnableIntRestoreRight(uAttrib);
  62. }else {
  63. DebugPrint((TRACE, "Function %s is not hooked at all.\n", pString));
  64. }
  65. return;
  66. }

  

写一篇Hook Driver.的更多相关文章

  1. 如何优雅的写一篇安利文-以Sugar ORM为例

    前言 我最近喜欢把写的十分优美的技术文章叫做安利文.首先,文章必须是原创而非软广:其次,阅读之后不仅能快速吸纳技术要点并入门开发,还能感同身受的体会作者热情洋溢的赞美和急于分享心得体验的心情,让人感觉 ...

  2. Python爬虫个人记录(四)利用Python在豆瓣上写一篇日记

    涉及关键词:requests库 requests.post方法 cookies登陆 version 1.5(附录):使用post方法登陆豆瓣,成功! 缺点:无法获得登陆成功后的cookie,要使用js ...

  3. 如何写一篇好的技术博客or技术文档(转链接)

    如何写一篇好的技术文档http://yunli.blog.51cto.com/831344/168352 程序员怎样才能写出一篇好的博客或者技术文章?http://www.zhihu.com/ques ...

  4. 再写一篇ubuntu服务器的环境配置文

    三年前写过一篇,但是环境和三年前比已经发生了比较大的变化,于是重新写一篇,自己以后再次配置也比较方便.我个人而言并没有觉得centos比ubuntu好用多少,所以继续选用ubuntu. 一.硬盘分区  ...

  5. 再写一篇tps限流

    再写一篇tps限流 各种限流算法的称呼 网上有很多文章介绍限流算法,但是对于这些算法的称呼与描述也是有点难以理解.不管那么多了.我先按我理解的维度梳理一下. 主要维度是:是正向计数还是反向计数.是定点 ...

  6. CesiumLab V1.4 分类3dtiles生成(倾斜单体化、楼层房间交互)我记得我是写过一篇关于倾斜单体化的简书文章的,但是现在找不到了。不过找不到也好,就让他随风逝去吧,因为当时我写那篇文章的时候,就发现了cesium实际是有另一种更高效的单体化。就下面这个示例https://cesiumjs.org/Cesium/Build/Apps/Sandcastle/index.html?src=

    我记得我是写过一篇关于倾斜单体化的简书文章的,但是现在找不到了.不过找不到也好,就让他随风逝去吧,因为当时我写那篇文章的时候,就发现了cesium实际是有另一种更高效的单体化.就下面这个示例 http ...

  7. 自学Python可以吗?怎样从入门到大师?我写这篇文章告诉你

    前言 很多粉丝朋友问我该如何去学习爬虫.学习Python.自学能找到工作吗?等一系列的问题.今天我就来回答一下大家. 第一点 确定好方向与目标 当决定踏入这个行业那一刻起,我想每一个人都爱已经准备投身 ...

  8. 写这篇博客之前,我又忘了“==”和equals的区别。

    没错.嘟嘟又把==号和equals 的区别给忘掉了 ==号比较基本类型的时候比的是值,比较引用类型的时候比较的是地址.equals比较基本类型的时候.... 脑子里关于这道题的答案好模糊好没有安全感 ...

  9. 想写一篇jvm的工具入门

    为什么要写一个jvm的工具入门呢,一是自己也不会,二是因为不会所以想学一下,还有就是这个确实很重要,对学习jvm有很多的用处,对定位问题有很大的便利,以前毕业那会我记得有个笔试,知道JAVA_HOME ...

随机推荐

  1. 新疆大学ACM-ICPC程序设计竞赛五月月赛(同步赛)-B-杨老师游戏

    题目链接:杨老师游戏 题目分析:将9个数字分成3块,分块枚举,话句话说,9个数字的所有排列组合,如果满足N=a*b-c就是一个答案,暴力枚举Orz. 代码如下:  #include<iostre ...

  2. Delphi中CPort控件之Timeout属性

    转载:http://blog.sina.com.cn/s/blog_70146dce0102wep1.html Cport的Timeout属性定义了详细的读写超时设置. 当一个特别操作的超时时间达到了 ...

  3. 构建高可靠hadoop集群之5-服务级别授权

    本人翻译自: http://hadoop.apache.org/docs/r2.8.0/hadoop-project-dist/hadoop-common/ServiceLevelAuth.html ...

  4. 编程 - 前端 - JavaScript - 库 - ECharts (开源可视化)

    ECharts,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等) ...

  5. vue 导出流文件excel

    第一种方法:需要设置响应类型,这里还需要安装 npm install js-file-download --save ,然后引用 var fileDownload = require('js-file ...

  6. pyqt 多窗口跳转

    今天在做pyqt5的多页面跳转时遇到问题,一点击button按钮,程序会崩溃.在网上查了下,应该是当窗口A调用窗口B的时候,两个窗口不能是同一类型.我写的时候把A.B同时写成了QWidget.把窗口B ...

  7. Angular : 响应式编程, 组件间通信, 表单

    Angular 响应式编程相关 ------------------------------------------------------------------------------------ ...

  8. PHP一些常用魔术方法

    魔术方法                          调用方法                                     作用__set                   有两个 ...

  9. centos 7 关闭IPtables

    systemctl status iptables.service systemctl stopiptables.service

  10. go学习笔记-函数

    函数 定义 格式 func function_name( [parameter list] ) [return_types] { 函数体 } 解析 func:函数由 func 开始声明 functio ...