一、HOOK介绍

1、什么是HOOK(钩子)

(1)对于Windows系统,它是建立在事件驱动机制上的,说白了就是整个系统都是通过消息传递实现的。

(2)HOOK技术即钩子函数,钩子函数是Windows消息处理机制的一部分,通过设置“钩子”,应用程序可以在系统级对所有消息、事件进行过滤,访问在正常情况下无法访问的消息。

(3)钩子的本质是一段用以处理系统消息的程序,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息(如屏幕取词,监视日志,截获键盘/鼠标输入等),也可以不作处理而继续传递该消息,还可以强制结束消息的传递。

(4)HOOK技术在windows系统下编程,应该会接触到api函数的使用,常用的api函数大概有2000个左右。今天随着控件,stl等高效编程技术的出现,api的使用概率在普通的用户程序上就变得越来越小了。当诸如控件这些现成的手段不能实现的功能时,我们还需要借助api。
(5)钩子的种类很多,每种钩子可以截获相应的消息,如键盘钩子可以截获键盘消息,外壳钩子可以截取、启动和关闭应用程序的消息等。钩子可以分为线程钩子和系统钩子,线程钩子可以监视指定线程的事件消息,系统钩子监视系统中的所有线程的事件消息。因为系统钩子会影响系统中所有的应用程序,所以钩子函数必须放在独立的动态链接库(DLL) 中。
(6)所以说,hook(钩子)就是一个Windows消息的拦截机制,可以拦截单个进程的消息(线程钩子),也可以拦截所有进程的消息(系统钩子),也可以对拦截的消息进行自定义的处理。Windows消息带了一些程序有用的信息,比如Mouse类信息,就带有鼠标所在窗体句柄、鼠标位置等信息,拦截了这些消息,就可以做出例如金山词霸一类的屏幕取词功能。

总结下:对于新人来说对说了这个词语的人真是崇拜至极,心里默念着牛逼,但其实这是一名程序员应该懂的基本功。其实钩子来源于英文词Hook,在windows系统中,一切皆消息,比如按了一下键盘,也是一个消息。Hook的意思是勾住,也就是在消息过去之前,可以先把消息勾住,不让其传递,你可以优先处理。也即这项技术就是提供了一个入口,能够针对不同的消息或者API在执行前,先执行你的操作,你的操作也称为[钩子函数]。所以,有的时候程序员在讨论的时候,也经常会说,可以先hook住,在处理,也即在执行某某操作之前,优先处理一下。

2、Hook分类

(1)线程钩子监视指定线程的事件消息。
(2)系统钩子监视系统中的所有线程的事件消息。因为系统钩子会影响系统中所有的应用程序,所以钩子函数必须放在独立的动态链接库(DLL)中。这是系统钩子和线程钩子很大的不同之处。

3、HOOK(钩子)

在正确使用钩子函数前,我们先讲解钩子函数的工作原理。当您创建一个钩子时,WINDOWS会先在内存中创建一个数据结构,该数据结构包含了钩子的相关信息,然后把该结构体加到已经存在的钩子链表中去。新的钩子将加到老的前面。当一个事件发生时,如果您安装的是一个线程钩子,您进程中的钩子函数将被调用。如果是一个系统钩子,系统就必须把钩子函数插入到其它进程的地址空间,要做到这一点要求钩子函数必须在一个动态链接库中,所以如果您想要使用系统钩子,就必须把该钩子函数放到动态链接库中去。

当然有两个例外:工作日志钩子和工作日志回放钩子。这两个钩子的钩子函数必须在安装钩子的线程中。原因是:这两个钩子是用来监控比较底层的硬件事件的,既然是记录和回放,所有的事件就当然都是有先后次序的。所以如果把回调函数放在DLL中,输入的事件被放在几个线程中记录,所以我们无法保证得到正确的次序。故解决的办法是:把钩子函数放到单个的线程中,譬如安装钩子的线程。
       几点需要说明的地方: 
(1)如果对于同一事件(如鼠标消息)既安装了线程钩子又安装了系统钩子,那么系统会自动先调用线程钩子,然后调用系统钩子。 
(2) 对同一事件消息可安装多个钩子处理过程,这些钩子处理过程形成了钩子链。当前钩子处理结束后应把钩子信息传递给下一个钩子函数。而且最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加入的先获得控制权。 
(3)钩子特别是系统钩子会消耗消息处理时间,降低系统性能。只有在必要的时候才安装钩子,在使用完毕后要及时卸载。

二、示例

1、LD_PRELOAD劫持.so

(1)前言:

