将数据作为代码执行?
我的客户要求我编写一个自定义的加密可执行文件,以防止许可系统被轻易破解。现在,我明白这是一种虚假的安全感,但尽管如此他还是坚持这样做。
因此,我挖掘了我对可移植可执行文件的了解,并提出了这个想法:
- 加密可执行文件
- 将其与加载程序可执行文件的大小一起粘贴到加载程序可执行文件的末尾
- 加载程序解密数据
- 将代码复制到使用 VirtualAlloc 分配的页面,该页面具有可执行权限
- 它找到应用程序的入口点
- 跳转到那里,我们就完成了。
我对跳跃部分有疑问。我怎样才能做到这一点?如果我要设置一个指向它的函数指针,签名是什么?加载的可执行文件的 main() 函数的签名?或者我需要诉诸组装吗?
我知道加载代码后可能需要更正绝对地址。我如何检查是否需要,以及如何实际执行此操作?
编辑:在 Windows 上工作并使用 GCC 进行编译。如果需要的话我可以切换微软编译器。
Edit2:澄清一下:我知道这几乎毫无意义。我相信这代表任何类型的 DRM。这由我的客户决定,尽管我警告过他,但他仍然想要它。
提前致谢。
My client asked me to write an custom encrypted executable to prevent easy cracking of the licensing system. Now, I understand that this is a false sense of security, but despite this he insisted on it.
So, I dug up my knowledge of portable executables and came up with this idea:
- Encrypt the executable
- Stick this to the end of a loader executable along with it's size
- The loader decrypts the data
- It copies the code to a page allocated with VirtualAlloc that has executable permissions
- It finds the entry point of the application
- Jumps there and we are all set.
I have a problem with the jumping there part. How can I do that? If I were to set a function pointer to it, what would be the signature? The signature of the loaded executable's main() function? Or do I need to resort to assembly?
I understand that it might be needed to correct absolute addresses after loading the code. How do I check if I need to, and how do I actually perform this?
Edit: Working on windows and compiling with GCC. I can switch the Microsoft compiler if necessary.
Edit2: To clarify: I KNOW it's mostly pointless. I believe that stands for any kind of DRM. It's up to my client to decide, and he still wants it despite me warning him about this.
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
不幸的是,跳转到代码的入口点是您最不用担心的。 可移植可执行 (PE) 文件(这是 Windows 上用于 EXE 和 DLL 文件的文件格式)不是您可以加载到单个内存块然后运行的东西。您的自定义 PE 加载程序必须处理以下工作:
将 PE 文件中的各种代码和数据部分加载到单独的内存块中。
从导入表中解析依赖关系,以加载 EXE 所依赖的 DLL。
执行重定位。
正确处理所有细节可能是一项相当复杂的工作。我建议您寻找一个可以购买的工具来进行这种 EXE 加密。
编辑:快速谷歌建议您可能需要查看以下内容:
EXECryptor (专有)
RLPack(专有)
UPX (GPL)据我所知,这个仅进行压缩,但您可以使用 The Source 添加加密(如果 GPL 与您的需求兼容)。
肯定会有更多类似的工具——这只是快速搜索的结果。
另一个编辑:
MSDN 杂志刊登了一篇由 Matt Pietrek 撰写的文章,名为“深入研究 Win32 可移植可执行文件格式”(第 1 部分、第 2 部分一个>)。它包含大量有关 PE 文件格式的信息,对您应该有用。一个有趣的信息是:Microsoft 链接器的最新版本似乎默认省略了 EXE 的基址重定位。您可能想要指示链接器将它们放回,因为您的包装器 EXE 很可能已经加载到有效负载 EXE 的首选加载地址处。或者,您可以尝试为您的包装器 EXE 提供一个奇异的首选加载地址,希望它不会干扰有效负载 EXE。
我还发现了一个讨论基本 PE 文件压缩器的页面。但它似乎并不完全通用,并且可能需要一些额外的工作才能使用它。
Unfortunately, jumping to the entry point of your code is the least of your worries. A Portable Executable (PE) file (which is the file format used for EXE and DLL files on Windows) is not something you can just load into a single memory block and then run. Your custom PE loader would have to take care of the following jobs:
Load the various code and data sections in the PE file into separate memory blocks.
Resolve dependencies from the import table to load DLLs that your EXE depends on.
Perform relocations.
Getting all of the details right would probably be a pretty involved job. I would suggest that you look for a tool you can buy that does this kind of EXE encryption.
Edit: A quick Google suggests you might want to take a look at the following:
EXECryptor (proprietary)
RLPack (proprietary)
UPX (GPL) This one only does compression as far as I understand, but you could Use The Source to add encryption (if the GPL is compatible with your needs).
There are bound to be more tools like these -- this is just the result of a quick search.
Another edit:
MSDN magazine carried an article by Matt Pietrek called "An In-Depth Look into the Win32 Portable Executable File Format" (Part 1, Part 2). It contains a lot of information on the PE file format that should be useful to you. One interesting bit of information: Recent versions of the Microsoft linker appear to leave out base relocations for EXEs by default. You'll probably want to instruct the linker to put these back in because it's likely that your wrapper EXE is already loaded at your payload EXE's preferred load address. Alternatively, you could try and give your wrapper EXE an exotic preferred load address where it hopefully won't interfere with the payload EXE.
I've also found a page that discusses a rudimentary PE file compressor. It doesn't appear to be fully general though and would probably require some additional work before you can use it.
正如其他人所提到的,简单地将整个 EXE 加载到数据部分并在运行时链接它是一项艰巨的任务;但是,还有另一种选择。
获取您的输入 EXE;找到它的代码和初始化数据(包括常量)部分。重命名这些节并将它们全部转换为可读写的初始化数据节;加密内容。现在添加一个包含解密存根的新代码段,并更改其中的入口点。该存根应该就地解密段,然后将其保护更改为适合其类型的任何内容,并跳转到原始入口点。
这避免了必须实现完整 PE 加载器的所有功能,因为导入表未加密,因此普通 Windows 加载器将为您处理它们。
当然,应该指出的是,这种幼稚的方法在任何时候都无法在协同攻击中幸存——攻击者可以简单地转储进程的内存来获取原始的解密代码。为了避免这种情况,可能需要持续加密和解密代码,此时 PE 处理是您最不关心的问题。
As others have mentioned, simply loading the entire EXE up into a data section and linking it at runtime is a difficult task; however, here's another option.
Take your input EXE; find its code and initialized data (including constant) sections. Rename these sections and convert them all to read-write initialized data sections; encrypt the contents. Now add a new code segment containing your decryption stub, and change the entry point there. This stub should decrypt the segments in-place, then change their protection to whatever is appropriate for their type, and jump to the original entry point.
This avoids having to implement all the functions of a full PE loader, as the imports tables are not encrypted, and thus the normal windows loader will take care of them for you.
It should be noted, of course, that this kind of naive approach will not survive a concerted attack for any time at all - an attacker can simply dump the process's memory to get the original, decrypted code. To avoid this one would likely need to encrypt and decrypt code on a continual basis, at which point PE handling is the least of your concerns.
除了正确加载 PE 映像的所有麻烦和麻烦之外,您还需要担心数据执行保护旨在防止执行此操作。
不要忘记,对于某些防病毒和反恶意软件工具来说,这也可能看起来像恶意软件行为。
In addition to all of the fuss and bother of correctly loading a PE image, you will also need to worry about Data Execution Protection which is intended to prevent doing this very thing.
Don't forget that this also can appear like malware behavior to some anitivirus and antimalware tools.
在我看来,您的类型化解决方案几乎没有问题,您的函数在做什么跳转到其他函数?它们修复了其他地址,我看到这个解决方案有很多问题,比如加密代码的静态链接库在哪里。
我认为你可以这样做:
Your typed solution in my point of view is little buggy, what this your functions doing jumps to other functions? They are fixed other addresses and i see many many problems with this solution like where is the static linked libraries of the encrypted code.
I think you can do something like:
这确实说明了一切。
为了使加载程序能够解密数据,它还必须包含(或至少知道)解密密钥。
因此,如果您将此加载程序物理分发给您的用户,他们将拥有对加载程序代码和所使用的密钥的完全访问权限。
也许这就是你所说的“虚假的安全感”?
由于您的客户似乎要么固执,要么只是无知,为什么不构建一个简单的小解密演示来清楚地显示他们思维中的缺陷呢?
This says it all really.
For the loader to be able to decrypt the data it must also contain (or at least know about) the decryption key.
Therefore if you distribute this loader physically to your users they will have full access to both the loader code and the key used.
Maybe this is what you mean by "false sense of security"?
As your client seems to be either stubborn or just ignorant, why not build a simple little decryption demo that clearly shows the flaws in their thinking?
您应该能够将您的地址转换为函数指针,并调用它:
You should be able to c-style cast your address to a function pointer, and call it:
在大多数操作系统中,您无法像代码一样执行数据,这要归功于 gdt(将数据与代码分开的全局描述符表)。如果您尝试执行数据,处理器会给出异常。
You can't execute data like code in most operating system, thanks to gdt, the global descriptors table that divides data from code. If you try to execute data an exception is given by the processor.