前言
最近在研究某某app的数据库,发现自己在so层的调试比较薄弱,专门找了看雪的CTF-变形金刚来学习。希望在用ida调试so方面有所突破。
利用国庆期间整理成笔记。技术不成熟或许描述的不够清晰请大伙见谅。
也拜读了几位大佬的文章。
工具准备ida7.0
Transformers.apk
idea
jadx
frida
小米4root手机(android6.0)
app分析目标
为了熟悉该app,先介绍一下大神分析后的结果。
输入错误密码截图
比如输入密码是:12345678,会提示错误信息:Transformers:error
输入正确密码截图
输入密码(长度16个字符)是:fu0kzHp2aqtZAuY6,会提示错误信息:Transformers:flag{android4-9}
静态分析-java
把Transformers.apk拖入jadx
障眼法1:该app设计作者采用了障眼法,很容易欺骗分析人员,让我们认为OnClick的回调处理逻辑在MainActivity中。
障眼法2:在MainActivity的OnCreate中欺骗代码注册OnClick回调。主要原理是利用Activity的onStart事件会晚与OnCreate事件,从而实现在OnStart中注册的OnClick回调覆盖了OnCreate中注册的回调。
Activity基类的onStart才是真正注册OnClick回调的地方
Base64解码图
为了方便理解eq中涉及的魔改的Base64编码,这里先贴上一直Base64解码的草稿图
下图是Base64编码4个字符'{6*的解码草稿图,画的不是很好,主要是方便我自己理解写解码Base64的逻辑代码。
它是用64个可打印字符表示二进制所有数据方法。由于2的6次方等于64,所以可以用每6个位元为一个单元,对应某个可打印字符。我们知道三个字节有24个位元,就可以刚好对应于4个Base64单元,即3个字节需要用4个Base64的可打印字符来表示。
静态分析与动态调试跟踪liboo000oo.so
这里将分3个关键步骤:1:JNI_OnLoad分析动态注册eq对应的函数sub_784,稍后再详细介绍。2:.fini_array部分跟踪,主要是eq函数用到的一下基础数据,比如Base64编码表、RC4加密算法用到的key初始值,之后它会通过一系列异或处理算出真正的密钥key。也稍后再详细介绍。3:eq函数的算法跟踪分析。
这里先列一下分析结果
JNI_onLoad部分==========
eq是由sub_784动态注册
ini_array部分==========
#解码36长度字符串byte_4020:
byte_4020 =650f909c-7217-3647-9331-c82df8b98e98+0x00(结束符)
#解码Base64为的64+1个编码字符byte_4050=
base64Chars = byte_4050 =!:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\';+0x00(结束符)
#app伪装java类的名称byte_40A0:
className_Sign= android/support/v7/app/AppCompiatActivity +0x00(结束符)
sub_784部分============
获取RC4的密钥算法============:
v5=算法01 = 删除(byte_4040中的"-") =650f909c721736479331c82df8b98e98
v4=算法02 =删除byte_4020中的”-“后,特殊运算又加上”-“符号=89e89b8f-d28c-1339-7463-7127c909f056
自定义算法03==========
v6=v17=自定义算法03 = 特殊算法处理后 =36f36b3c-a03e-4996-8759-8408e626c215
算法参数01:v4
算法参数02:unk_23DE(10位长度) =2409715836
算法参数03:unk_23D8(16位长度)=dbeafc2409715836
RC4魔改部分======(已经逆向算法)
RC4第1步:v48:拷贝&unk_B4D863E8中的256个字符到v48(应视是RC4算法的魔改数据)
RC4第2步:v49:计算RC4 的临时256自己T向量,公式:iK[i]=(byte)aKey.charAt((i % aKey.length()));
RC4第3步:V48状态向量S进行置换操作V48
RC4第4步:RC4产生密钥流iOutputChar,然后return new String(iOutputChar)
v27 =33 ,即v6[3];
RC4第5步:产生密钥流--其他还结合魔改Base64运算
分配输入密码对应的base64字节的存储空间
Base64算法的字典
Base64魔改部分======(已经逆向算法)
Base64的字典部分-64个字符+1个结束符
每4个字符中第0个与0x6异或,第0个与0xF异或
switch (i%4){
case 0:
base64char = (char) (iAscii ^0x07);
break;
case 2:
base64char = (char) (iAscii ^0xF);
break;
default:
base64char =encodeChars[i];
}
JNI_OnLoad 代码逻辑分析RegisterNatives
1:搜索JNI_OnLoad,双击进入函数体
2:导入Jni.h文件。菜单路径:ida/File/Load file/Parse C header file
3:修改参数类型为_JavaVM
4:按g快捷键直接跳转到0x4014
off_4010即可看到注册的函数
找到eq注册对应的sub_784函数
当然frida的hook_art_so_register.js脚本快速定位eq对应sub_784
该脚本通过hook art.so 的register函数,打印动态注册的地址//调用方式==测试ok
frida -U --no-pause -f package_name -l hook_art_so_register.js
或直接在fini_array初始化数据中可以看到
跟踪.init_array(其