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文件,其代码如下:
点击图片以查看大图

图片名称:	Image 1.png
查看次数:	0
文件大小:	83.0 KB
文件 ID :	107319

其中doThings()方法将对应Java层中的声明的native daThings(),而arc4random()是系统上的仿生标准库(bionic standard library),生成随机数
3.编写Android.mk
名称:  Image 2.png
查看次数: 0
文件大小:  49.6 KB

用于编译生成targetlib库文件
4.Java层编写
名称:  Image 3.png
查看次数: 0
文件大小:  99.4 KB

5.编译、调试运行、安装程序
在jni目录下,执行ndk-build进行库文件的编译
名称:  Image 4.png
查看次数: 0
文件大小:  28.9 KB

然后在项目目录下,执行ant debug进行项目的调试运行,生成apk
adb install ./bin/Mainactivity-debug.apk  //安装apk
程序打印结果如下:
名称:  Image 5.png
查看次数: 0
文件大小:  85.0 KB

6.查看库文件中的exported symbols
nm -aDC –defined-only libs/armeabi-v7a/libtargetLib.so //显示库文件所暴露的符号
名称:  Image 6.png
查看次数: 0
文件大小:  60.3 KB

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

这样可以查看库文件所调用其他库的符号,可以看到库文件调用了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
名称:  Image 8.png
查看次数: 0
文件大小:  43.5 KB

3.编写C++程序
在项目目录下,创建jni目录并新建***.cy.cpp文件,以最后编译生成.cy.so文件才能被Substrate框架所链接到。代码如下:
名称:  Image 9.png
查看次数: 0
文件大小:  53.2 KB

通过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
修改后,打印结果如下:
名称:  Image 10.png
查看次数: 0
文件大小:  89.3 KB

hook库文件内部暴露方法
编写Substrate模块来hook库文件中暴露的内部方法,进行修改返回值操作
可在上边C++源文件中添加下边代码,进行hook操作
名称:  Image 11.png
查看次数: 0
文件大小:  105.6 KB

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

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到该方法,结果输出如下:
名称:  Image 13.png
查看次数: 0
文件大小:  64.9 KB

2.静态分析定位non-exported方法
使用IDA pro工具打开libtargetLib.so库文件,可以定位到其中getAge()方法对应的汇编程序如下:
名称:  Image 14.png
查看次数: 0
文件大小:  45.7 KB

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

其中之所以在基地址上加上0xE48+1,是因为这里在运行在thumb体系下,+1使地址为奇数对应thumb
5.hook结果如下:
名称:  Image 17.png
查看次数: 0
文件大小:  29.2 KB

 

转载自:http://bbs.pediy.com/showthread.php?p=1446330    原文作者:KX头狼