GKLBB

当你经历了暴风雨,你也就成为了暴风雨

导航

应用安全 --- 应知应会 之 壳

核心概念:什么是加壳?

“壳”是一种保护技术。开发商将原始程序(Dex/So,即“源程序”)进行加密、压缩、混淆,然后包裹在一个独立的“外壳”程序中。原始程序对外不可见。

  • 运行过程:App启动时,先执行“外壳”程序。外壳在内存中完成解密、解压操作,并将原始Dex文件加载到内存中,最后将执行权交还给原始程序。

  • 目的:防止静态分析。逆向者直接反编译安装包(APK)只能看到外壳代码,而无法看到核心业务逻辑,从而保护知识产权、增加破解难度。

由于不同厂商(腾讯、360、爱加密、梆梆等)的“壳”每一代技术思路都不同,因此不存在一种通用的脱壳方案。脱壳的本质就是在正确的时机,从内存中抓到解密后的原始Dex文件。

1. 现象分析:为什么反编译后代码很少?

你把“酒仙App”的APK文件拖入Jadx后,发现看到的代码非常少,就像是看到了一个空壳子的“包装盒”,而不是里面的“商品”。

这是因为:
这个APK已经被加壳了。你看到的少量代码,并不是App真正的业务逻辑代码,而是“壳程序”的代码。

  • 壳的特征:你提到的腾讯、梆梆、360,正是国内主流的几家提供加壳服务的厂商。它们的壳程序都有自己独特的特征(比如特定的包名、so库名、初始化方法),有经验的分析者一眼就能看出来用的是哪家的壳。

一个简单的比喻:

  • 未加壳的App:像一个透明的玻璃瓶,里面的饮料(代码)一览无余。

  • 加壳的App:像一个不透明的、包装精美的易拉罐。你只能看到罐子的外观(壳程序),看不到里面装的是什么饮料(真实代码)。


2. 加壳原理:到底发生了什么?

我们一步步来看一个App是如何从“裸奔”变成“穿盔甲”的。

第1步:开发一个正常的App(“裸奔”状态)

一个正常的安卓App开发出来之后,它的核心组成部分是:

  • classes.dex 文件:这里面存放了你写的所有Java/Kotlin代码编译后的字节码。这是代码的核心。

  • lib/ 目录下的 .so 文件:这是你用C/C++写的 native 代码(JNI代码)编译后的动态链接库。

  • 资源文件:图片、布局文件(.xml)、字符串等。

此时的APK结构清晰,classes.dex 可以直接被Jadx这类工具反编译。

第2步:使用加壳工具进行加密(“穿上盔甲”)

开发者把这个正常的APK提交给加壳平台(比如梆梆加固)。加壳平台会做以下几件事:

  1. 抽取:将原始APK里最重要的 classes.dex 文件加密。加密后的数据看起来就是一串乱码,毫无意义。

  2. 隐藏:把这串加密后的“乱码”(即原始的dex),藏匿到一个原本的 .so 库文件中,或者单独放入assets文件夹。这就是为什么你感觉 “so文件很大” ,因为它里面可能就“藏私货”了。

  3. 包裹:加壳平台会生成一个新的、很小的 classes.dex 文件。这个dex不包含任何业务逻辑,它唯一的作用就是“壳” —— 负责在App运行时解密和加载那个被隐藏起来的原始dex。

  4. 重组:最后,加壳平台会用这个新的“壳dex”和被修改过的、藏有原始代码的so文件,重新打包成一个新的、加固后的APK。

所以,你用Jadx打开这个新APK,反编译的只是那个壳dex,自然看不到多少有价值的代码。


3. 运行时:壳是如何工作的?

App安装到手机后,它的启动和执行过程也发生了变化。

未加壳的App启动:

系统直接加载 classes.dex,然后正常执行里面的代码。简单粗暴。

加壳的App启动(“金蝉脱壳”):

这是一个“套娃”过程,如下图解所示:

Diagram
 
Code
 
 
flowchart TD
A[启动加壳App] --> B[系统加载“壳dex”<br>(Jadx所见即此)]
B --> C[“壳dex”开始执行]
C --> D[加载藏有密文的.so文件]
D --> E[执行.so文件中的解密程序]
E --> F[在内存中解密出<br>原始的“真实dex”]
F --> G[动态加载内存中的“真实dex”]
G --> H[执行原始业务逻辑<br>用户正常使用App]

