本系列文章,将全貌的讲解App安全中常见的一些内容,包含了逆向分析,正向防护等的相关工具和处理思路,涉及抓包、脱壳、分析等多个环节。
0、工具集简介
Frida官方[2]
适用于全平台,可动态注入js脚本,Hook应用内任何函数、监听api出入参、Trace代码调用链。【适用:全平台】
strongR-frIDA-android[3]
基于官方Frida修改,跟踪FRIDA最新代码自动打补丁,构建 Android 版 frida-server 的反检测版本【适用:Android】
frida-dexdump[4]
基于frida的工具,用于在内存中查找并转储 dex,以支持安全工程师分析恶意软件。【适用:Android】
手动编译Hluda Frida Server[5]
自行编译用于Android平台的去特征化Frida版本,可加入自定义的去特征化内容。【适用:Android】
Objection[6]
基于Frida开发的手机运行时搜索工具包,其功能强大,命令众多,而且不用写一行代码,便可实现诸如内存搜索、类和模块搜索、方法hook打印参数返回值调用栈等常用功能,是一个非常方便的,逆向必备、内存漫游神器。【适用:Android、iOS】
unidbg[7]
调试工具,支持在Windows/Linux/MacOS上模拟Native包的调用,包括.so、.dylib的动态调用。【适用:Android、iOS】
Charles[8]、Fildder、BurpSute、WireShark
HTTP/HTTPS代理工具
Xposed[9]
Xposed框架(Xposed Framework)是一套开源的、在Android高权限模式下运行的框架服务,可以在不修改Apk文件的情况下影响程序运行(修改系统)的框架服务,基于它可以制作出许多功能强大的模块,且在功能不冲突的情况下同时运作。
反射大师
一款基于Xposed的安卓修改工具。它可以帮助用户针对目标APP的界面进行可视化调整,拥有布局分析功能,获取当前Activity的所有变量等等功能,非常强大的一款工具。目标软件Activity启动后,反射大师会在启上面启动一个悬浮窗,基于当前的Activity对象进行可视化代码调用操作。反射大师是安卓脱壳神器,支持安卓8.0以下系统脱壳。
Apktool[10]
Android apk反编译&二次打包工具
jadx[11]
反编译工具,可将dex反编译成Java,提供图形化界面
Supersu、Magisk
Android Root工具,通常需要刷机安装
JEB[12]
模块化逆向工具,可进行Android下的反汇编、反编译,支持动态调试。
ProxyDroid[13]、Drony[14]
Android全局代理工具,可绕过App的代理检测进行抓包;
Stream[15]、HttpCanary[16]
iOS抓包工具
VMos Pro[17]
在Android手机上运行的Android模拟器
注:本文中实操环节使用的部分相关软件及版本号如下:
frida-server v15.2.2、MuMu模拟器Mac版(Android 6.0.1)、VMos Pro v2.9.4 Android5.1极客版;
采用了SSL Pinning的App样本:sample-v5.4.0.apk[18]
1、抓包
常规的http抓包,利用Charles、Fiddler、Burpsuite等抓包工具即可很便捷的实现。针对Https包,则需要在手机上安装SSL证书,利用中间人攻击的原理,实现数据包的抓取。
当前比较常见的防止被抓包的方法,有采用Https协议、代理屏蔽、证书锁定(即ssl Pinning)。下面,我们分别聊聊这两种方式。
1.1 Https协议
采用Https协议替代Http协议,实际上是在Http之外多了一个SSL加密协议。因此若App上未安装需要的SSL证书的话,抓包是无法看到完整的报文的。当前Https已经成为app网络请求的标准协议,与之相关的抓包方法在网络上已经很多了。以Charles为例,同时在电脑和手机上安装Charles的SSL证书即可进行抓包,这里不赘述了。
1.2 代理屏蔽
一般抓包工具都是基于流量代理的方式,通过中间人攻击的原理的来获取app流量。因此在app在进行流量请求时,禁止使用系统代理,即可防止常规的通过代理来抓包的方式。
// 以okhttp为例,设置代理屏蔽OkHttpClient client = new OkHttpClient().newBuilder().proxy(Proxy.NO_PROXY).build();
针对该方式的抓包应对方案有以下几种:
1.2.1 通过frida hook js 绕过代理屏蔽
try{ var URL = Java.use("java.net.URL"); URL.openConnection.overload('java.net.Proxy').implementation = function(arg1){ return this.openConnection(); }}catch(e){ console.log("" e);}try{ var Builder = Java.use("okhttp3.OkHttpClient$Builder"); var myBuilder = Builder.$new(); Builder.proxy.overload('java.net.Proxy').implementation = function(arg1){ return myBuilder; }}catch(e){ console.log("" e);}
1.2.2 通过ProxyDroid、Drony、HttpCanary等工具,实现全局流量代理
在手机上安装全局代理软件,接管手机全局网络流量,能做到对app透明以绕过app上的代理检测。ProxyDroid、Drony、HttpCanary均在使用时均会自动创建vpn,流量将通过vpn进出。其中,ProxyDroid和Drony需要设置将流量指向代理服务器(如:Charles),HttpCanary则直接在自身app上记录了流量。
1.3 SSL Pinning
SSL Pinning是通过在App中内置证书或公钥,对每次请求做证书/公钥比对,达到防止被中间人攻击的目的。大致分为两种:
- • 证书锁定(Certificate Pinning) 在客户端代码内置仅接受指定域名的证书,而不接受操作系统或浏览器内置的CA根证书对应的任何证书。(缺陷:证书有效期问题)
- • 公钥锁定(Public Key Pinning) 提取证书中的公钥并内置到客户端中,通过与服务器对比公钥值来验证连接的正确性。
相关资料可参考:证书锁定SSL/TLS Pinning [19]。下面,我们将重点聊聊如何绕过SSL Pinning限制
1.3.1 Xposed JustTrustMe插件 【推荐】(适用平台:Android)
手机需要root,安装Xposed框架后,安装JustTrustMe插件,或JustMePlush(升级版Just)插件。JustTrustMe是一个用来禁用、绕过 SSL 证书检查的Xposed模块。它将 APK 中所有用于校验 SSL 证书的 API 都进行了 Hook,从而绕过证书检查。JustMePlush则是在JustTrustMe的基础上,优化了对自定义SSL校验的支持。
1.3.2 Frida Objection(适用平台:Android、iOS)
Objection是基于Frida开发的客户端工具集,因此在使用方法上基本遵循Frida的使用方式。需要先在手机上安装frida服务端并启动(Android需Root,iOS需越狱 -_-!! ),然后在连接了手机的电脑上执行Objection指令。
objection -g <ios/apk package name> explore# 注意:# 若上述执行执行成果,会进入一个objection下的shell,以下指令均在objection的shell下执行。# Android 平台android sslpinning disable# iOS平台ios sslpinning disable
1.3.3 Frida Hook JS (适用平台:Android、iOS)
先在手机上安装frida服务端并启动frida-server,然后在电脑上执行如下命令(电脑上需安装frida-tools):
frida -U -l ./frida-android-unpinning.js -f <app-package-name> --no-pause
其中,./frida-android-unpinning.js 来自开源项目frida-android-unpinning[20]。app-package-name为目标app的包名,如com.android.settings。脚本在启动时,会加载hook js文件,达到动态修改/关闭app证书校验的机制。该js文件不一定对解决所有app的ssl pinning都能生效,app本身可能通过一些手段,绕开js的hook逻辑。
2、脱壳
通常Android加固分为dex加壳和so加固,因此我们讨论脱壳时也是从这两个方面来进行。相关的加壳器和加壳原理,大家可以参考看雪上的这篇文章:Android加壳与脱壳——各类加壳器和原理分析推荐[21]
2.1 apk文件脱壳
Android apk通常情况下,打包流程为:代码编译(含混淆) – 打包 – 签名。打包流程可参考掘金上的这篇文章:Android Apk 编译打包流程[22]。而采用第三方平台(如360加固,梆梆加固)后,会在上述流程之后,进行加固并重新签名。加固的原理可以简单理解为,加固程序首先对apk进行解压获取到原dex, 接着对原dex 进行加密,制作并生成壳dex(加载时用来解密原dex),并重新打包成apk,运行时利用壳dex对加密的dex进行解密并加载到内存中。
针对未加固的app,通常通过Apktool即可进行解压,并反编译成smali/Java代码
$ apktool d testapp.apkI: Using Apktool 2.0.0 on testapp.apkI: Loading resource table...I: Decoding AndroidManifest.xml with resources...I: Loading resource table from File: 1.apkI: Regular manifest package...I: Decoding file-resources...I: Decoding values */* XMLs...I: Baksmaling classes.dex...I: Copying assets and libs...
针对加固过的app,通过apktool反编译(或unzip解压包)后,发现核心的Java文件和包都不见了,只有一个硕大的classes.dex文件。因为核心文件都被打包藏到dex文件了,该dex文件是经过加密的也无法正常解压。这时通常的应对方案有如下几种:
2.1.1 frida-dexdump
因为app加固后必须保证能正常运行,因此app在实际运行时,原加密过的dex文件已经被解密,并且正确加载到内存中。次时若根据当下内存中的关键编码信息和字段,便壳找到解密后的dex文件在内存中的实际位置,通过内存转储到本地,即可得到原始的未经过加密的dex文件。以上即是frida-dexdump的基本原理。改工具需要安装名为frida-dexdump的python包,搭配frida-server一起使用。
2.1.2 反射大师
原理与frida-dexdump大体相同,都是动态获取内存中的dex信息并转储。区别是操作更简单,而且实测成功率更高。需要安装Xposed,反射大师app,比在xposed中激活反射大师模块。指定需要脱壳的app后,在目标app打开的页面中点开芒星,长按导出dex文件即可。
通过上述方案一般会得到多个dex文件,可以将单个文件直接用jadx打开, 便可以得到反编译后的Java代码,此时基本已经具备可读性了。也可以将得到的多个dex文件合并成一个dex文件,方便阅读。多dex的合并可以利用以下脚本,运行完成后会得到的全部反编译的代码。
import os, sys# 合并dex# file: merge.dex.py# e.g: python3 merge_dex.py ./source_dir/ output_dirif __name__ == "__main__": if len(sys.argv) < 3: print("start error") sys.exit() source_dir = sys.argv[1] output_dir = sys.argv[2] print(source_dir, output_dir)files = os.listdir(source_dir) # 得到文件夹下的所有文件名称s = []for file in files: # 遍历文件夹 if file.find(".dex") > 0: ## 查找dex 文件 sh = './bin/jadx -j 1 -r -d ' output_dir " " source_dir file print(sh) os.system(sh)
2.2 so文件脱壳
为了防止so包被反编译,或者被调试,开发者可以在原始so的基础上进行加密或者重新套壳。加壳思路与dex文件的加壳逻辑类似,因此其脱壳思路也与dex基本一致。即在app运行过程中,动态获取内存中的指定信息,并转储为原始的so文件。这个过程中,需要了解Android jni机制、汇编与反汇编。常用的分析工具是IDA 和 unidgb,这种重点介绍unidgb。
2.2.1 unidgb(适用平台:Android、iOS)
开源地址:https://github.com/zhkl0228/unidbg 。当前社区非常活跃,unidgb能模拟so的运行环境,并且可以进行单步调试so。unidgb可以自动脱掉一些处理相对常规一些的壳,在调试中,导入so文件,即可根据相关的jni函数名,直接在本地电脑的JVM环境下发起调用。一些复杂的so文件,则需要通过ida、unidgb分析,并手动打patch去壳后,才能导入unidgb正常发起jni调用。
public class SignUtil { ... public SignUtil() { emulator = AndroidEmulatorBuilder.for32Bit() .setProcessName("com.anjuke.android.app") .build(); Memory memory = emulator.getMemory(); memory.setLibraryResolver(new AndroidResolver(23)); vm = emulator.createDalvikVM(); vm.setDvmClassFactory(new ProxyClassFactory()); vm.setVerbose(false); DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/armeabi-v7a/libsignutil.so"), false); cSignUtil = vm.resolveClass("com/anjuke/mobile/sign/SignUtil"); dm.callJNI_OnLoad(emulator); } public String getSign0(String p1, String p2, Map<String, byte[]> map, String p3, int i) { String methodSign = "getSign0(Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;I)Ljava/lang/String;"; StringObject obj = cSignUtil.callStaticJniMethodObject(emulator, methodSign, p1, p2, ProxyDvmObject.createObject(vm, map), p3, i); return obj.getValue(); } private synchronized String sign(String p1, String p2, Map<String, String> paramMap, String p3, int i) { Map<String, byte[]> map = new HashMap<>(); for (String key : paramMap.keySet()) { map.put(key, paramMap.get(key).getBytes(StandardCharsets.UTF_8)); } return getSign0(p1, p2, map, p3, i); } public static void main(String[] args) throws Exception { Map<String, String> paramMap = new HashMap<String, String>() {{ put("a", "b"); put("b", "b"); }}; SignUtil signUtil = new SignUtil(); String sign = signUtil.sign("aa", "bb", paramMap, "cc", 10); System.out.println("sign=" sign); }}
比较典型的so脱壳案例,可以参考:https://blog.csdn.net/Y_morph/article/details/130361942
引用链接
[1] App逆向安全(二)- 调试与工具: https://blog.fh6766.com/2023/10/16/app-security-02/
[2] Frida官方: https://frida.re/
[3] strongR-frida-android: https://github.com/hzzheyang/strongR-frida-android
[4] frida-dexdump: https://github.com/hluwa/frida-dexdump
[5] 手动编译Hluda Frida Server: https://bbs.kanxue.com/thread-269889.htm
[6] Objection: https://github.com/sensepost/objection
[7] unidbg: https://github.com/zhkl0228/unidbg
[8] Charles: https://www.charlesproxy.com/
[9] Xposed: https://github.com/rovo89/Xposed
[10] Apktool: https://apktool.org
[11] jadx: https://github.com/skylot/jadx
[12] JEB: https://www.pnfsoftware.com/
[13] ProxyDroid: https://apkpure.com/proxydroid/org.proxydroid
[14] Drony: https://www.apkshub.com/app/org.sandroproxy.drony
[15] Stream: https://apps.apple.com/cn/app/stream/id1312141691
[16] HttpCanary: https://m.apkpure.com/httpcanary-—-http-sniffer-capture-analysis/com.guoshi.httpcanary
[17] VMos Pro: https://www.vmos.cn/
[18] sample-v5.4.0.apk: https://www.wandoujia.com/apps/366355/history_v109
[19] 证书锁定SSL/TLS Pinning : https://www.cnblogs.com/amyzhu/p/11838665.html
[20] frida-android-unpinning: https://github.com/httptoolkit/frida-android-unpinning
[21] Android加壳与脱壳——各类加壳器和原理分析推荐: https://bbs.kanxue.com/thread-275089.htm
[22] Android Apk 编译打包流程: https://juejin.cn/post/7113713363900694565
[23] Android-HTTPS认证的N种方式和对抗方法总结: https://ch3nye.top/Android-HTTPS认证的N种方式和对抗方法总结/
[24] Https防抓包机制: https://www.jianshu.com/p/a004f081d8aa
作者:团团何在
来源-微信公众号:剑城说
出处:https://mp.weixin.qq.com/s/9SSpVnA68R1FapGzccBVkg
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。