hook是什么?

windows系统下的编程,消息message的传递是贯穿其始终的。这个消息我们可以简单理解为一个有特定意义的整数,正如我们看过的老故事片中的“长江长江,我是黄河”一个含义。windows中定义的消息给初学者的印象似乎是“不计其数”的,常见的一部分消息在winuser.h头文件中定义。hook与消息有着非常密切的联系,它的中文含义是“钩子”,这样理解起来我们不难得出“hook是消息处理中的一个环节,用于监控消息在系统中的传递,并在这些消息到达最终的消息处理过程前,处 理某些特定的消息”。这也是hook分为不同种类的原因。

hook的这个本领,使它能够将自身的代码“融入”被hook住的程序的进程中,成为目标进程的一个部分。我们也知道,在windows2000以后的系统中,普通用户程序的进程空间都是独立的,程序的运行彼此间都不受干扰。这就使我们希望通过一个程序改变其他程序的某些行为的想法不能直接实现,但是 hook的出现给我们开拓了解决此类问题的道路。

api hook是什么?

在windows系统下编程,应该会接触到api函数的使用,常用的api函数大概有2000个左右。今天随着控件,stl等高效编程技术的出现,api的使用概率在普通的用户程序上就变得越来越小了。当诸如控件这些现成的手段不能实现的功能时,我们还需要借助api。最初有些人对某些api函数的功能不太满意,就产生了如何修改这些api,使之更好的服务于程序的想法,这样api hook就自然而然的出现了。我们可以通过api hook,改变一个系统api的原有功能。基本的方法就是通过hook“接触”到需要修改的api函数入口点,改变它的地址指向新的自定义的函数。api hook并不属于msdn上介绍的13类hook中的任何一种。所以说,api hook并不是什么特别不同的hook,它也需要通过基本的hook提高自己的权限,跨越不同进程间访问的限制,达到修改api函数地址的目的。对于自身进程空间下使用到的api函数地址的修改,是不需要用到api hook技术就可以实现的。

api hook和pe格式的关系

api hook技术的难点,并不在于hook技术,初学者借助于资料“照葫芦画瓢”能够很容易就掌握hook的基本使用技术。但是如何修改api函数的入口地址?这就需要学习pe可执行文件(.exe,.dll等)如何被系统映射到进程空间中,这就需要学习pe格式的基本知识。windows已经提供了很多数据结构struct帮助我们访问pe格式,借助它们,我们就不要自己计算格式的具体字节位置这些繁琐的细节。但是从api hook的实现来看,pe格式的访问部分仍然是整个编程实现中最复杂的一部分,对于经常crack的朋友不在此列。

假设我们已经了解了pe格式,那么我们在哪里修改api的函数入口点比较合适呢?这个就是输入符号表imported symbols table(间接)指向的输入符号地址。

下面对于pe格式的介绍这一部分,对于没有接触过pe格式学习的朋友应该是看不太明白的,但我已经把精华部分提取出来了,学习了pe格式后再看这些就很容易了。

pe格式的基本组成

+-------------------+

| DOS-stub     |  --DOS-头

+-------------------+

| file-header   |  --文件头

+-------------------+

| optional header |  --可选头

|- - - - - - - - - -|

|          |

| data directories |  --(可选头尾的)数据目录

|          |

+-------------------+

|          |

| section headers |  --节头

|          |

+-------------------+

|          |

| section 1    |  --节1

|          |

+-------------------+

|          |

| section 2    |  --节2

|     &// 本文转自 C++Builder 研究 - http://www.ccrun.com/article.asp?i=1036&d=cf6de2

nbsp;     |

+-------------------+

|          |

| ...        |

|          |

+-------------------+

|          |

| section n    |  --节n

|          |

+-------------------+

在上图中,我们需要从“可选头”尾的“数据目录”数组中的第二个元素——输入符号表的位置,它是一个IMAGE_DATA_DIRECTORY结构,从它中的VirtualAddress地址,“顺藤摸瓜”找到api函数的入口地点。

下图的简单说明如下:

OriginalFirstThunk 指向IMAGE_THUNK_DATA结构数组,为方便只画了数组的一个元素,AddressOfData 指向IMAGE_IMPORT_BY_NAME结构。

IMAGE_IMPORT_DESCRIPTOR数组:每个引入的dll文件都对应数组中的一个元素,以全0的元素(20个bytes的0)表示数组的结束

IMAGE_THUNK_DATA32数组:同一组的以全0的元素(4个bytes的0)表示数组的结束,每个元素对应一个IMAGE_IMPORT_BY_NAME结构

IMAGE_IMPORT_BY_NAME:如..@Consts@initialization$qqrv. 表示

Unmangled Borland C++ Function: qualified function __fastcall Consts::initialization()

为了减少这个图的大小,不得已将汇编和c++的结构都用上了。这个图是输入符号表初始化的情形,此时两个IMAGE_THUNK_DATA结构数组的对应元素都指向同一个IMAGE_IMPORT_BY_NAME结构。

程序加载到进程空间后,两个IMAGE_THUNK_DATA结构数组指向有所不同了。看下图:

初始化的,“两个结构都指向同一个IMAGE_IMPORT_BY_NAME”,此时还没有api函数地址

当PE文件准备执行时,前图已转换成上图。一个结构指向不变,另一个出现api函数地址

如果PE文件从kernel32.dll 中引入10个函数,那么IMAGE_IMPORT_DESCRIPTOR 结构的 Name1域包含指向字符串"kernel32.dll"的RVA,同时每个IMAGE_THUNK_DATA 数组有10个元素。(RVA是指相对地址,每一个可执行文件在加载到内存空间前,都以一个基址作为起点,其他地址以基址为准,均以相对地址表示。这样系统加载程序到不同的内存空间时,都可以方便的算出地址)

上述这些结构可以在winnt.h头文件里查到。

具体编程实现

我将手上的vc示例代码进行了适当修正,修改了一些资源泄漏的小问题,移植到c++builder6 & update4上,经过测试已经可以完成基本的api hook功能。有几个知识点说明一下:

1、  dll中共享内存变量的实现

正常编译下的dll,它的变量使用到的内存是独立的。比如你同时运行两个调用了某个dll的用户程序,试图对某一个在dll中定义的全局变量修改赋值的时候,两个程序里的变量值仍然是不同的。

共享的方法为:在.cpp文件(.h文件里如此设置会提示编译错误)的头部写上如上两行:

#pragma option -zRSHSEG      // 改变缺省数据段名

#pragma option -zTSHCLASS    // 改变缺省数据类名

HINSTANCE hdll = NULL;          // 用来保存该动态连接库的句柄

HHOOK hApiHook = NULL;          // 钩子句柄

HHOOK hWndProc = NULL;          // 窗口过程钩子用来拦截SendMessage

int threadId = 0;

另外建立一个与dll同名,不同后缀的def文件,如HookDll.def文件,写上:

LIBRARY HookDll.dll

EXPORTS

;...

SEGMENTS

SHSEG CLASS 'SHCLASS' SHARED

;end

这样设置后在.cpp文件中定义的变量,如果进行了初始化,将进入“SHCLASS”共享内存段(如果不初始化,将不改变其默认段属性)。

上述的共享对于本示例代码并不是必须的,只是稍微演示了一下。

2、  api hook修改api函数入口点地址的时机

很显然,我们必须通过hook进入目标进程的地址空间后,再在位于该地址空间里的hook消息处理过程里修改输入符号表“指向”的api函数入口点地址,退出hook前也必须在这个消息处理过程里恢复原来的地址。只要我们牢记修改的过程发生在目标进程的地址空间中,就不会发生访问违例的错误了。

示例代码使用了WH_GETMESSAGE、WH_CALLWNDPROC两中hook来演示如何hook api,但WH_GETMESSAGE实际上并没有完成具体的功能。

为了让初学者尽快的掌握重点,我将代码进行了简化,是一个不健壮、不灵活的演示示例。

3、  函数的内外部表现形式

例如api函数MessageBox,这个形式是我们通常用到的,但到了dll里,它的名字很可能出现了两个形式,一个是MessageBoxA,另一个是MessageBoxW,这是因为系统需要适应Ansi和Unicode编码的两种形式,我们不在函数尾端添加“A”或“W”,是不能hook到需要的函数的。

4、  辅助pe格式查看工具

PE Explorer是一个非常好的查看pe资源的工具,通过它可以验证自己手工计算的pe地址,可以更快的掌握pe格式。

调试器ollydbg也是非常好的辅助工具,例如查看输入符号表中的api函数。

5、  程序文件列表

dll基本文件:Hook.h,Hook.cpp,HookDll.def

client验证方基本文件:HookTest.h,HookTest.cpp,ApiHookTest.cpp

6、  实现的功能

对记事本的MessageBoxW函数进行了hook,先执行自定义的

int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR M1, LPCWSTR M2, UINT M3)

{

return oldMessageBoxW(hWnd, M1, L"my api hook", M3);

}

从这里可以看到,由于目标进程空间中的执行线程并不知道你已经改变了api函数的实际入口地址,它在调用时仍旧将参数一成不变的压入堆栈(这个说法是汇编代码时看到的等价情形),事实上你已经提前接收到了函数调用的所有参数。这里就是篇首帖子的回复了。

hook之前

hook以后

示例代码

1、client验证方的代码非常简单。建立一个Application工程,在窗体上放一个memo(提示信息),两个button(一个SetHook,另一个RemoveHook)。

void __fastcall TForm1::Button1Click(TObject *Sender)

{

DWORD dwProcessId, dwThreadID;

HWND hWnd = FindWindow("Notepad", NULL);

if (!hWnd)

{

Memo1->Lines->Add("Nodepad is not found");

}

else

{

dwThreadID = GetWindowThreadProcessId(hWnd, &dwProcessId);

Memo1->Lines->Add(dwThreadID);

SetHook(dwThreadID);

}

}

//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)

{

RemoveHook();

}

//---------------------------------------------------------------------------

