Android 逆向工程 —— Android 原生程序逆向 2

APK 下载
可调试的 APK
可动态调试的 APK

这次的 APP 是 2015 年移动安全挑战赛(看雪&阿里主办)中的第二题,网上已经有很多关于这个 APP 的破解方法,但是我跟着这些教程里的步骤来做,有些步骤总是不能成功,有些步骤也是半知半解,所以想把这个过程详细地记录下来

1. 逆向 APK####

首先用 jadx 大致看看程序的结构和流程

Android 逆向工程 —— Android 原生程序逆向 2_第1张图片

程序由 4 个类组成,大致浏览之后将注意力集中在 MainActivity 上,这个 Activity 有一个 native 方法,securityCheck,并且通过该方法来判断输入是否正确,我们要做的就是逆向这个方法来找到正确的输入

2. 静态分析####

打开 IDA,载入对应的 so 文件,找到 Java_com_yaotong_crackme_MainActivity_securityCheck 函数

Android 逆向工程 —— Android 原生程序逆向 2_第2张图片

导入 JNINativeMethod 和 JNINativeInterface 结构,进行简单处理后按下 F5

Android 逆向工程 —— Android 原生程序逆向 2_第3张图片

留意到影响函数返回值的实际上在最后的 while(1) 循环中,在该循环中将 v5 和 v7 的值进行比较,如果不相等就跳出循环返回 0 (即 false),而 v7 的值是 v6 存放的地址中的值,查看 v6 存放的地址处的值

看到一个很像答案的字符串 “Wojiushidanan”,然而试过之后发现并不是。这就说明前面乱七八糟的代码对这个字符串做了一定的处理,而具体是怎么处理的看起来太复杂了,于是来试试动态分析

3. 动态分析####

要用 IDA 对某个 APP 进行动态分析的前提是要有一台 root 过的手机,我之前用的华为 Mate 7 是 Android 6.0 的系统,root 起来特别麻烦,root 之后调试 APP 的效果也不太好,推荐使用低版本的 Android。模拟器好像也是不行的,我试了好几个,一运行就闪退,可能是程序对运行的环境也有检测,也可能是架构问题。反正最好是用一部装有低版本 Android 系统而且已 root 的真机

在有了满足条件的手机以后,将 IDA 安装目录下的 dbgsrv 目录下的 android_server 拷贝到手机上,拷贝的方法有很多,用 QQ 直接传也可以,用 adb push 也可以,只要能找到存储路径就行。接着用 adb shell 进入系统的 shell,然后在 root 权限下用 chmod 755 命令将 android_server 修改为可运行,修改好后运行 android_server,如果运行成功会显示:

说明现在 android_server 在手机的 23946 端口监听

现在要做的是把手机的 23946 端口映射到电脑上,用 adb forward tcp:23946 tcp:23946 就可以把手机的 23946 端口映射到电脑的 23946 端口

接下来在手机上运行该 APP,然后尝试用 IDA 进行连接,在 Debugger 选项卡中选择 Attach to,找到这个 APP,点击 OK 后发现程序闪退了,那就说明在程序中进行了判断,不允许动态调试

一般的反调试原理是这样的:IDA 使用 android_server 在 root 环境下注入到被调试的进程中,其用的技术是 Linux 中的 ptrace。在 Android 中如果一个进程被另一个进程 ptrace 之后,在它的 status 文件中的一个字段 TracePid 就标识了是那个进程 trace 了它自己。因此,只要在程序运行的过程中循环检测进程中的 TracePid 标识就可以知道程序是否被调试。需要注意的是,这种方法不仅可以用在程序启动的时候,在程序正常流程中间随机插入这样的检测代码(暗桩),往往可以给调试带来更大的难度。

再回过来看这个程序,这个程序是一开始运行就退出了调试界面,说明这个检测的执行时机比较早,已知的比较早运行的两个函数是 .init_array 和 JNI_onload,.init_array 是一个 so 最先加载的段信息,时机最早,一般的 so 解密操作都是在这里做的;而 JNI_onload 是在 so 被 System.loadLibrary 加载后紧接着调用的,时机早于 native 方法,但是在 .init_array 方法之后

