Android应用的逻辑代码是由Java进行开发,所以是第一层就是java代码,Java虚拟机JVM运行的是java文件编译过后的class文件,Android虚拟机Dalvik并不是执行Java虚拟机JVM编译后生成的class文件,而是执行再重新整合打包后生成的dex文件编译之后的smali文件。
APK:是编译完成后的Android应用程序安装包
dex文件:是class文件的打包文件
smali文件:是Dalvik字节码文件
class文件:是JVM字节码文件
Android工程编译完成会得到我们想要的APK安装包,APK文件其实是一个压缩包
META-INF文件夹:
存放apk签名信息,用来保证apk包的完整性和系统的安全。
res文件夹:
存放资源文件,包括icon,xml文件。
AndroidManifest.xml文件:
应用程序配置文件,每个应用都必须定义和包含的,它描述了应用的名字、版本、权限、引用的库文件等信息。
classes.dex文件:
可以直接在Dalvik虚拟机上加载运行的文件,由java文件经过IDE编译生成。
resources.arsc文件
二进制资源文件,包括字符串等。
我们在分析一个Apk的时候,一般来说通过静态分析才能够开始破解之门,但随着现在的APK程序加固的越来越高级,只依赖静态分析也是不够的,更需要静态分析和动态分析一定会结合在一起才能事半功倍。
JEB:一款强大的跨平台Android 静态分析工具,相比jd-gui、jadx、bytecode-viewer这类jar查看工具,JEB提供类似IDA Pro的方法交叉引用与重命名功能,JEB的脚本化功能在自动分析与对抗代码混淆中很实用。
打开jeb,将要分析的APK拖入并等待分析完成
下面以具体一个恶意APP为实例,运用动静态分析方法结合工具使用来分析该APP。
我们解压APK文件后,发现在r文件夹下存放了资源文件,dex为Dalvik
虚拟机可执行文件,resources
存放了一些字符串,meta
包含该APP签名信息,AndroidManifest
文件中包含了APP的配置信息。
将要分析的APP文件拖入jeb之后,进入MainActivity
,然后选择Decompile
,通过代码分析发现该APP首先注册了Broadcast
,然后寻找该类Class.forName("com.shimeng.qq2693533893.MyServiceOne")
,最后用startService
来启动该类。主要逻辑在MyServiceOne
类里。
点开MyServiceOne
查看具体的逻辑
通过在模拟器运行该APP发现,连接模拟器的ADB断掉,而且重启模拟器会自动弹出APP的页面并且自动播放声音,该声音无法关掉,而且重启手机后也会自动播放声音。
所以该setprop persist.sys.usb.config none
执行断掉自身USB的操作。
通过运行发现APP一直在调用MyServiceOne$100000007
,通过静态分析找到100000007
,发现该方法是调用getStreamMaxVolume
系统音量最大的api,所以该APP运行之后无法关闭音量。
回头来看我们输入的解锁码然后打印出来的内容,相当于输入了一个解锁码的参数,下图涉及到的调用方法即APP的执行流程。
com.shimeng.qq2693533893 on (Android: 8.0.0) [net] # android hooking watch class com.shimeng.qq2693533893.MyServiceOne
发现主要的判断逻辑如下,如果与9DDEB743E935CE399F1DFAF080775366
相等,则移除MyServiceOne.this.util.removeView()
,进入sm2
if(QQ2693533893.getSaltMD5(MyServiceOne.(v2.substring(0, 3))) + v2.substring(3, v2.length()).equals("9DDEB743E935CE399F1DFAF080775366" + v3_1)) {
MyServiceOne.this.util.removeView();
MyServiceOne.this.sm2();
发现通过字符串搜索,最终利用静态分析定位到关键性逻辑。
针对一些小厂家较早期的APP,搜索字符串的方法确实能做到一步到位。
再比如下面这款看电视的APP,发现有强制升级我们尝试使用静态分析的方法来进行破解。
通过搜索字符串“立刻升级”定位代码位置
public void update_show(Bundle arg4) {
if(arg4 != null && (arg4.containsKey("ver")) && (arg4.containsKey("info")) && (arg4.containsKey("path"))) {
new AlertDialog.Builder(this).setTitle("发现新版本 " + arg4.getString("ver") + " 是否升级").setMessage(arg4.getString("info")).setPositiveButton("立刻升级", new o(this, arg4)).show();
}
}
发现如果有一个条件不满足,就不会进行升级,然后我们找到info
对应的smali,将判断结果的地方if-eqz改成if-nez即可让条件链失效,从而达到去强制升级的目的。
修改完之后打包签名,然后运行发现没有了强制升级
IDA Pro:目前功能最强大的静态反编译分析工具,具备可交互、可编程、可扩展、多处理器支持等特点,软件逆向分析必备工具。从6.1版本开始提供对 Android 的静态分析与动态调试的支持,包括 Dalvik 指令集的反汇编、原生库(ARM/Thumb 代码)的反汇编、原生库(ARM/Thumb 代码)的动态调试等。
在进行静态分析之前,我们需要先手动运行一下APP,了解下该程序的操作流程和进行更改的目的。寻找突破口是分析Android程序的关键。一般的做法是按程序中的错误提示信息来找到关键代码,因为错误提示代码附近通常就是程序的核心验证代码,可以通过阅读这些代码来理解程序的流程。
通过运行该APP我们发现该程序需要进行注册码校验,只有通过校验成功的注册码才可进行下一步操作。还发现了两个按钮监听的事件,因此从onclick可以作为破解该程序的出发点。
下一步我们解压APK取得 classes.dex,打开IDA Pro,将DEX拖入IDA Pro,选择默认选项,等待分析完成。
IDA Pro支持以结构化形式显示数据结构。单击“IDA View-A”选项卡,来到反汇编代码界面,然后单击菜单项“Jump”->“jump to address”,或按“G”键,会弹出地址跳转对话框,输入0,跳转到DEX文件的开头。可看到IDA Pro已自动解释了结构体信息并加上了注释。
DEX中所有方法的详细信息可在“Exports”选项卡中查看,方法的命名规则为“类名.方法名@方法声明”
用IDA Pro定位关键代码的方法整体上与定位smali关键代码类似。方法主要有三种:
一、搜索特征字符串
按组合键“Ctrl+S”,打开段选择对话框,双击“STRINGS”,跳转到字符串段,然后单击菜单项“Search”->“text”,或按组合键“Alt+T”,打开文本搜索对话框,在“String”旁输入要搜索的字符串,单击“OK”,等待片刻即可
二、搜索关键 API
按组合键“Ctrl+S”,打开段选择对话框,双击第一个“CODE”,跳转到数据起始段,然后单击菜单项“Search”->“text”,或按组合键“Alt+T”,输入要搜索的 API 名称。若 API 被多次调用,可按组合键“Ctrl+T”搜索下一项
三、通过方法名判断方法的功能
此方法较笨拙,因为对混淆过的代码,定位其关键代码是较困难的。如,知道 Crackme程序的主Activity类为MainActivity,在“Exports”中输入“Main”,会自动定位以“Main”开头的行(由此可粗略判断每个方法的作用)
通过分析APK文件后,以按钮点击事件为突破口查找关键代码,所以我们选择使用搜索特征字符串的方式来破解程序。
首先我们搜索字符串onclick
找到onclick
对应的方法,判断逻辑分析发现有两个onClick()
第一个onClick()
调用了MainActivity.access$000()
,在反汇编界面双击MainActivity.access
,可看到其调用了MainActivity
的 getAnnotations()
。可看出,MainActivity$1.onClick()
是“获取注解”按钮的事件响应代码
第二个onClick() ,来到其对应的反汇编代码,按“空格”键切换到 IDA Pro 的流程视图,代码的“分水岭”就是if-eqz p0, loc_116518,如下图所示,在第一个方框下,左边的箭头表示条件不满足时程序执行的路线,右边的箭头表示条件满足时执行的路线。可看出MainActivity$2.onClick() 是“检测注册码”按钮的事件响应代码
经过上面的分析,可知只要修改if-eqz指令为if-nez即可破解程序
将鼠标定位到指令“if-eqz v2, loc_2D0DCD ”所在行,然后点击IDA Pro主界面的“Hex View-A”选项卡,可看到这条指令所在的文件偏移为0x2D0BE,相应的字节码为“38 02 0f 00 ”,将 if-eqz 的OpCode值38 改成if-nez的OpCode值39即可。
再比如一款抓包请求和响应全加密的APP,我们尝试使用静态分析的方法找到加密逻辑。
在登录处抓包发现,request包和response包都为加密传输:
我们使用字符串搜索的方法,在String窗口搜索loginbypassword(这个是登录时的信息),搜索后进入对应的类,接下来我们进入这个类看它用了哪些方法
找到这个字符串引用的代码位置
之后双击callWebAPI:data:method:ssl:completionHandler:
找到[WebService callWebAPI:data:method:ssl:completionHandler:]
然后F5一下
浏览该类发现可以看到data等关键加密信息,接着我们尝试搜索data前面的setValue:forKey
[_priv_NBSSafeMutableDictionary setValue:forKey:]查看该类发现无结果,返回上一步重新查看加密所在的类
v87由v86 = -[WebService returnDictionaryWithDataPath:](v11, “returnDictionaryWithDataPath:”, v201)返回
查看returnDictionaryWithDataPath
:
v8 = +[RSA encryptString:privateKey:](&OBJC_CLASS___RSA, “encryptString:privateKey:”, v4, v6);
v4由convertToJsonData:返回(明文)v6由AppPrivate返回(密钥)
查看密钥返回函数AppPrivate和encryptString:privateKey函数
找到了加密算法的逻辑后,我们可以编写脚本然后再使用frida进行hook
if (ObjC.available){
try{
var className = "RSA";
var funcName = "+ encryptString:privateKey:";
var hook = eval('ObjC.classes.' + className + '["' + funcName + '"]');
console.log("[*] Class Name: " + className);
console.log("[*] Method Name: " + funcName);
Interceptor.attach(hook.implementation, {
onEnter: function(args) {
var param1 = new ObjC.Object(args[2]);
console.log("args[2] -> " + param1);
var param2 = new ObjC.Object(args[3]);
console.log("args[3] -> " + param2);
},
onLeave: function(retval) {
var retur = new ObjC.Object(retval);
console.log("retval -> " + retur);
}
});
}
catch(err){
console.log("[!] Exception2: " + err.message);
}
}
else{
console.log("Objective-C Runtime is not available!");
}
可以发现通过字符串搜索的方式最终找到了加密算法。
目前破解一个Apk的时,发现只使用静态分析的方式几乎毫无用途,随着加固技术的升级静态分析变得无从下手,所以动态分析是必须的,动态分析在运行代码的情况下,通过跟踪分析相关的内存,如寄存器内容,函数执行结果,内存使用情况等等,分析函数功能,明确代码逻辑。在某些场景下,静态分析作为辅助分析的一种手段,没有静态分析之后的结果,动态分析是无法开展的。因为动静结合的分析方式才会是高效的手段。
参考资料
https://www.cxyzjd.com/article/qq_44906504/89419090
https://toutiao.io/posts/amtx3y/preview
https://www.cnblogs.com/ichunqiu/p/9565028.html
https://blog.csdn.net/zlmm741/article/details/104886648?spm=1001.2014.3001.5502
E
N
D
关
于
我
们
Tide安全团队正式成立于2019年1月,是新潮信息旗下以互联网攻防技术研究为目标的安全团队,团队致力于分享高质量原创文章、开源安全工具、交流安全技术,研究方向覆盖网络攻防、系统安全、Web安全、移动终端、安全开发、物联网/工控安全/AI安全等多个领域。
团队作为“省级等保关键技术实验室”先后与哈工大、齐鲁银行、聊城大学、交通学院等多个高校名企建立联合技术实验室。团队公众号自创建以来,共发布原创文章370余篇,自研平台达到26个,目有15个平台已开源。此外积极参加各类线上、线下CTF比赛并取得了优异的成绩。如有对安全行业感兴趣的小伙伴可以踊跃加入或关注我们。