关键点在于:

  • 原始代码从未出现在磁盘上:解密后的、完整的原始dex只存在于内存中。APK安装包里永远只是加密状态。这有效地防止了静态分析。

  • 牺牲速度换安全:这一系列的解密操作,必然会导致App启动速度变慢。


4. 大厂 vs 小公司的选择

你最后提到的点非常准确:

  • 大厂(如淘宝、微信):他们一般不自研加壳,或者用很轻的壳。

    • 为什么? 因为加壳影响启动速度和用户体验。对他们来说,用户体验是重中之重。

    • 那他们怎么安全? 他们采用 “强加密”+“自研安全方案”。

      1. 核心算法放在so库:把最关键的业务逻辑、加密算法、风控规则用C++实现,编译成so库。so库的反编译和逆向难度远大于dex。

      2. 运行时防护:在App内植入大量反调试、反注入、环境检测的代码,动态防御。

      3. 服务器端校验:把核心逻辑放在服务器,App只是一个客户端,即使被破解了也拿不到核心数据。

    • 这种方案技术门槛极高,需要养一个强大的安全团队,但效果好,对用户体验影响小。

  • 小公司/创业公司:非常依赖第三方加壳服务。

    • 为什么? 因为他们没有足够的技术力量和资金去自研一套强大的安全体系。使用第三方加壳是成本最低、见效最快的安全方案。

    • 虽然会牺牲一些启动速度,但能有效防止 apk 被直接反编译、破解、二次打包,抵御绝大部分普通黑产玩家。


脱壳方案详解

1. 手动脱壳(难度大)

原理:通过动态调试(如使用 IDA Pro、GDB),跟踪分析外壳的解密逻辑,精确找到解密后的 Dex 文件在内存中的起始地址和大小,然后将其 dump(导出)到本地文件。

  • 技术要点:

    • 定位关键点:需要在外壳代码中定位到调用 dalvik.system.DexClassLoader 或 dexFileParse 等底层函数的地方。

    • 计算偏移:通过分析寄存器(如 ARM 架构的 R0、R1)和内存指针,计算出解密后 Dex 文件的内存映射地址和长度。

    • 内存操作:使用调试器或命令行工具(如 ddgdb)将指定内存区域的数据拷贝出来。

  • 为什么难度大?

    • 反调试:强壳会植入大量反调试技术,如检测调试器连接、检查进程状态、代码混淆等,一旦发现被调试立即退出或执行错误逻辑。

    • 代码混淆:外壳代码本身被高度混淆,增加静态分析和动态跟踪的难度。

    • 完整性校验:外壳会校验自身和脱壳后的 Dex 完整性,防止内存被修改或 dump。

    • 需要深厚的功底:要求分析者熟悉 ARM 汇编、Android 运行时机制和各种反调试技巧。

2. 工具脱壳(主流方案)

这类方案基于 Hook 技术,通过拦截系统关键函数或扫描内存特征,自动化的发现和 dump 内存中的 Dex 文件。

a. 基于 Xposed 的脱壳工具
  • 代表工具:

    • Fdex2:其经典思路是 Hook ClassLoader.loadClass 方法。当外壳解密 Dex 并加载第一个类时,必然要调用此方法。此时通过堆栈回溯,可以找到 DexFile 对象,进而获取其对应的内存地址,完成 dump。这是一种“时机”抓取。

    • dumpDex:原理类似,但通常更先进。它可能 Hook 更底层的函数(如 dvmDexFileOpenPartial)或结合内存扫描,兼容性和成功率更高。

  • 优点:通常一键操作,简单易用。

  • 缺点:需要安装 Xposed 框架,环境修改明显,容易被壳检测到 Xposed 环境而导致脱壳失败或 App 闪退。

