REVERSE ENGINEERING

马甲包APK逆向修改
通用方法论

从识别到修改,从原生到跨平台 -- 一份覆盖主流框架的完整逆向工程实践指南

01

什么是马甲包

马甲包(Vest APP)是指基于同一套源码,通过修改包名、更换图标、调整皮肤主题、混淆代码等方式重新打包发布到应用市场的APP变体。其本质是对同一产品的反复套壳上架,以绕过平台审核和竞品检测。

常见应用场景

视频类APP

影视聚合、短视频解析、直播聚合等。此类马甲包数量最多,通常内置大量广告SDK和VIP付费解锁逻辑。

社交类APP

聊天、交友、社区类应用。常通过换皮实现多账号矩阵运营,核心通信逻辑完全一致。

工具类APP

清理、加速、壁纸、日历等。功能简单但广告密集,马甲包迭代速度极快。

共性特征

无论外表如何变化,马甲包在技术层面具有高度可识别的共性:

02

逆向修改标准流程(SOP)

以下是经过大量实践验证的7步标准操作流程。每一步都有明确的输入、操作和验证标准,确保修改过程可重复、可追溯。

flowchart TD
    S1["Step 1: 快速分析
apktool d + grep关键词
~5分钟"] S2["Step 2: Tab隐藏
setVisibility GONE
不改数组大小"] S3["Step 3: VIP解锁
6个核心方法
return true/1/-1"] S4["Step 4: 广告去除
开屏+弹窗+公告
return-void"] S5["Step 5: 金币视频
金币对话框屏蔽
return-void"] S6["Step 6: 打包签名
apktool b + zipalign
+ apksigner"] S7["Step 7: 验证安装
v1+v2+v3签名验证
真机测试"] S1 --> S2 --> S3 --> S4 --> S5 --> S6 --> S7 style S1 fill:#0f3460,stroke:#e94560,stroke-width:2px,color:#eee style S2 fill:#0f3460,stroke:#e94560,stroke-width:2px,color:#eee style S3 fill:#0f3460,stroke:#e94560,stroke-width:2px,color:#eee style S4 fill:#0f3460,stroke:#e94560,stroke-width:2px,color:#eee style S5 fill:#0f3460,stroke:#e94560,stroke-width:2px,color:#eee style S6 fill:#0f3460,stroke:#e94560,stroke-width:2px,color:#eee style S7 fill:#0f3460,stroke:#e94560,stroke-width:2px,color:#eee
1

快速分析 ~5分钟

使用 apktool d 反编译APK,然后通过 grep 搜索关键类名和方法名,确定框架类型和核心修改点。

# 反编译
apktool d target.apk -o output/

# 快速识别框架
ls output/lib/arm64-v8a/          # 看SO库
ls output/smali*/                  # 看DEX结构
find output/ -name "*.smali" | wc -l  # smali文件数量

# 搜索关键类
grep -rl "UserInfo" output/smali*/
grep -rl "SplashActivity" output/smali*/
2

Tab隐藏

隐藏底部导航栏中不需要的Tab页(如"我的"页中的充值入口)。关键原则:只改可见性,不改数组大小

// 定位到 Tab 隐藏代码
// 修改前:
invoke-virtual {v0}, Landroid/view/View;->setVisibility(I)V
    const/16 v1, 0x0    # VISIBLE

// 修改后:
invoke-virtual {v0}, Landroid/view/View;->setVisibility(I)V
    const/16 v1, 0x8    # GONE
严重警告: 绝对不要删除Tab对应的Fragment数组元素。如果将 Fragment[] 数组从5个改成4个,后续所有 getItemAt(index) 调用都会产生索引越界崩溃。
3

VIP解锁

找到VIP相关的6个核心判断方法,将其返回值修改为"已VIP"状态。这是整个逆向修改的核心步骤。

# 需要修改的6个核心方法:
isVIP()           → return true
isVip()           → return true
vipType()          → return 1
getFreeWatches()   → return -1     # 无限观看
isCanWatch()       → return true
getExpiredVip()    → return "2099-12-31"

# smali 修改示例:
# 修改前:
.method public isVIP()Z
    iget-boolean v0, p0, Lcom/xxx/UserInfo;->mIsVip:Z
    return v0
.end method

# 修改后:
.method public isVIP()Z
    const/4 v0, 0x1
    return v0
.end method
4

广告去除

移除开屏广告、弹窗广告和福利公告弹窗。将广告展示方法的函数体清空为 return-void

# 开屏广告 - SplashActivity
.method public adShowMine()V
    .registers 2
    return-void
.end method

# 福利弹窗
.method public showWelfareDialog()V
    .registers 2
    return-void
.end method

# 活动弹窗
.method public showActivityDialog()V
    .registers 2
    return-void
.end method
5

金币视频屏蔽

屏蔽"看视频领金币"等激励广告对话框,避免用户误触。

# 金币对话框
.method public createGoldDialog()V
    .registers 2
    return-void
.end method

.method public showGoldDialog()V
    .registers 2
    return-void
.end method
6

打包签名

将修改后的smali重新打包为APK,并完成对齐和签名。

# Step 6a: 重新打包
apktool b output/ -o modified.apk

# Step 6b: ZIP对齐
zipalign -v -p 4 modified.apk aligned.apk

# Step 6c: 签名(v1+v2+v3)
apksigner sign \
  --ks keystore.jks \
  --ks-key-alias alias \
  --ks-pass pass:password \
  --key-pass pass:password \
  --v1-signing-enabled true \
  --v2-signing-enabled true \
  --v3-signing-enabled true \
  aligned.apk
7

验证安装

签名完成后,验证APK签名信息并在真机上安装测试。

# 验证签名
apksigner verify --print-certs -v final.apk

# 真机安装测试
adb install final.apk

# 确认v1+v2+v3签名方案均存在
apksigner verify --verbose final.apk
03

举一反三 -- 适配不同马甲包

马甲包虽然外表千变万化,但底层框架通常只有几种。通过识别框架类型,可以快速确定对应的修改策略。以下决策树帮助你在5分钟内完成框架识别。

flowchart TD
    START(["拿到一个APK"]) --> Q1{"lib/下有哪些SO文件?"}

    Q1 -->|"libflutter.so + libapp.so"| FLUTTER["Flutter/Dart框架"]
    Q1 -->|"libpython3.xx.so"| PYTHON["Python/Kivy框架"]
    Q1 -->|"libojdcosca.so
assets/apps/__UNI__/"| UNIAPP["uni-app/DCloud框架"] Q1 -->|"无特殊SO
3个DEX
smali 18000+"| NATIVE["原生Android框架"] FLUTTER --> F1["reflutter重打包
+ frida hook"] PYTHON --> P1["反编译pyc为py
+ buildozer重打包"] UNIAPP --> U1["JS层逆向
需要解密JS资源"] NATIVE --> N1["标准SOP直接适用
成功率99%"] style START fill:#e94560,stroke:#e94560,color:#fff style FLUTTER fill:#fdcb6e,stroke:#fdcb6e,color:#1a1a2e style PYTHON fill:#6c5ce7,stroke:#6c5ce7,color:#fff style UNIAPP fill:#e94560,stroke:#e94560,color:#fff style NATIVE fill:#00b894,stroke:#00b894,color:#1a1a2e style F1 fill:#16213e,stroke:#fdcb6e,color:#eee style P1 fill:#16213e,stroke:#6c5ce7,color:#eee style U1 fill:#16213e,stroke:#e94560,color:#eee style N1 fill:#16213e,stroke:#00b894,color:#eee
A. 原生Android(com.androidx.lv.base 架构) 容易 | 成功率 99%
识别特征
  • 3个DEX文件(classes.dex, classes2.dex, classes3.dex)
  • smali文件数量 18,000+
  • 存在 UserInfo.smaliVideoBean.smaliCdnBean.smali 等核心类
  • 包名路径中包含 com.androidx.lv.base
修改方案
完全适用上述7步SOP,所有修改均在smali层完成,无需处理JS或Dart代码。
关键类清单
UserInfo | VideoBean | CdnBean | SplashActivity | MainActivity | FastDialogUtils
实战经验
这类马甲包最容易修改,代码结构清晰,所有业务逻辑都在smali中可直接定位。成功率接近100%。
B. uni-app / DCloud(H5混合应用) 困难
识别特征
  • 仅有1个超大DEX文件
  • smali文件极少(通常仅2-5个)
  • assets目录下存在 apps/__UNI__XXXXXX/ 目录结构
  • 存在 libojdcosca.so 加固文件
修改方案
需要进入JS层进行逆向。核心业务逻辑在加密的JS文件中,smali层几乎没有可修改内容。
核心难点
JS资源被 libojdcosca.so 加密,需要先脱壳解密JS,再定位业务逻辑进行修改。
实战经验
不建议在smali层面修改此类框架。如果可能,寻找同一产品的原生Android版本进行修改。
C. Flutter / Dart 中等偏难
识别特征
  • lib目录下存在 libflutter.so
  • 存在 libapp.so(Dart编译产物,AOT Snapshot)
  • assets目录下存在 flutter_assets/
修改方案
  1. 使用 reflutter 提取Dart Snapshot
  2. 分析并修改Snapshot中的关键逻辑
  3. 使用frida进行动态Hook辅助
  4. 重新打包 libapp.so
核心难点
Dart代码编译为Native机器码,无法直接反编译为可读源码。需要依赖 reflutter 进行Snapshot级别的修改。
实战经验
Flutter马甲包的修改难度明显高于原生。reflutter是目前最成熟的工具,但版本兼容性需要注意。
D. Python / Kivy(P4A) 极难
识别特征
  • lib目录下存在 libpython3.xx.so(如libpython3.8.so)
  • 存在 libpybundle.so
  • assets或私有目录中包含 private.tar,其中有 main.pyc
修改方案
  1. 解压 private.tar 获取 main.pyc
  2. 使用 uncompyle6 / decompyle3 反编译pyc为py源码
  3. 修改Python源码中的VIP判断、广告逻辑等
  4. 重新编译pyc并使用 buildozer 打包
核心难点
C扩展依赖(如numpy、opencv等)难以在重打包时补齐。如果 private.tar 缺少 _applibs 目录,说明打包不完整,几乎无法修复。
实战经验
除非有完整的Python环境和所有依赖,否则不建议尝试。成功率极低,建议放弃或寻找其他版本。

修改难度对比

04

核心修改模式速查表

以下表格总结了马甲包逆向修改中最常见的10个修改目标,包括搜索关键词、修改方式和适用框架。建议打印此表作为实操时的快速参考。

修改目标 搜索关键词 修改方式 适用框架
VIP身份 isVIP, isVip, vipType return true / 1 原生Android
观看次数 getFreeWatches, freeWatch return -1(无限) 原生Android
视频权限 isCanWatch, canPlay return true 原生Android
CDN线路 isVip(CdnBean内) return true 原生Android
开屏广告 SplashActivity, adShowMine goto失败分支 或 return 原生Android
弹窗广告 showWelfareDialog, showActivityDialog return-void 原生Android
金币弹窗 createGoldDialog, showGoldDialog return-void 原生Android
Tab隐藏 llSwitch, tabLayout.getChildAt setVisibility(GONE) 原生Android
VIP到期时间 getExpiredVip, vipExpireTime return "2099-12-31" 原生Android
广告点击 AdClickService, onAdClick 删除 或 return-void 原生Android
05

避坑指南

以下8条规则来自大量实战踩坑经验总结。违反任何一条都可能导致APK无法运行或功能异常。

1. 不要改数组大小

隐藏Tab时只改 setVisibility(GONE)绝对不能删除Fragment数组元素,否则 getItemAt(index) 索引越界直接崩溃。

2. 不要改 BaseSdk.init()

该方法同时初始化网络模块和Context。一旦修改,整个APP的网络请求全部失效,所有功能瘫痪。

3. 不要改服务器连接域名

API域名是APP运行的基础。修改域名后APP无法连接后端服务器,所有数据加载失败。

4. goto跳转注意寄存器初始化

使用 goto 跳转到其他分支时,必须确保目标分支使用的寄存器已经正确初始化,否则空指针闪退。

5. 不要删return-void方法的注解

清空方法体改为 return-void 时,保留原有的 @Bindable 等注解。删除注解会导致DataBinding框架崩溃。

6. 不要改SplashActivity核心流程

权限申请、CDN线路选择、初始化逻辑是启动链路的核心,任何改动都可能导致APP卡在启动页或闪退。

7. 打包前全面检查

确认文件大小合理(与原包差异不超过30%)、DEX数量不变、SO文件完整未删除。任何遗漏都会导致功能异常。

8. 签名必须用 v1+v2+v3

仅使用v2签名在某些低版本Android设备上无法安装。三重签名方案确保最大兼容性。

06

工具清单

以下是马甲包逆向修改过程中使用的全部工具及其用途。按功能分类列出,建议搭建完整的工具链环境。

反编译与重打包

AT
apktool
APK反编译与重打包的核心工具,支持资源解码和回编
v2.9.3
JX
jadx
DEX反编译为可读Java源码,用于快速理解代码逻辑
v1.5.0
ZA
zipalign
ZIP文件对齐优化,APK打包必需步骤
Android SDK
AS
apksigner
APK签名工具,支持v1/v2/v3签名方案
Android SDK
KT
keytool
Java密钥库管理,生成和管理签名密钥
JDK
AA
aapt
Android Asset Packaging Tool,查看和操作APK资源
Android SDK

动态分析与高级工具

FR
frida
动态Hook框架,运行时修改方法行为,无需重打包
v17.15.5
OB
objection
基于Frida的运行时探索工具包,快速Hook常用API
latest
RF
reflutter
Flutter APK重打包工具,用于修改Dart Snapshot
latest
AG
androguard
APK深度分析框架,支持签名验证、权限分析、恶意行为检测
v4.1.4
QK
quark
恶意行为检测引擎,基于五元组模型分析APK危险行为
latest
AP
apkid
APK壳/编译器/混淆器识别工具,快速判断加固方案
latest
BW
binwalk
二进制文件分析工具,提取嵌入的固件和加密资源
latest