更新记录

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/腾讯/网易易盾/爱加密等)以及将核心敏感逻辑放到服务端。


插件测试使用方法

从插件市场「试用」获取本插件后,请按以下步骤在本地项目中跑通验证。

  1. 使用HBuilderX导入示例项目
  2. 选择试用:在插件市场点击「试用」,绑定要试用的项目 appid。
  3. 下载到本地项目:选择绑定好的 appid 后,将插件下载并导入到对应的本地项目中。
  4. 引入插件:参照本文档的「快速开始」,在业务代码中先引入插件 API:
    import { initHarden, hardenCheck, startMonitor, stopMonitor } from '@/uni_modules/xiake-uts-harden'

    注意:必须先引入插件,否则后续打包的基座中不会包含本插件的原生能力。

  5. 制作自定义基座:发行 → 云打包 → 选择「制作基座」→ 点击打包,等待基座制作完成。
  6. 运行在手机上:运行 → 运行到手机或模拟器 → 运行到 Android App 基座 → 选择「使用自定义基座运行」→ 选择你的手机 → 点击运行。
  7. 卸载旧基座:若之前安装过旧的自定义基座,请先卸载手机上原有的基座,再安装新基座运行,避免出现「基座不匹配」或插件未生效的情况。

⚠️ 本插件依赖原生能力(libharden.so),必须使用自定义基座运行,直接用标准基座或 HBuilderX 内置调试运行会导致检测项无法生效。


功能特性

  • 反调试:检测 APP 是否正在被调试器附加(Android /proc/self/status TracerPid + 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 当前为基础检测阶段,反调试、签名校验等完整能力将在后续版本深化。


安装

  1. 将本插件导入到项目根目录的 uni_modules/ 下。
  2. 在 manifest.json → App 模块配置 中确认已勾选对应原生模块。
  3. Android 端已预置 4 个 ABI 的 libharden.so(armeabi-v7a / arm64-v8a / x86 / x86_64),无需额外配置即可使用。
  4. 必须使用自定义云基座真机运行验证(标准基座与内置调试不含本插件原生能力)。完整流程见上方「插件测试使用方法」。

快速开始

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)

  1. 多用户 / userId:Process.myUid() >= 100000(uid = userId×100000 + appId,主用户 uid < 100000)或数据目录落在 /data/user/<非0>/(厂商官方多开、工作资料的唯一可靠信号,此时包名与 cmdline 往往不变,无法靠包名区分)。
  2. cmdline 校验:/proc/self/cmdline 真实进程名命中已知多开/容器包名(虚拟容器常伪造包名)。注意:DCloud 运行时进程名与包名可能合法不一致(如 uni.app.<appid>),单独不一致不判风险,仅记参考信息。 2.5. 数据目录宿主包名校验(通用):提取 App 自身 getFilesDir() 路径顶层宿主包名,若 ≠ 自身包名(如 /data/user/0/com.lbe.parallel.intl/.../files),说明运行在虚拟化容器内(VirtualApp / MultiDroid 引擎)。该维度不依赖已知包名,可通用覆盖第三方多开/双开助手,是比包名白名单更稳的兜底。
  3. 已知多开/容器包名(参考信号):设备上已安装 Parallel Space、双开助手、LBE 平行空间(含 com.lbe.parallel / com.lbe.parallel.intl)、应用转生等。注意:已安装 ≠ 本 App 被多开(如模拟器里装过多开工具但直接运行本 App),该维度仅记 pkginst: 参考信息、不单独判风险,只在其它强证据命中时辅助 cloneType 分类。
  4. codePath 命中:getPackageCodePath() 包含容器包名(精确匹配,不使用模糊词以避免误报)。
  5. mountinfo 命中:/proc/self/mountinfo 包含容器包名挂载点。
  6. 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 位小写十六进制,无冒号
})

最佳实践

  1. 尽早初始化:建议在 App.vue 的 onLaunch 中调用 initHarden,再做一次性 hardenCheck。
  2. 关键页面二次校验:在登录、支付、核心功能入口等位置再次调用 hardenCheck()。
  3. 持续监控 + 埋点:startMonitor 用于高敏感业务场景,命中风险时上报服务端并记录上下文。
  4. 不要硬编码敏感逻辑:本插件仅做环境检测,业务核心逻辑仍应放在服务端或配合商业加固。
  5. 真机验证:检测项依赖原生能力,务必使用自定义云基座或真机包测试,不要只依赖模拟器/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 元数据,不上传任何数据。
  • 不需要额外系统权限。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

无

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件仅在本地做环境检测,不上传任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

暂无用户评论。