从运行机制谈 Among Us 模组的反破解加固:五层防御体系

2026年7月21日星期二·1978 字·10 分钟·
实践笔记逆向工程反破解Among Us加固
AI 摘要- DeepSeek

以 FinalSuspect 的三重检测被一个 dnSpy + ret 指令组合一次性解除为例,说明托管层检测为何必然失效,并给出由弱到强的五层加固方案:混淆加密、IL 完整性自校验、原生 DLL 检测、分散时机加蜜罐、服务端验证。

封面图
从运行机制谈 Among Us 模组的反破解加固:五层防御体系 - 封面图

以 FinalSuspect 为例,它的三重检测被一个 dnSpy + ret 指令的组合就全部解除了。根本原因只有一个:所有检测逻辑都在托管代码层(IL)里,和攻击者的修改工具处于同一个信任层。本文从运行机制角度,讲清楚为什么现有方案会失败,以及如何一层一层加强。

一、为什么现有检测容易被绕过#

FinalSuspect 的检测失败链路如下:

检测逻辑在 IL 层
↓
dnSpy 可以直接反编译看到
↓
直接把方法体改成 ret
↓
检测逻辑永远不执行

根本问题是检测代码和被检测的环境在同一个进程、同一个信任层里。任何在托管代码里写的检测,理论上都可以被同样在托管层运行的代码绕过。下面从弱到强介绍五个加固层级。

二、层级 1:混淆 + 字符串加密#

FinalSuspect 已经用了 XOR 加密字符串,但逻辑本身没有混淆,反编译后整体结构一目了然。更进一步的做法是用 ConfuserEx 或 Obfuscar 在编译后对 DLL 做整体混淆。

<project>
<rule pattern="true">
<protection id="ctrl flow" />
<protection id="constants" />
<protection id="ref proxy" />
<protection id="anti tamper" />
<protection id="anti debug" />
</rule>
</project>

**局限:**混淆只是提高反编译成本,不能从根本上阻止修改。有经验的人依然可以动态调试绕过。

三、层级 2:完整性自校验(Anti-Tamper)#

让 DLL 在运行时校验自身的 IL hash。如果有人修改了某个方法的指令,hash 就对不上,直接退出。

internal static class IntegrityChecker
{
// 编译时预先计算好关键方法的 hash,硬编码进来
// 注意:这些 hash 本身也要混淆存储,不能明文
private static readonly Dictionary<string, byte[]> _expectedHashes = new()
{
// MethodToken → 预期的 IL bytes 的 SHA256
{ "DllChecker.OnInitialization", new byte[] { 0x3A, 0xF1, ... } },
{ "Git.Prefix", new byte[] { 0x7C, 0x2B, ... } },
};
internal static void Verify()
{
var asm = Assembly.GetExecutingAssembly();
foreach (var type in asm.GetTypes())
{
foreach (var method in type.GetMethods(
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance))
{
string key = $"{type.Name}.{method.Name}";
if (!_expectedHashes.TryGetValue(key, out byte[] expected))
continue;
// 读取运行时实际的 IL bytes
var body = method.GetMethodBody();
if (body == null) { Quit(); return; }
byte[] actual = SHA256.HashData(body.GetILAsByteArray());
if (!actual.SequenceEqual(expected))
{
// IL 被篡改,静默退出(不报错,防止攻击者定位触发点)
Quit();
return;
}
}
}
}
private static void Quit()
{
// 故意延迟几秒再退出,让攻击者难以定位触发点
Thread.Sleep(new Random().Next(2000, 8000));
Application.Quit(1);
}
}

关键点:

  • Verify() 要在多个时机调用(启动时、进入游戏时、每隔一段时间),不能只在一处
  • hash 值本身要混淆存储,否则攻击者直接改 hash 就绕过了
  • 退出前故意加随机延迟,防止攻击者通过”哪里卡了”来定位检测代码

