Hook && Anti-Hook

0x0 零

Hook是我们常用的一种技术手段,在开发中,也经常看到Self-Hook等操作,而在逆向分析中,Hook也是用的不少。民间也流传着很多Hook框架,比如Android上的Xposed,IOS上的Tweak,以及Substrate、Frida等等。那么作为Hook框架,他们之间有啥异同?

0x01 壹

说到Hook,不得不提一下注入,想要Hook其他进程的内容就得先注入别的进程。在Android上,进程注入一般有两种方式,一是ELF文件感染,通过添加各种信息(比如新增section信息、新增依赖库等),当被感染的ELF文件加载、执行时,便可达到进程注入的目的;第二种方式比较常用,就是老生常谈的ptrace注入,具体怎么注入的,见这个小demo

0x02 贰

Android上常见的Hook Native方式根据原理不同大致分为三种:异常Hook、导入表Hook、inline Hook。

Inline Hook

三种Hook方式各有各的优缺点,那么先说说最常见的inline hook,这种方式是最暴力、最直接的方式。简单说,inline hook 就是进程注入后通过修改你要hook的那行指令为跳转指令,并且目的地址是你自己的代码区域,以此来获取到程序的控制权。

inline hook

那么在跳转到我们的代码领空之后,我们要做的第一件事就是保存当前的寄存器环境,以免等会跳转回去执行LDR R3,[R2,R3](以及之后的指令)时报错。接下来,就可以执行我们的代码,执行结束后,第一步当然是要恢复刚才的寄存器环境,除此之外,还有一件重要的事情,就是执行被改成跳转指令的那条无辜的指令,对应上图中的指令是Mov R0,R2。完事后,跳转回刚才被修改过的指令的下一条指令地址,对应上图中的就是LDR R3,[R2,R3]指令的地址。

inline hook stub

这样一来,我们就悄无声息的把注入代码给执行了,并且也把控制权归还给了原始代码流程。了解了inline hook的大致流程,我们该怎么去防止这种hook方式呢?讲道理,其实是防不住的,最多也就算给逆向工作者添加一些难度系数。我们常常看到有检测注入模块的方式去防止hook和注入,也有根据匹配某些特征去防的。但是他们都比较容易误报,我们这次来一点高精度的防护!想想看,一般hook都是针对function来的,也就是说,它们通常会去修改一个function的第一条指令为跳转指令(对于一个正常的function来说,第一条指令基本不可能会是跳转指令)。那么我们就从这里下手,去检测某一个关键函数的头几个字节是不是跳转指令(好捉急的方法%>_<%)。

我们这里针对frida来做inline hook的防御。先自己写几个脚本去hook某个function,同时对这个function的头几个字节做个内存快照,最后同步到IDA里,我们会发现frida使用的跳转指令在ARM和ARM64下由B系列或LDR构成(下图为我自己手动构造,请只关注指令,不需在意后面的目的地址)。

frida-inline hook BL
frida-inline hook LDR

再看看frida的源码(这里是arm的这里是thumb的这里是arm64的

frida-arm-writer
frida-arm-writer

frida通过B[..] XXXXXX或者LDR[..] PC, XXXXXX跳转到我们的功能函数里。看到这里,两个问题:1.为啥要用两种指令?2.既然有两种方式跳转,为啥不加一个MOV PC,XXXXX这种跳转

第一个问题,先看看B系列指令的字节码构成:

B系列指令

offset是一个有符号的24bit数据,所以大小在-8Mb到8Mb之间,在实际跳转过程中,offset会左移2位(乘4,和ARM指令长度有关),并且B系列是一种相对跳转指令,所以算下来,跳转范围在(PC-32Mb,PC+32Mb)之间。而LDR跳转就不存在范围的问题了,后面的立即数是多少就跳多远,所以当范围过大的时候(通常在ARM64下)会选择使用LDR PC,XXXX来跳转。

第二个问题,MOV指令,它后面的立即数必须满足一个条件,能由8bit连续有效位通过偶数次移位能得到。比如0x1100、0xAF000000等,如果目的地址是0xEE0014这种地址,MOV PC,XXXXX就无法跳转过去。

好了,话说回来,根据上述情况,针对某些函数防inline hook,就可以通过一个宏去检测函数头部字节是否匹配跳转指令(opcode+异常的目的地址)。

绕过方式嘛....太多了

导入表Hook

我们知道在一个SO文件的.GOT表会在内存中存储导入函数的地址,那么导入表Hook原理就是去替换.GOT表里的那些地址,比如你把strcmp函数的地址替换成你的helloWorld函数地址,那么程序每次调用strcmp时,你都可以在控制台看到“Hello World”输出。

原理很简单,操作时第一步就是定位.GOT表的地址,通过遍历ELF文件的SectionHeader,然后获取其sh_name的值,这个值就是.shstrtab内容中的偏移值,取[.shstrtab_addr + Elf32_SectionHeader.sh_name]的字符串,如果是“.got”,就恭黑勒啦;第二步就是在.GOT表中找到strcmp的地址,然后替换成你helloWorld的地址就ok了(很好找,4字节对齐)。

防这种hook很容易,把编译好的SO文件的section信息抹去就行了,反正SO文件执行的时候不需要这些信息。绕过呢,看这里吧

在IOS上有一种Hook方式和这种导入表方式有那么点点相似,都是替换的地址,叫做Method Swizzling。在编写Tweak插件的时候,对于OC的函数的Hook,就是通过替换函数的IMP实现的。那么IOS上怎么防这种Hook方式呢?不可能把Mach-O文件的dyld_info_command结构体给抹了吧。我是这样考虑的,既然地址被替换了,那么该函数与同模块的其他函数的相对偏移也就改变了,而且变化后的偏移肯定大的离谱。那么给个阈值,稍微检测一下,应该就可以了吧?绕过呢。。。

异常Hook

异常Hook,顾名思义,就是弄个异常,然后在异常处理的时候执行我们的功能函数。程序在运行时,如果遇到异常,系统会使用程序已注册的异常处理函数去处理抛出来的异常。那么各指令集对应的异常指令如下:

异常指令

具体实施,就是注入后,把你要Hook的地址的指令给改成异常指令,然后注册你的异常处理函数,在异常处理时,修复异常指令,执行自己的功能函数。这里有个问题不知道大家发现没,就是异常指令被修复后,下次执行到这里的时候,就没办法触发我们的异常处理函数了,导致我们的Hook挂上之后执行一次就掉了。怎么确保每次执行到呢?我们需要在异常处理函数里将接下来要执行的那行指令也替换成异常指令,并且在第二处异常触发的异常处理函数里将第一处被修复的异常指令再次替换成异常指令,并且再修复第二处异常指令就ok了(好拗口)。

问题来了,怎么防?检测异常代码?异常处理函数白名单? 自定义异常处理函数陷阱?

0x3 叁

Android上最常见的Hook方式应该属于Xposed,它是针对java方法的一个Hook方式。简单说,Xposed的原理就是将一个java方法给修改成Native方法,方法对应Method结构体里的insns指针就指向的是你在Xposed里注册的功能函数,如果还要执行原始方法,Xposed会在insns里的代码执行结束后再去反射调用原始的方法。

Method结构体insns指针
DVM设置NativeFunction

怎么防?检测方法的属性,是否该为Java方法的变成了Native的;反射获取Xposed的一些属性,检测注册了关于你的函数的钩子;more。

慢慢更~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容