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

时间:2012-05-20 05:20:10

标签: c++ security assembly polymorphism

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

我必须与之合作:

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

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

我计划采取的步骤(我的问题在于第2步):

  1. 展开说明

    • 找到像mov这样的简单指令,或推送并用一对指令替换它们,这些指令通过更多指令实现相同目的。在这一步中,我还将添加大量垃圾代码。
    • 我计划通过在数据库中使用一系列转换表来实现这一目的。这应该不是很难做到。
  2. 改组

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

    • 压缩说明并实施一系列不常见的&过程中模糊的说明。并且,与第一步一样,通过使用代码签名数据库来执行此操作。
  4. 为了再次澄清,我需要帮助执行第2步,我不确定我应该如何开始。我尝试制作一些图表,但它们变得非常混乱。

    OH:显然受保护的代码不是最优的 - 但这只是我想要为学校玩的安全项目。

3 个答案:

答案 0 :(得分:2)

我认为你所追求的“指令依赖树”是data flow analysis。这是一种经典的编译器技术,它确定每个代码元素(编程语言中的基本操作),从其他代码元素传递给它的信息。当你完成后,你最终会得到一个图表,其中节点是代码元素(在你的情况下,是个别指令),它们之间的有向弧显示了哪些信息必须流动,以便后面的元素可以对由“早期的“图表中的元素。

您可以在我的网站上看到some examples of such flow analysis(专注于执行程序分析的工具;此工具可能不适合二进制分析,但示例应该有用)。

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

您需要处理许多问题:

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

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

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

  • 保守分析:您无法获得理想的数据流,因为实际上您正在分析任意算法(例如,图灵机);指针严重加剧了这个问题,机器代码充满了指针。因此,当无法确定“x馈送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

答案 1 :(得分:1)

我不确定你的尝试是否有助于防止篡改过程。如果有人附加调试器(进程)并中断发送/接收功能,则内存的校验和保持不变,所有后换将保持不变,即使不是,客户端也将被视为有效。当您询问进程使用的页面时,此调试器或注入的代码能够操作您(因此您不会看到注入的代码,因为它不会告诉您它所在的页面)。

对于您的实际问题:

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

我在Windows上使用gcc测试了这个 - 它可以工作。通过重新排序.o文件链接时所有函数都放在不同的地址。

答案 2 :(得分:1)

  

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

不可能。欢迎来到停机问题。