因为今天早上上课的时候才做出来,在此复现一下,顺便记录一下第一次反调试

前记

本来是练习动态调试才开始做这个题,最后发现并不简单,还有反调试,经过艰苦卓绝的努力,查了多方WP后才发现我根本没在SecurityCheck函数里插断点,所以才跪了那么久

开始

工具:

  • IDA 7.0
  • jadx
  • Google
  • 一台root过的真机

这时将APK拖进jadx中,
p1

箭头所指就是重点,加载的so与关键函数

首先启动IDA的连接模式

$ adb devices
确定adb连接到了设备
$ adb push android_server /data/local/tmp
这个android_server在IDA根目录的dbgsrv文件夹里

$ adb shell
$ su
# cd data/local/tmp
# chmod 755 android_server
# ./android_server

然后在本机终端中

adb forward tcp:23946 tcp:23946

做端口转发,这时IDA就可以远程调试我的手机了

动态调试

经过这次动态调试的练习才发现有很多细节在其他人的文章里都没有涉及,例如

  1. jdb connect之后在IDA没有F9之前都是没有连接上的;
  2. jdb 在AndroidManifest.xml没有加android:debuggable="true"的时候是无法连接的,显示“致命错误:无法附加到目标VM”
  3. 需要在SecurityCheck加断点;
  4. 在jdb之后再attach进程,所有的so均已加载完毕,JNIOnload就进不去了;
  5. 输入问题;

为了解决进入调试模式的问题,这里首先需要apktool将apk逆一下,
p2

在application标签下加入android:debuggable="true"之后在build成apk,才能进入调试模式

下一步IDA连接:打开IDA,Debugger选项卡 -> Attach -> Remote Android Debugger(真机调试)Hostname填入localhost,端口不变(23946)

在连接成功后,会弹出Choose process to attach to,这时搜索crackme,会出现一个进程
p3

选中这个就进入了入口
p4

这时需要jdb连接使app进入调试模式,在这之前,需要打开DDMS,因为AS改版了,无法再在Android Studio中直接打开DDMS,这里我将monitor.bat添加到环境变量里了,直接在命令行输入monitor打开DDMS

哦吼这里有个问题了
p5

进程变问号了,这里还是在am之前打开吧_(:з)∠)_

重新来一遍
p6

IDA重新连接(无图)

jdb -connect "com.sun.jdi.SocketAttach:hostname=localhost,port=8700"

p7

输入之后进入等待,这时需要再配置IDA然后F9执行

配置:Debugger选项卡 -> Debugger option

p8

勾选Suspend on thread start/exit与library load/unload

意思是在线程开始或退出的时候暂停,在库加载或退出的时候暂停。

之后F9执行
这时会停留在linker处,这个linker是载入so的一个过程,这时搜索libcrackme是没有的,是因为还没有载入,但是这时app已经进入调试模式了,打开DDMS看一下会看到那个虫子已经变绿了

p9

jdb也连接上了
p10

按照一般的思路,F9就会一直执行下去,直到正常的页面出现,但是这时F9的话,会导致程序直接退出,Attach的进程也断掉了,可以推断出这个题是有反调试的

而看那些反调试的文章里,一般简单的反调试都是在JNIOnload加一下骚操作,比方说令其一个进程查有没有调试PID,有的话直接退出程序,这个题就是这样。

然后接着执行到下一次linker
这时Ctrl + S搜索一下libcrackme,看到内存中有三个段,起始地址为D781A000
p11

这时新打开一个IDA,将libcrackme.so拖进去,找JNIOnload的入口,这里是相对地址
p12

可以看到00001B9C

D781A000 + 00001B9C = D781BB9C

在IDA中 按G键,出现JUMP到指定地址的输入框,输入上面得到的地址即可(因为每次内存载入so的位置都不同,每次libcrackme在内存中的地址可能都不相同,但是Jnionload在so中的相对地址是确定的)

得到的这个JNIOnload在内存中的入口
p13

然后F2加断点,F9运行到断点处,F8单步调试,看看是哪一步退出的。
p14

嗯,就是这一句了,将光标放在R7处会看到,调用了pthread_create,看来是创建新线程,虽然看不到但还是要点进去假装看看

这时WP中告诉我们要做的就是把这个函数或者把BLX R7给NOP掉,在打开so文件的IDA里,点击地址
p15

再进入Hex选项卡
可以看到,这行命令对应的16进制
p16

这时用010 Editor打开apktool逆过的文件夹下的so文件,搜索37 FF 2F E1

改成00 00 00 00 再重新打包(apktool + 签名)即可,将原来的app卸载掉再安装
p17

然后开始重新调试
最后一次采用一点不一样的,先将so加载进IDA,选择SecurityCheck在第一句加断点

p18

再选择Debugger选项卡 -> select debugger
p19

然后再Debugger选项卡 -> process options

hostname选择localhost
p20

再Attach to process
p21

完成打开jdb连接,进入调试模式

在一顿F9与输入之后进入到这里
p22

就是SecurityCheck部分了
直到这里
p23

发现R0是我输入的内容,CMP比较后跳转,那么R3,即上面的R2中的内容应该就是密码了,分号后面也写出来了

aiyou,bucuoo

输入之后真的可以正确跳转,即可认证。

总结

调试模式

进入调试模式需要

monitor.bat
adb shell am start -D -n com.yaotong.crackme/.MainActivity
jdb -connect "com.sun.jdi.SocketAttach:hostname=localhost,port=8600"

而且IDA进入的时间也很关键,如果是jdb之后进入的话,JNIOnload已经执行完了,这时就无法再对JNIOnload进行调试了,所以如果是对JniOnload调试,需要在jdb前进入IDA的调试模式

apktool

这个工具在这个过程中真的是举足轻重,因为无法直接修改解压apk过后的AndroidManifest.xml,所以需要apktool反编译之后再修改so或者Manifest文件

apktool牛逼

忘了

最后这里两种动态调试的方法都用到了,这可海星