四、层级 3:把检测逻辑移到原生层#

这是最关键的跨越。托管代码(C#)可以被 dnSpy 修改;原生代码(C++ DLL)需要 x64dbg + IDA,门槛高出一个数量级。

做法是写一个原生 DLL(C++),负责执行真正的检测逻辑,C# 只负责调用:

// NativeGuard.cpp(编译成 NativeGuard.dll)
#include <windows.h>
#include <tlhelp32.h>
// 扫描插件目录,发现白名单外的 DLL 返回 -1
extern "C" __declspec(dllexport)
int __stdcall ScanPluginDirectory(const wchar_t* pluginDir,
const wchar_t** whitelist,
int whitelistCount)
{
WIN32_FIND_DATAW findData;
wchar_t pattern[MAX_PATH];
swprintf_s(pattern, L"%s\\*.dll", pluginDir);
HANDLE hFind = FindFirstFileW(pattern, &findData);
if (hFind == INVALID_HANDLE_VALUE) return 0;
int count = 0;
do {
bool allowed = false;
for (int i = 0; i < whitelistCount; i++) {
if (wcscmp(findData.cFileName, whitelist[i]) == 0) {
allowed = true;
break;
}
}
if (!allowed) {
FindClose(hFind);
return -1; // 发现非法 DLL
}
count++;
} while (FindNextFileW(hFind, &findData));
FindClose(hFind);
return count;
}
// 检测已知调试器进程
extern "C" __declspec(dllexport)
bool __stdcall IsDebuggerRunning()
{
// 方法 1:Windows API
if (IsDebuggerPresent()) return true;
// 方法 2:检查调试器进程名
const wchar_t* debuggers[] = {
L"dnSpy.exe", L"x64dbg.exe", L"cheatengine-x86_64.exe",
L"ida64.exe", L"OllyDbg.exe", L"ProcessHacker.exe"
};
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snap == INVALID_HANDLE_VALUE) return false;
PROCESSENTRY32W pe = { sizeof(pe) };
if (Process32FirstW(snap, &pe)) {
do {
for (auto& dbg : debuggers) {
if (_wcsicmp(pe.szExeFile, dbg) == 0) {
CloseHandle(snap);
return true;
}
}
} while (Process32NextW(snap, &pe));
}
CloseHandle(snap);
return false;
}

在 C# 中调用:

internal static class NativeGuard
{
[DllImport("NativeGuard.dll", CharSet = CharSet.Unicode)]
private static extern int ScanPluginDirectory(
string pluginDir,
string[] whitelist,
int whitelistCount);
[DllImport("NativeGuard.dll")]
private static extern bool IsDebuggerRunning();
internal static void Check()
{
// 调试器检测
if (IsDebuggerRunning())
{
SilentQuit();
return;
}
// 插件目录扫描
string pluginDir = Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location)!;
string[] whitelist = { "FinalSuspect.dll", "PolarNight.dll" };
int result = ScanPluginDirectory(pluginDir, whitelist, whitelist.Length);
if (result == -1)
{
SilentQuit();
}
}
private static void SilentQuit()
{
Thread.Sleep(new Random().Next(3000, 10000));
Application.Quit(1);
}
}

**为什么有效:**攻击者要绕过这个,必须先找到原生 DLL(名字可以随便起,混在游戏 DLL 里),再用 x64dbg 动态调试原生层,最后找到具体函数并 patch。这个门槛比改 IL 高出一个数量级。

五、层级 4:分散检测时机 + 蜜罐#

不要把检测集中在一个地方,分散到各个角落,让攻击者找不全:

// 在多个不相关的 Patch 里随机触发检测
[HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))]
internal static class HudUpdatePatch
{
private static int _frameCount = 0;
public static void Postfix()
{
_frameCount++;
// 每隔随机帧数触发一次检测,不规律、难预测
if (_frameCount % (UnityEngine.Random.Range(800, 1200)) == 0)
{
IntegrityChecker.Verify();
NativeGuard.Check();
}
}
}
[HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.OnGameJoined))]
internal static class JoinGamePatch
{
public static void Prefix()
{
// 进游戏时也检测一次
NativeGuard.Check();
}
}
[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))]
internal static class MeetingStartPatch
{
public static void Prefix()
{
// 每次开会议时也检测
IntegrityChecker.Verify();
}
}

配合蜜罐使用——故意留一个看起来像检测方法的”假靶子”,让攻击者优先清空它,真正的检测在别处:

// 这个方法什么都不做,就是个蜜罐
// 攻击者反编译后会优先清空"看起来最危险"的方法
internal static class FakeChecker
{
public static void CheckPlugins() { } // 空的,故意的
public static void ScanDirectory() { } // 空的,故意的
}

六、层级 5:服务端验证(最终形态)#

如果你的模组有联网功能,可以把合规性验证放到服务端。检测逻辑不在客户端,本地改再多也没用:

客户端启动
↓
发送签名请求到服务器
(请求里包含插件目录的 hash 列表)
↓
服务器验证 hash 是否合规
↓
返回一次性 Token
↓
客户端没有 Token → 无法使用联网功能
internal static class ServerValidator
{
private const string ValidateEndpoint = "https://your-server.com/api/validate";
internal static async Task<bool> ValidateAsync()
{
string pluginDir = Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location)!;
// 计算插件目录所有 DLL 的 hash 列表
var hashes = Directory
.EnumerateFiles(pluginDir, "*.dll")
.Select(f => new
{
name = Path.GetFileName(f),
hash = Convert.ToHexString(
SHA256.HashData(File.ReadAllBytes(f)))
});
// 发送给服务端验证
using var client = new HttpClient();
var response = await client.PostAsJsonAsync(ValidateEndpoint, hashes);
if (!response.IsSuccessStatusCode) return false;
// 服务端返回一次性 Token,后续联网功能需要带上
string token = await response.Content.ReadAsStringAsync();
SessionToken.Set(token);
return true;
}
}

**代价:**需要维护一个服务器,且离线玩家无法使用联网功能。适合竞技或排行榜类场景。

七、各层级对比与选型建议#

层级方案防护对象被绕过难度实现成本
1混淆 + 字符串加密静态分析低(动态调试可绕)低
2IL 完整性自校验IL 篡改中(改 hash 可绕)中
3原生 DLL 检测托管层修改高(需 x64dbg + IDA)中
4分散时机 + 蜜罐定点清除高(找不全触发点)低
5服务端验证所有本地修改极高(逻辑不在本地)高

按需求选型:

  • **提高普通用户绕过成本:**层级 1 + 层级 2
  • **对抗有经验的逆向者:**层级 3 + 层级 4
  • **竞技 / 排名场景:**层级 5

八、核心原则#

没有 100% 防破解的方案,目标是让破解成本高于收益。

FinalSuspect 失败的原因不是技术不好,而是所有鸡蛋放在一个篮子里——找到检测代码在哪儿,一次性清空就结束了。真正有效的防护是多层、分散、跨信任层的组合。攻击者面对的不是”找到一个开关关掉”,而是”拆解整个防御体系的每一层”,破解成本自然就上去了。

从运行机制谈 Among Us 模组的反破解加固:五层防御体系
https://catvo.net/posts/among-us-mod-anti-crack-hardening/
作者
Catvo
发布于
2026-07-21
许可协议
CC BY-NC-SA 4.0
逆向解析 FinalSuspect 的"独占运行"机制:如何让它与其他模组共存
主页

评论区

动作模组
等待模型加载…
看板娘
暂无歌词

暂未播放

0:00
0:00
70
目录
日历
logo

隐私政策

更新日期: 2026 年 7 月 15 日
生效日期: 2026 年 7 月 15 日

适用范围#

