在 Windows 上检测或防止进程内存注入(反黑客)

信息安全 视窗 攻击预防 注射 记忆
2021-08-16 13:33:58

标准黑客案例。Hack 注入一个已启动的游戏进程,并使用WriteProcessMemory调用写入进程内存。

情况是这样的:

  1. 我们正在托管一个游戏服务器
  2. 客户端与他们的游戏一起加入服务器,他们可以使用各种黑客来破坏他们的游戏
  3. 我们没有机会改变游戏源,就这样。但是,我们确实有可能在客户端加入服务器之前强制运行我们的程序。

所以说清楚一点:我们不能混淆游戏内存,但我们确实有可能同时运行一个单独的程序。我已经尝试使用EnumProcessModules列出所有进程 DLL 的调用,但没有成功。在我看来,黑客直接注入进程内存,因此未被检测到。在做了很多“谷歌研究”之后,我得出了几个选择:

  1. 扫描正在运行的进程名称、游戏目录中的文件、文件的字节模式、正在运行的进程的字节模式......这个任务非常耗时,因为我必须获取所有可用黑客的样本并在每次新的时候更新我们的程序出来。所有 hack 信息都需要存储在源中,这会使程序变得非常大。

  2. ReadProcessMemory用于监视众所周知的内存偏移量的变化(黑客通常使用相同的偏移量来实现某些目标)与正常运行相比,我需要运行一些 hack,监控行为并获取 hack 行为样本。该程序基本上会做与黑客相同的事情,但相反。

  3. 检测WriteProcessMemory内存中的调用。我不确定这是否会从合法的 DLL 中带来一些误报,但这个想法似乎很有趣。我将如何扫描此调用的进程内存?如何获取它的字节值?

这是一个 hack 调用的示例:

WriteProcessMemory(phandler,0xsomeoffset,&datatowrite,...);

偏移量实际上至少在低级黑客中是固定的。如果我们能以某种方式重新排列堆栈或以某种方式将其向下推,它可能已经搞砸了 hack 以使游戏崩溃。

还有一些事实:

  1. 很少发布新的黑客攻击,并且有固定数量的公开可用并且实际有效。他们中的大多数也以类似的方式工作。
  2. 目标是检测黑客或使其无法正常工作

我的问题是,有什么好的方法可以在这里实现我的目标?欢迎任何会混淆黑客或有助于检测黑客被注入或内存被更改的想法。

我知道没有办法拥有一个 100% 安全的反黑客系统,但如果我们只抓住那些使用公开黑客的人,那已经是 95% 的黑客,我们不在乎少数聪明的黑客。

4个回答

哦,我喜欢这样的问题。

对了,先上:

我们正在托管一个游戏服务器

巴姆,给你。如果客户端必须在将状态更新推送到其他客户端之前将状态更新发送回游戏服务器,您就有机会分析游戏状态的变化。这意味着您可以检测到异常模式。因此,例如,如果您突然发现金币的价值发生了巨大变化,您就可以将该用户拒之门外。

您可以采用许多统计方法。除了明显的“巨大变化”或“不可能的行动”之外,您还可以应用更长期的解决方案——例如随着时间的推移黄金。假设我知道“不要为我的角色添加大量黄金”的技巧,我可能会随着时间的推移以安全数量增加黄金。太好了,如果我总是推动边缘。但是,这种持续增长与在真正一致的游戏玩法中获得的等量金币无关,因此……再次检测并关闭帐户。

这里的关键是,这些是您可以在服务器端做的事情,而最终用户却无能为力,即使他们已经操纵了游戏状态。

现在,进入您的 Win32 附带问题。首先,WriteProcessMemory除了调试器(它将替换代码中的指令——这就是调试器设置断点的工作方式)之外,我认为对任何 DLL 进行的调用都不是特别有效的调用,但是,你无法可靠地调用为系统上的每个调用替换它,而无需编写有效的 rootkit - 即您会影响每个人,而不仅仅是您自己。所以这不是一个真正的选择。

