观前提示:
本文章仅供学习交流,切勿用于非法通途,如有侵犯贵司请及时联系删除
样本:aHR0cHM6Ly9wYW4uYmFpZHUuY29tL3MvMVVTYXk1S2pPUkdfQy1NWjhjWWdLUnc/cHdkPWxpbm4=
0x1 脱壳
网上冲浪的时候看到一个CrackMe样本 拿下来把玩把玩
界面很简单 只需要输入正确的Flag即可
将APK拖入JADX中 可以发现是360加固
那就上FRIDA-DEXDUMP
脚本脱个壳先
不出意外 就出意外了
一运行FRIDA-DEXDUMP
样本App马上就崩了 排除了其他问题 那么就是App有Frida反调
这里我尝试使用葫芦娃大佬魔改过的Frida来测试
果然用了魔改的Frida 脱壳都顺畅了
把脱下来的dex拉进jadx
可以看到 flag并非在java层进行校验 还得到native-lib.so
去分析
直接解压APK
能看到只有一个so文件 盲猜frida的反调也是在里面的 待会做个验证
0x2 Frida反调
用大姐姐打开native-lib.so
先看导出表
看到.datadiv_decode
巴拉巴拉的 ollvm没跑了
因为frida反调的代码一般较早加载 所以直接进入.init_proc
看
sub_10E0
这里创建了一个线程
继续进入sub_E80
手动还原字符串
function get_str(ptr) { var so_addr = Module.findBaseAddress("libnative-lib.so"); console.log(hexdump(so_addr.add(ptr))) }
就能看得出来就是在sub_E80
进行的frida字段检测 如果有问题 就kill
Pass的方法多种多样 可以hook住strstr
sscanf
甚至可以不让它启动这个线程
0x3 寻找Flag
从导出表没有找到check
那猜是动态注册的
老规矩 用lasting-yang大佬的hook_RegisterNatives
hook到一个动态注册 就是我们需要的check
方法
[RegisterNatives] java_class: com.kanxue.reflectiontest.MainActivity name: check sig: (Ljava/lang/Object;)Z fnPtr: 0xcd8344c9 fnOffset: 0x14c9 callee: 0xea4c7ba1 libart.so!_ZN3art8CheckJNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi+0x1e0
上大姐姐跳转0x14c9
这里我已经将字符串还原备注好了
从伪代码上可以看到 拿到我们输入的flag后 先进行长度判断 不为20则返回0
接着往下看 下面又动态注册了一次
在strcmp(s1, aSyvM)
处
aSyvM
对应的字符是kanxue
所以 字符串里面应该包含kanxue
随便输入kanxue12345678901234
果然 事情不会那么简单 前面看到check
又被动态注册了一次 所以继续看RegisterNatives
[RegisterNatives] java_class: com.kanxue.reflectiontest.MainActivity name: check sig: (Ljava/lang/Object;)Z fnPtr: 0xcd8344c9 fnOffset: 0x14c9 callee: 0xea4c7ba1 libart.so!_ZN3art8CheckJNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi+0x1e0 [RegisterNatives] java_class: com.kanxue.reflectiontest.MainActivity name: check sig: (Ljava/lang/Object;)Z fnPtr: 0xcd834235 fnOffset: 0x1235 callee: 0xea4c7ba1 libart.so!_ZN3art8CheckJNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi+0x1e0 [RegisterNatives] java_class: com.kanxue.reflectiontest.MainActivity name: check sig: (Ljava/lang/Object;)Z fnPtr: 0xcd834149 fnOffset: 0x1149 callee: 0xea4c7ba1 libart.so!_ZN3art8CheckJNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi+0x1e0
这里居然在0x14c9
之后又注册了一次0x1235
最后又注册了0x1149
且名字同样是check
在判断strcmp(s1, aSyvM)
存在后继续往下走 然后取了输入flag的后14位作为参数继续call前面注册的
sub_1234
的方法
跳转到0x1235
这里的代码逻辑几乎和前面的一致
其中aFSU2
对应training
跳转到0x1149
这里代码逻辑短了许多 也没有再去注册方法了
其中byte_5096
对应course
判断取反为真则返回1 也就是验证成功
一共动态注册了三次分别检测了kanxue
training
course
所以Flag即为kanxuetrainingcourse
0x4流程梳理
- 输入
kanxuetrainingcourse
点击验证 - 判断长度是否为20
- 判断是否包含
kanxue
- 截取字符串
trainingcourse
再次调用check
- 判断长度是否为14
- 判断是否包含
training
- 截取字符串
course
再次调用check
- 判断长度是否为6
- 判断是否包含
course
- 验证成功返回1
感谢各位大佬观看
感谢大佬们的文章分享
如有错误 还请海涵
共同进步
[完]