b. 基于 Frida 的脱壳工具(当前主流)
  • 代表工具:frida-dexdump (https://github.com/hluwa/FRIDA-DEXDump)

  • 原理:它不依赖特定加载时机,而是采用 “主动搜索” 策略。

    1. 内存扫描:遍历应用程序的所有内存区域。

    2. 特征匹配:寻找符合 Dex 文件格式 的魔数(dex\n035\0 或 dex\n036\0 等)。

    3. 头部校验:找到魔数后,进一步解析 Dex 头部结构,检查其合法性(如 checksum 校验和、sha1 签名等)。

    4. 导出文件:将找到的、合法的 Dex 内存块 dump 到本地。

  • 优点:

    • 无需特定时机:只要 Dex 文件被映射到内存中,任何时候都可以扫描。

    • 对抗性强:Frida 的隐蔽性优于 Xposed,搭配 strongR-frida 等对抗工具后,成功率更高。

    • 通用性强:基于格式特征搜索,理论上能应对各种不同的壳。

  • 使用方法(命令行):

    bash
     
    # 启动App
    adb shell am start com.example.target.app
    
    # 在电脑上运行frida-dexdump
    frida-dexdump -U -p <进程名或PID> -d <输出目录>

3. 定制化脱壳机(高阶方案)

原理:直接修改 Android 操作系统(AOSP)的源码,在系统底层主动记录所有 Dex 文件的加载行为。

  • 实现方式:

    1. 下载 AOSP 源码。

    2. 找到 dalvik 或 art 虚拟机中加载 Dex 文件的关键函数(如 DexFile::OpenOpenCommon)。

    3. 在这些函数中加入日志代码,或者更直接地,加入将传入的 Dex 数据buffer自动保存到文件的功能。

    4. 编译整个系统,烧录到手机中。

  • 优点:

    • 降维打击:在系统层面实现,完全无法被App层面的壳检测和对抗。只要壳要运行,就必须通过系统接口加载 Dex,一加载就会被捕获。

    • 效果极佳:堪称“万能脱壳机”,尤其是对付那些运行时才解密、且反调试极强的第三代、第四代壳。

  • 缺点:

    • 技术门槛极高:需要深厚的 Android 系统编译和移植经验。

    • 过程繁琐:需要为特定手机型号编译和刷机,耗时极长。

4. 商业脱壳工具(付费方案)

  • 代表工具:ArmPro 等。

  • 原理:通常是上述多种技术的集大成者。它们可能是:

    • 一个高度定制化的、已经刷好脱壳系统的手机(即“脱壳机”)。

    • 一个强大的、持续更新的软件工具,集成了虚拟机、内存搜索、反反调试等多种功能。

  • 优点:

    • 省心省力:用户无需研究技术细节,交钱即可使用。

    • 成功率最高:商业工具会持续更新以对抗最新的壳,并提供技术支持。

  • 缺点:

    • 费用高昂:通常按次数或时间收费,价格不菲。

    • 黑盒操作:你不知道它具体如何工作,也无法自定义。

总结与选择建议

方案适用场景优点缺点推荐度
手动脱壳 学习研究、对付未知新壳 理解原理,锻炼能力 难度极大,耗时极长 ⭐⭐
Xposed工具 初学者、对付普通壳 简单易用 易被检测,环境明显 ⭐⭐⭐
Frida-dexdump 当前主流,对付大部分常见壳 通用性强,隐蔽性好,免费 对某些强壳可能失效 ⭐⭐⭐⭐⭐
定制脱壳机 专业分析、对付最强壳 理论上万能,无法防御 技术门槛高,需刷机 ⭐⭐⭐⭐
商业工具 有预算的企业、无技术背景 省心,成功率最高 费用高,黑盒 ⭐⭐⭐

给你的建议:

  1. 从 frida-dexdump 开始:这是目前免费方案中最有效、最通用的选择。遇到大多数情况都应该先尝试它。

  2. 如果 frida-dexdump 失效,检查是否是Frida环境被检测,尝试使用 strongR-frida 等对抗工具后再试。

  3. 如果依然无效,说明壳很强,可以考虑寻找定制好的脱壳手机(市面上有人出售)或求助商业脱壳服务。

  4. 手动脱壳和自建脱壳机是安全研究人员的终极道路,适合希望深入理解系统原理的人。

 

posted on 2025-08-24 07:41  GKLBB  阅读(42)  评论(0)    收藏  举报