您可以做的一件事——这绝非易事——定期检查您自己的可执行内存以进行修改。有关更多信息,请参阅codeproject 上的Tamper Aware/Self Healing Code基本上,如果您检测到任何修改,请定期调用它并使游戏崩溃。

您也可以考虑代码签名——它的成本并不高,而且它确实提供了一种内置的 Windows 方法来防止离线可执行文件修改。

如果您在本地存储已保存的状态,您可能会考虑保存校验和并将其发送到您的服务器帐户。不,这不是万无一失的,但它增加了额外的复杂性。

如果您要实现这些功能中的任何一个,您将需要稍微提高屏障,使破解者难以禁用、跳过或以其他方式绕过您的保护机制。让我们明确一点——如果某人足够坚定,你就完了,但你至少可以让他们的生活变得非常痛苦。

我的阅读清单上反逆向工程的顶级文章也来自代码项目该指南非常详尽,应该为您提供良好的基础,确切地了解您可以做什么来混淆和扰乱调试器。我将介绍其中一个,我认为这很棒:

 SetUnhandledExceptionFilter(UnhandledExcepFilter);
 __asm{xor eax, eax}
 __asm{div eax}

这是邪恶的。基本上,正如文章所解释的,UnhandledExceptionHandler 作为最后的处理程序在非调试进程上被调用;但是,在这种情况下,我们故意清除eax,然后除以零。这将导致处理器故障,然后操作系统将其发送回可执行文件的异常处理程序 - 仅当连接了调试器时。如果附加了调试器,调试器会收到通知并退出可执行文件。

当然,攻击者很容易div eax用一条或多nop条指令或其他东西替换,这意味着执行会滑过,但一点自我验证就很容易找到了。

所以,总而言之:

  • 我的第一个建议是尝试检测服务器端的作弊行为。在这里,您掌握所有的钥匙。您甚至可以“暗”引入这些更改,即检查并查看谁在作弊,然后分析他们的状态以查看其是否有效,而无需将其切断。
  • 然后,我会尝试以多种形式进行定期自我验证:
    • 在内存中,尽可能多的可执行文件。
    • 在内存中,尽可能多的关键数据结构。
    • 磁盘上的可执行文件也是如此。
  • 最后,我会从头到尾阅读逆向工程指南——看看你可以将什么应用于你的可执行文件。我意识到你说过你不能修改你的可执行文件,但老实说,除非你这样做,否则你很可能会反对它。毕竟,第二个“观察者进程”可以被攻击者杀死。

我知道你提到这个效率低下,我完全同意,但是你当然可以运行某种计时器并连续扫描像作弊引擎和 tsearch 之类的程序 :)

这是另一个完全随机的想法:您可以编写一个函数来检查游戏中偏移处的字节,看看它是否与您想要的字节匹配,如果不匹配,那么您可以调用一个事件来关闭游戏或将正确的字节写入该偏移量,另一种选择可能是根据存储在服务器上的字节检查字节,如果字节不同,则用户被踢。

希望能给你一些想法:)

有关如何击败游戏聊天的信息,我推荐以下文章:

它很好地概述了一些挑战。

如果你想要更多,你也可以看看下面的书:

你会制作自己的 WriteProcessMemory 函数并将其链接到游戏 exe 并过滤虚假调用吗?或者您可以使用可以过滤的某些流拦截的任何其他功能。无论如何,这是非常先进的,您需要提供所有 kernel32.dll 调用或类似的东西。基本上,如果你想在某种程度上保护它,你真的必须这样做,也许对流进行某种过滤会有所帮助,但要找到这一点,你会花一些时间在调试器上寻找命令的时刻解码,所以你可以用零填充它。SSL 代理像在 EMAIL 中一样单独拥有它是一件好事,因此您收到了消息,在发送它之前,您在单独的进程中对其运行扫描检查,然后发送到另一个帐户的邮箱。