我们用到的函数实现几乎全部来自于glibc,.so文件是glibc编译得到的库,类似于Windows系统下的DLL(动态链接库)。LD_PRELOAD是一个Linux下的动态链接相关的环境变量,它可以影响程序的运行时的链接(Runtime linker);更具体的说这个变量允许你定义在程序运行时优先加载的动态链接库通过这个环境变量我们可以在主程序和其动态链接库的中间加载别的动态链接库,达到覆盖正常的函数库的目的。一方面,我们可以一次功能使用自己的或者更好的函数。另一方面,通过这种方法也可以向别人的程序注入恶意程序,从而达到不可告人的目的。

为了更好的理解LD_PRELOAD这个环境变量,这里先说下链接。所谓链接,简单来说就是编译器找到程序中所引用的函数或全局变量所存在的位置。一般来说程序的链接分为静态链接和动态链接。静态链接就是把所有所引用到的函数或者变量全部编译到可执行文件中;动态链接则不会把函数编译到可执行文件中,而是在程序运行的时候动态的载入函数库,也就是常说的运行时链接。所以对于动态链接来说,必然需要一个动态链接库。

动态链接库的好处在于一旦动态库中的函数发生变化对于可执行程序来说是透明的,可执行程序无需重新编译。这对于程序的发布、维护、更新起到了积极的作用。对于静态链接的程序来说,函数库中一个小小的改动需要对整个程序进行重新编译、发布,显然可维护性大打折扣。有得就有失,任何事情都有两面性动态链接技术也不例外。动态链接所带来的的坏处和好处同样巨大。因为程序在运行是动态加载函数,这也就为他人创造了影响主程序的机会。试想,你的程序动态载入的函数不是你写的函数,而是未知的别人的函数;通过函数的返回值能控制你的程序的执行流程,就问你怕不怕?对于这种情况通常就认为你的程序被“劫持”了。

我们知道Linux用的都是glibc,其中有一个叫libc.so.6的文件几乎包括Linux动态链接的标准C的各种函数。对于GCC而言默认情况下所编译的程序对标准C函数的链接都是通过动态链接的方式来链接libc.so.6这个函数库的。

(2)LD_PRELOAD劫持实例

1)首先有如下目标文件target.cpp;执行“gcc target.cpp -o target”得到可执行文件 target。

#include <stdio.h>
#include <string.h>
#include <dlfcn.h>typedef int(*Strcmp)(const char*, const char*);int strcmp(const char* s1, const char* s2)
{static void* handle = NULL;static Strcmp org_strcmp = NULL;if(!handle){handle = dlopen("libc.so.6", RTLD_LAZY);org_strcmp = (Strcmp)dlsym(handle, "strcmp");}printf("Hacked by way of ld_preload\n\n\n");return org_strcmp(s1, s2);
}

2)另外又有如下伪造的.so文件preload.cpp;执行“gcc -fPIC preload.cpp -shared -o preload.so -ldl”编译得到.so文件。

#include <stdio.h>
#include <string.h>
#include <dlfcn.h>typedef int(*Strcmp)(const char*, const char*);int strcmp(const char* s1, const char* s2)
{static void* handle = NULL;static Strcmp org_strcmp = NULL;if(!handle){handle = dlopen("libc.so.6", RTLD_LAZY);org_strcmp = (Strcmp)dlsym(handle, "strcmp");}printf("Hacked by way of ld_preload\n\n\n");return org_strcmp(s1, s2);
}

3)修改LD_PRELOAD变量

LD_PRELOAD=./preload.so
export LD_PRELOAD
echo $LD_PRELOAD

设置环境变量 LD_PRELOAD 预加载我们编译好的恶意preload.so库。

 注:使用如下代码更简易直观

//getuid.c#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main(void)
{printf("my uid is %d\n",getuid());
}//gcc -o getuid getuid.c

//muid.c
//让恶意的getuid函数返回1000这个固定数值#include<sys/types.h>
uid_t getuid(void)
{return 1000;
}//gcc -shared -lc -fPIC -o muid.so muid.c
LD_PRELOAD="./muid.so"
export LD_PRELOAD
echo $LD_PRELOAD

几个相关链接:

https://zhuanlan.zhihu.com/p/202670441

https://blog.csdn.net/maijian/article/details/40856587

https://www.cnblogs.com/zlgxzswjy/p/10399996.html

