更新记录
1.0.4(2026-10-14)
应用多开检测
1.0.3(2026-10-13)
修复bug
1.0.2(2026-09-11)
优化模拟器检测功能
查看更多平台兼容性
uni-app(3.8.6)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | × | × | √ | √ | 5.0 | 12 | × |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × | × | × | × |
uni-app x(4.0)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | - | - | - | - |
其他
| 多语言 | 暗黑模式 | 宽屏模式 | 蒸汽模式 |
|---|---|---|---|
| × | × | × | √ |
xiake-uts-harden · APP 运行时自保护哨兵
一个基于 uni-app UTS 原生插件的 APP 运行时安全自检与加固 SDK。在应用运行阶段持续检测设备是否处于被调试、Root/越狱、模拟器、Hook 框架等风险环境,并支持 APK 签名校验与调试标志检测,帮助提升逆向与重打包成本。
重要声明:本插件提供的是运行时防护 + 提高逆向门槛,无法让 APK 达到“绝对不可反编译”。如需更高安全等级,请配合 ProGuard/R8 代码混淆、商业加固方案(梆梆/360/腾讯/网易易盾/爱加密等)以及将核心敏感逻辑放到服务端。
插件测试使用方法
从插件市场「试用」获取本插件后,请按以下步骤在本地项目中跑通验证。
- 使用HBuilderX导入示例项目
- 选择试用:在插件市场点击「试用」,绑定要试用的项目 appid。
- 下载到本地项目:选择绑定好的 appid 后,将插件下载并导入到对应的本地项目中。
- 引入插件:参照本文档的「快速开始」,在业务代码中先引入插件 API:
import { initHarden, hardenCheck, startMonitor, stopMonitor } from '@/uni_modules/xiake-uts-harden'注意:必须先引入插件,否则后续打包的基座中不会包含本插件的原生能力。
- 制作自定义基座:
发行→云打包→ 选择「制作基座」→ 点击打包,等待基座制作完成。 - 运行在手机上:
运行→运行到手机或模拟器→运行到 Android App 基座→ 选择「使用自定义基座运行」→ 选择你的手机 → 点击运行。 - 卸载旧基座:若之前安装过旧的自定义基座,请先卸载手机上原有的基座,再安装新基座运行,避免出现「基座不匹配」或插件未生效的情况。
⚠️ 本插件依赖原生能力(
libharden.so),必须使用自定义基座运行,直接用标准基座或 HBuilderX 内置调试运行会导致检测项无法生效。
功能特性
- 反调试:检测 APP 是否正在被调试器附加(Android
/proc/self/statusTracerPid +Debug.isDebuggerConnected;iOS 进程父子关系)。 - Root / 越狱检测:检查常见 Root 管理器、su 路径、Magisk 包名与 test-keys 等特征(Android);检查 Cydia、MobileSubstrate 路径与 URL Scheme(iOS)。
- 模拟器识别:覆盖主流模拟器指纹,包括 x86 架构、goldfish/ranchu、QEMU/VBox、特殊 Build.HARDWARE、IMEI 异常等。
- Hook 框架检测:识别 Frida、Xposed、LSPosed、Substrate 等常见 Hook 框架特征。
- 签名 / 重打包校验:将运行期 APK 证书 SHA-256 与预期值比对,发现重打包或签名异常。
- 篡改 / 调试标志检测:检查 release 包是否意外开启
android:debuggable。 - 应用多开 / 虚拟容器检测:识别 App 被克隆到多开分身、平行空间、VirtualApp 系(太极阴 / 应用转生)、企业工作资料等虚拟环境运行,并区分多开类型(
virtual_app/container/oem_dual/work_profile)。 - 定时持续监控:支持按设定周期轮询检测,命中风险时通过回调上报,并可配置自动退出。
- NDK 原生加固(Android):核心检测下沉到
libharden.so(C/C++),增强对抗 Java 层 Hook 与反编译能力。
平台支持
| 平台 | 支持情况 | 最低系统版本 |
|---|---|---|
| uni-app App Android | ✅ 支持 | Android 5.0(API 21) |
| uni-app App iOS | ⚠️ 基础支持 | iOS 9.0 |
| 微信小程序 / H5 / 其他小程序 | ❌ 不支持 | — |
iOS 当前为基础检测阶段,反调试、签名校验等完整能力将在后续版本深化。
安装
- 将本插件导入到项目根目录的
uni_modules/下。 - 在
manifest.json→App 模块配置中确认已勾选对应原生模块。 - Android 端已预置 4 个 ABI 的
libharden.so(armeabi-v7a/arm64-v8a/x86/x86_64),无需额外配置即可使用。 - 必须使用自定义云基座真机运行验证(标准基座与内置调试不含本插件原生能力)。完整流程见上方「插件测试使用方法」。
快速开始
import { initHarden, hardenCheck, startMonitor, stopMonitor } from '@/uni_modules/xiake-uts-harden'
// 1. 初始化(expectedSignatureSha256 不传或为空则跳过签名比对)
initHarden({
expectedSignatureSha256: '', // 你的发布证书 SHA-256,去掉冒号、小写十六进制
exitOnViolation: false, // true=命中风险直接退出 App;false=仅回调/上报
checks: { // 缺省全部开启,可按需关闭
debug: true,
root: true,
emulator: true,
hook: true,
signature: true,
tamper: true,
clone: true
}
})
// 2. 一次性体检
const report = hardenCheck()
console.log('综合安全:', report.safe)
// report.safe 为 false 表示至少命中一项风险
// 3. 持续监控(原生逐条回调)
startMonitor({
intervalMs: 2000,
onViolation: (v) => {
// v 为单项违规项(HardenViolation),本轮每个违规项各回调一次
console.warn(`风险项: ${v.item}, 详情: ${v.detail}`)
}
})
// 4. 停止持续监控
// stopMonitor()
API 文档
initHarden(options?: HardenOptions): void
初始化插件。建议在整个应用生命周期内尽早调用(如 App.vue 的 onLaunch)。
type HardenOptions = {
/** 期望的 APK 证书 SHA-256(去掉冒号、小写十六进制)。不传或为空则跳过签名比对 */
expectedSignatureSha256?: string,
/** 命中风险是否直接退出 App,默认 false */
exitOnViolation?: boolean,
/** 各检测项开关,缺省全部开启 */
checks?: {
debug?: boolean,
root?: boolean,
emulator?: boolean,
hook?: boolean,
signature?: boolean,
tamper?: boolean,
clone?: boolean
}
}
hardenCheck(): HardenReport
执行一次性完整检测,返回结构化报告。
type HardenReport = {
safe: boolean, // 综合是否安全
debug: HardenItemResult,
root: HardenItemResult,
emulator: HardenItemResult,
hook: HardenItemResult,
signature: HardenItemResult,
tamper: HardenItemResult,
clone?: HardenItemResult, // 多开/虚拟容器检测项(开启 clone 时返回)
cloneType?: string, // 多开分类:virtual_app / container / oem_dual / work_profile,空串=命中但未归类
cloneDetail?: string // 多开命中的原始证据串(如 userid:10;encloser:com.lbe.parallel.intl;clone:libvirtual.so;)
}
type HardenItemResult = {
passed: boolean, // 是否通过(未命中风险)
risk: boolean, // 是否命中风险
detail: string // 检测详情说明
}
startMonitor(options?: HardenMonitorOptions): void
启动定时持续监控。每轮检测完成后,对本轮的每个违规项逐个回调一次 onViolation(v)(v 为单项 HardenViolation);若 initHarden 时设置 exitOnViolation: true,命中后还会自动退出 App。未命中风险的轮次不回调。
type HardenMonitorOptions = {
/** 检测周期,单位毫秒,默认 2000 */
intervalMs?: number,
/**
* 命中风险时的回调,对本轮每个违规项各回调一次。
* ⚠️ 回调参数务必保持单项对象类型(HardenViolation),勿改为数组(HardenViolation[]):
* 数组类型会导致 UTS 的 @UTSJS.keepAlive 回调保留机制失效,回调触发一次后即被回收。
*/
onViolation?: (v: HardenViolation) => void
}
type HardenViolation = {
item: string, // 风险项,如 'debug' | 'root' | 'emulator' | 'hook' | 'signature' | 'tamper' | 'clone'
detail: string // 详情说明
}
stopMonitor(): void
停止持续监控,释放原生定时器与回调。
检测项说明
| 模块 | Android 检测内容 | iOS 检测内容 |
|---|---|---|
| 反调试 | /proc/self/status TracerPid、Debug.isDebuggerConnected |
getppid() !== 1 等进程关系 |
| Root / 越狱 | su/Magisk 路径、root 应用包名、test-keys、可执行权限 | Cydia、MobileSubstrate 路径与 URL Scheme |
| 模拟器 | Build.HARDWARE/PRODUCT/DEVICE 指纹、x86 架构、IMEI 异常、QEMU/VBox 特征文件 | SIMULATOR_DEVICE_NAME 等环境变量 |
| Hook 框架 | Frida 进程/库、Xposed/LSPosed/Substrate 包名与文件 | MobileSubstrate 目录特征 |
| 签名 / 重打包 | APK 证书 SHA-256 比对 | 后续版本支持 |
| 篡改 / 调试标志 | release 包下 debuggable 标志检查 |
后续版本支持 |
| 多开 / 虚拟容器 | userid 非 0、数据目录 /data/user/<非0>/、数据目录宿主包名 ≠ 自身、cmdline 命中容器包名、codePath/mountinfo 命中、maps 命中 VirtualApp 系 so(详情见下节) |
后续版本支持 |
应用多开 / 虚拟容器检测
某些业务场景(如营销防刷、账号风控、付费校验)需要识别 App 是否运行在「被多开/被虚拟化」的环境中。本插件通过 6 个维度综合判定,并给出 多开类型分类,便于业务侧差异化处理。
判定维度(Android)
- 多用户 / userId:
Process.myUid() >= 100000(uid = userId×100000 + appId,主用户 uid < 100000)或数据目录落在/data/user/<非0>/(厂商官方多开、工作资料的唯一可靠信号,此时包名与 cmdline 往往不变,无法靠包名区分)。 - cmdline 校验:
/proc/self/cmdline真实进程名命中已知多开/容器包名(虚拟容器常伪造包名)。注意:DCloud 运行时进程名与包名可能合法不一致(如uni.app.<appid>),单独不一致不判风险,仅记参考信息。 2.5. 数据目录宿主包名校验(通用):提取 App 自身getFilesDir()路径顶层宿主包名,若 ≠ 自身包名(如/data/user/0/com.lbe.parallel.intl/.../files),说明运行在虚拟化容器内(VirtualApp / MultiDroid 引擎)。该维度不依赖已知包名,可通用覆盖第三方多开/双开助手,是比包名白名单更稳的兜底。 - 已知多开/容器包名(参考信号):设备上已安装 Parallel Space、双开助手、LBE 平行空间(含
com.lbe.parallel/com.lbe.parallel.intl)、应用转生等。注意:已安装 ≠ 本 App 被多开(如模拟器里装过多开工具但直接运行本 App),该维度仅记pkginst:参考信息、不单独判风险,只在其它强证据命中时辅助cloneType分类。 - codePath 命中:
getPackageCodePath()包含容器包名(精确匹配,不使用模糊词以避免误报)。 - mountinfo 命中:
/proc/self/mountinfo包含容器包名挂载点。 - maps 特征:
/proc/self/maps命中 VirtualApp 系专属 so/框架(如libvirtual.so、libva++.so、virtualhook、VirtualXposed、io.virtualapp)。
cloneType 分类口径
| cloneType | 含义 | 判定依据(命中即判,优先级从高到低) | 典型样本 |
|---|---|---|---|
virtual_app |
VirtualApp 系(同引擎伪造) | libvirtual.so / libva++.so / virtualhook / VirtualXposed / cmdline:io.virtualapp / pkginst:io.virtualapp / pkginst:com.taichi |
太极阴、应用转生、VirtualXposed、平行匣 |
container |
第三方独立虚拟容器 | pkginst/cmdline 命中平行空间(含 LBE com.lbe.parallel / com.lbe.parallel.intl)、双开助手、LBE 平行空间 |
Parallel Space、双开助手、LBE 平行空间 |
work_profile |
企业工作资料 / MDM 多用户 | workprofile:1 |
企业 MDM 工作资料 |
oem_dual |
厂商官方多开(真多用户) | userid:<非0> 或 datapath:/data/user/<非0>/ |
小米应用双开、手机分身、华为隐私空间、三星安全文件夹、OV 分身 |
优先级:
virtual_app>container>work_profile>oem_dual。当cloneType为空串但clone.risk=true时,表示命中了证据但未归入上述四类,可结合cloneDetail自行判断。
业务用法示例
const report = hardenCheck()
if (report.clone != null && report.clone.risk) {
console.warn(`检测到多开环境: type=${report.cloneType}, detail=${report.cloneDetail}`)
// 按 cloneType 差异化处理,例如 virtual_app/container 直接拦截,oem_dual 仅做风控标记
}
配置签名 SHA-256
在 HBuilderX 中打开项目 → manifest.json → App 常用设置 → 查看/设置签名证书。获取证书 SHA-256 后,去掉所有冒号并转为小写,填入 expectedSignatureSha256。
示例:
initHarden({
expectedSignatureSha256: 'a1b2c3d4e5f6...', // 64 位小写十六进制,无冒号
})
最佳实践
- 尽早初始化:建议在
App.vue的onLaunch中调用initHarden,再做一次性hardenCheck。 - 关键页面二次校验:在登录、支付、核心功能入口等位置再次调用
hardenCheck()。 - 持续监控 + 埋点:
startMonitor用于高敏感业务场景,命中风险时上报服务端并记录上下文。 - 不要硬编码敏感逻辑:本插件仅做环境检测,业务核心逻辑仍应放在服务端或配合商业加固。
- 真机验证:检测项依赖原生能力,务必使用自定义云基座或真机包测试,不要只依赖模拟器/HBuilderX 内置调试。
常见问题
Q:签名一直不一致怎么办?
A:请确认 expectedSignatureSha256 已去掉冒号并转为小写。本插件内部使用 split(':').join('').toLowerCase() 做归一化比对。不同签名证书(测试证书 / 发布证书 / 云打包证书)的 SHA-256 也不同,请使用与运行包一致的证书。
Q:持续监控提示“回调函数已释放”?
A:最常见原因是回调参数被改成了数组类型(HardenViolation[])——实测这会让 UTS 的 @UTSJS.keepAlive 保留机制失效,回调触发一次后即被回收。请保持回调签名为单项对象 HardenViolation(本插件 1.0.4 已固定为该形式)。其次确认 HBuilderX 版本:@UTSJS.keepAlive 需 4.27+;若版本较低,可退而用 JS 侧 setInterval 轮询 hardenCheck()(同步导出,不依赖回调保留)。
Q:持续监控只收到第一个风险项 / 监控跑几轮就不再更新?
A:同样先排查回调签名是否为数组类型(见上一条)。此外本插件已加固:检测与回调均包在 try/catch 中,下一轮调度写在 finally,即使单轮检测或回调抛异常,监控循环也不会中断。
Q:iOS 支持哪些检测? A:iOS 当前为基础阶段,支持越狱与模拟器基础识别;完整反调试、签名校验等将在后续版本完成。
Q:多开检测会误伤正常用户吗?
A:检测严格采用「完整包名 / 特定 so / 非 0 userId / 数据目录宿主包名」等硬证据,不使用 unknown、memu 等模糊关键词,避免对华为等真机造成误报。两类常见干扰已排除:① DCloud 运行时进程名(uni.app.<appid>)与包名不一致属正常现象,不判风险;② 设备上 merely 安装过多开工具(如模拟器里装了平行空间)只记 pkginst: 参考信息,不代表本 App 被多开、不会单独判风险。厂商官方多开(如小米应用双开)仅通过 userId 判定,不影响同包名正常用户的识别。如担心误伤,可先用 clone: true 跑监控上报 cloneType,确认无误后再做业务拦截。
隐私与权限
- 本插件仅在本地读取设备环境与 APK 元数据,不上传任何数据。
- 不需要额外系统权限。

收藏人数:
购买源码授权版(
试用
使用 HBuilder 导入示例项目
赞赏(0)
下载 29
赞赏 0
下载 12716117
赞赏 1958
赞赏
京公网安备:11010802035340号