欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[分享]Hook Android C代码基础总结

[分享]Hook Android C代码基础总结

这几天自己开始深入来学习Cydia Substrate这个框架在Hook Android C上的使用,但一开始对Android native的开发不怎么了解,所以直接通过学习这方面的博文容易碰壁,碰到的问题没有相应的思路来很好解决、实现。便先学习了Android native开发方面的知识,这里给大家推荐一篇Android native的学习博文,讲的很详细:Android 开发 之 JNI入门
下边是我学习Hook Android C的知识总结,希望可以给学习这方面的初学者有些帮助,也希望大牛们可以多多指点。
参考学习的英文博文:Substrate - hooking C on Android
实验apk在附件中
hook Android C代码
  
  创建一个目标apk
  编写目标项目,用于本次实操过程的hook对象
  1.创建项目
  android create project --target android-23 --path targetapp --package com.example.targetapp --activity Mainactivity
  //执行命令,在当前目录下创建Android项目
  

  2.编写C程序
  在项目下创建jni目录,并新建targetlib.c文件,其代码如下:
  

  其中doThings()方法将对应Java层中的声明的native daThings(),而arc4random()是系统上的仿生标准库(bionic standard library),生成随机数
  3.编写Android.mk
  

  用于编译生成targetlib库文件
  4.Java层编写
  

  5.编译、调试运行、安装程序
  在jni目录下,执行ndk-build进行库文件的编译
  

  然后在项目目录下,执行ant debug进行项目的调试运行,生成apk
  adb install ./bin/Mainactivity-debug.apk  //安装apk
  程序打印结果如下:
  

  6.查看库文件中的exported symbols
  nm -aDC --defined-only libs/armeabi-v7a/libtargetLib.so //显示库文件所暴露的符号
  

  忽略其中_的符号,该库文件暴露了下边两个方法
  00000e95 T Java_com_example_targetapp_Mainactivity_doThings
  00000e6d T getAge
  这些暴露出来的方法将可以直接被其他程序或库文件调用
  nm -aDCu libs/armeabi-v7a/libtargetLib.so  //显示库文件中未定义的请求符号
  

  这样可以查看库文件所调用其他库的符号,可以看到库文件调用了arc4random()
  
  创建Substrate模块
  编写Substrate扩展模块来hook上边库文件中的arc4random()方法,修改其返回值,使其返回固定值
  1.创建项目
  android create project --target android-23 --name Hooknative --package com.example.hooknative --path Hooknative --activity Mainactivity
  //创建hook项目
  2.修改AndroidManifest.xml
  声明权限:cydia.permission.SUBSTRATE,设置android:installLocation和android:hasCode
  

  3.编写C++程序
  在项目目录下,创建jni目录并新建***.cy.cpp文件,以最后编译生成.cy.so文件才能被Substrate框架所链接到。代码如下:
  

  通过MSConfig()方法来配置过滤对象,这里是可执行文件,参数2应为文件的绝对路径,再调用MSHookFunction()方法来hook其中的arc4random()方法
  4.编译、调试运行、安装模块
  在jni目录下,执行ndk-build进行库文件的编译
  然后在项目目录下,执行ant debug进行项目的调试运行,生成apk
  adb install ./bin/Hooknative-debug.apk  //安装apk
  然后通过Substrate链接模块,重启系统,或执行下边命令重启zygote
  adb shell setprop ctl.restart zygote
  修改后,打印结果如下:
  

  hook库文件内部暴露方法
  编写Substrate模块来hook库文件中暴露的内部方法,进行修改返回值操作
  可在上边C++源文件中添加下边代码,进行hook操作
  

  这里我们使用lookup_symbol()这个定义的方法来查找getAge()方法在库文件libtargetLib.so在的地址,需要注意的是我们的Substrate模块将会在作为所有进程初始化的孵化器zygote中第一个被加载,这时候库文件libtargetLib.so还没被加载到进程空间,直接查找其暴露的方法是行不通的。这里通过dlopen()方法人为的打开和加载在zygote的内存中的ELF二进制文件,并通过dlsym()方法来找到库文件中的暴露方法。同时Substrate也提供MSGetImageByName()和MSFindSymbol()来实现相同的功能。
  hook结果输出如下:
  

  hook内部non-exported方法
  1.将内部方法getAge()设置为non-exported
  在C++程序中将getAge()设置为static,则方法就不会暴露出来给其他程序直接调用
  通过nm -aDC --defined-only libs/armeabi-v7a/libtargetLib.so将不会打印出:
  00000e6d T getAge
  当然由于doThings()方法要被Java层调用,所以仍是暴露的。由于getAge()设置为static,所以上边的模块将不再hook到该方法,结果输出如下:
  

  2.静态分析定位non-exported方法
  使用IDA pro工具打开libtargetLib.so库文件,可以定位到其中getAge()方法对应的汇编程序如下:
  

  其中的sub_E48就是对于getAge(),由图可得出sub_E48对应的地址为0xE48,但这不是方法getAge()在库文件中的地址,而是基于库文件基地址的偏移量,所以应先找出库文件的基地址,然后加上方法的偏移量便可确定方法的地址。
  3.获取库文件的基地址
  通过将库文件加载到zygote的内存空间,然后通过/proc/self/maps来读取其基地址
  
   
  4.hook non-exported方法
  

  其中之所以在基地址上加上0xE48+1,是因为这里在运行在thumb体系下,+1使地址为奇数对应thumb
  5.hook结果如下:
  

  

上传的附件 Image 1.png
Image 2.png
Image 3.png
Image 4.png
Image 5.png
Image 6.png
Image 7.png
Image 8.png
Image 9.png
Image 10.png
Image 11.png
Image 12.png
Image 13.png
Image 14.png
Image 15.png
Image 16.png
Image 17.png
apk.zip

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功