hook原理介绍与简单实例相关推荐

  1. (三)AJAX基本介绍和简单实例03

    (三)AJAX基本介绍和简单实例03-----Ajax与数据库的动态应用 前台显示界面: 选择所有客户之后: 选择其中一个客户---杜森: Demo03.html代码 <html> < ...

  2. 大数据Hadoop之——Kafka Streams原理介绍与简单应用示例

    文章目录 一.Kafka Streams概述 1)Kafka Streams是什么 2)流式计算与批量计算区别 3)Kafka Streams特点 二.Kafka Streams流处理拓扑 1)相关概 ...

  3. Adaboost入门教程——最通俗易懂的原理介绍(图文实例)

    写在前面 说到Adaboost,公式与代码网上到处都有,<统计学习方法>里面有详细的公式原理,Github上面有很多实例,那么为什么还要写这篇文章呢?希望从一种更容易理解的角度,来为大家呈 ...

  4. zk-SNARKs详细原理介绍(简单通俗易懂)

    zk-SNARKs 什么是zk-SNARKs? 1. 引言 2. 为什么zk-SNARKs "应该"是很难实现的? 3. zk-SNARKs基础概念 3.1 polynomial ...

  5. JNI介绍及简单实例

    JNI概念 JNI是Java Native Interface的缩写,中文为JAVA本地调用. 使用JNI, 可以调用用其他语言写成的库或程序, 尤其是C和C++. 好了,概念性的内容就不多介绍了, ...

  6. java BASE64Encoder详细介绍及简单实例

    java  BASE64Encoder详解 Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,在发送电子邮件时,服务器认证的用户名和密码需要用Base64编码,附件也需要用Base6 ...

  7. 简单概括Xposed hook原理

    转载自:https://www.jianshu.com/p/b29a21a162ad 这块知识本身是挺多的,网上有对应的源码分析,本文尽量从不分析代码的角度来把原理阐述清楚. Xposed是一个在an ...

  8. Xposed hook原理

    先来个总结 java源码经过编译后,得到很多个class文件, 考虑到手机的内存较小,google改进了字节码的组织形式,将一个app中的所有class文件合到了一起构成dex文件,当然并不是简单的拼 ...

  9. API hook原理和实例快速入门(inline hook),以dll线程注入方式使用(win7-64bit)

    一个完整的hook,如果hook程序是以dll形式生成的,是分两步:1.完成dll本身的设计和生成,2.完成dll注入程序的设计和生成 本文完成第一步. 第二步在http://blog.csdn.ne ...

  10. 生成对抗式网络 GAN及其衍生CGAN、DCGAN、WGAN、LSGAN、BEGAN等原理介绍、应用介绍及简单Tensorflow实现

    生成式对抗网络(GAN,Generative Adversarial Networks)是一种深度学习模型,是近年来复杂分布上无监督学习最具前景的方法之一.学界大牛Yann Lecun 曾说,令他最激 ...

最新文章

  1. ASP.NET MVC3 快速入门--第二节 添加一个控制器
  2. 什么是分布式系统中的幂等性
  3. SQL Server 2005中的分区表
  4. 第一章 Spark系统概述
  5. commons-logging log4j的联系区别
  6. android 更新平台,Android更新平台架构方案
  7. graphql_GraphQL在Wildfly群上
  8. 深度学习目标检测网络个人总结
  9. android电池剩余使用时间,android电池剩余使用时间
  10. GTX1060 6G是低端电脑显卡吗?
  11. 暴力/set Codeforces Round #291 (Div. 2) C. Watto and Mechanism
  12. 2020暨大计算机考研失败经验总结
  13. gels imagej 图片处理_科研论文作图之ImageJ
  14. 空中网创始人杨宁:忽悠就是融资能力
  15. 读取U盘 PID,VID,SN等信息
  16. mybatis 整合spring之mapperLocations配置的问题
  17. Android 之路20---Java基础14
  18. 艾永亮超级产品:企业管理者对企业发展起到什么作用?
  19. 74行代码实现浪漫的红心下落的动画效果
  20. 俊成码付出修复版源码

热门文章

  1. 《高翔视觉slam十四讲》学习笔记 第四讲 李群与李代数
  2. 力扣-1337. 矩阵中战斗力最弱的 K 行
  3. vue 异步更新队列 Vue.nextTick(callback)
  4. Android-【报错】java.lang.ClassCastException: .MainActivity cannot be cast to java.lang.Runnable
  5. [技术博客]使用wx.downloadfile将图片下载到本地临时存储
  6. C# 从磁盘中读取文件
  7. winfrom 窗口起始位置为屏幕中央
  8. 11月13号例会记录
  9. Java加密与解密笔记(二) 对称加密
  10. BZOJ1013球形空间产生器sphere 高斯消元