本政策适用于 Catvoの博客(以下简称“本站”)。本站是个人博客,用于发布和分享内容;不提供账户注册、支付、定位或广告投放服务。访问本站、发表文章评论或在留言板留言前,请阅读本政策。

信息收集与使用#

本站只在提供内容、评论和留言功能,以及维护站点安全所需的范围内处理信息。

  • 访问与统计信息:访问页面时,统计服务可能处理访问时间、页面地址、来源页、浏览器和设备相关信息,用于了解内容访问情况、排查故障和改进站点。
  • 评论信息:使用文章评论功能时,Waline 可能处理您主动提交的昵称、邮箱、站点链接和评论内容;还可能处理 IP 地址等必要信息,用于防止垃圾评论、滥用和维护服务安全。评论内容、昵称和站点链接(如填写)可能公开展示在文章下方;邮箱不会公开展示。
  • 留言信息:留言板使用 Waline /guestbook/ 频道。Waline 可能处理您主动提交的昵称、可选邮箱、站点链接、留言内容和图片,以及浏览器、操作系统、IP 地址等必要的反滥用信息。默认情况下,留言图片以内嵌数据随留言提交;如站点维护者配置了远程图片上传接口,图片会先发送至该接口并在留言中保存返回的图片地址。留言内容、昵称、图片和站点链接(如填写)可能公开展示;邮箱和 IP 地址不会在留言板公开展示。

请不要在评论或留言中提交身份证件、银行卡、住址、密码或其他不必要的敏感个人信息。

第三方服务#

为实现本站功能,以下第三方会在各自服务范围内处理相关数据:

  • Umami:用于匿名化的网站访问统计和出站链接点击统计,帮助我了解本站的使用情况。
  • Waline:用于文章评论、留言板及访问量统计。服务会按照其自身规则处理您在评论或留言时提交的信息及必要的反滥用信息。
  • Cloudflare:可为本站提供静态资源分发和域名基础设施。
  • unpkg:用于加载 Waline 的前端脚本、样式和表情资源;请求这些资源时,您的浏览器会与该服务建立连接。

第三方服务可能有独立的隐私政策和数据保存规则。请在使用相关功能前查阅其规则;本站无法控制其独立的数据处理活动。

本站主要使用浏览器本地存储(Local Storage 或 Session Storage)保存使用偏好,例如主题颜色、明暗模式、文章列表视图和音乐播放设置。留言板会在本地保存匿名资料、未发送草稿和登录状态,以便恢复输入与会话;管理员登录状态仅保存在当前会话。

本站不主动设置用于广告定向的第一方 Cookie。评论、统计或资源服务可能按照其自身规则使用 Cookie 或类似技术。您可以通过浏览器设置查看、删除或限制 Cookie 和本地存储;清除后,部分偏好或互动状态可能会恢复为默认值,评论功能也可能受到影响。

信息公开、保存与安全#

评论和留言属于公开互动内容,提交后可能被搜索引擎收录、被他人引用或在缓存中短暂保留。请谨慎决定发布内容。除非您提出删除请求、内容违反规则或法律法规另有要求,公开内容会持续保留以维持讨论上下文。

本站会采取合理措施保护数据安全,包括使用 HTTPS、输入校验、内容转义和访问频率限制。但互联网传输和第三方服务均无法保证绝对安全,请理解并自行承担公开发布信息的相应风险。

你的权利#

你可以通过 mikucatovo@gmail.com 联系我,申请查询、更正或删除由本站直接保存的评论、留言或相关公开内容。为保护他人权益,请在请求中提供足以定位内容的信息,并说明你与该内容的关系;必要时可能需要进行合理核验。

对于由 Waline、Umami、Cloudflare 或 unpkg 独立处理的数据,你也可以直接向对应服务提供方行使相关权利。删除公开评论或留言后,第三方缓存、搜索引擎索引或他人转载的副本可能无法立即同步删除。

未成年人条款#

