Android逆向之动态调试so(上)

时间:2024-03-19 14:46:45

Android逆向系列之动态调试1–入门篇 
Android逆向系列之动态调试2–Smali注入
Android逆向系列之动态调试3–Eclipse调试apk
Android逆向系列之动态调试4–IDA调试dex
Android逆向系列之动态调试5–代码注入(JDB调试)
Android逆向系列之动态调试6–gdb调试
Android逆向系列之动态调试7–IDA调试so文件(上)
Android逆向系列之动态调试8–IDA调试so文件(下)

一、前奏
1.demo.apk、IDA6.6以上、adb等工具,具体可参考工具篇
demo.apk的主逻辑代码如下:

Android逆向之动态调试so(上)

2.什么是so文件?

so文件是unix的动态连接库,我们知道Android系统是类linux,所以这里也沿用其动态链接库so,一般用c语言实现,是二进制文件,作用相当于windows下的.dll文件,在Android中调用动态库文件(*.so)都是通过jni的方式。

Android中加载so文件的提供的API: void System.load(String pathName);

Android系统目前支持以下七种不同的CPU架构:ARMv5,ARMv7 (从2010年起),x86 (从2011年起),MIPS (从2012年起),ARMv8,MIPS64和x86_64 (从2014年起),每一种都关联着一个相应的ABI。我们将apk解压后,在/lib目录下可以看到不同cpu架构的文件夹,其中的so文件是功能相同的,只是实现的指令等细节不同,主流是ARM架构,所以这里我们也是重点分析arm下的so文件。

3.分析so文件

一般逆向so文件,光动态分析仍旧是不够的,一般我们需要先静态简单分析一下,再结合动态调试,这样才能事半功倍

我们直接将libencrypt.so文件拖进IDA,如下图:
Android逆向之动态调试so(上)

这里我们找到 Java_类名_方法名 的函数,重点分析这个函数(当然有时候并没有java开头,这时可以借助jd-gui等工具找出函数名)

我们简单分析下arm代码,BLX调用函数,然后有一个判断跳转,再使用BL调用 get_encrypt_str函数,然后有一常量字符串,再调用strcmp进行比较
(这里为了演示,相对逻辑简单,当然静态分析就可以了,但这并不是目的)

强大的F5,如果ARM指令看着费劲,可以使用F5查看对应的c语言
Shirt+F12快捷键,速度打开so中所有的字符串内容窗口
Android逆向之动态调试so(上)
具体就不分析了C语言你们比我厉害多了。

问题分析:这里我们看一下划线处,是不是觉得有点奇葩。
解决方法:

还原JNI函数方法名,一般JNI函数方法名首先是一个指针加上一个数字,比如v3+676。然后将这个地址作为一个方法指针进行方法调用,并且第一个参数就是指针自己,比如(v3+676)(v3…)。这实际上就是我们在JNI里经常用到的JNIEnv方法。因为Ida并不会自动的对这些方法进行识别,所以当我们对so文件进行调试的时候经常会见到却搞不清楚这个函数究竟在干什么,因为这个函数实在是太抽象了。解决方法非常简单,只需要对JNIEnv指针做一个类型转换即可。
选中a1变量,然后按一下y键,输入:JNIEnv*,确定即可。

二、准备调试
1.调试准备

在IDA目录下的dbgsrv目录下找到android_server,是不是有点眼熟,是的,没错!有点类似gdbserver,操作也是类似,具体可查看上一篇文章;
adb remount
adb push android_server /system/bin
adb shell chmod 755 /system/bin/android_server
adb shell android_server
adb forward tcp:23946 tcp:23946

2.IDA-attach
模拟器里启动要调试的APP
启动IDA,打开debugger->attach->remote Armlinux/andoid debugger
填写hostname为127.0.0.1或localhost(推荐),端口确定为23946或你自定义转发的端口,其他默认,点击确定
弹出Choose process to attach to窗口,找到app的进程名,点击ok,等待分析后即可进入调试界面
Android逆向之动态调试so(上)

问题分析:为什么会断在libc.so中
问题解决:
android系统中libc是c层中最基本的函数库,libc中封装了io、文件、socket等基本系统调用。所有上层的调用都需要经过libc封装层。所以libc.so是最基本的,所以会断在这里,而且我们还需要知道一些常用的系统so,比如linker;这个linker是用于加载so文件的模块,如何在.init_array处下断点;还有一个就是libdvm.so文件,他包含了DVM中所有的底层加载dex的一些方法

3.定位函数
使用快捷键Ctrl+s打开segment窗口,选择so文件,这里可以使用Ctrl+f进行搜索;同时这里需要记下so文件的起始地址(A8924000)
用另一个IDA打开so文件,找到对应函数的便宜位置,在上面的图可以看到偏移为:00000E9C
绝对地址=基址+偏移地址=A8924000+00000E9C=A8924E9C
按下快捷键G,输入A8924E9C即可跳转到正确的函数。然后使用F2或者点击前面的小圆点 下一个断点
Android逆向之动态调试so(上)

问题分析:窗口里有多个so文件怎么办?应该选择哪一个?
问题解决:
其实这里并不是多个so文件,而是so文件对应的不同Segement信息被映射到内存中,包括代码段,数据段等,很明显,代码段会有执行权限的特点,所以我们选择带有X属性的so文件,即是我们想要调试的so文件。
Android逆向之动态调试so(上)

4.调试
按F9或点击绿色三角形按钮运行程序
触发断点:这里是点击程序的按钮,具体视应用不同而不同
接着就是F7/F8调试的常规步骤了!!

参考资料: http://blog.csdn.net/jiangwei0910410003/article/details/51500328

转载自https://blog.csdn.net/nangongyanya/article/details/77992280