11.优化 - Native Hook 介绍(xHook)

  在后面的分析中会经常使用到 native hook,有必要先对 native hook 有个大概的了解。native hook 可以分为 3 类,GOT/PLT Hook、inline Hook 和 Trap Hook。了解的不到,只能聊一聊第一个,给出一些自己的理解。

inline hook

  inline hook 是将函数调用开始时的指令更替为跳转指令,使得原函数直接跳转到 Hook 的目标函数函数,并保存调用原函数时的寄存器和堆栈,在 Hook 的目标函数执行完成后,在原函数调用的下面几条指令使用跳转指令跳回原函数继续执行并保证原函数的这几条指令已经执行。可能说的不是很明白,配合一张图片来说明。

inline_hook.png
  • 1.将原函数的指令1改成跳转指令,并将指令1时的寄存器保存下来,这样指令以就跳转开始执行目标函数并将可以正常使用寄存器。

  • 2.在目标函数执行完成之后跳转回原函数执行并恢复寄存器,比如跳转回原函数的指令2开始执行,但是现在执行的并不是正常执行过程中的原函数,因为指令1被改成了跳转指令,如果原函数的指令1操作了寄存器或者其他的,那就会造成原函数执行的环境不一致。所以先要模拟原函数执行,使得在后面的执行指令环境与原函数正常执行环境一致(修改寄存器、堆栈等与原函数执行一样),可能到指令4或者5时就可以使原函数正常接下去执行了。

  • msg:实际操作难度高

GOT/PLT Hook

  利用 ELF 文件中的导入表,在一个 so 被正确加载之前,导入表只有对于函数的符号,而没有函数的真正执行地址,在被 linker 连接之后导入表就有了相对应的函数符号及地址。所以可以动态修改导入表中的函数真正执行地址。当调用该函数时,实际执行的时修改过后的函数执行地址。

  上面就是我对 GOT/PLT Hook 的理解,当然说的很不严谨。对于 GOT/PLT Hook 来说 ELF 文件格式是最重要的 ,理解了 ELF 的文件格式及加载到内存的过程就理解了 GOT/PLT Hook,所以可以先去了解 ELF。

下面介绍下 xHook 使用及原理 。

