我需要帮助开发多态引擎 - 指令依赖树

I need help developing a polymorphism engine - instruction dependency trees

本文关键字:指令 依赖 引擎 多态 帮助 开发      更新时间:2023-10-16

我目前正在尝试编写一个多态引擎,以C++玩弄我有一个整洁的反黑客保持活动检查的想法。然而,编写多态引擎被证明是相当困难的 - 我什至还没有确定我应该如何去做。这个想法是将可执行代码流式传输给用户(即我正在保护的应用程序(,并偶尔向他们发送一些代码,这些代码在内存映像上运行一些校验和并将其返回到服务器。问题是我不希望有人简单地劫持或以编程方式破解保持活动状态的检查;相反,每个代码都将在服务器上生成,并使用简单的代码存根并通过多态引擎运行它。每个保持活动状态检查将返回一个值,该值取决于数据的校验和,以及潜入保持活动状态检查内部的随机算法。如果存根返回不正确,我知道保持活动状态检查已被篡改。

我必须使用什么:

*可执行映像 PDB 文件。*汇编器和反汇编引擎,我已经在它们之间实现了接口,允许重新定位代码等...

以下是我正在考虑执行的步骤以及如何执行这些步骤。我正在使用Windows PE可执行文件上的x86指令集

我计划采取的步骤(我的问题是第 2 步(:

  1. 展开说明

    • 找到像 mov 这样的简单指令,或者用几个指令推送并替换它们,这些指令通过更多指令实现相同的目的。在此步骤中,我还将添加大量垃圾代码。
    • 我计划仅通过在数据库中使用一系列转换表来执行此操作。这应该不难做到。
  2. 洗牌

    • 这是我最麻烦的部分。我需要将代码隔离到函数中。然后我需要建立一系列指令依赖树,然后我需要根据一个依赖另一个来重新定位它们。我可以通过解析 pdb 文件来找到函数,但创建指令依赖树是我完全迷失的棘手部分。
  3. 压缩指令

    • 压缩指令,并在此过程中实现一系列不常见和晦涩的指令。并且,与第一步一样,使用代码签名数据库来执行此操作。

再次澄清,我需要帮助执行第 2 步,并且不确定我应该如何开始。我尝试制作一些图表,但它们变得非常混乱。

OH:显然,受保护的代码不会是最佳代码 - 但这只是我想在学校玩的一个安全项目。

我认为您对"指令依赖树"所追求的是数据流分析。 这是一种经典的编译器技术,它确定每个代码元素(编程语言中的原始操作(从其他代码元素传递到它的信息。 完成后,您最终会得到一个图表,其中节点是代码元素(在您的情况下是单独的指令(,并且它们之间的定向弧显示哪些信息必须流动,以便后面的元素可以执行由图中"早期"元素产生的结果。

你可以在我的网站上看到这种流分析的一些示例(专注于进行程序分析的工具;这个工具可能不适合二进制分析,但这些示例应该会有所帮助(。

编译器书籍中有大量关于进行数据流分析的文献。 请参阅任何编译器教科书。

您需要处理许多问题:

  • 分析代码以提取代码元素。 您听起来好像已经可以访问所有说明。

  • 确定每个代码元素所需的操作数和生成的值。 这对于"ADD register,register"来说非常简单,但您可能会发现这对于具有惊人大而疯狂指令集的生产 x86 CPU 来说令人生畏。你必须为CPU可能执行的每个指令收集这个,这意味着几乎所有的指令。 尽管如此,这只是汗水和花费大量时间查看说明参考手册。

  • 循环。 值可以从指令流经其他指令,返回到同一指令,因此数据流可以形成循环(复杂循环的大量循环(。 数据流文献将告诉你如何在计算图形中的数据流弧方面处理此问题。 我不知道这些对您的保护计划意味着什么。

  • 保守分析:你无法获得理想的数据流,因为实际上你正在分析任意算法(例如,图灵机(;指针严重加剧了这个问题,机器代码充满了指针。 因此,当无法确定"x feed y"时,数据流分析引擎通常会简单地假设"x(可能(馈送 y"。 数据流图在概念上从"x(必须(馈送 y"转变为实用的"x(可能(馈送 y"类型弧;事实上,文献中充满了"必须"和"可能"算法,正因为如此。同样,文献告诉你很多方法可以进行[保守]流分析(大多数具有不同程度的保守主义;事实上,最保守的数据流分析只是说"每个x都养活每个y"!(。 我不知道这对你的计划在实践中意味着什么。

有很多人对二进制代码分析感兴趣(例如,NSA(,他们对机器指令进行数据流分析,并完成指针分析。 您可能会发现此演示文稿很有趣:http://research.cs.wisc.edu/wisa/presentations/2002/0114/gogul/gogul.1.14.02.pdf

我不确定您正在尝试的内容是否有助于防止篡改进程。如果有人附加调试器(进程(并在发送/接收函数上中断,则内存的校验和保持不变,所有随机播放将保持原样,即使客户端不是,客户端也将被视为有效。当您询问进程使用哪些页面时,此调试器或注入的代码能够操纵您(因此您不会看到注入的代码,因为它不会告诉您它所在的页面(。

对于您的实际问题:

无法通过重新链接可执行文件来实现随机播放。链接器跟踪 .o 文件导出和导入的所有符号。读取所有 .o 文件时,函数的实际地址将放在导入的占位符中。如果将每个函数放在单独的 cpp 文件中并将它们编译为 .o 文件。在链接器调用中对 .o 文件重新排序时,所有函数都将位于不同的地址上,可执行文件仍然可以正常运行。

我在 Windows 上使用 gcc 对此进行了测试——它可以工作。通过在链接时重新排序.o文件,所有功能都放在不同的地址。

我可以通过解析 pdb 文件来找到函数,但创建 指令依赖树是我完全迷失的棘手部分。

不可能的。欢迎来到停止问题。