65.9K
CodeProject 正在变化。 阅读更多。
Home

通过 Hooking 技术提高 Android 应用程序的安全性:第 2 部分

2016 年 5 月 6 日

CPOL

6分钟阅读

viewsIcon

9935

通过 Hooking 技术提高 Android 应用程序的安全性:第 2 部分

Intel® Developer Zone 提供用于跨平台应用开发、平台和技术信息、代码示例以及专家经验的工具和操作指南,帮助开发者创新并取得成功。加入我们的社区,获取 Android物联网Intel® RealSense™ 技术Windows 的相关信息,下载工具、访问开发套件、与志同道合的开发者交流想法,并参与黑客马拉松、竞赛、巡展和本地活动。

目录

libtest_PIC.so 中 PIC 代码的研究

如果对象以 PIC 模式编译,则重定位的实现方式有所不同。通过观察如图 17 所示的 libtest_PIC.so 的段信息,printf() 重定位信息位于两个重定位段:.rel.dyn 和 .rel.plt。使用了两种新的重定位类型 R_386_GLOB_DAT 和 R_386_JMP_SLOT,并且应该用这些偏移地址填充替换函数的绝对 32 位地址。

图 1:libtest_PIC.so 的重定位段

图 18 展示了以非 PIC 模式编译的 libtest2() 函数的汇编代码。在图 17 的 .rel.dyn 和 .rel.plt 重定位段中标记为红色的 printf() 的入口地址被指定。

图 2:libtest2() 的反汇编代码,使用 -PIC 参数编译

图 3:“printf("libtest2: 1st call to the original printf()\n");”的工作流程

图 4:“global_printf2("libtest2: global_printf2()\n");”的工作流程

图 5:“local_printf("libtest2: local_printf()\n");”的工作流程

从图 19-21 可以看出,当使用 -PIC 参数生成的动态库进行工作时,libtest2() 中的代码将跳转到偏移地址 0x1fe0、0x2010 和 0x2000 处放置的地址,这些是 printf() 的入口。

Hook 解决方案

如果 hook 模块想要拦截对 printf() 的调用并将其重定向到另一个函数,它应该在链接器将动态库加载到内存后,将重定向函数的地址写入重定位段中定义的符号“printf”的偏移地址。

为了将对 printf() 函数的调用替换为对重定向的 hooked_printf() 函数的调用,如图 22 的软件流程图所示,应该在 dlopen() 和 libtest() 调用之间实现一个 hook 函数。hook 函数首先从名为 .rel.dyn 的重定位段获取符号 printf 的偏移地址,即 0x1fe0。然后 hook 函数将 hooked_printf() 函数的绝对地址写入偏移地址。之后,当 libtest2() 中的代码调用 printf() 时,它将进入 hooked_printf()。

图 6:hook 函数拦截对 printf() 的调用并将调用重定向到 hooked_printf() 的示例。原始函数调用过程在图 21 中描述。

为了考虑前面列出的所有可能情况,hook 函数的整个流程图如图 23 所示。main() 函数中的更改部分如图 24 所示。

图 7:ELF hook 模块的流程图

图 8:hooking 后 main() 中的代码

程序的输出如图 25 所示,可以看到,当执行 libtest1()/libtest2() 的第一次调用时,函数内部调用了 printf()。再次调用这两个函数后,在 hook 函数执行之后,对 printf() 的调用被重定向到了 hooked_printf() 函数。hooked_printf() 函数将在正常打印的字符串末尾附加字符串“is HOOKED”。图 26 显示了 hooking 后的程序运行流程,与图 8 中显示的原始流程相比,hooked_printf() 已被注入到 libtest1() 和 libtest2() 中。

图 9:测试程序的输出,printf() 已被 hook

图 10:hooking 后测试项目的运行流程

案例研究——Android 中一种基于 Hook 的保护方案

基于前面几节对 hooking 技术的研究,我们开发了一个插件来帮助 Android 应用程序开发者提高其应用程序的安全性。开发者只需将一个 Android 原生库添加到他们的项目中,并在启动时添加一行 Java 代码来加载此原生库。然后,该库会将一些保护代码注入到应用程序中的其他第三方库。保护代码将帮助加密本地文件的输入/输出流,并绕过 __android_log_print() 函数,以避免通过 Logcat 打印调试信息而导致用户隐私泄露。

为了验证保护插件的有效性,我们编写了一个 Android 应用程序来模拟包含第三方库的应用程序场景。在测试应用程序中,第三方库执行两项操作:

  1. 当外部 Java 指令调用库中的函数时,它会通过调用 __android_log_print() 打印一些信息。
  2. 在库中,代码创建一个文件(/sdcard/data.dat)将数据保存在本地存储中而不进行加密,然后将其读回并在屏幕上打印。此操作旨在模拟应用程序尝试将一些敏感信息保存在本地文件系统中。

图 27-30 比较了在 hooking 前后,测试程序截图、Logcat 输出以及设备本地文件系统中保存的文件内容。

图 11:Android* 平台为 Teclast X89HD,Android 4.2.2

图 12:App 输出 - hooking 后无变化

图 13:Logcat 输出 - hooking 后为空

图 14:hooking 后,位于 /sdcard 的本地文件 'data.dat' 已加密

如图所示,hooking 后程序的运行流程与没有 hooking 时的流程相同。然而,Logcat 无法捕获原生库在 hooking 后的任何输出。此外,本地文件的内容不再以明文格式存储。

该插件帮助测试应用程序 提高安全性,防止恶意攻击者通过 Logcat 收集信息,以及防止对本地文件系统的离线攻击。

结论

Hooking 技术可以在许多开发场景中使用,为 Android 应用程序提供无缝的安全保护。基于 Hook 的保护方案不仅可以在 Android 上使用,还可以扩展到其他操作系统,如 Windows*、嵌入式 Linux 或其他专为物联网 (IoT) 设备设计的操作系统。它可以显著缩短开发周期和维护成本。开发者可以开发自己的基于 Hook 的安全方案,或者使用市场上现有的专业第三方安全解决方案。

参考文献

共享 ELF 库中的函数重定向
Apriorit Inc, Anthony Shoumikhin, 2013 年 7 月 25 日
https://codeproject.org.cn/Articles/70302/Redirecting-functions-in-shared-ELF-libraries

x86 API Hooking 揭秘
Jurriaan Bremer
http://jbremer.org/x86-api-hooking-demystified/

Android 开发者指南
https://developer.android.com.cn/index.html

Android 开源项目
https://aosp.org.cn/

© . All rights reserved.