未满 14 周岁的未成年人应在监护人同意和指导下使用本站的评论、留言等互动功能。监护人如发现未成年人未经同意提交了个人信息,可通过上述联系方式与我联系,我会在合理范围内协助处理。

政策更新与联系#

我可能因本站功能或适用规则变化更新本政策,更新后的版本将在本站公布并标明日期。继续使用相关功能即表示你已阅读并理解更新后的政策。

如对本政策或数据处理有疑问,请联系 mikucatovo@gmail.com。

用户协议

更新日期: 2026 年 5 月 19 日
生效日期: 2026 年 5 月 19 日

适用范围#

本协议适用于你访问 Catvoの博客,以及使用文章评论、留言板等互动功能的行为。继续浏览本站或提交评论、留言,即表示你已阅读、理解并同意遵守本协议及本站的隐私政策。

评论及留言规则#

请在交流中保持友善、理性和尊重。你不得利用本站发布、传播或实施以下行为:

  • 发布任何违反中华人民共和国法律法规的内容。
  • 发布任何侵犯他人合法权益的内容,包括但不限于隐私、名誉、肖像、著作权、商标权和其他知识产权。
  • 恶意攻击、辱骂、骚扰、威胁、歧视其他用户或任何第三方。
  • 发布垃圾广告、恶意推广、刷屏、灌水,或与讨论主题明显无关的重复内容。
  • 利用本站进行网络诈骗、钓鱼、传播恶意软件,或发布可能危害网络和信息安全的内容。
  • 绕越或试图绕越本站的审核、限流、封禁等管理措施。
  • 冒充他人、伪造身份,或收集、公开他人的个人信息。

内容与访问管理#

你应对自己发布的评论和留言负责,并保证拥有发布该等内容所需的合法权利。论坛管理员有权在不另行通知的情况下删除违规内容、限制或封禁违规账号,或限制其继续使用本站互动功能。

如发现涉嫌违法犯罪、严重侵权或危及本站安全的内容,本站可保留相关记录,并在法律法规要求或必要时向有关部门提供协助。对管理措施有疑问时,可通过文末联系方式说明情况;本站会结合实际情况处理,但不承诺恢复已删除内容或访问权限。

知识产权与内容授权#

本站原创文章、页面设计和其他受保护内容的权利归作者或权利人所有。未经授权,请勿复制、转载、镜像或用于商业用途;法律法规允许的合理使用除外。

你发布评论或留言时,授予本站为展示、存储、备份、审核、删除和维护互动功能所必需的非独占、免费的使用许可。该许可不改变你对原创内容依法享有的权利。

免责声明#

本站内容仅用于个人记录、学习交流和一般信息参考,不构成任何专业意见、承诺或担保。你应结合自身情况独立判断,并对据此采取的行动负责。

评论、留言和外部链接中的内容由其发布者或运营者负责,不代表本站立场。本站会在合理范围内处理明显违规内容,但不保证所有内容均及时发现,也不对第三方网站的可用性、内容、安全性或隐私实践承担责任。

因网络故障、不可抗力、第三方服务异常、维护升级或超出合理控制范围的原因导致本站暂时无法访问、内容延迟或数据丢失的,本站会尽力恢复,但不承担由此产生的间接损失。

未成年人条款#

未满 14 周岁的未成年人应在监护人同意和指导下使用评论、留言等互动功能。监护人应协助未成年人理解本协议,并对其使用行为进行必要的引导。

其他条款#

我可以根据本站功能、管理需要或法律法规变化更新本协议,更新后的版本将在本站公布并标明日期。继续使用本站即视为接受更新后的协议。

本协议的订立、执行和解释适用中华人民共和国法律。因本协议或使用本站产生争议时,双方应先友好协商;协商不成的,依法向有管辖权的人民法院解决。

如对本协议或内容管理有疑问,请联系 mikucatovo@gmail.com。

复制成功,转载请标注本文地址