2、api hook dll稍微复杂些,建立一个dll工程之后,修改之。代码中有一些函数并未用上,ReplaceApiAddress是核心函数,文章开始处有示例代码下载。

java hook技术_API Hook基本原理和实现 - - JavaEye技术网站相关推荐

  1. android hook截取其他程序的按钮事件_Hook技术

    概述 Hook,英文直译是"钩子"的意思.在程序中将其理解为"劫持"可能会更好理解,我们可以通过hook技术来劫持某个对象,从而控制它与其他对象的交互. Hoo ...

  2. Hook技术之Hook Activity

    一.Hook技术概述 Hook技术的核心实际上是动态分析技术,动态分析是指在程序运行时对程序进行调试的技术.众所周知,Android系统的代码和回调是按照一定的顺序执行的,这里举一个简单的例子,如图所 ...

  3. Java可以hook微信吗,【第一篇】【安卓微信】HOOK微信发消息,当HOOK遇上HOOK。

    前人栽树,后人吃桃. 准备入坑 安卓 xposed hook 微信(及时通信),好吧,第一步当然是论坛里面搜索啦,像掷骰子.计步器什么的都是小孩子过家家入门级别的,当然是要搞就搞(及时通信).微信 a ...

  4. 9.3 挂钩API技术(HOOK API)

    HOOK API HOOK API是指截获特定进程或系统对某个API函数的调用,使得API的执行流程转向指定的代码.例如,在挂钩了系统对User32.dll模块中MessageBoxA函数的调用以后, ...

  5. 古典黑客技术之HOOK API

    古典黑客技术之HOOK API HOOK API技术可以拦截.控制某些API函数的调用.当一个API函数被拦截之后,用户可以让目标程序执行事先准备好的代码.(比如说,构造的代码是过滤此API函数传入的 ...

  6. PLT hook与Inline hook

    前言 在目前的安卓APP测试中对于Native Hook的需求越来越大,越来越多的APP开始逐渐使用NDK来开发核心或者敏感代码逻辑. 个人认为原因如下: 安全的考虑.各大APP越来越注重安全性,ND ...

  7. 【Android 插件化】Hook 插件化框架 ( Hook 实现思路 | Hook 按钮点击事件 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  8. android hook 第三方app_基于 VirtualApp 结合 whale hook框架实现hook第三方应用

    要点 1. whale hook framework 使用示例: 2. 参考项目:VirtualHook: 3. 按照 VirtualHook 修改 VirtualApp: 4. 编写 hook pl ...

  9. java架构师,必须掌握的几点技术?

    一.前言 一个成熟的大型网站(如淘宝.京东等)的系统架构并不是开始设计就具备完整的高性能.高可用.安全等特性,它总是随着用户量的增加,业务功能的扩展逐渐演变完善的,在这个过程中,开发模式.技术架构.设 ...

最新文章

  1. 通过身份证号提取性别_身份证号提取生日、年龄、性别、籍贯,最简单的方法!...
  2. sql 一对多获得一条数据_从真实销售数据获得insights——SQL部分
  3. XAMPP环境下配置Phalcon框架
  4. 全网独发gensim中similarities.Similarity用法
  5. ORACLE TEXT FILTER PREFERENCE(三)
  6. 华为海思MPP媒体处理软件开发学习(基础)
  7. crontab基本命令
  8. 现在多少钱能和以80年代的万元户持平?
  9. C++(STL):23 ---序列式容器queue源码剖析
  10. Python实现HTTP服务器(四)单进程线程非阻塞实现多任务
  11. normalize函数_【ADAMS】矩阵/数组函数
  12. 如何在Shell脚本中漂亮地打印JSON?
  13. .net知识和学习方法系列(十七)CLR-CLR中的值类型和引用类型
  14. Atitit 数据库映射到redis存储的模式 1. 常规 每条db记录映射一个redis记录 1 1.1. 表名:主键为key ,记录序列化为json为val 1 2. 每个字段映射一个redi
  15. 极化码:信道极化原理(一)——两信道极化定理
  16. 一:计算机基础入门及介绍
  17. 甲基化芯片Beta值意义详解,以及minfi包使用
  18. 一个简单的SQL注入攻击
  19. 【web系列十一】使用django创建数据库表
  20. js在指定的td中插入html元素,js在指定位置增加节点函数insertBefore()用法实例

热门文章

  1. python 中pandask的 iterrows、itertuples、iteritems的理解及遍历,用‘列名’和‘索引’方式访问,及速度比拼
  2. 051 [转载]《黑客是共享 黑客是沉寂》及番外四篇
  3. java新建项目流程,记录vue创建项目过程
  4. 亲密关系沟通-【边界感】-梳理边界感的沟通方法
  5. 如何翻译视频?3分钟告诉你翻译视频用什么软件
  6. Python:实现pancake sort煎饼排序算法(附完整源码)
  7. SAP中销项税MWSI和MWST区别
  8. java静态方法的调用
  9. 安利:华为鲲鹏920云主机部署Nginx服务器一键拉起自动化脚本
  10. CF 739E Gosha is Hunting