【问题标题】:Execute data as code?将数据作为代码执行?
【发布时间】:2010-08-14 21:41:22
【问题描述】:

我的客户要求我编写一个自定义的加密可执行文件,以防止许可系统被轻易破解。现在,我明白这是一种虚假的安全感,但尽管如此,他还是坚持了下来。

所以,我挖掘了可移植可执行文件的知识并提出了这个想法:

  • 加密可执行文件
  • 将此粘贴​​到加载程序可执行文件的末尾以及它的大小
  • 加载器解密数据
  • 它将代码复制到分配有具有可执行权限的 VirtualAlloc 的页面
  • 它找到应用程序的入口点
  • 跳到那里,我们都准备好了。

我在跳转那里的部分有问题。我怎样才能做到这一点?如果我要设置一个指向它的函数指针,签名会是什么?加载的可执行文件的 main() 函数的签名?还是我需要诉诸组装?

我了解在加载代码后可能需要更正绝对地址。如何检查是否需要,以及如何实际执行此操作?

编辑:在 windows 上工作并使用 GCC 编译。如果需要,我可以切换微软编译器。

Edit2:澄清一下:我知道这几乎没有意义。我相信它代表任何类型的 DRM。由我的客户决定,尽管我警告过他,但他仍然想要。

提前致谢。

【问题讨论】:

  • 在我看来,您输入的解决方案有点问题,您的函数在做什么会跳转到其他函数?它们是固定的其他地址,我看到这个解决方案有很多问题,比如静态链接库在哪里?谁使用加密代码?
  • 我会说 - 如果你真的想要 DRM。买它。为什么?即使您确实得到了“某些东西”并开始工作。当它破裂时,你在六个月内做什么?跟上饼干的步伐是一项全职工作。
  • 这由我的客户决定。我真的不在乎他是否做出了错误的决定。我诚实地警告过他,他仍然想要它。
  • 这里有一些不错的提示:inner-smile.com/nocrack.phtml#howto

标签: c++ windows assembly loader


【解决方案1】:

不幸的是,跳转到代码的入口点是您最不必担心的事情。 Portable Executable (PE) 文件(这是 Windows 上用于 EXE 和 DLL 文件的文件格式)不是您可以加载到单个内存块然后运行的东西。您的自定义 PE 加载器必须处理以下工作:

  • 将 PE 文件中的各种代码和数据部分加载到单独的内存块中。

  • 解决导入表中的依赖关系以加载您的 EXE 所依赖的 DLL。

  • 执行重定位。

正确处理所有细节可能是一项相当复杂的工作。我建议您寻找一种可以购买的工具来执行这种 EXE 加密。

编辑:快速的 Google 建议您可能需要查看以下内容:

  • EXECryptor(专有)

  • RLPack(专有)

  • UPX (GPL) 据我所知,这个只进行压缩,但您可以使用源代码添加加密(如果 GPL 符合您的需求)。

肯定会有更多这样的工具——这只是快速搜索的结果。

另一个编辑:

MSDN 杂志刊登了 Matt Pietrek 的文章,名为“深入了解 Win32 可移植可执行文件格式”(Part 1Part 2)。它包含很多关于 PE 文件格式的信息,这些信息应该对您有用。一个有趣的信息:Microsoft 链接器的最新版本似乎默认省略了 EXE 的基本重定位。您可能需要指示链接器将它们放回原处,因为您的包装器 EXE 很可能已经加载到您的有效负载 EXE 的首选加载地址。或者,您可以尝试为您的包装器 EXE 提供一个奇异的首选加载地址,希望它不会干扰有效负载 EXE。

我还找到了page that discusses a rudimentary PE file compressor。不过,它似乎并不完全通用,可能需要一些额外的工作才能使用它。

【讨论】:

  • 我知道其中一些工具,并向客户推荐了这些工具,但他在谷歌上搜索了每一个工具的解包器,并觉得他需要一个定制的工具。即使我不能承担这个任务,我也想了解它,因为我觉得这是一个非常有趣的话题。你能就你提到的那些点向我推荐一些材料吗?尤其是搬迁。
  • @sztomi:我添加了一些指向更多信息的链接。有关搬迁的更多信息,请查看 Matt Pietrek 文章的第 2 部分。
  • @sztime: "WINE" (winehq.org) 项目已经为 linux 实现了 PE 加载器,所以你至少可以研究一下源码。 MPlayer (mplayerhq.hu/design7/news.html) 也使用了某种代码(可能来自 wine)在 linux 平台上加载 windows dll。无论如何,这是可以做到的,但如果这是一个“复制保护防御”,它可以被破解,如果产品足够好就会被破解。任何有权访问您的 exe 的人都可以(尝试)通过绕过保护或解包来破解它。
  • +1。 UPX 是行不通的,因为您要么必须使用未经修改的 UPX,要么根据 GPL 分发程序。如果您可以将自己的加密添加到(合理地)免费的压缩器中,我认为滚动自己没有任何优势。但最终,简单的解密到内存的方法很容易被内存转储打败。
【解决方案2】:

正如其他人所提到的,简单地将整个 EXE 加载到数据段中并在运行时链接它是一项艰巨的任务;但是,这里有另一种选择。