int ProxyOpen(const char *path, int flags, mode_t mode) {
    __android_log_print(ANDROID_LOG_ERROR, "TAG", "监听到文件打开:%s", path);

    int fd = open(path, flags, mode);

    return fd;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_dabaicai_moniter_NativeBridge_xhookInit(JNIEnv *env, jclass clazz) {
    /**
     * int xhook_register(const char  *pathname_regex_str,  //匹配规则
                   const char  *symbol,                     //需要 hook 的函数名
                   void        *new_func,                   //hook 后的函数
                   void       **old_func);                  //hook 的原函数
     */
    xhook_register("libopenjdkjvm.so", "open", (void *) ProxyOpen, NULL);
    xhook_register("libjavacore.so", "open", (void *) ProxyOpen, NULL);
    xhook_register("libopenjdk.so", "open", (void *) ProxyOpen, NULL);

    xhook_register("libopenjdkjvm.so", "open64", (void *) ProxyOpen, NULL);
    xhook_register("libjavacore.so", "open64", (void *) ProxyOpen, NULL);
    xhook_register("libopenjdk.so", "open64", (void *) ProxyOpen, NULL);
    // 执行真正的 hook 操作
    xhook_refresh(1);
}
xhook_result.png

以上就实现了对打开文件操作的 hook。
除此外还有几个 api

// 忽略部分 hook 信息
int xhook_ignore(const char *pathname_regex_str,  
                 const char *symbol);
                 
// 清除缓存
void xhook_clear();

// 启用/禁用 调试信息 给 flag 参数传 1 表示启用调试信息,传 0 表示禁用调试信息。 (默认为:禁用)
// 调试信息将被输出到 logcat,对应的 TAG 为:`xhook`。
void xhook_enable_debug(int flag);

// 启用/禁用 SFP (段错误保护)
// 给 flag 参数传 1 表示启用 SFP,传 0 表示禁用 SFP。 (默认为:启用)
void xhook_enable_sigsegv_protection(int flag);
  • 原理

爱奇艺 xHook 原理介绍,在这篇文章中很详细的分析 so 导入表中 malloc 函数的地址修改,也就不多说了。我换一个角度来看看是怎么找到 malloc 的地址为 3f90。

在连接文章中查找 malloc 地址的步骤:

  • 1.验证 ELF 头信息。
  • 2.在 PHT 中找到类型为 PT_DYNAMIC 的 segment,从中获取到 .dynamic section,从 .dynamic section中获取其他各项 section 对应的内存地址。
  • 3.在 .dynstr section 中找到需要 hook 的 symbol 对应的 index 值。
  • 4.遍历所有的 .relxxx section(重定位 section),查找 symbol index 和 symbol type 都匹配的项,对于这项重定位项,执行 hook 操作。

详情点击连接查看

换一个角度看:

  • 1.查找 ELF 头信息。
  • 2.在 PHT 中找类型为 PT_DYNAMIC 的 segment。
          0200 0000 642e 0000 643e 0000
643e 0000 0801 0000 0801 0000 0600 0000
0400 0000 

type            0200 0000
offset          642e 0000       文件偏移
virtual addr    643e 0000
physical addr   643e 0000       没用
file length     0801 0000       264(0108)
mem length      0801 0000       264
RWX             0600 0000       6
align           0400 0000       对齐
  • 3.通过偏移 2e64 找到 PT_DYNAMIC 的 segment 。
                    0300 0000 7c3f 0000
0200 0000 f000 0000 1700 0000 b80c 0000
1400 0000 1100 0000 1100 0000 780c 0000
1200 0000 4000 0000 1300 0000 0800 0000
faff ff6f 0300 0000 0600 0000 f001 0000
0b00 0000 1000 0000 0500 0000 9005 0000
0a00 0000 b104 0000 0400 0000 440a 0000
0100 0000 1500 0000 0100 0000 9304 0000
0100 0000 9b04 0000 0100 0000 a804 0000
0e00 0000 1d00 0000 1a00 0000 3c3e 0000
1c00 0000 0800 0000 1900 0000 443e 0000
1b00 0000 0400 0000 1e00 0000 0800 0000
fbff ff6f 0100 0000 f0ff ff6f c80b 0000
fcff ff6f 3c0c 0000 fdff ff6f 0100 0000
feff ff6f 580c 0000 ffff ff6f 0100 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000

上面中的 0300 0000 7c3f 0000 为一组数据,其中 0300 0000 为type ,7c3f 0000 为其type 类型在 ELF 文件中的地址。

  • 4.解析 PT_DYNAMIC 的 segment 中的字符串表

0500 0000 9005 0000

找到 type 为 5 的,地址为 9005 0000,即 0x950 开始的是字符串表的内容,没有提供字符串表的长度。这里就取得长一点

005f 5f63 7861 5f66 696e 616c 697a 6500
4c49 4243 006c 6962 632e 736f 006c 6962
7465 7374 2e73 6f00 736e 7072 696e 7466
006d 616c 6c6f 6300 5f5f 6378 615f 6174
6578 6974 0070 7269 6e74 6600 7361 795f
6865 6c6c 6f00 5f5f 6165 6162 695f 756e
7769 6e64 5f63 7070 5f70 7231 005f 6564
6174 6100 6162 6f72 7400 6d65 6d63 7079
005f 656e 6400 5f5f 676e 755f 556e 7769
6e64 5f46 696e 645f 6578 6964 7800 5f5f
6273 735f 7374 6172 7400 5f5f 6165 6162
695f 756e 7769 6e64 5f63 7070 5f70 7230
005f 5f61 6561 6269 5f75 6e77 696e 645f
6370 705f 7072 3200 5f5f 676e 755f 556e
7769 6e64 5f52 6573 746f 7265 5f56 4650
5f44 005f 5f67 6e75 5f55 6e77 696e 645f
5265 7374 6f72 655f 5646 5000 5f5f 676e
  • 5.找到符号表

0600 0000 f001 0000

符号表是地址和字符串的对应关系,type= 6.

type 为 6,地址为 0x1f0

0000 0000 0000 0000 0000 0000 0000 0000     第 0 项不使用
0100 0000 0000 0000 0000 0000 1200 0000     
                                            0100 0000 在string的偏移 590+1=591 __cxa_atexit
                                            0000 0000 地址 导入表之前为0
                                            0000 0000 函数或者变量大小
                                            1200 0000 附加的(不知道什么用)
    
2800 0000 0000 0000 0000 0000 1200 0000
3100 0000 0000 0000 0000 0000 1200 0000
...
  • 6.找到导入表

导入表大小

0200 0000 f000 0000

导入表

1700 0000 b80c 0000

导入表的 type = 17 ,导入表大小的 type = 2

所以导入表开始地址为 0xcb8,大小为 f0 / 8 = 240/8 = 30 项

883f 0000 1604 0000
                883f 0000   导入地址
                16          导入表类型
                04 0000     符号表索引
8c3f 0000 1601 0000 903f 0000 1603 0000
943f 0000 1602 0000 983f 0000 1605 0000
9c3f 0000 160c 0000 a03f 0000 1610 0000
....
  • 7.逆向查找

(8c3f 0000 1601 0000)正向查找:找到符号表索引为 1 的

0100 0000 0000 0000 0000 0000 1200 0000
0100 0000 在字符串的偏移 0x590 + 0x1= 0x591 查找为 __cxa_atexit
0000 0000 地址 导入表之前为0
0000 0000 函数或者变量大小
1200 0000 附加的(不知道什么用)

结论 :函数名 __cxa_atexit 导入地址 0x3f8c

逆向查找:

  1. 已知函数名为 malloc 。

  2. 查找在字符串表中的地址为 0x5c1。


    malloc.png
  3. 减去字符串表起始地址 0x590 ,0x5c1 - 0x590 = 0x31

  4. 在符号表中查找在字符串的偏移为 0x31 的项

3100 0000 0000 0000 0000 0000 1200 0000

该项为符号表的第 3 项

  1. 在导入表中查找符号表索引为 3 的项

903f 0000 1603 0000

结论 :函数名 malloc 导入地址 0x3f90

解析完毕,理论可行。

Android Native Hook技术你知道多少?
字节跳动开源 Android PLT hook 方案 bhook

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

推荐阅读更多精彩内容

  • Hook翻译过来就是“钩子”的意思,是指截获进程对某个API函数的调用,使得API的执行流程转向到我们自己实现的代...
    修塔寻千里阅读 987评论 0 1
  • 博客已迁移至:https://leeon7.github.io Hook Hook在Android系统的应用根据框...
    leeon7阅读 10,808评论 1 8
  • 0x0 零 Hook是我们常用的一种技术手段,在开发中,也经常看到Self-Hook等操作,而在逆向分析中,Hoo...
    老江_阅读 122,212评论 1 7
  • Preload简介Linux常见Hook技术对比函数调用类型内核模块Hook应用层Inline HookGot表应...
    超哥__阅读 16,279评论 1 3
  • 一、Hook概述 HOOK中文译为挂钩或钩子。在iOS逆向中是指改变程序运行流程的一种技术。通过hook可以让别人...
    HotPotCat阅读 4,825评论 1 12