入门
本指南将逐步引导您完成从安装 OZero Security 到应用首个安全功能的整个过程。即使没有安全专业知识,约 3 分钟即可完成基本设置。
概述
OZero Security 通过在一般黑客工具难以访问的 Native C++ 层执行安全逻辑来保护 Unity 游戏。只需在 Unity 编辑器内的仪表板中激活模块,即可运行核心保护功能。无需场景设置或编写额外代码。
- 构建完整性检查(应用篡改检测)
- 速度黑客及时间黑客检测
- 内存注入监控
- 加密的游戏内变量类型(Secure Types)
- 加密的存档文件及 PlayerPrefs
- 激活的检测器将在 SDK 启动时自动准备就绪。无需在场景中放置独立对象或编写重复的初始化代码。
- 安全设置在构建过程中受到保护,因此明文设置不会暴露在一般玩家的发布版本中。
- Native C++ 运行时守卫在托管 Unity 代码之外提供了额外的验证层。
- 检测结果可通过回调、日志和 Pro 遥测进行确认,便于在测试和运营中追踪原因。
1
导入包
打开 Unity 编辑器并导入 OZero Security 包。您可以通过 Unity 包管理器或双击 .unitypackage 文件进行导入。
当出现 Import Unity Package 对话框时,在勾选所有项目的情况下点击 Import。所需的脚本、原生插件和编辑器工具将自动添加。
2
打开仪表板
导入完成后,从 Unity 菜单栏打开 Config Dashboard:
打开 Config Dashboard 后,可以在此屏幕上一次性管理预设、安全模块、许可证和构建完整性设置。无需在 Project 窗口中直接查找并修改文件。
Unity 编辑器菜单说明
OZeroSDK > Security 菜单集中提供 SDK 设置和诊断命令。安全预设有意放在 Config & Dashboard 中应用,而不是放在顶部菜单中,这样您可以在保存前确认实际变更的设置。
| 菜单 | 作用 | 使用场景 |
|---|---|---|
| OZeroSDK > Security > Config & Dashboard | 打开或创建主 OZeroSecurityConfig 资产。 | 首先在这里应用预设、启用模块、配置响应策略并检查构建完整性设置。 |
| OZeroSDK > Security > License > Settings | 打开或创建 OZeroLicenseConfig。 | 用于输入 Standard、Plus 或 Pro 许可证设置、服务器端点和遥测选项。 |
| OZeroSDK > Security > Tools > Check Setup | 在编辑器中诊断常见的项目和发布配置问题。 | 在导入包后、发布构建前,或模块行为不符合预期时运行。 |
| OZeroSDK > Security > Tools > Check Integrity Manifest | 打开 OZero 完整性清单并显示解码后的内容。 | 用于构建完整性故障排查或支持调查。 |
| OZeroSDK > Security > Tools > Bake Security Config Blob | 在 StreamingAssets 中重新生成受保护的安全配置 blob。 | 用于高级调试或 CI 工作流。普通播放器构建会自动 bake。 |
| OZeroSDK > Security > Tools > Bake Assembly Hash | 为最近一次构建输出重新生成 oz_ahash.bin。 | 仅在未重新运行完整构建流水线、只进行了代码重建之后使用。 |
| OZeroSDK > Security > Tools > Keystore SHA Extractor | 从 Android keystore 中提取 SHA-1 和 SHA-256 指纹。 | 在填写 Build Integrity 的 Android 签名指纹时使用。 |
| OZeroSDK > Security > Tools > Add Debug SHA Key to Config | 查找 Android debug keystore,并将其 SHA-256 指纹加入 config。 | 仅用于本地 Android 调试构建。发布构建应使用发布签名密钥指纹。 |
| OZeroSDK > Security > Tools > Steam Anti-Piracy > Scan Steam Redistributable | 扫描 PC 构建或插件文件夹中的 Steam redistributable 文件和已知 emulator artifact。 | 在 Steam 发布打包前,或检查是否包含可疑 Steam 文件时使用。 |
| OZeroSDK > Security > Tools > Check Time.timeScale Usage | 扫描可能与 OZero 时间保护冲突的直接 Time.timeScale 写入代码。 | 在发布前,或 Speed & Time Hack 模块报告项目侧 time-scale 策略问题时运行。 |
3
激活模块
在仪表板内可以查看安全模块列表及切换开关。请激活您要使用的模块。以下是推荐的初始配置。
选择安全预设
首先选择一个预设,然后根据项目进行个别模块调整。对于一般的实时在线游戏,建议从 Standard 开始。这能在保护级别、性能和误报率之间取得最佳平衡。
| 预设 | 推荐用途 | 适用策略摘要 |
|---|---|---|
| Low | 原型、开发版本、初期 QA | 仅保留轻量的核心检查。放宽平台原生检查及强制关闭策略,以免测试环境过早被封锁。 |
| Standard | 大多数发售游戏的推荐默认值 | 启用核心保护套件、启动验证、运行时再验证、模拟器检查以及推荐的 IL2CPP 文件覆盖。是一个平衡了兼容性与保护级别的配置。 |
| Strict | 高风险实时服务、PvP、竞技类构建 | 采用最广泛的覆盖范围,将更多的失败视为致命违规。请在充分测试平台、签名及商店发布流程后再采用。 |
| 模块 | 功能说明 | 是否推荐 |
|---|---|---|
| Build Integrity Validator | 检测应用二进制是否被篡改 | 推荐 |
| Speed Hack Detector | 检测时间操控作弊 | 推荐 |
| Injection Detector | 监控内存 Hook 工具 | 推荐 |
| Install Source Validator | 拦截非法 APK(仅限 Android) | 选择 |
只需在仪表板中开启要使用的模块并保存 OZeroSecurityConfig 资产即可。播放器启动时,SDK 会自动准备已激活的模块。
许可证模型 — Standard / Plus / Pro
OZero Security 提供 Standard、Plus、Pro 三种等级。Standard 模式不与服务器联动,仅使用本地保护功能。Plus 模式在此基础上加入了各项目特定的 Native Variant 包及清单 / Bundle ID 绑定。Pro 模式包含 Plus 的配置,并增加了遥测、签名验证的服务器时间、远程策略、服务器校验以及设备限制等运营功能。
| 项目 | Standard | Plus | Pro |
|---|---|---|---|
| 许可证密钥 | — (无) | OZ-PLS-XXXX ×6 |
OZ-PRO-XXXX ×6 |
| 启动时网络连通 | 无需 — 可离线执行 | 无需运行时服务器 — 仅从门户下载 Variant 即可 | 每设备进行 1 次 POST /v1/activate 后缓存 |
| 10 个保护模块 | 全部 10 个保护模块激活 | 全部 10 个(本地保护模块与 Standard 相同) | 全部 10 个(与 Standard 相同) |
| 原生 Variant | 共用的原生模块 | 各应用特定的 Variant + 清单绑定 | 包含 |
| 云端遥测 | 不发送 | 关闭 (无服务器) | 开启 — 将威胁事件发至 /v1/telemetry |
| 签名时间 (防时钟篡改) | 关闭 — WebTime 仅使用 HTTPS HEAD |
关闭 — 与 Standard 相同 | 开启 — 使用签名的 /v1/time 响应 |
| 设备限制 | 无限制 (无密钥,不强制) | 归属项目的许可证,无运行时设备限制 | 默认 5 台 / 可调节 |
| 源代码权限 | 仅托管 C# | 仅托管 C# | 仅托管 C# |
OZeroLicenseConfig 的服务器功能。
Plus / Pro 许可证密钥注册
Standard 级别无需额外设置。Plus 或 Pro 需要添加 1 个 ScriptableObject 资产并将购买后获得的密钥粘贴进去。Plus 密钥用于分项目的 Variant 校验与门户下载,而 Pro 密钥还会被用于运行时服务器激活。
1. 创建设置资产
打开 Config Dashboard (菜单: OZeroSDK → Security → Config Dashboard) ,在 License & Server 栏目点击 Create OZeroLicenseConfig 按钮。资产会自动生成到正确的 Resources/ 文件夹,无需手动移动。
Assets → Create → OZero → License Config 手动生成。但必须自行确保资产位于 Resources/ 文件夹下并且名称准确为 OZeroLicenseConfig (区分大小写)。
2. 填写 Inspector 字段
| 字段 | 是否必需 | 说明 |
|---|---|---|
| tier | 所有层级 | 在下拉菜单中选择 Standard、Plus、Pro 之一。Standard 使用基本原生模块。Plus 需要与项目相连的 Variant manifest。Pro 在 Plus 基础上提供服务器运营功能。 |
| licenseKey | Plus / Pro | 收到的邮件中的密钥。Plus 密钥采用 OZ-PLS-... 格式,Pro 采用 OZ-PRO-... 格式。如果将密钥留空,即使选了 Plus 或 Pro 也将不启用服务器功能,按 Standard 方式运行。 |
| appIdentifier | 自动传输 | SDK 激活时会将 Unity 的 Application.identifier 作为 appIdentifier 传送。服务器会将此值与许可证绑定的 Bundle/Package ID 进行比对,所以 Player Settings 的 Identifier 必须与签发的密钥匹配。 |
| serverBaseUrl | Plus / Pro | 默认值 https://api.ozero.security — 除非 OZero 支持团队给出了专门的 endpoint 否则请保留原状。在发布构建中必须为 HTTPS 且会自动移除结尾斜杠。 |
| serverPublicKeyHex | Plus / Pro | 用于验证 OZero 许可证服务器响应签名的公钥。请直接粘贴购买邮件中的 64 位 hex 值。建议发布版本中不要将此项留空。 |
| tokenTtlSeconds | 可选 | 在离线状态下能信任缓存激活结果的秒数。默认值 604800 (7 天)。过期后 SDK 仍可继续运行,但至下一次成功激活前,需要连网的专属功能 (遥测/签名时间) 会被关闭。 |
| offlineProPolicyMode | Plus / Pro | 当设备离线时应如何应用带有签名的 Pro 门户屏蔽策略。推荐使用 ApplyCachedBlockPolicies。只有对必须阻止旧版策略的纯在线游戏才使用 RequireFreshPolicy。IgnoreCachedBlockPolicies 仅是针对特殊测试场景的选项,不建议正式版本使用。 |
| activationTimeoutSeconds | 可选 | 等待 /v1/activate 响应的最长时间 (秒)。如果超时则 SDK 会应用缓存的激活信息或回退至 Standard 继续运行。默认 6.0 秒。 |
| enableLog | 可选 | 为 true 时将使用 OZeroSecLog 输出如调用缓存、成功激活、超时、签名不符等步骤日志。如果不希望在发布版显示此类日志可关闭。 |
3. 构建与验证
无需修改代码。应用启动时 SDK 将自动读取 OZeroLicenseConfig 资产。首次执行后,请在 Player 日志中寻找类似于 [OZeroLicense] activated; tier=pro caps=5 的输出。如果配置为了 Pro 却出现了在 Standard 模式下运行的日志,请再三确认资产是否放在 Resources/ 目录下且名为确切的 OZeroLicenseConfig。
服务器激活流程
激活会在应用开启的后台进行。即使服务器响应延迟或临时失败也不会阻断场景加载,并且有缓存即使用之。
引导序列
- SDK 将在应用启动时自动初始化许可证的运行时。
- Standard 与 Plus 将在无运行时服务器调用的状态下继续进行。
- Pro 将在后台发出轻量的激活请求。
- 一旦成功激活,遥测、签名时间以及认证(attestation)等 Pro 服务器功能将变为可用。
- 发生激活失败、过期或超时等情况,它也会以不提示给玩家的形式继续在 Standard 模式下运行。
网络传输数据
激活请求是一个短小的 JSON POST。必须字段是 licenseKey、deviceId、sdkVersion 以及 platform。appIdentifier、companyName、productName、webglOrigin 会在 Unity 端给出非空值时加入。设备 ID 数据来源可借助 OZeroLicenseRuntime.DeviceIdProvider 覆盖。
POST https://api.ozero.security/v1/activate
Content-Type: application/json
{
"licenseKey": "OZ-PRO-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX",
"deviceId": "<DeviceIdProvider result; default SystemInfo.deviceUniqueIdentifier>",
"sdkVersion": "<OZeroSdkVersion.ManagedVersion>",
"platform": "<android | ios | windows | macos | linux | webgl | ...>",
"appIdentifier": "<Application.identifier>",
"companyName": "<Application.companyName>",
"productName": "<Application.productName>",
"webglOrigin": "<WebGL origin only>"
}
服务器以 JSON 格式返回带签名的令牌、确定的层级等级、可使用的权限列表以及过期时间。SDK 会先用提供的公钥来校验响应的签名,而后才会去激活 Pro 功能。
无法使用服务器功能时
服务器维护、网络超时、许可证的过期/暂停/废除或 Bundle ID 不符等问题不会被草率地认定为黑客攻击。在此类情况下,它将停用仅适用于 Pro 的功能而继续常规的防御功能。相对的,明显遭受如版本失配、被封禁、注入以及调试工具等篡改的场合,将遵循已设定的应对策略行动。
await OZeroLicenseRuntime.Initialize();,然后查询 OZeroLicenseRuntime.Entitlement?.cachedAtMillis 的值。如果数值落在几秒前则代表服务器刚作答,否则是在以缓存基础运行。
离线操作
OZero 被设计成无论网络条件如何,都能让玩家运行游戏。具体行为受级别的制约:
Standard — 永远支持离线
Standard 只负责本地防御且无需请求激活或遥测。在不连网时可以照常启动,这也就意味着不能享有特供 Pro 的功能。
Pro — TTL 内的离线运行支持
当某设备成功运行第一次 /v1/activate 后,Pro 激活数据就会保留在 PlayerPrefs (借设备绑定的钥匙加密 — 请参阅下方的缓存保障)。在随后的启用中它将在触发联网前读取留存数据,如此玩家即使断网,SDK 也能获取属于何种层级或拥有何等 Pro 功能的状况。
存下的 Pro 信息在其激落时点起算到指定的 tokenTtlSeconds 前会被采信。默认 7 天 (604800)。当持续断网走完了此时限,被保留的情报会被销毁,直到下次重新完成激活并被转作 Standard 水平运作。探测器则照常,而只有遥测和验证签名时间相关步骤将处于闭塞状态。
Pro — 具备签名的离线拦截策略
遭受连接失效仍带普通保护运行和默许于系统中被拉黑封杀的组件是截然不同的。倘使 Pro 获取成功,服务器会颁发以含签约格式返回的现行屏蔽策略供 SDK 存留。
采用建议的 ApplyCachedBlockPolicies 模式,凡是带有合格签名的策略存续期间,开启着飞行模式运行依旧对已被制裁的散列、SDK版本或是产品版本进行有效的阻挠。因为效能受制于附属时效,若需改变门户拦截规则,必须使之在线认证一回。
| 状态 | 探测器 | 遥测 | Signed Time |
|---|---|---|---|
| 连线,刚完成激活 | 10 项皆起作用 | 开启 | 开启 |
| 离线且 Cache < TTL | 10 项皆起作用 | 暂缓发列 (待连网时传送) | 以 WebTime 协议为依归 |
| 离线且 Cache > TTL | 10 项皆起作用 | 停顿 (下调标准) | 停顿 (下调标准) |
| 无缓存 (首次游玩亦离线) | 10 项皆起作用 | 中止,及至顺利上网 | 中止,及至顺利上网 |
故障排除
大部分许可事件均被安排由 OZeroSecLog 将讯息打进原生的 Debug.Log 中 (借 OZeroSecurityConfig 定制)。于终端中依 [OZeroLicense] 探寻可洞悉起因,另外利用 [OZeroTelemetry] 查询回报实况。以下为典型情况以及相关应对措施:
| 表象 (输出字句) | 可能缘由 | 核实项 |
|---|---|---|
[OZeroLicense] Standard / serverless mode. |
欠缺预设又或指明 tier=Standard,或者密钥一片空白 | 理应令 OZeroLicenseConfig.asset 长驻 Resources/ 深层,名确为该字、层级定在 tier=Pro 且持有妥当未亏的 licenseKey。 |
/v1/activate failed: 401: invalid_key |
键入偏差与或阶层前缀用误 | 回到邮件原始档里头重新拷贝密钥;除了大小写明察秋毫以外,切莫遗漏划线以及确凿开头须是 OZ-PRO-。 |
/v1/activate failed: 403: bundle_mismatch |
appIdentifier 未比对成功 |
系统远端的发放是以专户、专属 Bundle ID 绑约的形式记录。烦请再三检阅 Player Settings 里的属性配置和当时颁赐的资讯同处。 |
activation token signature verification failed |
serverPublicKeyHex 填写出错或逢受 MITM |
对照从电邮取得的原生公钥把 64 码完整对碰,如若仍落得折戟的田地即可高度确信受制于企业拦网或者代理服务了。 |
/v1/activate timed out |
局域延迟及防范墙 | 除非初启动又或苦无纪录方会发作,不然 SDK 有能力自觉倚重过往资料。查清主机否能顺利联络上 https://api.ozero.security/health 并在跨地域慢网下抬高 activationTimeoutSeconds 容限。 |
cached activation past TTL; clearing. |
玩家断连时日大于 TTL | 纯属常态;检测手段不变,惟遥测记录与验证授期会按规矩暂停,至玩家上架前停息,当遇到远行常客可提升 tokenTtlSeconds 放宽。 |
cache hit; tier=pro on a different machine than expected |
机体生物鉴别转移 | 当出现类似操作系统换代等带来标识代码变换情况,那过去储备的信息顿失意义所以只待联机重新执行取权流程。 |
enableLog 关闭。研发日志可能显露防御手法甚至状态详情供人刺探,即便对内品保管用,对大众发行可是多此一举。
项目设置
在调整各个安全模块之前,请先检查影响原生插件、商店构建和平台验证的 Unity Player Settings。
最低构建目标
| 平台 | 最低目标 | 说明 |
|---|---|---|
| iOS | 12.0+ |
在 iOS 构建中,请将 Project Settings > Player > iOS > Target minimum iOS Version 设置为 12.0 或更高。OZero 不会强制覆盖此 PlayerSettings 值,因此您可以根据应用的支持策略进行保留。 |
| Android | API 21+ |
对于 Android 构建,请将 Project Settings > Player > Android > Minimum API Level 设置为 Android 5.0 Lollipop (API level 21) 或更高版本。建议商店发布构建使用 IL2CPP 和 ARM64。 |
Android ProGuard / R8 设置
OZero Security 不需要单独的 Java SDK 包。但是,如果您的 Android 部署版本启用了 Minify、ProGuard 或 R8,则必须保留 Unity Java 桥接以及项目中使用的自定义 Android 桥接类。这样才能确保获取包信息、安装来源、APK 签名证书检查和启动资产加载所需的 JNI 调用在混淆后依然稳定运行。
proguard-user.txt 中。如果不使用 Minify,则无需单独进行 ProGuard 设置。
# OZero Security - Unity Android ProGuard/R8 keep rules
-keep class com.unity3d.player.UnityPlayer { *; }
-keep class com.unity3d.player.UnityPlayerActivity { *; }
-keep class com.unity3d.player.UnityPlayerGameActivity { *; }
-keep class com.unity3d.player.UnityPlayerForActivityOrService { *; }
-keepattributes *Annotation*,InnerClasses,EnclosingMethod,Signature
# If your game adds custom Java/Kotlin bridge classes that OZero or your code
# calls through AndroidJavaClass / AndroidJavaObject, keep those classes too.
# Replace the package below with your own bridge package.
# -keep class com.yourcompany.yourgame.bridge.** { *; }
- 不要重命名、删除或重新打包
libOZeroSecurity.so。将插件保留在Assets/OZeroSDK/Plugins/Android/arm64-v8a下。如果您要分发 32 位版本,也请保留armeabi-v7a。 - 如果您使用 Build Integrity > Check Platform Native 和 Android SHA Keys,请务必在应用 Minify/R8 后,使用最终签名的 APK 或 AAB 进行测试。调试密钥库的指纹与发布密钥库的指纹是不同的。
- 如果只有在开启 Minify 之后,Android 日志中才出现 JNI 查找失败、安装来源检测失败或 APK 签名检查结果为空的情况,请先检查您的自定义桥接的 keep 规则。
- 对于商店分发的构建版本,请基于 IL2CPP、Release 签名、
Android Sha Keys中注册的预期 Android SHA-256 指纹,并在至少一台真机上进行干净运行测试后再做判断。
5
OZeroSecurityConfig 设置
OZeroSecurityConfig ScriptableObject 资产会在包导入时包含。在 Project 窗口中选择它即可查看并调整所有安全模块设置。在运行时通过 OZeroSecurityConfig.Instance 进行访问。
Common Setting
这是全局应用于所有模块的顶级字段。
| 字段 | Type | 默认值 | 说明 |
|---|---|---|---|
| developerSecret | string | — | 用于派生加密密钥的唯一密码短语。请为游戏设置一个唯一值并保密。发布后更改会导致现有存档数据无法读取。 |
| enableLog | bool | false | 开启 Enable Debug Logs 会将 SDK 初始化、设置加载、许可证/遥测流程、检测事件等内部状态输出到 Unity Console 和 Player 日志中。这在开发/QA 阶段有助于查明原因,但可能暴露检测流程和模块状态,建议在生产构建中关闭。 |
| enableFailureDiagnostics | bool | false | 开启 Enable Failure Diagnostics 时,如果发生安全违规,本地诊断文件会保存到 Application.persistentDataPath。因文件内可能包含模块名、哈希、设备状态、安装包名以及部分运行时配置,建议仅在 QA 或客户服务支持时开启。按平台的默认保存位置:
|
Developer Secret。不要使用默认值,发布后请勿更改。
Global Threat Response
决定确认安全威胁后游戏的响应方式。在测试期间请先检查回调和日志,在实际部署构建中请根据项目的运营策略选择给玩家的提示时间和终止策略。
| 字段 | Type | 默认值 | 说明 |
|---|---|---|---|
| forceQuitOnDetection | bool | true | forceQuitOnDetection 决定在检测到确切威胁时 SDK 是否自动终止游戏。关闭后只检查回调和日志,便于 QA,但在实际部署构建中可能导致被绕过的客户端继续运行,请慎重选择。 |
| fatalCallbackGraceSeconds | float | 10 | fatalCallbackGraceSeconds 是在检测到威胁后,游戏侧安全回调向玩家显示提示 UI 的最长容许时间。默认值为 10 秒。设置为 0 时会恢复之前的无提示直接退出行为。 |
构建完整性验证器设置
配置构建完整性检查器,以检测被修改的游戏文件、调试器连接以及异常的运行环境。
| 字段 | Type | 默认值 | 说明 |
|---|---|---|---|
| Activate Build Integrity | checkbox | On | 激活 Build Integrity 模块。 |
| validateOnStartup | bool | true | 游戏启动后立即执行构建完整性检查。 |
| validateInEditor | bool | false | 在 Unity 编辑器中也执行验证(对测试有帮助,建议在常规开发期间关闭)。 |
| enablePeriodicValidation | bool | true | 在游戏运行期间也循环进行完整性验证。如果您的构建不足以通过启动时的单次验证,建议开启此功能。 |
| periodicCheckInterval | float | 300 s | 游戏运行中执行定期安全检查的间隔(秒)。 |
| periodicCheckJitterPercent | float | 35% | 给验证周期添加随机变化,使检查时机更难被预测。公开文档中未提供具体周期与范围,推荐使用默认值。 |
| timingAnomalyConsecutiveRequired | int | 7 | 确定基于时间的异常信号需要累积多少次才判定为调试器时序漂移。强烈的调试器信号可能仍会导致立即失败。 |
| timingAnomalyWindowSeconds | float | 900 s | 用于累加时间异常信号的时间窗。越长容错越高,Strict 使用更短的时间窗。 |
| timingAnomalyFrameHitchSuppressionSeconds | float | 20 s | 在发生了如场景加载、着色器编译、GC 或 OS 调度延迟等大规模帧卡顿后,在一定时间内放宽对基于时间的调试器检测。 |
| checkAssemblyHash | bool | true | 作为构建完整性检查的一部分,验证已编译 DLL 程序集的哈希值。 |
| checkDebugger | bool | true | 在运行时检测进程是否连接了调试器。 |
| failOnDebugBuild | bool | false | 将 Unity 的 Debug 构建视为违规(建议用于发布构建)。 |
| checkPlatformNative | bool | true | 检查是否有在模拟器或异常环境中运行的迹象。 |
| failIfManifestMissing | bool | true | 如果 oz_manifest.ozero 文件丢失或无法读取,则作违规处理。在发布构建中请保持开启,防止缺少清单的构建被部署。 |
| failIfAssemblyHashBlobMissing | bool | true | 如果清单中未捆绑程序集哈希 Blob,则作违规处理。 |
| requireCodeSignature (Windows) | bool | false | 主执行文件必须具有代码签名。仅限 Windows。 |
| blockVirtualMachine (Windows) | bool | false | 阻止游戏在虚拟机内部运行。仅限 Windows。 |
| blockHyperV (Windows) | bool | false | 拦截 Hyper-V VMBus 信号。WSL2、Docker Desktop 或 Windows Sandbox 用户可能也会被阻止,因此仅限在受控环境中审慎使用。 |
| blockNetworkProxies (Windows) | bool | false | 检测疑似网络代理、数据包检测或流量分析工具的运行信号。用于竞技型构建,但请事先测试是否存在误报可能。 |
| blockReverseEngineeringTools (Windows) | bool | false | 检测疑似逆向工程或调试工具的运行信号。请在开发/QA 环境与线上环境分别进行验证。 |
| blockSystemMonitorTools (Windows) | bool | false | 检测疑似进程/系统监控工具的运行信号。请注意普通用户环境中可能存在的误报情况。 |
| il2cppHashGameAssembly | bool | true | 对 Windows IL2CPP 构建的 GameAssembly.dll 进行哈希验证。这是 IL2CPP 文件保护的最低建议项。 |
| il2cppHashGlobalGameManagers | bool | true | 将 globalgamemanagers 添加到 IL2CPP 清单验证范围内。 |
| il2cppHashSharedAssets | bool | true | 将 sharedassets* 文件添加到 IL2CPP 验证范围内。 |
| il2cppHashSceneFiles | bool | true | 将 level* 之类的 Unity 场景文件添加到 IL2CPP 验证范围内。 |
| il2cppHashResourcesAssets | bool | false | 将 resources.assets 添加到 IL2CPP 验证范围内。有助于 Strict 模式,但请先测试补丁流程。 |
| il2cppAdditionalWatchedFiles | List<string> | — | 当项目包含额外的原生 payload 时,指定需要受监控的 Windows IL2CPP 额外输出文件。 |
| blockEmulator (Android) | bool | true | 仅限 Android。将模拟器或不支持的运行时信号视为完整性违规。建议在 QA/模拟器测试期间放宽,而在生产构建中使用更严格的策略。 |
| blockSystemRwMount (Android) | bool | true | 仅限 Android。若系统分区处于可写状态,或有类似的 root mount 状态,将被视为完整性违规。 |
| androidShaKeys | List<string> | — | 预期的 APK 签名证书 SHA-256 指纹列表。如果安装的 APK 没有用这些密钥之一签名,验证将失败(仅限 Android)。 |
| expectedBundleIds (iOS) | List<string> | — | 允许的 iOS Bundle ID 列表。留空则跳过 Bundle ID 检查。 |
| excludedAssemblies | List<string> | — | 要从哈希验证中排除的程序集名称列表(不带 .dll 扩展名)。用于在运行时发生改变的程序集(例如生成的代码)。 |
| checkIntegrityWithServer (Pro) | bool | false | 开启 Pro 服务器 Attestation。客户端请求 nonce 并提交完整性证据后,获取可由游戏服务器或 OZero 服务器校验的签名 OZA 令牌。服务器会将 nonce 与 manifest hash、platform、SDK version 以及应用标识信息绑定在一起,减少被复用/替换证据的可能。 |
| enableManagedVerification (Pro) | bool | false | 为没有自有游戏服务器团队准备的委托验证选项。它让 OZero 服务器重新核对下发的 OZA 令牌,返回允许/警告/屏蔽结果与短期会话。SDK 会在会话到期前自动尝试再验证。需要 checkIntegrityWithServer 处于开启状态。 |
| requireManagedVerification (Pro) | bool | false | 开启后,若委托验证发生网络失效亦会被认作验证失败。一般建议关闭,令其可自动切换至普通(Standard)级保护。 |
| attestRefreshLeadSeconds (Pro) | float | 300 s | 确定在 OZA 令牌失效前几秒去尝试续约。如果设 0 即不使用提前更新。 |
| attestRefreshCooldownSeconds (Pro) | float | 30 s | Attestation 更新尝试间的最低等待用时。 |
| manifestSigningPublicKey | string | — | 启用 requireManifestSignature 时,用于验证清单签名的 RSA 公钥 (PEM)。 |
| requireManifestSignature | bool | false | 验证完整性清单本身是否通过 manifestSigningPublicKey 进行签名。 |
| manifestSigningPrivateKeyPath | string | OZeroSigningKeys | 构建期间使用的私钥 PEM 路径以签署清单。它仅在 Editor 出现并不在用户构建版内。 |
Events
| Event | Description |
|---|---|
| OnValidationPassed | 当本地完整性检查顺利完成而无违规时发生。此时 Pro 服务器证明 (attestation) 可能仍在进行中。 |
| OnAttestationPassed | 仅在实际颁发了 Pro OZA 证明 (attestation) 令牌后触发。请使用此事件或 AttestationToken.IsValid(nowMillis) 来校验,只有通过后才能进行游戏服务器登录、PvP、排名、货币结算等流程。 |
| OnValidationFailed | 当完整性检查检测到违规时触发。同时也会随着 ModulationType.BuildIntegrity 触发全局的 onHackDetected 事件。 |
生成 RSA 签名密钥(构建完整性)
如果启用了 构建完整性 (Build Integrity) 并且开启了 Require Manifest Signature,OZero 会使用基于公钥的签名来验证完整性清单是否未被更改。在制作发布构建之前,必须在 Unity 编辑器中生成密钥对。
在构建时,OZero 会使用 私钥 对程序集清单进行签名,并将生成的签名嵌入到构建中。在运行时,它会使用保存在 OZeroSecurityConfig 中的 公钥 来验证签名。如果签名不匹配 — 即清单或二进制文件已被篡改 — 游戏会将其视为篡改并根据响应设置进行处理。
生成密钥对
- 在 Unity 编辑器的 Project 窗口中选择
OZeroSecurityConfig。 - 在检查器 (Inspector) 中展开 Build Integrity 选项卡。
- 勾选 Require Manifest Signature 复选框。
- 点击 Generate Key Pair 按钮。
- OZero 将生成签名密钥对。公钥 存储在
OZeroSecurityConfig中,私钥 则保存在以下路径:[ProjectRoot]/OZeroSigningKeys/manifest_private_key.pem - 将显示指示私钥位置的确认对话框。点击 OK 关闭它。
- 私钥文件存储在
Assets/文件夹 外部,以防止 Unity 将其打包进构建中。切勿将其移入Assets/中。 - 请立即将
OZeroSigningKeys/添加到.gitignore中。将私钥提交到版本控制中是严重的安全隐患。 - 请将私钥备份到安全的离线位置(如加密 USB 驱动器、密码管理器等)。任何拥有此文件的人都可以伪造有效的清单。
- 如果您丢失了私钥,必须重新生成一个新的密钥对。新公钥将自动包含在下一次构建中。以前分发的所有构建都会因为新公钥而导致清单验证失败,因此您必须部署更新。
自定义私钥路径(CI/CD 和团队环境)
您可以在检查器的 Manifest Signing — Editor Only 下的 Manifest Signing Private Key Path 字段中指定私钥的替代位置。这在以下两种情况下很有用:
- CI/CD 管道 — 将私钥保存为 CI Secret,并在构建时注入路径,这样构建机器就不需要将密钥永久保存在磁盘上。
- 团队环境 — 将密钥保存到共享的安全服务器或机密管理器中,并将该字段指定为挂载路径。只需确保运行发布构建的团队成员具有访问权限即可。
验证现有密钥对
要验证磁盘上的私钥与存储在 OZeroSecurityConfig 中的公钥是否匹配,请点击 Validate Key Pair 按钮。OZero 会用私钥对一个小测试载荷签名,然后用公钥进行验证。如果匹配,将显示成功消息;如果不匹配,您需要生成一对新密钥。
- 当私钥丢失或泄露时。
- Validate Key Pair 报告不匹配(密钥未同步)时。
- 作为既定安全策略的一部分,有意轮换密钥时。
重新生成后,新的公钥将自动包含在下一次构建中。此前分发的构建使用新公钥将导致清单验证失败,因此必须部署更新。
双指纹无中断密钥轮换
点击 Generate Key Pair 按钮后,公钥不仅会保存在 OZeroSecurityConfig 中,同时识别相同密钥的 fingerprint 也会记录在 OZeroManifestTrustAnchor.cs 中。运行时将先验证这两个值是否匹配,然后再验证清单的签名。如果二者不匹配,它将不再信任该清单。
在 OZeroManifestTrustAnchor.cs 中,您可以记录当前使用的密钥 fingerprint,以及仅在密钥轮换期间临时允许的旧密钥 fingerprint。平时只使用当前密钥,仅在更换新密钥时才会暂时填入旧密钥槽。通过这种方式,您可以减少在部署新版本期间现有构建用户突然验证失败的情况。
密钥轮换步骤
- 备份当前指纹。 打开
Assets/OZeroSDK/Scripts/Security/BuildIntegirity/OZeroManifestTrustAnchor.cs,复制ExpectedPublicKeyFingerprintHex的值。 - 注册到旧密钥槽。 在同一文件中,将第 1 步复制的值粘贴到
PreviousPublicKeyFingerprintHex中并保存。 - 生成新密钥对。 在
OZeroSecurityConfig检查器中点击 Generate Key Pair,在弹出的确认窗口中继续操作。新公钥与新指纹将被自动更新。 - 部署新版本构建。 新的清单将使用新的私钥进行签名。
- 预留更新过渡期。 在新旧版本共存期间,需同时允许使用旧密钥。对于在线游戏,通常设定在 1 至 4 周左右。
- 清空旧密钥槽。 当旧版本的使用量足够低后,将代码改回
PreviousPublicKeyFingerprintHex = "",再次发布后轮换即告完成。
在实时在线服务中,并非所有用户都会在同一时间迁移到新版本。通过暂时保留旧密钥槽,可以减少新旧构建共存期间引发的清单验证失败。经过充分的过渡期后,再清空旧密钥槽即可。
故障排除
大部分与密钥相关的错误,均因私钥、OZeroSecurityConfig 中的公钥以及 OZeroManifestTrustAnchor 中的 fingerprint 三者不匹配所致。请按顺序检查以下项目。
ExpectedPublicKeyFingerprintHex 可能为空。解决:在 Unity 编辑器中运行一次 Generate Key Pair,然后进行 Clean Build。若值已填写但仍失败,可能是因为以前构建的产物残留,请清空构建文件夹后重新构建。
当 OZeroSecurityConfig.Integrity.ManifestSigningPublicKey 为空时触发。解决:在检查器中打开 OZeroSecurityConfig,在 Build Integrity 选项卡中点击 Generate Key Pair,再重新构建。
OZeroSecurityConfig 的公钥与代码中记录的 fingerprint 不匹配。解决:在 Unity 编辑器中运行 Tools → OZero → Validate Manifest Signing Keys。如果工具报告不匹配,请使用 Generate Key Pair 重新签发密钥对后再重新构建。如果该提示出现在分发版中,则还应检查 APK 或可执行文件是否被重新打包过。
极有可能是因为在部署新密钥之前,未将旧 fingerprint 填入 PreviousPublicKeyFingerprintHex 中。解决:发布一个将旧指纹放入 Previous 槽的热修复版本,并在经过充分过渡期后再将其清空。
当 CI 机器上缺失 OZeroSigningKeys/manifest_private_key.pem 时发生。解决:将私钥保存在 CI Secret 中,并在 Unity 构建前恢复至相同路径;或者在 OZeroSecurityConfig 的 Manifest Signing Private Key Path 中指定 CI 可访问的安全路径。所有发版机器必须使用相同的私钥。
安装来源设置
限制游戏仅在通过已批准的商店或途径安装时才能运行。这有助于防止侧载或重新打包的 APK。
| 字段 | Type | 默认值 | 说明 |
|---|---|---|---|
| Activate Install Source | bool | true | 激活 Install Source 模块。 |
| allowGooglePlayStore | bool | true | 允许通过 Google Play 商店安装。 |
| allowSamsungGalaxyStore | bool | false | 允许通过 Samsung Galaxy Store 安装。 |
| allowAmazonAppstore | bool | false | 允许通过 Amazon Appstore 安装。 |
| allowHuaweiAppGallery | bool | false | 允许通过华为 AppGallery 安装。 |
| allowOneStore | bool | false | 允许通过 ONE Store (韩国) 安装。 |
| allowXiaomiGetApps | bool | false | 允许通过小米 GetApps 安装。 |
| allowOppoAppMarket | bool | false | 允许通过 OPPO App Market 安装。 |
| allowVivoAppStore | bool | false | 允许通过 Vivo App Store 安装。 |
| allowADB | bool | false | 允许通过 ADB (Android Debug Bridge) 安装。仅供内部测试时启用。 |
| allowDetectionFailed | bool | false | 如果因 Android installer package 的提取失误或者 JNI 调取出错都任其通行游戏。发布版本建议将其闭锁。 |
| allowUnknownSources | bool | false | 允许并非出自官方列表或自订许可列表中的源头途径。遇到必要对应地方商店时再行开启测试使用。 |
| enableServerSync (Pro) | bool | false | 将探测所得的 installer package 送上 OZero 检查库校验并且建档,专属 Pro 级别。 |
| customAuthorizedPackages | List<string> | — | 额外允许的安装程序包名称(例:com.yourcompany.launcher)。 |
| reportViolationToCallback | bool | true | 若检测到未被许可的安装来源,则向服务器发送报告。 |
| logRawInstallerPackage | bool | true | 在控制台中输出原始安装程序包名的日志。在开发阶段确定自定义商店的正确包名时非常有用。 |
Steam 防盗版配置
对在 Steam 发售的 PC 端查明 Steam 调用通道、App ID、权限情况、发布档设定。Standard 是局端核实,要想通过 Steam 取得牢固权证唯有依赖 Pro 级别之内的 Steam Attestation 来供给。
| 字段 | Type | 默认值 | 说明 |
|---|---|---|---|
| Activate Steam Anti-Piracy | checkbox | Off | 启动 Steam 防盗版侦察的勾选位。有鉴于 Steam App ID 及铺货形态随项目多变,初始定作 Off。理应首先处 observe/QA 情境查其状,尔后针对发行端上紧限制。 |
| expectedSteamAppId | int | 0 | 项目的 Steam App ID 标识。设使之前倚仗除错用 AppID 480 则应在交差前必定修正为正当的 App ID。 |
| requireSteamLaunch | bool | true | 断明是否借由 Steam 而非执行文件独立启航。需厘清研发内部自测操作与外发政策。 |
| requireSteamApiInit | bool | true | 探察 Steam API 奠定起手成效。研发时期直接试玩因 Steamworks 配定生变有败局几率,决断还得以确实的 Steam 散播流为基准。 |
| requireSubscribedCurrentApp | bool | true | 核准当前挂号的 Steam 主能否掌握此件及赋予进入权限。此是机内考核,至于服端盘查必得用 Pro 解决。 |
| requiredDlcAppIds | List<int> | — | 在进行保护的 DLC 流程中,必须持有的 DLC App ID 清单。 |
| blockSteamAppIdTxtInRelease | bool | true | 如果在发布构建中残留了开发用的 steam_appid.txt 文件,则作失败处理。此文件仅供本地开发确认使用,请勿向客户分发。 |
| validateSteamApiDllHash | bool | false | 通过将 Steam API DLL 的哈希值与已知的 SHA-256 值进行比较来进行验证。 |
| allowFamilySharing / allowFreeWeekend / allowTimedTrial | bool | true | 控制是否允许 Steam 家庭共享、免费周末以及限时试用权限状态。 |
| enableServerSteamAttestation (Pro) | bool | false | 仅限 Pro。将 Steam 权限证据提交到 OZero 服务器,执行比客户端本地结果更强的服务器端所有权验证。 |
设备绑定设置
使用硬件指纹将游戏账号与首次运行的设备绑定。检测账号向其他硬件的转移。
商用运营目的
设备绑定作为 Pro 的运营层最为有用。通过将许可证与服务器记录的硬件指纹关联,可以隔离风险设备,增加随意共享许可证的代价,并在不阻断整个许可证的前提下支持合法的设备更换。
阻断重复风险设备
请在确认 SpeedHack、Injection、Install Source、Build Integrity 等安全事件的证据后使用。被阻断的设备在下次激活、注册、验证(verify)或策略(policy)检查时将收到 DEVICE_BLOCKED。
支持合法用户重置
在手机更换、OS 重装、硬件更换,以及正常环境变化导致的指纹不匹配时使用 Reset Token。令牌有效期 5 分钟,仅限使用一次,且与准确的许可证和设备绑定。
控制设备槽位
在 Pro 许可证中,maxDevices 限制了可注册的活动服务器指纹数量。被阻断的指纹不属于可重复使用的信任槽位,因此仅在客户支持验证后才可进行重置或删除。
Reset Token 客户支持流程
- 按照正常的客服流程确认玩家账号及重置原因。
- 进入 Customer Portal → Device Binding,找到目标设备并发放 Reset Token。
- 令牌应仅通过已认证的客户支持渠道发送。切勿将其存放在长期保留的公开聊天或截图中。
- 游戏或客服 UI 需将令牌传递给
OZeroDeviceBindingDetector.Instance?.ClearStoredFingerprint(token.Trim())。 - SDK 消耗令牌后,重启应用或重新进入保护初始化流程,即可重新注册当前的硬件指纹。
| 字段 | Type | 默认值 | 说明 |
|---|---|---|---|
| Activate Device Binding | bool | true | 激活 Device Binding 模块。 |
| hardwareChangeTolerance | int (0–3) | 1 | 触发违规前允许的硬件组件变更次数。0 = 严格(不可更改),3 = 宽松(主要硬件更换)。1 属于允许小幅度 OS 或固件更新的级别。 |
| storageKey | string | "ozero_dfp" | 存储加密设备指纹的 PlayerPrefs 键。仅在与游戏内现有键冲突时才需修改。 |
| enableServerSync | bool | false | 将设备指纹与后端服务器同步,以进行服务器端验证。 |
| maxDevices (Pro) | int | 0 | 这是一个记录预期服务器端设备限制的文档值。实际限制由服务器许可证记录强制执行,仅更改此本地值并不能提升运营限制。 |
速度黑客检测器设置
通过将 Unity 的 Time.realtimeSinceStartup 与原生平台计时器,甚至可选的受信任 Web 时间源进行对比,以检测时间缩放操控 (速度黑客)。
| 字段 | Type | 默认值 | 说明 |
|---|---|---|---|
| Activate Speed & Time Hack | bool | true | 激活 Speed Hack Detector 模块。 |
| autoStart | bool | true | 游戏执行时自动开始检测。如果禁用,需通过 OZeroSpeedHackDetector.StartDetection() 手动启动。 |
| checkInterval | float | 1.0 s | 检测器对计时器进行采样比对的间隔(秒)。 |
| requiredDetections | int | 3 | 触发违规前所需的连续异常样本数量。调高此值可减少在不稳定设备上的误报。 |
| ratioTolerance | float | 0.15 | 用于确认 Unity 时间流速与原生计时器是否出现异常偏差的容差范围。请先使用默认值,并在实际游戏环境中确认有无误报后再作调整。 |
| maxAllowedRatio | float | 4.0 | 用于快速捕获严重超出正常范围的时间流速的上限值。一般建议保留默认值。 |
| detectSlowHack | bool | true | 除加速工具外,还会检测用来放慢时间的工具(低于 1.0 减去容差的比例)。 |
| enableTimeScaleDetection | bool | true | 检测被内存修改器等通过编程方式设置的异常 Time.timeScale 值。 |
| hackDetectMultiplier | float | 1.3 | 用于更快汇总高强度可疑信号的校正系数。值越低越敏感,请在 QA 后调整。 |
| enableThreadTimerCheck | bool | true | 使用后台线程计时器作为额外的参考时钟,使只影响主线程的黑客手段变得更困难。 |
| useWebTimeValidation | bool | false | 定期从 webTimeUrl 获取当前时间并与设备时钟比较,以检测设备级别的时间篡改。 |
| webTimeUrl | string | — | 受信任的 Web 时间 API 终端 URL(必须返回 Unix 时间戳或 RFC 2616 Date 头部)。启用 useWebTimeValidation 时必填。 |
| webSyncInterval | float | 15 s | 与 Web 时间服务器同步的时间间隔(秒)。 |
| webRatioTolerance | float | 0.15 | 用于判断设备时间与 Web 服务器时间差异的容差范围。请综合考虑网络延迟和地区环境,从默认值开始验证。 |
| timeOffsetTolerance | float | 60 s | 在触发违规之前允许的设备和 Web 服务器之间的绝对时钟偏移量(秒)。 |
| focusIgnoreTime | float | 4 s | 应用重新获得焦点后忽略检测的秒数。可防止操作系统暂停应用时产生的误报。 |
| loadingGraceTime | float | 6 s | 用于在应用启动或场景加载等可能出现正常延迟的阶段,减少误报的初始缓冲时间。 |
| lagSpikeIgnore | float | 0.5 s | 帧时间差超过此值的样本将被丢弃(视为实际的卡顿,而非时间操控)。 |
| buildFailIfTimeScaleTampered | bool | true | 一种保护措施,如果受保护的代码疑似在策略之外更改 Time.timeScale,则在构建/验证阶段触发失败。 |
| timeScaleTamperExemptions | List<string> | — | 将诸如暂停或子弹时间等有意更改 Time.timeScale 的类/方法模式注册为例外。 |
| webTimeUrls | string[] | — | 您可以指定多个受信任的时间端点。要求有多个成功的响应以提高 Web 时间的可靠性。 |
| minSuccessfulEndpoints | int | 2 | 使用多个 Web 时间端点时必须成功响应的最小数量。 |
| maxConsecutiveFailures | int | 6 | 决定连续多少次 Web 时间查询失败将触发不可用策略。 |
| onWebTimeUnavailable | enum | WarnOnly | 无法访问受信任的 Web 时间时应用的策略。在测试网络环境后请提升至严格模式。 |
| detectTimeHack | bool | true | 除速度比率检查外,还开启设备时钟和 Web 时间操控检查。 |
| webSyncJitterPercent | float | 20% | 为 Web 时间同步周期添加随机偏差,使得查询时机难以预测。 |
| sustainedLagThreshold | float | 0.15 | 用于将反复出现的慢帧分类为持续卡顿而非作弊证据的标准。 |
| sustainedLagGraceDuration | float | 3 s | 在判断为持续卡顿或加载延迟期间,用于减少误报的缓冲时间。 |
| overloadStrictMultiplier | int | 3 | 在反复出现异常时序条件后,更严格地应用 overload 处理标准的乘数。 |
| enableRemoteSpeedHackConfig (Pro) | bool | false | 允许通过 Pro 服务器策略远程调整部分 Speed & Time Hack 阈值。 |
| remoteSpeedHackConfigInterval | float | 300 s | 获取新远程 Speed & Time Hack 设置的周期。 |
| enableSignedServerTime (Pro) | bool | false | 如果可用,使用签名的服务器时间,防止伪造无签名响应。 |
防止长时间加载时 Watchdog 意外终止应用
OZero 的原生 Watchdog 会通过定期 heartbeat 确认 Unity 主线程是否仍在正常运行。在发布构建中,非 Android 平台大约使用 6 秒 heartbeat deadline,Android 在启动宽限后大约使用 10 秒 deadline。如果在该时间内没有收到 heartbeat,应用可能会被判定为卡死,并按配置的响应策略终止。
大型场景加载、同步资源解压、shader warmup 或 Addressables 准备等正当工作,也可能因为主线程被有意阻塞数秒而触发这种情况。
请使用 OZeroWatchdog.BeginLoadingGrace(maxGraceMs) 包住这类可信加载边界。加载开始时 grace 开始,scope 被 dispose 或调用 End() 时会立即结束,因此不需要提前知道准确的加载时长。
using OZeroSDK.Security;
using UnityEngine.SceneManagement;
public void LoadLargeScene()
{
using (OZeroWatchdog.BeginLoadingGrace(60000))
{
SceneManager.LoadScene("Battle", LoadSceneMode.Single);
// Grace ends as soon as the using scope exits.
}
}
public void WarmUpLargeAssets()
{
OZeroWatchdog.RunWithLoadingGrace(() =>
{
BuildLargeRuntimeCache();
}, 60000);
}
Loading Grace 只会有限延后 Watchdog deadline。不要把它滥用为无限循环或 keep-alive 机制,用来绕过正常监控并让应用持续运行。
如果一个大型阻塞操作可能超过最大 grace window,请把工作拆成多个较小的 chunk,并按步骤处理。
或者使用 Unity 的 async/await、Coroutine 等异步加载流程,避免主线程长时间完全阻塞。
物理黑客检测器
OZeroPhysicsHackDetector 专为需要为每个玩家对象设置独立检测阈值的多人游戏/MMORPG 游戏而设计。将组件直接添加到玩家预制件上,并在检查器中为每个对象配置设置。在生成逻辑中调用 Initialize(playerId) 来启用检测。| 字段 | Type | 默认值 | 说明 |
|---|---|---|---|
| maxAllowedSpeed | float | 15 u/s | 允许的最大移动速度(Unity 单位/秒)。请根据游戏中允许的合法最高玩家速度进行微调。 |
| distanceTolerance | float | 2.0 u | 用于补偿网络延迟或物理计算误差的额外距离容差。 |
| obstacleLayer | LayerMask | — | 代表墙壁和障碍物的层遮罩。用于通过射线投射检测穿墙行为。 |
| checkInterval | float | 0.05 s | 物理验证器对玩家位置和速度进行采样的频率(秒)。 |
| maxDeltaTimeCap | float | 0.1 s | 用于距离计算的增量时间上限。可防止因卡顿导致非法传送被掩盖。 |
注入检测器设置
检测程序集注入、DLL 劫持、IL2CPP 修补等未经授权的代码注入。
| 字段 | Type | 默认值 | 说明 |
|---|---|---|---|
| Activate Injection & Hooking | checkbox | On | 启用 Code Injection Detector 模块。检测逻辑完全在 Native C++ 层运行,无需额外配置。 |
| enableServerWhitelist (Pro) | bool | false | 从服务器下载信任模块列表,以允许获批的覆盖层或合作伙伴模块。 |
| serverWhitelistRefreshInterval | float | 0 s | 服务器管理的白名单策略更新周期。如果为 0,则仅在启动或策略初始化时更新。 |
| requireSignerForNativeWhitelist | bool | false | 对原生白名单项目不仅要求文件哈希,还要求签名者识别信息。保护更强,但需要干净的模块签名数据。 |
| enableRemoteInjectionConfig (Pro) | bool | true | 允许通过 Pro 服务器策略远程调整 Injection 检查阈值和检查配置。 |
| remoteInjectionConfigInterval | float | 300 s | 获取新远程 Injection 策略的周期。 |
| enableWindowsModuleIdentityScan | bool | true | 扫描已加载的 Windows 原生模块,并将哈希/签名者信息与信任策略进行比较。 |
| scanIntervalSeconds | float | 1 s | Injection 检查的基本执行周期。 |
| windowsModuleIdentityScanIntervalSeconds | float | 5 s | 相对繁重的 Windows 模块识别扫描的独立周期。 |
| scanJitterPercent | float | 20% | 为检查周期添加随机偏差,使得检查时机难以预测。 |
| enableExecutablePrivateMemoryScan | bool | true | 检测 injected shellcode 或运行时 patcher 经常使用的可执行私有内存区域。 |
| enableInlineHookScan | bool | false | 检测已知代码入口点的可疑内联补丁。这是在 Strict 模式下经过兼容性测试后开启的项目。 |
| enableThreadStartAddressScan | bool | true | 检查线程启动地址是否位于信任模块之外的可疑位置。 |
| enableExternalProcessHandleScan | bool | true | 检测外部进程是否持有游戏进程的可疑句柄。 |
| detectionConfidenceThreshold | int | 70 | 综合多个 Injection 信号时,确定为违规所需的最低置信度分数。 |
| enableWebRuntimeTamperScan (WebGL) | bool | true | 仅适用于 WebGL 的轻量级浏览器篡改检查。因其不是 Native C++ 保护,故仅作为辅助信号使用。 |
| WebGL probes | bools | true | 控制在 WebGL 构建中的 DevTools、时钟操控、网络 Hook、WASM Hook、存储 Hook 以及加密 API Hook 检查。 |
PlayerPrefs 加密
要保护存储在 Unity PlayerPrefs 中的数据(设置、用户偏好等),请将 PlayerPrefs 替换为 OZeroSafePlayerPrefs。API 完全相同。
using OZeroSDK.Security;
// Save a value
OZeroSafePlayerPrefs.SetInt("score", 4200);
OZeroSafePlayerPrefs.SetFloat("volume", 0.8f);
OZeroSafePlayerPrefs.SetString("username", "Hero");
// Read a value
int score = OZeroSafePlayerPrefs.GetInt("score", 0);
float volume = OZeroSafePlayerPrefs.GetFloat("volume", 1.0f);
string username = OZeroSafePlayerPrefs.GetString("username", "");
存档文件加密
要加密存档文件,请使用 OZeroSV_File 代替 File.ReadAllText / File.WriteAllText。文件在写入时自动加密,在读取时自动解密。加载时还会检查是否被篡改。
using OZeroSDK.Security;
string path = Application.persistentDataPath + "/save.json";
// Write encrypted file
OZeroSV_File.WriteAllText(path, jsonString);
// Read and decrypt file
string json = OZeroSV_File.ReadAllText(path);
developerSecret。developerSecret 是保护 OZeroSafePlayerPrefs 和 OZeroSV_File 数据的基准值之一。若发布后更改此值,之前版本中保存的受保护数据可能将无法打开。
4
游戏内变量保护(Secure Types)
Secure Types 会将常规 C# 变量类型替换为加密类型。因为值存储在 Native C++ 堆中,诸如 Cheat Engine 的工具即使扫描内存也无法找到。只需更改类型名称,其余代码即可照常运行。
示例代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using OZeroSDK.Security;
public class PlayerStats : MonoBehaviour
{
[SerializeField] OZeroSV_Int Gold = 5000;
[SerializeField] OZeroSV_Float Speed = 3.5f;
[SerializeField] OZeroSV_Int HP = 1000;
}
支持类型
| 现有 | 应用 OZero 后 |
|---|---|
| int | OZeroSV_Int |
| long | OZeroSV_Int64 |
| uint | OZeroSV_UInt |
| ulong | OZeroSV_UInt64 |
| short | OZeroSV_Short |
| ushort | OZeroSV_UShort |
| byte | OZeroSV_Byte |
| float | OZeroSV_Float |
| double | OZeroSV_Double |
| decimal | OZeroSV_Decimal |
| bool | OZeroSV_Bool |
| string | OZeroSV_String |
| Vector2 | OZeroSV_Vector2 |
| Vector3 | OZeroSV_Vector3 |
| byte[] | OZeroSV_Buffer |
7
安全事件处理(可选)
默认情况下,当 OZero 检测到威胁时,它会按照配置的响应策略来终止应用或只留存日志。如果您需要直接显示警告屏幕、发送您自己的服务器日志或在退出之前执行保存操作,则可以注册回调。该回调将通过 OZeroSecurityEvent 提供修改类型、中止代码、消息键、详细消息以及是否即将退出等信息。
using UnityEngine;
using OZeroSDK.Security;
public class SecurityHandler : MonoBehaviour
{
void OnEnable()
{
// RegisterUserCallback runs on the user chain only.
// The built-in default handler runs independently and cannot be silenced.
OZeroSecurityManager.Instance.RegisterUserCallback(OnThreatDetected);
}
void OnDisable()
{
OZeroSecurityManager.Instance.UnregisterUserCallback(OnThreatDetected);
}
void OnThreatDetected(OZeroSecurityEvent evt)
{
// evt contains Type, AbortCode, AbortCodeHex, MessageKey, Message, and WillAbort.
Debug.LogWarning(
$"OZero threat: {evt.Type} {evt.AbortCodeHex} {evt.Message}");
switch (evt.Type)
{
case ModulationType.SpeedHack:
// e.g. kick the player, show warning, report to server
break;
case ModulationType.BuildIntegrity:
// evt.WillAbort is usually true for fatal build integrity violations.
break;
case ModulationType.Injection:
break;
}
if (evt.WillAbort)
{
// Last chance to flush your own analytics or save state.
}
}
}
OZeroSecurityEvent、ModulationType 以及 OZeroAbortCode 的完整列表已记录在 API 参考中。
evt.WillAbort 为 true,按照当前响应策略,应用将在回调之后退出。在这种情况下,请只执行简短的自定义 analytics flush 或是保存操作。
当检测到威胁时,OZero 会首先应用 SDK 基础的响应策略,并将同样的安全事件派发给项目中注册的回调和 Inspector 事件。如果希望直接显示警告画面或留下服务器日志,请注册回调。关于应用是否退出,可以通过 Config Dashboard 的 Response 设置以及 evt.WillAbort 的值来确认。
下一步
现在 OZero 的核心防线已经在为您保驾护航了。翻查文档,全面探究每个接口,类、或控制选项的真谛。