把你输入的EXE;找到它的代码和初始化数据(包括常量)部分。重命名这些部分并将它们全部转换为读写初始化数据部分;加密内容。现在添加一个包含解密存根的新代码段,并在那里更改入口点。此存根应就地解密这些段,然后将其保护更改为适合其类型的任何内容,然后跳转到原始入口点。

这避免了必须实现完整 PE 加载器的所有功能,因为导入表没有加密,因此普通的 windows 加载器会为您处理它们。

当然,应该注意的是,这种幼稚的方法在任何时候都无法在协同攻击中幸存下来——攻击者可以简单地转储进程的内存来获取原始的解密代码。为避免这种情况,您可能需要持续加密和解密代码,此时 PE 处理是您最不关心的问题。

【讨论】:

  • 这是有道理的。因此,如果我在 exe 中添加一个新部分并更新部分表和入口点,我可以简单地跳转到解密的代码,因为操作系统加载程序负责导入和重定位(如果需要)?
  • 基本上,是的——除非重定位不会如果它们在相关部分中,则不会被处理。因此,请确保它是不可重定位的 EXE。导入在 PE 文件中有一个单独的存根部分,我相信......(不确定,你应该检查一下:)
【解决方案3】:

除了正确加载 PE 图像的所有麻烦和麻烦之外,您还需要担心Data Execution Protection,它旨在防止这样做。

不要忘记,对于某些杀毒软件和反恶意软件工具,这也可能看起来像恶意软件行为。

【讨论】:

  • 数据执行保护只适用于数据页;如果您使用带有 PAGE_EXECUTE_* 标志之一的 VirtualAllocEx() 分配页面,您将能够从中执行代码。
  • 对此进行扩展:DEP 并非旨在防止有意加载和执行代码;它旨在防止意外(或更可能是恶意)从数据页执行代码 - 例如从堆栈执行代码的缓冲区溢出攻击。动态创建和执行自己的代码是合法行为——JIT 编译器就是一个突出的例子。
  • 你说得对,Martin,我在提问前查阅了 DEP 文档。
  • @Martin,对。但是您必须意识到这一点并正确分配内存以使其可执行,否则它会在某个不合时宜的时刻站起来殴打您。
【解决方案4】:

在我看来,您输入的解决方案有点小错误,您的函数在做什么会跳转到其他函数?它们是固定的其他地址,我看到这个解决方案有很多问题,比如加密代码的静态链接库在哪里。

我认为你可以这样做:

  1. 使用您的秘密程序集传输加密的 dll 文件
  2. 在 tmp 目录中加密她
  3. 对此执行 LoadLibrary
  4. 解锁 DLL 文件并从系统中删除?

【讨论】:

  • 是的,这就是我所看到的。加密的 DLL 甚至可以存储在您的主 .exe 资源中。您可能还希望通过传入的跳转表调用主 .exe 中的函数来执行大多数操作,从而防止提取的 DLL 独立运行。但无论如何,你最好还是买这种东西。
【解决方案5】:

加载器解密数据

这确实说明了一切。

要让加载程序能够解密数据,它还必须包含(或至少知道)解密密钥。

因此,如果您将此加载器实际分发给您的用户,他们将可以完全访问加载器代码和使用的密钥。

也许这就是你所说的“虚假的安全感”?

既然您的客户似乎要么固执要么只是无知,为什么不构建一个简单的小解密演示,清楚地显示他们思维中的缺陷?

【讨论】:

  • 代码混淆确实“起作用”,假设防止 some 破解让一些人购买完整的应用程序 - 这是一个猜测什么的问题曲线看起来像并投入了适当的努力。
【解决方案6】:

您应该能够将您的地址以 c 样式转换为函数指针,然后调用它:

typedef void (*MyPtr)();

MyPtr p = (MyPtr)1234;
p();

【讨论】:

    【解决方案7】:

    在大多数操作系统中,您无法像代码一样执行数据,这要归功于 gdt,这是一个将数据与代码分开的全局描述符表。如果您尝试执行数据,处理器会给出异常。

    【讨论】:

    • 直到最近,读取权限和执行权限在 x86 上还是一样的。
    • 仅仅因为操作系统没有使用他们应该使用的 GDT,这并不意味着他们在哪里做同样的事情。请查看维基百科或英特尔数据表
    • 在平面内存模型(所有常见的 x86 操作系统都使用)中,GDT 不能用于此目的,因为只有一个段包含整个平面地址空间。 NX 位 (en.wikipedia.org/wiki/NX_bit) 在页表级别上实现了相同的目的,但仅在 2004 年与 Prescott (en.wikipedia.org/wiki/Pentium_4) 的 5x0J 系列一起引入。
    • 如果 osdev 设计者决定使用平面内存模型是他可以做的决定。我知道这更容易,但 gtd 存在是为了某些东西,而不是被隐藏并将内存用作一个长而扁平的块。从 2004 年到今天有 6 年的不同,我想今天没有人使用 Pentium 3。
    • 只有在哈佛架构上你不能执行数据,但是因为我们在这里谈论的是 Windows。此外,即使在哈佛,代码也必须以某种方式加载到内存中才能执行,所以“代码”和“数据”之间的区别更加模糊(只有在简单的控制器上,当代码从 ROM 执行时才会有真正的区别)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-07
    • 1970-01-01
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多