篇幅有限
完整内容及源码关注公众号:ReverseCode,发送 冲
样本
来自阿里聚安全的Crackme,自毁程序密码_1.0原版.apk
随机输入密码后报错验证码校验失败
,通过jadx-1.2.0搜索后发现调用了校验逻辑在SO层的securityCheck
中
SO分析
解压该apk后IDA打开自毁程序密码_1.0原版\lib\armeabi\libcrackme.so
,搜索java找到securityCheck
导出函数
通过F5将汇编转成伪C代码,分析大致逻辑后点击v3通过JNIEnv*
还原指令
还原后使用/
添加注释,n
修改别名为易读变量,输入的字符串和密码逐位对比,
动态调试
将IDA中的D:\IDA 7.0\dbgsrv\android_server
拷贝到真机/data/local/tmp
下
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附加调试
ctrl+s
找到需要调试的so,ctrl+f
搜索so名,找到第一个带x权限的so文件双击进入
函数在内存中绝对地址=so文件基地址+函数地址偏移量,即EF0DD000+11A8=EF0DE1A8
g
跳转到该函数的内存地址中EF0DE1A8
,进入该函数中右键加上断点,F8单步不进入函数调试,F7单步进入函数调试
F8单步调试或者点击左上角绿色三角按钮,闪退并报错FFFFFFFF
,目测加了反调试。
一般检测是否可调试的技术方案是通过linux系统的ptrace实现,当当应用被调试时应用内存里的TracerPid字段就不为0,只要是不为0的时候,就会直接的退出程序,达到反调试的目的。端点调试报错FFFFFFFF
后该TracerPid变成了0。
反反调试
附加调试
程序的so文件在加载阶段会先执行JNI_OnLoad
,之后就不再执行,在程序的so文件加载阶段才能给JNI_OnLoad
打断点调试即可,首先需要将app回编译添加可调试权限。
配置Android Killer
在application中添加android:debuggable="true",保存后编译生成新apk,卸载原apk后重新安装
adb shell
cd /data/local/tmp/
./as7.0
adb forward tcp:23946 tcp:23946
adb shell am start -D -n com.yaotong.crackme/.MainActivity 以debug方式启动
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
jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700 继续运行程序
设置未捕获的java.lang.Throwable
设置延迟的未捕获的java.lang.Throwable
正在初始化jdb...
寻找JNI_Onload
内存计算
点击左上角运行,直到ctrl+s
找到so被加载的时候,找到crackme.so的第一个可执行时机,双击进入找到该so的偏移量
通过静态分析的JNI_OnLoad地址,相加得到JNI_Onload的内存地址=EF09AB9C
g
跳转到该地址EF09AB9C
IDA搜索
Modules中搜索crack,进入so后搜索JNI找到EF09AB9C
SO修复
通过反复调试发现在图中断点出BLX R7的位置跳出报错FFFFFFFF
,此处应该就是就是反调试检测位置了
双击或者右侧打开R7寄存器,出现pthread_create
新建一个线程不停的检测TracerPid这个字段是否不为0, 不为0,就立即退出程序。
我们可以通过修改R7为00 00 00 00
直接nop掉该指令,因为删除的话so文件有固定格式,多段内容的偏移值容易发生错乱。
在静态调试页面中找到BLX R7位置,进入Hex View-1,修改指令
将修改后的so替换原Android Killer中的so,并重新签名打包安装。
破解密码
./as7.0
adb forward tcp:23946 tcp:23946
启动好该app后,获取该app的进程id并进程转发
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
进入断点后,在Modules中搜索crack,直接找到securityCheck函数并g
定位到该函数的具体地址EF0DF1A8
结合静态分析,找到判断的位置并打上断点,这个R3相比就是真实的密码了
点击左上角启动,输入onejane
确认后R0就是我们输入的密码
F5进入C伪代码后查看v6 = off_EF0E428C
密码为aiyou,bucuoo
。
重新输入密码完成So层的逆向。
总结
利用Android Killer回编译,IDA逆向SO层转汇编为伪C代码进行动静态分析调试,SO修复反反调试等手段完成该Crackme的逆向。
完整内容见威信公众号:ReverseCode