SO逆向之IDA过CrackMe反调试

篇幅有限

完整内容及源码关注公众号:ReverseCode,发送

样本

来自阿里聚安全的Crackme,自毁程序密码_1.0原版.apk

image-20211028131854661

随机输入密码后报错验证码校验失败,通过jadx-1.2.0搜索后发现调用了校验逻辑在SO层的securityCheck

image-20211028132440308

SO分析

解压该apk后IDA打开自毁程序密码_1.0原版\lib\armeabi\libcrackme.so,搜索java找到securityCheck导出函数

image-20211028132706851

通过F5将汇编转成伪C代码,分析大致逻辑后点击v3通过JNIEnv*还原指令

image-20211028132828843

image-20211028133142558

或者通过Y修改参数类型

int __fastcall Java_com_yaotong_crackme_MainActivity_securityCheck(JNIEnv *a1, jobject a2, jstring a3)

还原后使用/添加注释,n修改别名为易读变量,输入的字符串和密码逐位对比,

image-20211028133850230

image-20211028134025191

动态调试

将IDA中的D:\IDA 7.0\dbgsrv\android_server拷贝到真机/data/local/tmp

1
2
3
4
5
6
adb push android_server /data/local/tmp
cd /data/local/tmp/
mv android_server as7.0
chmod 777 as7.0
./as7.0 在23946端口启动
adb forward tcp:23946 tcp:23946 端口转发

新建IDA的Instance,打开该app后以attach附加调试

image-20211028140819383

image-20211028140843111

image-20211028140859678

ctrl+s找到需要调试的so,ctrl+f搜索so名,找到第一个带x权限的so文件双击进入

image-20211028141506740

函数在内存中绝对地址=so文件基地址+函数地址偏移量,即EF0DD000+11A8=EF0DE1A8

image-20211028150803420

image-20211028150856645

g跳转到该函数的内存地址中EF0DE1A8,进入该函数中右键加上断点,F8单步不进入函数调试,F7单步进入函数调试

image-20211028151440946

image-20211028151848042

F8单步调试或者点击左上角绿色三角按钮,闪退并报错FFFFFFFF,目测加了反调试。

image-20211028152841350

一般检测是否可调试的技术方案是通过linux系统的ptrace实现,当当应用被调试时应用内存里的TracerPid字段就不为0,只要是不为0的时候,就会直接的退出程序,达到反调试的目的。端点调试报错FFFFFFFF后该TracerPid变成了0。

image-20211028152236652

反反调试

附加调试

System.loadLibrary()加载so文件流程

  1. 先读取so文件的.init_array段
  2. 再执行JNI_OnLoad函数
  3. JNI_ONLoad是.so文件的初始函数
  4. 然后调用具体的native方法

程序的so文件在加载阶段会先执行JNI_OnLoad,之后就不再执行,在程序的so文件加载阶段才能给JNI_OnLoad打断点调试即可,首先需要将app回编译添加可调试权限。

修改回编译打包

1
2
3
4
5
apktool b 青青草视频/   回编译
cd 青青草视频/dist 编译完成的apk
keytool -genkey -alias abc.keystore -keyalg RSA -validity 20000 -keystore abc.keystore
jarsigner -verbose -keystore abc.keystore -signedjar qqc2_signed.apk 青青草视频.apk abc.keystore 重签名
adb install -r qqc2_signed.apk

或者配置Android Killer

image-20211028185542576

在application中添加**android:debuggable=”true”**,保存后编译生成新apk,卸载原apk后重新安装

image-20211028185825928

1
2
3
4
5
adb shell
cd /data/local/tmp/
./as7.0 启动安卓server,在ida目录下
adb forward tcp:23946 tcp:23946
adb shell am start -D -n com.yaotong.crackme/.MainActivity 以debug方式启动

image-20211027105256522

image-20211027153817469

image-20211028190325441

1
2
3
adb shell ps | findstr com.yaotong.crackme  找到进程id为14383
u0_a72 14383 589 1619304 37312 futex_wait 00f263141c S com.yaotong.crackme
adb forward tcp:8700 jdwp:14383 端口转发

Debugger-Debugger options 点击左上角启动

image-20211027155851356

1
2
3
4
jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700  转发8700端口,继续运行程序
设置未捕获的java.lang.Throwable
设置延迟的未捕获的java.lang.Throwable
正在初始化jdb...

寻找JNI_Onload

内存计算

点击左上角运行,直到ctrl+s找到so被加载的时候,找到crackme.so的第一个可执行时机,双击进入找到该so的偏移量

image-20211028191814413

通过静态分析的JNI_OnLoad地址,相加得到JNI_Onload的内存地址=EF09AB9C

image-20211028192039413

image-20211028192144366

g跳转到JNI_OnLoad地址EF09AB9C,F2打断点,F8单步执行,鼠标一到寄存器R值可以显示字符串的值

image-20211028192238589

IDA搜索

Modules中搜索crack,进入so后搜索JNI找到EF09AB9C

image-20211028193250882

image-20211028193329058

SO修复

image-20211028193555880

通过下一步反复调试发现在图中断点出BLX R7的位置跳出报错FFFFFFFF,期间ctrl+s可以不断尝试看libcrackme.so是否出现,此处应该就是就是反调试检测位置了

image-20211028194259087

双击或者右侧打开R7寄存器,出现pthread_create新建一个线程不停的检测TracerPid这个字段是否不为0, 不为0,就立即退出程序。

image-20211028194338042

我们可以通过修改R7为00 00 00 00直接nop掉该指令,因为删除的话so文件有固定格式,多段内容的偏移值容易发生错乱。

在静态调试页面中找到BLX R7位置,进入Hex View-1,修改指令

image-20211028195314108

image-20211028195020110

image-20211028195044816

image-20211028195131350

或者ultraedit直接修改保存即可,将修改后的so替换原Android Killer中的so,并重新签名打包安装。

image-20211028195315218

破解密码

1
2
./as7.0
adb forward tcp:23946 tcp:23946

启动好该app后,获取该app的进程id并进程转发

1
2
3
adb shell ps | findstr com.yaotong.crackme
adb forward tcp:8700 jdwp:8741
jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700

image-20211028195809434

image-20211028202136860

image-20211028195904582

进入断点后,在Modules中搜索crack,直接找到securityCheck函数并g定位到该函数的具体地址EF0DF1A8

image-20211028202239022

image-20211028202400928

结合静态分析,找到判断的位置并打上断点,这个R3相比就是真实的密码了

image-20211028202625267

点击左上角启动,输入onejane确认后R0就是我们输入的密码

image-20211028203134231

F5进入C伪代码后鼠标悬浮查看v6 = off_EF0E428C密码为aiyou,bucuoo

image-20211028203231959

重新输入密码完成So层的逆向。

image-20211028203444152

总结

利用Android Killer回编译,IDA逆向SO层转汇编为伪C代码进行动静态分析调试,SO修复反反调试等手段完成该Crackme的逆向。

01:17

文章作者: J
文章链接: http://onejane.github.io/2021/10/28/SO逆向之IDA过CrackMe反调试/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 万物皆可逆向
支付宝打赏
微信打赏