从 Releases 下载对应平台的安装包,安装后直接使用。
macOS 首次打开(未签名版本)
macOS 会提示「无法验证开发者」,在终端执行以下命令去除隔离标记,执行后正常双击打开即可,只需操作一次:
xattr -rd com.apple.quarantine /Applications/Shellsmith.app
正式 GUI 为 Tauri 版,Linux / macOS / Windows 使用同一套界面。当前界面以加固、签名、证书、设置、关于为主,签名证书已从设置页拆出,由证书页统一管理。
- 加固:在 Android/iOS 间切换;Android 选择 APK,iOS 选择 Xcode 工程并在工作副本中接入保护
- 签名:拖入或选择 APK → 选择证书 → 点击签名;签名成功后只保留“继续签名”入口
- 证书:导入已有 keystore / p12,或创建新的 PKCS12 证书;可设置默认证书
- 设置:配置主题、语言与应用级选项
- 设置 → 问题反馈:在软件内填写反馈表单,Bug 反馈的诊断信息自动附带,发送前可预览
- 关于:显示版本号与构建信息、检查更新,并支持手动重新检测环境
从 v1.4.5 开始,启动时或在「关于 → 检查更新」读取 GitHub 最新稳定版清单,不再使用一天的版本缓存。发现更新后点击顶部「查看更新」,阅读说明并选择「下载并安装,完成后重启」。仅创建 tag 不会触发客户端更新:Release 工作流必须成功公开安装包、签名与 latest.json。预发布版不会进入稳定更新通道。
- macOS 支持 Intel 与 Apple Silicon;请先将
.app从 DMG 移入「应用程序」后运行。 - Windows x64 使用带进度的 NSIS 安装器,系统需要时可能请求授权。
- Linux x64 AppImage 支持覆盖更新;deb 仍需到 Release 页面下载并通过系统安装。
- 加固或签名尚未结束时不能更新,更新期间不能新建加固/签名任务或普通退出。强制结束进程、断电与磁盘故障不在此保护范围内。
- 安装前校验更新包签名及签名绑定版本;下载或验签失败不会进入安装。本地
config.toml、shield.db、keystores/不随更新清除。未保存的表单请先保存。 - v1.4.4 及更早版本需手动安装一次 v1.4.5,之后才能使用覆盖更新;开发模式只检查版本。
- 优先使用 GUI:日常加固、重新签名、管理签名证书
- 使用 CLI:批处理脚本、CI 流水线、本地调试加固过程
- 先在 证书 页面导入已有 keystore / p12,或创建新的 PKCS12 证书
- 将常用证书设为默认
- 返回 加固 页面选择已签名 APK
- 需要直接得到可安装产物时,使用默认启用自动签名的证书
- 只做重签名时,使用 签名 页面并选择证书
当前版本签名资料由证书页统一维护:
- 导入证书保存前会校验 keystore 密码、alias 与证书可用性
- 创建证书默认生成 PKCS12 keystore,并保存到应用数据目录
keystores/ - 创建证书时 Keystore 密码至少 6 位;Key 密码可留空,填写时同样至少 6 位
- PKCS12 证书的 Alias 可能会被
keytool规范为小写;GUI 会按大小写不敏感方式校验,并保存 keystore 中实际返回的 Alias - 已保存证书的材料不可直接编辑;编辑入口只用于修改名称、备注、签名版本和自动签名偏好
- 如需更换 keystore 文件、Alias、类型或密码,请重新导入或创建一条证书记录
- 启用自动签名时,加固页会先校验原 APK 与当前所选证书指纹,一致时才执行
- 签名页不会维护临时签名配置,只从证书列表中选择
- 自动签名产物默认建议名为
{name}_protected_signed.apk,开始前可修改 - GUI 内部会在输出前自动完成 APK ZIP 对齐,无需手动运行
zipalign
常用加固选项保存到 config.toml 的 protect_defaults:运行系统兼容性、运行环境保护、加固页证书选择与自动签名偏好、输出目录模式及固定目录。重新启动后沿用已保存值;加固页所选证书与证书管理中的默认证书不是同一个概念。
输出目录可选择原 APK 同目录或固定目录;文件名根据当前输入和签名选择生成建议值,也可在执行前修改,不把上一个 APK 的文件名作为通用默认。任务开始后使用固定快照,运行中及结果页不能修改本次配置。旧 ABI 排除确认仍只对当前任务有效,不持久化。
Beta.6 起,加固和签名页分别提供“分享加固使用情况”“分享签名使用情况”单行选择。新应用默认选中;取消只针对当前包名,两页共用并长期记住选择,同包名升级或更换 APK 路径不会重置。
成功操作可发送应用包名、名称、版本码、工具版本、操作类型、流程和成功日期,以及协议版本、说明版本和去重提交编号;不上传 APK、路径、证书、密码或原始日志,不关联匿名安装标识。仅维护者可查询,明细保留 180 天。取消停止同包名后续分享,不自动删除以前已收到的数据。应用分享独立于错误报告通道:是否分享只由加固页和签名页的选择决定,不受错误报告是否发送的影响。
分享识别和网络失败不会阻止本地加固或签名;加固后的 APK 不包含本功能的运行时上报。详细说明见数据通道与边界。
如果 APK 同时包含受支持架构与旧 SDK 附带的 armeabi、mips、mips64 等不支持架构,开始加固时会列出排除与保留清单。选择“排除这些架构并继续”后,仅从输出 APK 移除对应架构目录,原 APK 不变。此确认不保存,每个新任务重新确认;只有不支持架构的 APK 仍会被阻止。保留架构的业务库需完整,完成后请验证启动及相关 SDK 功能。
CLI 默认拒绝这类混合 APK,需要显式传入本次排除清单,例如:
shield protect -i input.apk -o output.apk --exclude-abis armeabi,mips,mips64清单必须与原 APK 中实际需要排除的架构匹配,不允许排除本工具支持的架构。Android 4.4 工控模式继续执行原有 ABI 限制。
建议提前准备以下材料:
- 已签名的原始 APK
keystore/p12aliaskeystore密码key密码(相同可留空)
启用自动签名时,GUI 会在预检时比对原 APK 与当前所选证书的指纹,并在后端开始加固前再次校验。指纹不一致或证书读取失败都会阻止加固,因为改用其他证书签名会导致运行时无法解密和启动。
加固页提供“运行系统兼容性”选项。默认使用“Android 5.0 及以上”标准模式;目标设备包含 Android 4.4 工控板时,可选择“兼容 Android 4.4”。标准模式已覆盖 Android 5.0~6.0 的旧版 ART 注入路径,并包含 ARouter 运行期扫描和 Android 9 org.apache.http.legacy 兼容处理。兼容模式当前仅接受不含 Native 库,或 Native 库仅包含 armeabi-v7a 的 APK;后端会再次检查 ABI,并从应用内置的固定兼容资源包加固,前端不能传入任意资源路径。GUI 会将该选择保存为常用设置,每个任务开始时冻结,旧版请求未携带此字段时仍按标准模式执行。Android 4.4.2 armeabi-v7a/NEON 工控真机已确认能够正常运行;完整业务测试未全部覆盖,其他 CPU、厂商系统和硬件交互仍需按实际设备验证。
加固页同时提供“运行环境保护”选项:
| 模式 | 默认值 | 行为 | 适用建议 |
|---|---|---|---|
| 标准保护(推荐) | 初始默认 | 始终保留反调试检查;Root 信号不阻止应用启动 | 普通应用、模拟器、工控设备以及无法确认设备环境时使用 |
| 严格保护 | 否 | 反调试或高置信 Root、ADB Root、注入信号命中时拒绝启动 | 仅用于明确不允许 Root 环境运行的受控部署场景 |
运行环境策略写入 config.toml 的常用加固设置,每个任务仍使用开始时固定的快照。任务开始后不能修改;如需切换策略,必须重新选择并加固 APK,运行时不会从严格模式静默降级。严格策略只能提高常见提取和分析成本,不能承诺抵御隐藏 Root、检测绕过、内核级控制或进程内提取。若目标设备出现误判,请改用标准保护重新加固,并提供设备系统及 Root 方案信息协助排查。
GUI 会在应用启动时检测一次本机 Java 环境,并将结果缓存到全局状态中;若未检测到完整 JDK 8+,或缺少 keytool,加固、签名、Alias 识别会直接阻断并给出明确提示。运行流程不依赖 javac。
如果应用启动后你又安装或切换了 JDK,可在关于页手动点击“重新检测环境”刷新状态。
iOS 完整构建要求 macOS、完整 Xcode、可用的 Apple Team 和 Provisioning Profile。Shellsmith 会自动发现常见位置的完整 Xcode,即使系统 xcode-select 暂时仍指向 Command Line Tools,也会对本次任务使用发现到的 Xcode;Windows/Linux 可以查看静态检查结果,但不能 Archive 或导出 IPA。
- 在 加固 页面切换到 iOS,选择
.xcodeproj或.xcworkspace。 - 填写 scheme、Release configuration、10 位 Team ID 和允许的 Bundle ID;多 Bundle ID 用逗号或空格分隔。
- 点击“检查工程”。存在非应用 target、共享 scheme 缺失、完整 Xcode 缺失或上游已知错误接法时,构建按钮保持禁用。
confidential.yml和 freeRASPwatcherMail都是可选项。提供confidential.yml时,只保护明确列入配置的 Swift 字面量;未提供时仍启用 freeRASP,只跳过项目自定义敏感字面量保护。本地化键、selector、反射名称和资源名不要加入。strict的 App Attest 服务端地址可选。不填写时仍执行严格客户端加固;填写后,客户端只生成调用接口,业务服务端仍须实现挑战、证明校验和重放防护。- 选择独立的空输出目录和导出方式。默认已开启“允许更新 Provisioning Profile”:导出
app-store-connect、enterprise需要 App Store 分发描述文件,而它通常不在本机,必须允许 Xcode 联网用已登录的开发者账号获取或创建。关闭该选项后,只有本机已装齐全部 Bundle ID(含 Share Extension 等扩展)的分发描述文件时才能导出成功。已自带ExportOptions.plist(signingStyle=manual加provisioningProfiles映射)时可以改用文件导入,此时该选项不影响导出。自动生成的导出配置固定为生成本地 IPA(destination=export),不会直接上传。 - 完成后在输出目录检查工作副本、
.xcarchive、IPA 和shellsmith-report.json,再用目标设备验证启动、敏感流程和威胁响应。
标准纯 Objective-C UIKit 工程可通过 AppDelegate.m 中已有的 application:didFinishLaunchingWithOptions: 回调接入 balanced/strict 运行时保护;若发现多个启动回调,在“iOS 启动入口”中明确填写目标 .m 路径。Shellsmith 会在工作副本该回调的开头启动保护,保持 main.m 和原有回调逻辑不变。Swift Confidential 不处理 OC 字符串,纯 OC 工程请勿提供 confidential.yml;无该回调的自定义启动方式暂不支持自动注入。
Shellsmith 不修改原工程,也不保存 Apple 账号令牌、钥匙串密码或私钥。生成的本地 Swift Package 锁定 Swift Confidential 0.5.2 和 freeRASP iOS 7.1.4,并直接链接到应用 target,避免 XCFramework 重复产物与二级 framework 嵌套问题。
freeRASP 支持“一次准备,多次复用”:在 iOS 保护方案中点击“下载 / 检查缓存”,或从能访问 GitHub 的电脑下载 官方 v7.1.4 源码 ZIP,再点击“导入官方 ZIP”。无需付费授权字段,但仍须遵守上游免费版许可、公平使用与隐私要求。首次开始加固也会自动准备;缓存后使用相对路径本地依赖,换输出目录无需重新克隆 freeRASP。文件会逐项校验,损坏或错误版本会阻断,不能靠关闭保护绕过。
缓存仅保存在当前用户的 ~/Library/Caches/dev.mocika.shield-gui/ios-dependencies/,不进入 Shellsmith 安装包;CLI 可用 --freerasp-zip 导入、--ios-cache-dir 指定缓存目录。官方许可证、说明和隐私清单会保留在输出工作副本。缓存解决 freeRASP 的构建下载问题,不关闭 SDK 运行时通信;Swift Confidential、工程原有依赖和签名仍可能需要网络。详见 本机依赖准备。
三个档位的边界:
| 档位 | 行为 |
|---|---|
compat |
Apple 原生 Release/Archive、签名和产物检查,不接入第三方 RASP |
balanced |
freeRASP 分级事件;提供 confidential.yml 时再启用选择性 Swift Confidential,推荐默认值 |
strict |
balanced + App Attest 客户端接口;服务端地址可选,未配置时明确标记为没有服务端证明闭环 |
freeRASP 的越狱、Hook、签名异常等结果是风险信号。生成的封装会发出稳定回调与通知,不会擅自退出应用或封禁账号。Dopamine 2 RootHide 漏检属于上游闭源实现的残余风险,strict 应结合 App Attest 和服务端业务风控。完整说明见 iOS 加固实现。
GUI 启动时会一次性加载应用配置与证书数据库,运行期间使用同一份内存状态,不会在页面切换时反复从磁盘读取。应用级配置写入 config.toml;证书列表、默认证书、签名密码与校验状态写入本地 SQLite 数据库 shield.db。密码字段以 enc:v1 格式加密落盘;旧明文记录不再兼容,如遇到旧测试数据请重新导入或创建证书。
证书记录和托管 keystore 属于当前 macOS/Linux/Windows 用户的本地应用数据,不会打进项目、APK 或 Shellsmith 安装包,也不会上传到 CI。升级或重新下载并安装 Shellsmith 时,系统通常会保留原应用数据目录,因此旧证书仍会显示。要删除单条记录,请在 证书 页面使用删除按钮;若要彻底清空本机资料,请退出 Shellsmith 后备份并删除下表中的应用数据目录,再重新启动应用。不要直接删除仍在使用的生产 keystore。
| 平台 | 应用配置 | 证书数据库 |
|---|---|---|
| Linux | ~/.config/dev.mocika.shield-gui/config.toml |
~/.local/share/dev.mocika.shield-gui/shield.db |
| macOS | ~/Library/Application Support/dev.mocika.shield-gui/config.toml |
~/Library/Application Support/dev.mocika.shield-gui/shield.db |
| Windows | %APPDATA%\\dev.mocika.shield-gui\\config.toml |
%APPDATA%\\dev.mocika.shield-gui\\shield.db |
应用数据目录还会新增:
shield.db:证书列表、默认证书、签名密码、校验状态keystores/:应用内新建或托管的 keystore 文件
先复制并修改 examples/shellsmith-ios.toml。需要保护项目自定义敏感字面量时,再按需创建 examples/confidential.yml 的副本:
# 只读检查,输出 JSON;不要求修改工程
shield check-ios /path/App.xcworkspace --scheme App
# 验证配置和已知问题处理,不执行 Archive
shield protect-ios \
--ios-config shellsmith-ios.toml \
--output /path/to/empty-output \
--dry-run --json
# 在完整 Xcode 的 macOS 上构建、签名、导出和验证
shield protect-ios \
--ios-config shellsmith-ios.toml \
--output /path/to/empty-output \
--export-method development自动化可以传入预先审查的 --export-options ExportOptions.plist。命令使用参数数组调用 xcodebuild,不会拼接 shell 命令。输出目录不得位于源码目录内,且必须不存在或为空。
shield protect -i input.apk -o protected.apk保护级别和载荷压缩选项可以独立选择;后者当前沿用 ai-resistance 参数名:
shield protect -i input.apk -o protected.apk \
--profile balanced \
--ai-resistance balancedcompat:优先兼容 API 19–36,关闭高风险高级变换。balanced:默认策略。未提供 Xop 参数时显示xop-contract-only;显式启用嵌入式 PVM2 时显示xop-pvm2-embedded。strict:要求真实嵌入式 Xop PVM2。GUI 默认使用安装包内置的 Packer,只需提供至少一个自有业务类前缀;CLI 仍需显式传入 Packer 路径。严格模式同时启用资源路径缩短、同类型资源 ID 重排、PAS2 分块认证加密和符合安全策略的业务 ELF 函数区域选择性加密。资源 ID 若出现在 Native/opaque 数据或 packed-switch 中会自动固定;PAS2 会改写可识别的AssetManager.open/openFd/getAssets,以 DEX/ELF 中的路径或目录常量覆盖常见动态拼接,并通过应用私有 overlay 支持常见 NativeAAssetManager读取。缺少必要条件会在变换前失败关闭。该状态为xop-pvm2-embedded,不代表 Hollow、LLVM Native VMP 或完整 Xop RASP 已融合。ai-resistance支持off、balanced、high,映射为 DEXB v6 认证载荷中的 1/2/3 层 Zstandard 压缩。层数不改变包内密钥可离线恢复的边界,也不能作为已验证的抗 AI 语义恢复能力。可选的 PVM2 方法虚拟化让成功转换的方法由 Native 解释器执行,需要单独核验覆盖范围。两者都不能替代服务端授权和密钥保护。
将 Xop PVM2 嵌入 Shellsmith 单 Stub(不引入第二个 Application/JNI 壳):
shield protect -i input.apk -o protected.apk \
--profile balanced --ai-resistance high \
--xop-pvm2-packer /path/to/protector-packer.jar \
--xop-true-vmp-prefix 'Lcom/example/payment/'可重复传入 --xop-true-vmp-prefix。前缀必须指向自有业务类,建议先从少量纯业务方法开始,避免把 Activity、Application、框架回调和大型 SDK 全包虚拟化。所选 Runtime 必须声明 xop_pvm2=true;API19 资源不支持此能力并会在变换前拒绝。
GUI 安装包已经内置 Xop PVM2 Packer:Packer 路径留空即使用内置版本,无需额外选择文件;“选择自定义 Packer JAR”会覆盖内置版本,“恢复使用内置 Packer”可随时切回。自定义 JAR 会以当前用户权限在本机执行,因此必须来自可信来源,并兼容 pvm2-transform、code.bin v4 容器、PVM2 v8 镜像及 schema 2 方法报告契约(当前运行时也可读取 v7 旧镜像);输出仍会由核心验证。业务类前缀可在“调整设置 → Xop PVM2 方法虚拟化”中用逗号填写,也可仅提供关键方法清单。严格模式要求 PVM2 转换成功率至少达到 70%,并输出选中、尝试、成功、跳过原因及未覆盖指令统计;低于门槛会失败关闭。该比率为成功数除以尝试数,部分提前跳过的方法不进入分母,不能据此声称全部业务或关键方法已获得保护。严格代码保护只有在标准运行时、Java 17+、可用 Packer 和有效选择范围都就绪时才允许开始;路径和业务类名不会出现在脱敏诊断摘要中,摘要只记录 PVM2 是否已配置。
PVM2 自 v7 起已支持普通/复杂条件分支、switch、异常表与 throw、对象/原始数组、标准反射调用所需的 invoke 路径,以及 monitor-enter/exit 同步语义。每次构建会改变虚拟 Opcode、虚拟寄存器映射、立即数编码、Handler 顺序,并从三套 Dispatcher 模板中选择一套;覆盖报告中的 isa 可用于确认变体。仍不满足契约的方法(例如个别 invoke-custom/invoke-polymorphic、超出寄存器或代码预算的方法)必须记入跳过原因,不能当作成功。
为保证音频/视频拖动、解码器状态和框架回调,内置 Packer 对播放器、音频/波形、RecyclerView 适配器、Widget/View/Binding、资源/文件 Helper(兼容历史包名中的 hepler)执行方法兼容检查。涉及框架或对象状态的方法及 Kotlin/R8 合成访问器保留在 ART;符合下文 PVM2 方法级规则的独立计算方法可以转换。逐方法报告保留兼容排除分类。资源 PAS2 同样默认跳过常见音视频扩展名,避免把需要随机访问的媒体流包装成只读顺序流。
这些是按 DEX 描述符、方法指令和 Android 生命周期边界计算的通用规则,不依赖某个业务包名或某个应用的类名。PVM2 对对象接收者执行路径敏感的控制流保护:if-eqz/if-nez 已证明非空的路径可以继续虚拟化,多个路径合流时只保留所有路径都能证明的非空事实;直线调用仍保持 ART 与 PVM2 相同的空接收者异常语义。跨分支或异常边界、又无法证明非空的接收者记为 nullable_receiver 并保留 ART,本地创建且可证明非空的对象仍可继续虚拟化。静态调用不会被误当作需要接收者证明的实例调用。工具对无法证明语义等价的方法失败关闭并保留 ART;这能显著降低兼容风险,但不能对任意第三方 APK、厂商 ROM 或未提供的业务 Native SDK 做绝对“零崩溃”保证,正式发布仍需用目标 APK 和设备矩阵回归。
业务 .so 的 APK 后处理层是“按库策略选择 + ELF 符号函数边界静态加密 + PSO2 认证密钥表 + 私有目录按函数区域解密加载”,能够提高直接静态反汇编成本。任一 ABI 缺少安全函数符号、含不安全重定位、超预算或属于系统/壳/高风险运行库时,整个同名库会跳过并计入报告,避免只加密部分 ABI。它仍是函数粒度的静态保护。
v8 新增经认证的声明参数类型表,修复把 Object 传入的 Integer、Long 等包装引用误拆箱的问题。非空推导同时覆盖真实异常边和 instanceof 成功分支。新产物须配套当前 Packer 与标准运行时,旧 APK 需要重新加固才能获得修复。
关键方法清单中的方法采用 clear_after_use:最后一个递归或并发调用退出后,立即覆写并释放解析出的代码、字符串池和映射等明文;异常退出同样清理,下次调用重新认证解密。普通转换方法采用 bounded_cache,默认最多保留 32 个方法、8 MiB 自有明文存储;在用方法可暂时超出预算。策略随 PVM2 v7 镜像一起加密认证,不由外部报告控制。schema 2 报告的 plaintext_policy 记录实际核验结果,跳过方法为 null。旧打包器、旧运行时或缺少版本声明的资源包会被拒绝,请先执行 make build-stub。这会增加必保热点方法的重复解密成本,仍需在目标设备测量;清理不覆盖交给业务的 Java 对象,也不意味着运行中无法观察明文。
需要真实 Native VMP 时,使用 native-vmp 接入业务 CMake/NDK 编译链:显式 MOCIKA_VMP 函数会在 LLVM bitcode 阶段变为自定义 VM 字节码,原函数体替换为解释器入口;不支持的已标注语义会编译失败。当前真实子集覆盖最多 64 位的整数和 float/double 参数/返回、算术/位运算、比较、分支、switch、循环、PHI、select、标量类型转换、整数 min/max 和融合乘加;指针/内存、通用外部调用、严格浮点环境、半精度/向量、异常、原子与同步仍不在子集内。它不能对 APK 中已有的第三方 ELF 补做 VMP,但可以先对有源码的业务函数做 VMP,再由 strict PSO2 保护最终 .so。
GUI 的系统推荐默认值是“标准运行时 + 兼容环境保护 + balanced 代码保护 + balanced AI”,无需配置 PVM2 即可直接加固。高级设置会持久化;若上次保存了尚未配置完整的 strict 设置,主卡片会显示“使用推荐默认值(可直接加固)”,点击后恢复可用的推荐方案。该操作是显式切换,不会把 strict 静默降级。
如果匹配到类但 PVM2 转换成功数为 0,任务仍会失败,并显示 PVM2_ZERO_METHODS、逐方法清单涉及的类数、方法数及实际跳过原因统计。无 DEX 方法体、初始化器、兼容排除、指令/寄存器等限制分别计数,未知原因不会猜测成指令问题。APK/AAB 输出目录会保留独立的 pvm2-failure-*.json,明确标记 failed,不覆盖成功产物或成功报告。该本地报告包含业务方法标识;“复制诊断摘要”只复制固定原因分类和数量。报告缺失、损坏或保存失败时会明确说明,不把零转换当作成功,也不自动关闭保护。
“第几代”没有统一行业标准。当前能力应按实际范围描述:基础 DEX 加密封装、成功转换方法的 PVM2、构建级多态、资源/asset 与业务 ELF 静态保护,以及可选的源码级标量语义 Native VMP。不能把这些组件的存在等同于整个 APK 达到“3.5 代”。代码保护升级方案把“3.5 代”作为待验收的内部目标,要求关键方法清单、最终产物核验与运行时/性能证据;关键方法清单、产物核验、运行时清理和 Native 构建证据接入已实现,完整设备语义与性能矩阵仍待完成。Native VMP 的通用 C/C++ 语义、Play 内测也未完成,不能把本地结构验证算成真实设备或 Play 证据。
AAB 预检不会把 APK 解包器误用于 AAB:
shield check-aab app.aab输出中的 module_processing=preflight-only 表示尚未执行模块变换;正式 AAB 处理需在 AGP/bundletool 产物阶段完成并通过 split APK 真机验收。
如果本机已经准备好 bundletool 和签名测试证书,可以额外验证 AAB 并生成本地 APKS:
shield check-aab app.aab \
--bundletool /path/to/bundletool.jar \
--apks-output build/app.apks \
--apks-mode universal \
--ks test.jks --ks-alias test --ks-pass "$MOCIKA_SHIELD_KS_PASS"这一步只验证 bundletool/APKS 转换,不执行加固。模块变换必须使用下方
protect-aab,并以其模块报告、Play 内测与设备回归为准。
有连接的测试设备时,可以继续验证 split APK 安装链路:
shield install-apks build/app.apks --bundletool /path/to/bundletool.jarinstall-apks 只负责 bundletool 安装和设备选择,不会绕过签名、模块或运行时门禁。
protect-aab --engine mocika 可处理单 base、install-time/条件/on-demand dynamic-feature,以及 install-time/fast-follow/on-demand Asset Pack。动态功能 DEX 与 base 共用 PVM2 密钥和全局 DEX 编号;dynamic-feature 与 Asset Pack 的 assets 必须全部转为 PAS2 后才会写回模块;dynamic-feature 的独立 lib/<abi>/*.so 会与 base 共用 PSO2 变换和运行时密钥表。fast-follow/on-demand Asset Pack 必须显式声明 --play-delivery-adapter,否则失败关闭。Instant App、dynamic-feature 的 root/ 文件和无法被 PAS2/PSO2 覆盖的模块仍拒绝生成半保护包:
MOCIKA_SHIELD_KS_PASS='upload-keystore密码' \
MOCIKA_SHIELD_KEY_PASS='upload-key密码' \
shield protect-aab \
-i app.aab \
-o app-protected.aab \
--bundletool /path/to/bundletool-all.jar \
--aapt2 "$ANDROID_HOME/build-tools/35.0.0/aapt2" \
--runtime-cert-sha256 "$PLAY_APP_SIGNING_SHA256" \
--ks upload.jks \
--key-alias upload \
--profile strict \
--xop-pvm2-packer /path/to/protector-packer.jar \
--xop-true-vmp-prefix 'Lcom/example/payment/' \
--play-delivery-adapter \
--apks-output build/app.apks该命令会执行 AAB 校验、base APK 加固、模块级 PVM2/PAS2/PSO2 写回、protobuf base 重建、upload key 签名和最终 bundletool 校验。多模块保护要求 --engine mocika --profile strict、PVM2 Packer 和至少一个真实业务类前缀;任一代码、资源或 Native 模块未覆盖都会终止。--runtime-cert-sha256 是最终设备证书绑定,不是 upload key。若只是本地设备实验,可改用 --allow-upload-cert-binding,但该结果不能作为 Play 发布证据。最终仍必须在目标 Play 应用的内部测试轨道验证 Play 应用签名、服务端转换、下载/卸载/更新生命周期和真实 split APK。
延迟 Asset Pack 的业务侧使用稳定类 dev.mocika.shield.loader.MocikaPlayDelivery。scripts/build-stub.sh 会生成 shield-stub/build/outputs/resources/mocika-play-delivery-api.jar,业务工程只允许用 compileOnly(files(".../mocika-play-delivery-api.jar")) 引用;不要把这个 JAR 打进 APK,真实实现会由加固 Stub 注入。Pack 可用后用 openAsset(context, packName, path) 流式读取认证明文,或用 materializeAsset(...) 写入应用私有目录供需要 seek/文件路径的 Native SDK 使用。运行时会反射注册可选的 SplitInstall/AssetPack 完成监听;业务未使用 Play Core 或监听不可用时,在自己的安装 Task 成功回调里调用 MocikaPlayDelivery.refresh(context)。
多模块 AAB 必须让 Shellsmith 使用内嵌 PVM2,在上述命令追加:
--xop-pvm2-packer /path/to/protector-packer.jar \
--xop-true-vmp-prefix 'Lcom/example/payment/'如果要让单 base AAB 走 Xop 的 PVM/Hollow/SO 单壳路径,可把 APK 变换引擎切换为
xop(仍然不能处理 dynamic-feature 或 Asset Pack):
MOCIKA_SHIELD_KS_PASS='上传密钥库密码' \
MOCIKA_SHIELD_KEY_PASS='上传私钥密码' \
shield protect-aab \
-i app.aab -o app-xop-protected.aab \
--engine xop \
--xop-packer /path/to/protector-packer.jar \
--xop-shell-dir /path/to/exportShellFiles \
--xop-profile industry \
--ai-resistance high \
--runtime-cert-sha256 "$PLAY_APP_SIGNING_SHA256" \
--bundletool /path/to/bundletool-all.jar \
--aapt2 "$ANDROID_HOME/build-tools/35.0.0/aapt2" \
--ks upload.jks --key-alias upload这里 Xop 是唯一的 APK 壳引擎,Shellsmith 不会再套一层;--runtime-cert-sha256 必须填写
最终 Play App Signing 证书,而不是 upload key。最终 AAB 仍由本地
bundletool 重建、upload key 签名并校验。该路径同样需要 Play 内部测试和目标设备回归,
且 Xop Packer 默认输出未签名的中间 APK,最终 AAB 签名由本命令完成。
若 --runtime-cert-sha256 与 upload key 指纹相同,可继续加上
--apks-output build/app.apks --install-apks --device-id <serial> --smoke-package <applicationId> 做本地安装和进程存活烟测;也可以配合 --device-spec device-spec.json 只生成目标设备的 split APKS;
若使用 Play App Signing 证书,则本地 APKS 只能做结构验证,不能冒充 Play 设备验证。
如果要同时使用尚未融入 Shellsmith Stub 的 Xop Hollow/Native SO/RASP,应选择 Xop 独立单壳入口,不要先执行 shield protect 再执行 Xop:
shield protect-xop \
-i app.apk \
-o app-xop.apk \
--packer /path/to/protector-packer.jar \
--shell-dir /path/to/exportShellFiles \
--profile industry \
--ai-resistance high \
--ks release.jks \
--key-alias releaseprotect-xop 默认要求 keystore、alias 和密码,先让 Xop 按最终证书绑定,再签出可安装 APK;密码建议通过 MOCIKA_SHIELD_KS_PASS / MOCIKA_SHIELD_KEY_PASS 传入。只有内部调试才使用 --allow-unsigned。它会拒绝已含 Shellsmith/Xop 载荷的 APK;该入口的生命周期和回退矩阵由 Xop 负责。只需 PVM2 且要求 Shellsmith 单 Stub 时,使用前文 --xop-pvm2-packer 路径。
运行 CLI 前请先确认本机已安装完整 JDK 8+,且 java、keytool 可执行。
详细日志输出:
shield protect -v -i input.apk -o protected.apk签名命令会先执行内置 ZIP 对齐,再调用发布包中的 apksigner.jar:
MOCIKA_SHIELD_KS_PASS='keystore密码' \
MOCIKA_SHIELD_KEY_PASS='key密码' \
shield sign \
-i protected.apk \
-o protected-signed.apk \
--ks release.jks \
--key-alias release未设置 MOCIKA_SHIELD_KEY_PASS 时,Key 密码默认沿用 Keystore 密码。也可以使用 --ks-pass 和 --key-pass 显式传入,但自动化环境优先使用环境变量,避免密码直接出现在命令历史中。
CLI 人工配置建议固定命名为 shield-cli.toml,与 GUI 自动维护的 config.toml 完全独立。当前格式版本为 1:
schema_version = 1
[protect]
input = "input.apk"
output = "build/protected.apk"
environment_policy = "compatible"
profile = "balanced"
ai_resistance = "balanced"
[sign]
input = "build/protected.apk"
output = "build/protected-signed.apk"
keystore = "release.jks"
key_alias = "release"
keystore_type = "jks"
v1 = true
v2 = true
v3 = true
v4 = false配置中的相对路径以配置文件所在目录为基准。命令行参数优先于配置文件:
shield --config shield-cli.toml protect
MOCIKA_SHIELD_KS_PASS='keystore密码' shield --config shield-cli.toml sign
shield --config shield-cli.toml protect -i another.apk -o another-protected.apk配置文件不接受密码字段,密码只能通过环境变量或当前命令参数提供;CLI 不会把密码写入进度、错误或调试输出。
protect、sign 增加 --json 后,每行输出一个独立 JSON 事件,事件类型固定为 progress、done 或 error。原有 --json-progress 继续作为 protect --json 的兼容别名。
- 成功退出码为
0,并以done事件结束。 - 参数、配置、加固、对齐或签名失败的退出码为
1。 - JSON 模式下错误写入标准输出的
error事件;普通模式错误写入标准错误。 - 调试日志不会混入 JSON 标准输出。
加固完成后 APK 未签名,需手动签名后才能安装:
# 1. 加固
shield protect -i input.apk -o protected.apk
# 2. 签名(无需额外执行 zipalign)
MOCIKA_SHIELD_KS_PASS='keystore密码' \
shield sign -i protected.apk -o protected-signed.apk \
--ks keystore.jks --key-alias alias
# 3. 安装
adb install -r protected-signed.apkshield --help
shield --version# 查看 DEX 与 Native 库条目;壳库可能使用任务生成的别名
unzip -l protected.apk | grep -E 'lib/|classes.*\.dex'应看到:
lib/<abi>/*.so— 输出所需 ABI 的业务库与壳库;壳库文件名不应假定固定为libmocikashield.soclasses.dex— 壳 DEX,末尾追加加密载荷;静态工具不展示载荷不代表载荷无法被发现或提取
条目存在只能验证结构,不能代替签名验证与设备安装、启动测试。
# 对比体积(off/balanced/high 的压缩层数会影响最终大小和首次加载成本)
ls -lh input.apk protected.apk- 发布包:jar 已内置,确保发布包目录结构完整(
lib/、resources/在bin/同级父目录下) - 开发环境:先执行
make build-stub,jar 在项目根tools/目录下
-
查看日志:
adb logcat | grep -E "AndroidRuntime|ax|dx|lx|rx|e[1-4]"
当前壳层日志 tag 已做弱特征化处理,常见 tag 为
ax(StubApp)、dx(DEX 注入)、lx(Ld)、rx(ARouterCompat)。 -
确认未用未签名 APK 加固(必须先签名再加固):
java -jar apksigner.jar verify input.apk
apksigner verify退出码为0表示 APK 已签名;V2/V3/V4 签名不一定会在META-INF/下留下证书文件。 -
确认设备架构与注入的 so 匹配:
unzip -l protected.apk | grep libmocikashield.so adb shell getprop ro.product.cpu.abi -
标准模式按 Android 5.0(API 21)及以上设计:API 21、23 已通过官方 ARM64 模拟器回归,Android 6.0 工控设备已验证首次安装、清除数据、覆盖安装、多 DEX、Native 库和主要业务功能;Android 4.4(API 19~20)须选择“Android 4.4 工控兼容”模式,当前已验证 Android 4.4.2
armeabi-v7a/NEON 工控设备
不可以。GUI 会在选择文件时提示,核心加固入口也会在解包和创建输出前再次检测,因此 GUI 和 CLI 都无法对已加固 APK 重复操作。请始终使用原始未加固的 APK。
GUI 只维护一份全局证书状态。证书页保存、删除或切换默认证书后,会同时更新内存状态和本地 shield.db,加固页、签名页会立即复用最新证书列表。
如果需要在 GitHub issue 中反馈加固、签名或环境检测问题,建议直接在 设置 → 问题反馈 中提交:填写表单后 Bug 反馈的诊断信息会自动附带,发送前可以预览反馈正文与诊断信息。诊断信息只包含版本、平台、Java 状态、工具状态和配置/数据目录可用性,不包含 APK 路径、证书路径、密码或完整用户目录。服务端不可用时,软件会提供在浏览器打开预填 issue 页面的入口。
DEX 文件经 Zstd 压缩后体积通常会明显减小;high 会再增加压缩层,实际体积和启动耗时应以目标 APK/设备实测为准。
典型压缩率(Zstd level 19):
| 文件 | 原始大小 | 压缩后 | 压缩率 |
|---|---|---|---|
| classes.dex | 30 MB | 4.2 MB | 14% |
| classes2.dex | 12 MB | 3.7 MB | 30% |
| classes3.dex | 6.7 MB | 1.9 MB | 29% |
- 首次启动额外耗时:取决于 AI 抵抗等级(单层/双层/三层解压、JNI 解密和缓存策略),必须用目标设备实测
- Runtime 内存占用:约 1–2 MB
以下截图使用当前 Shellsmith 界面,具体选项以当前版本为准。
类前缀选择可以继续使用,也可以通过 --pvm2-required-methods methods.tsv 单独指定必保方法。UTF-8 清单允许空行和 # 注释,模块名与签名之间使用一个制表符:
base Lcom/acme/license/Verifier;->verify([B)Z
feature_rules Lcom/acme/rules/Calculator;->score(II)I
普通 APK 的模块名为 base;AAB 填实际模块名。方法签名必须与待处理 DEX 一致(包括 R8 后名称、参数及返回类型),示例不能直接代替项目清单。重复、格式错误、模块/方法未命中、不能转换或产物核验失败都会终止。清单与类前缀取并集,必保方法必须全部通过,其他方法的跳过原因保留在报告中。
shield protect --input input.apk --output protected.apk \
--xop-pvm2-packer tools/xop-pvm2-packer.jar \
--pvm2-required-methods methods.tsvprotect-aab 接受同一参数,其他 AAB 签名/工具参数保持原用法。GUI 在 PVM2 设置中选择“关键方法清单”。API19 兼容资源仍不支持 PVM2。
启用 PVM2 的成功输出旁会生成 protected.apk.protection.json 或 protected.aab.protection.json。统计分别展示转换成功率、选中方法覆盖率、原始指令字节覆盖率和必保方法覆盖率;未声明必保方法时该指标为 null,不记为 100%。这些百分比仅针对选择范围,不代表整个应用。报告包含逐方法原因、最终索引与产物摘要,不包含密钥或明文镜像,也不进入安装包。
选择范围在兼容性过滤之前统计。UI/导航、数据/资源辅助和媒体命名不再直接排除整类:没有对象状态访问、外部调用或同步的独立方法,可以继续进入 PVM2 指令与产物检查。支持基本类型计算,以及对象/数组参数未使用、引用透传、空值分支和引用身份比较;引用参数不会再仅因其类型被排除,但数组元素和字段访问仍不在这一兼容放行范围内。私有、静态和实例方法适用相同的方法体检查;继承父类或实现接口本身不再排除普通实例方法。跳板保留原声明、访问标志、参数与接收者,虚方法分派仍由 ART 完成;hashCode/finalize 等特殊对象契约仍保守保留。分支、循环和数值运算仍须通过现有编译器检查,不能只凭命名认定可转换。
独立方法中的异常处理不再仅因存在异常表而被排除。捕获、异常透传、重新抛出和不访问外部状态的清理逻辑继续经过异常表映射、控制流及指令检查;throw null 产生可被捕获的 NullPointerException。这不意味着任意 try/catch/finally 都受支持:异常区中的外部调用、字段、数组元素或同步仍受上述限制。
构造器、静态初始化器、生成桥接/合成方法和仍涉及框架状态的候选保持原兼容边界;放行继承类的独立方法不等于放行包含 invoke-super 等外部调用的方法体。跳过项仍计入覆盖率分母,并保留 ui_runtime_glue、compiler_generated_bridge、data_resource_runtime_glue 或 playback_compatibility 等实际分类。精确必保清单同样受方法兼容检查约束,必保项被排除时任务失败,不会自动降级。所有候选都不可转换时仍返回 PVM2_ZERO_METHODS,不会把零转换记为成功。这些规则不代表已识别应用全部关键业务;完整覆盖率需用配套的新打包器和运行时重新生成。
兼容排除的本地原因带有首个阻断条件,例如 ui_runtime_glue:virtual_contract;脱敏摘要分别统计特殊对象方法或虚方法契约未验证、同步方法及叶子方法白名单之外的指令,并兼容旧打包器返回的异常区排除原因。它们表示准入限制,不能据此认定方法一定是生命周期回调。旧报告没有细分信息时仍按原分类展示,不能反推具体方法体。基础预检通过也不代表 PVM2 方法覆盖已经通过。
只有一条 return 的参数透传方法同样可转换,包括对象、数组及基本类型/宽值。PVM2 重建完整方法体,不再沿用旧式原地回填的最小字节数限制;最终跳板与加密镜像仍必须通过产物校验。
严格模式的 70% 转换成功率门槛保持原口径:类兼容预筛排除项不算编译尝试,媒体准入失败仍计入。该指标与完整选择范围覆盖率分别报告;例如 1 个计算方法转换、1 个界面回调保留时,转换成功率可以为 100%,选中方法覆盖率仍只有 50%。
使用 shield sign 或 GUI 自动签名时,公共签名流程会重新比对 DEX 并更新最终文件摘要。另用外部签名工具会改变文件摘要,原报告不再对应签名后的文件。报告为本地构建记录,不是不可伪造的安全认证。新能力要求从当前源码重建的 Packer(make build-pvm2),旧 JAR 即使镜像版本相同也会被明确拒绝。
有 C/C++ 源码的项目先按 Native VMP SDK 接入业务构建,再用
--native-vmp-evidence native-evidence.tsv 将链接报告与待加固库绑定。该参数不会对已有
第三方二进制补做虚拟化。UTF-8 清单每行两列,中间为真实制表符:
base/lib/arm64-v8a/libbusiness.so build/arm64-v8a/libbusiness.so.native-vmp.json
feature_rules/lib/x86_64/librules.so build/x86_64/librules.so.native-vmp.json
APK 只填 base,AAB 填实际模块;不同 ABI 各用对应报告。报告路径相对清单目录解析,
也可用绝对路径。要求 SDK schema 2 链接报告,旧报告需要重新生成。重复/缺失条目、
错误 ABI、修改过的库和排除必验 ABI 均会终止。
shield protect --input input.apk --output protected.apk \
--native-vmp-evidence native-evidence.tsvAPK 的 shield-cli.toml 可在 [protect] 设置 native_vmp_evidence,相对配置路径基于
配置文件目录。protect-aab --engine mocika 同样接受此参数;多模块仍要求既有 strict、
PVM2 与模块覆盖条件。GUI 的 APK/AAB 页均提供“Native 构建证据清单(可选)”选择入口。
普通 APK 可只核验 Native 证据而不启用 PVM2;叠加 PSO2 时沿用 strict + PVM2 配置。
统一 .protection.json 的 native_vmp 记录输入、输出库及构建报告摘要。PSO2 改写库时
必须通过完整还原核验,并绑定密钥表摘要。后续打包、AAB 重组和 Shellsmith 签名重新比对
这些产物。清单以外的库不算 Native VMP 覆盖;构建核验成功仍保留
execution=not_recorded,设备执行结果须独立验证。
详细范围、运行时待办和设备验收见 代码保护升级方案。
首次加固时,Shellsmith 按“应用包名 + 运行时绑定证书 SHA-256”自动创建本机项目种子。
以后 GUI、CLI 和 AAB 加固自动复用这个身份,每次构建再用独立随机盐和 HKDF-SHA256
派生构建材料,用于既有 DEX、资源、SO 与 PVM2 保护链路。无需联网、选择密钥文件或
给手机导入激活资料。APK 的 .protection.json 会记录公开项目身份、构建盐和交付模式,
不记录项目种子。LLVM Native VMP 仍需上述源码接入,不会因为有项目身份而自动覆盖预编译 SO。
在“设置 → 项目专属保护”可以查看项目身份与证书,并导出或恢复备份。
种子按既有 enc:v1 方案存入应用数据目录的 shield.db,不写入源码仓库;macOS 默认路径为
~/Library/Application Support/dev.mocika.shield-gui/。并发首次加固只创建一个身份,损坏记录会
终止构建,不会悄悄生成替代种子。同身份的有效备份可修复损坏密文;无法识别身份的记录
仍会拒绝覆盖。换电脑后,先恢复备份即可沿用同一身份。
备份包含私有种子,不能公开或提交到 Git;导出拒绝覆盖已有文件,恢复拒绝覆盖同一包名和
证书下的不同身份。存储加密沿用本地账户/路径派生机制,不抵抗已控制电脑账户的攻击者。
这里采用“手机安装即用”的交付方式:独立项目种子不随 APK 分发,但运行所需的派生材料 仍有包内恢复路径。项目隔离与每次构建变化不代表 APK 不可静态还原,也不代表全部方法 已虚拟化;覆盖和抗还原效果仍需按每个实际产物核验。