先试试是不是在 JNI_onload 中进行的反调试检测

  1. 首先看看 AndroidManifest.xml 里面有没有添加 android:debuggable="true",发现没有,把它加到 application 标签下,最后重新打包签名成 APK 再安装到手机上
  2. 用 am 以调试的方式启动 MainActivity,命令如下:
    am start -D -n com.yaotong.crackme/.MainActivity-D 的意思是以调试的方式启动,具体用法可参见 Android AM 命令及使用
    使用 adb jdwp 命令可以看到当前可被调试的程序的 pid,如果该命令没有输出说明第一步出错了
  3. 用 IDA Attach 上调试方式启动的程序,在此之前要修改 Debug Options 修改为:


    Android 逆向工程 —— Android 原生程序逆向 2_第4张图片

    不在 library 加载之前挂起那 library 执行后程序就退出啦

  4. 按 F9 让程序跑起来,然后用 jdb 连接,具体命令为:jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700
    这里的 port=8700 是在 DDMS 中看到的(好像要打开 DDMS 才能让 jdb 命令生效)
  5. 在静态分析 so 文件中查看 libcrack.so 中 JNI_onload 函数的偏移


    Android 逆向工程 —— Android 原生程序逆向 2_第5张图片

    偏移是 1B9C

  6. 在动态调试中按下 Ctrl + S 查看段信息


    Android 逆向工程 —— Android 原生程序逆向 2_第6张图片

    看到带有 X 属性的 libcrackme.so (至于为什么要找带有 X 属性的 so,我个人理解是只有这个 so 才是会执行的)的起始地址是 7651D000,加上 1B9C 就是 7651EB9C

  7. 按下 G 跳转到 7651EB9C,然后按下 F2 下个断点


    Android 逆向工程 —— Android 原生程序逆向 2_第7张图片
  8. 按下 F9,让程序跑起来,程序没有闪退,说明没有在 .init_array 做反调试检测
  9. 接下来单步一步步往下走,看看是哪里让程序退出的。在单步往下走的过程中,最好在每个跳转指令的地方下个断点,防止程序退出以后又要重新定位退出点
  10. 试了几次之后,发现跑到 BLX R7 的时候,R7 存放是地址是 pthread_create 的地址,进一步分析发现,这里新建线程的目的就是循环检测程序是否在被调试

  11. 记下这行指令的地址,再减去 libcrackme.so 的起始地址,在 WinHex 中定位到该语句,将这部分十六进制的字节码修改为 NOP,即 00 F0 20 E3,然后保存修改、重新打包 APK 并签名,再安装到手机上运行
  12. APP 成功运行后,用 IDA 附加到该进程上
  13. 在静态的 libcrackme.so 中定位到 Java_com_yaotong_crackme_MainActivity_securityCheck 的地址,加上 libcrackme.so 的起始地址就得到了该函数在进程中的地址


    Android 逆向工程 —— Android 原生程序逆向 2_第8张图片
  14. 随便输入一个注册码,然后运行程序,在 IDA 中跳转到
    Java_com_yaotong_crackme_MainActivity_securityCheck,进行单步步过


    Android 逆向工程 —— Android 原生程序逆向 2_第9张图片
  15. 运行到下图时
    Android 逆向工程 —— Android 原生程序逆向 2_第10张图片

    发现,程序出现了分支,在 R1 和 R3 不相等的时候,执行 MOV R1, #0,然后接着执行 MOV R0, R1,这就说明把返回值(R0)置成了 false。此时 R1 和 R3 一个存放的是我们的输入的第一个字符的 ASCII 码,另一个存放的就是正确的注册码的字符的 ASCII 码。而 R1 和 R3 是通过 LDRB R3, [R2]LDRB R1, [R0] 赋值的,查看 R0 和 R2,刚好一个是输入,一个是正确的注册码,如下:
    Android 逆向工程 —— Android 原生程序逆向 2_第11张图片

最后推荐一个ARM 转机器码的网站

参考文档:
深入理解 JNI
IDA 调试 Android native(Crackme)
Android 逆向之动态调试总结
Android AM 命令及使用

你可能感兴趣的:(Android 逆向工程 —— Android 原生程序逆向 2)