我一直在思考如何保护我的C/ c++代码不被反汇编和逆向工程破坏。通常情况下,在我的代码中,我绝不会宽恕这种行为;然而,为了各种人的安全,我目前正在研究的协议决不能被检查或理解。

现在这对我来说是一个新的主题,互联网并没有真正的资源来防止逆向工程,而是描述了大量关于如何逆向工程的信息

到目前为止我想到的一些事情是:

Code injection (calling dummy functions before and after actual function calls) Code obfustication (mangles the disassembly of the binary) Write my own startup routines (harder for debuggers to bind to) void startup(); int _start() { startup( ); exit (0) } void startup() { /* code here */ } Runtime check for debuggers (and force exit if detected) Function trampolines void trampoline(void (*fnptr)(), bool ping = false) { if(ping) fnptr(); else trampoline(fnptr, true); } Pointless allocations and deallocations (stack changes a lot) Pointless dummy calls and trampolines (tons of jumping in disassembly output) Tons of casting (for obfuscated disassembly)

我的意思是,这些是我想过的一些事情,但它们都可以在适当的时间框架内由代码分析师解决。我还有别的选择吗?


当前回答

正如很多人已经说过的:在一个普通的CPU上,你不能阻止它们,你只能延迟它们。就像我以前的密码学老师告诉我的那样:你不需要完美的加密,破解密码的代价肯定比获得的代价更大。你的困惑也是一样。

但还有3个注意事项:

It is possible to make reverse engineering impossible, BUT (and this is a very very big but), you cant do it on a conventional cpu. I did also much hardware development, and often FPGA are used. E.g. the Virtex 5 FX have a PowerPC CPU on them, and you can use the APU to implement own CPU opcodes in your hardware. You could use this facility to really decrypt incstuctions for the PowerPC, that is not accessible by the outside or other software, or even execute the command in the hardware. As the FPGA has builtin AES encryption for its configuration bitstream, you could not reverse engineer it (except someone manages to break AES, but then I guess we have other problems...). This ways vendors of hardware IP also protect their work. You speak from protocol. You dont say what kind of protocol it is, but when it is a network protocol you should at least protect it against network sniffing. This can you indeed do by encryption. But if you want to protect the en/decryption from an owner of the software, you are back to the obfuscation. Do make your programm undebuggable/unrunnable. Try to use some kind of detection of debugging and apply it e.g. in some formula oder adding a debug register content to a magic constant. It is much harder if your program looks in debug mode is if it where running normal, but makes a complete wrong computation, operation, or some other. E.g. I know some eco games, that had a really nasty copy-protection (I know you dont want copyprotection, but it is similar): The stolen version altered the mined resources after 30 mins of game play, and suddenly you got just a single resource. The pirate just cracked it (i.e. reverse engineered it) - checked if it run, and volia released it. Such slight behaviour changings are very hard to detect, esp. if they do not appear instantly to detection, but only delayed.

所以最后我想建议: 估算逆向工程人员的收益,将其转化为一些时间(例如,使用最便宜的印度工资),并进行逆向工程,使时间成本更大。

其他回答

安布尔说的完全正确。你可以让逆向工程变得更难,但你永远无法阻止它。永远不要相信依赖于防止逆向工程的“安全性”。

That said, the best anti-reverse-engineering techniques that I've seen focused not on obfuscating the code, but instead on breaking the tools that people usually use to understand how code works. Finding creative ways to break disassemblers, debuggers, etc is both likely to be more effective and also more intellectually satisfying than just generating reams of horrible spaghetti code. This does nothing to block a determined attacker, but it does increase the likelihood that J Random Cracker will wander off and work on something easier instead.

安全网哨兵(原阿拉丁)。不过要注意的是——他们的API很烂,文档也很烂,但与他们的SDK工具相比,这两者都很棒。

I've used their hardware protection method (Sentinel HASP HL) for many years. It requires a proprietary USB key fob which acts as the 'license' for the software. Their SDK encrypts and obfuscates your executable & libraries, and allows you to tie different features in your application to features burned into the key. Without a USB key provided and activated by the licensor, the software can not decrypt and hence will not run. The Key even uses a customized USB communication protocol (outside my realm of knowledge, I'm not a device driver guy) to make it difficult to build a virtual key, or tamper with the communication between the runtime wrapper and key. Their SDK is not very developer friendly, and is quite painful to integrate adding protection with an automated build process (but possible).

Before we implemented the HASP HL protection, there were 7 known pirates who had stripped the dotfuscator 'protections' from the product. We added the HASP protection at the same time as a major update to the software, which performs some heavy calculation on video in real time. As best I can tell from profiling and benchmarking, the HASP HL protection only slowed the intensive calculations by about 3%. Since that software was released about 5 years ago, not one new pirate of the product has been found. The software which it protects is in high demand in it's market segment, and the client is aware of several competitors actively trying to reverse engineer (without success so far). We know they have tried to solicit help from a few groups in Russia which advertise a service to break software protection, as numerous posts on various newsgroups and forums have included the newer versions of the protected product.

最近,我们在一个较小的项目上尝试了他们的软件许可解决方案(HASP SL),如果您已经熟悉HL产品,那么这个解决方案就足够简单了。它似乎有效;目前还没有关于盗版事件的报道,但这款产品的需求要低得多。

当然,没有什么保护措施是完美的。如果有人有足够的动机,并且有大量的现金可以烧,我相信HASP提供的保护是可以规避的。

可能最好的选择仍然是使用虚拟化,这引入了另一层需要绕过的间接/混淆,但正如SSpoke在他的回答中所说,这种技术也不是100%安全的。


关键是你不会得到终极保护,因为根本就没有这种东西,即使有,也不会持续太久,这意味着它一开始就不是终极保护。

凡是人组装起来的东西,都可以拆卸。

通常情况下,(正确的)拆卸通常是(一点或更多)更困难的任务,所以你的对手必须更熟练,但你可以假设总有这样的人,这是一个安全的赌注。

如果您希望保护某些内容不受REs的影响,那么您必须至少了解REs使用的常见技术。

这样的话

互联网并不是真正的资源预防逆向工程,而是描述了大量关于如何逆向工程的信息

表现出你的坏态度。我并不是说要使用或嵌入保护,你必须知道如何打破它,但要明智地使用它,你应该知道它的弱点和陷阱。你应该明白这一点。

(有一些软件以错误的方式使用保护,使得这种保护实际上不存在。为了避免含糊,我给你举一个在网上简单描述的例子:牛津英语词典第二版CD-ROM - v4。您可以在以下页面了解SecuROM使用失败的原因:16、32或64位Windows环境下CD-ROM上的牛津英语词典(OED):硬盘安装、错误、字处理宏、网络、字体等)

每件事都需要时间。

如果你是这门学科的新手,没有几个月甚至几年的时间来学习正则表达式,那么就使用其他人提供的可用解决方案。这里的问题很明显,它们已经在那里了,所以你已经知道它们不是100%安全的,但制作自己的新保护只会给你一种被保护的错误感觉,除非你非常了解逆向工程和保护的艺术状态(但你不知道,至少目前不知道)。

软件保护的目的是吓唬新手,拖延常见的正则,并让经验丰富的正则在她/他(希望很有趣)到达应用程序中心后面带微笑。

在商业谈话中,你可能会说这都是为了尽可能地推迟竞争。

(看看Philippe Biondi和Fabrice Desclaux在Black Hat 2006上展示的Skype中的银针)。


你知道有很多关于RE的东西,所以开始阅读吧。:)

我说过虚拟化,所以我将给你一个链接到EXETOOLS论坛的一个示例线程:最佳软件保护:Themida还是Enigma protector ?这可能会对你进一步的搜索有所帮助。

起初,虚拟机中受保护的代码似乎不可能进行逆向工程。Themida封隔器

但它不再那么安全了。无论你如何打包你的代码,你总是可以对任何加载的可执行文件进行内存转储,并使用任何反汇编程序(如IDA Pro)进行反汇编。

IDA Pro还提供了一个漂亮的汇编代码到C源代码转换器,尽管生成的代码看起来更像一个指针/地址数学混乱。如果你把它与原来的比较,你可以修复所有的错误,并撕下任何东西。

使代码难以进行逆向工程称为代码混淆。

你提到的大多数技术都很容易解决。他们专注于添加一些无用的代码。但是无用的代码很容易被发现和删除,留下一个干净的程序。

为了有效地混淆,您需要使程序的行为依赖于正在执行的无用部分。例如,与其这样做:

a = useless_computation();
a = 42;

这样做:

a = complicated_computation_that_uses_many_inputs_but_always_returns_42();

或者不这样做:

if (running_under_a_debugger()) abort();
a = 42;

这样做(其中running_under_a_debugger不应该很容易被识别为测试代码是否在调试器下运行的函数-它应该将有用的计算与调试器检测混合在一起):

a = 42 - running_under_a_debugger();

有效的混淆并不是仅仅在编译阶段就能做到的。编译器能做的,反编译器也能做。当然,您可以增加反编译器的负担,但这不会有太大的帮助。有效的混淆技术,就其存在而言,包括从第一天开始编写混淆的源代码。让你的代码自修改。你的代码中充斥着从大量输入中得到的计算跳跃。例如,而不是简单的调用

some_function();

这样做,你碰巧知道some_data_structure中精确的位的预期布局:

goto (md5sum(&some_data_structure, 42) & 0xffffffff) + MAGIC_CONSTANT;

如果你认真对待混淆,那就在你的计划中增加几个月的时间;混淆视听代价不菲。请务必考虑到,到目前为止,避免人们对您的代码进行逆向工程的最好方法是使其无用,这样他们就不会费心了。这是一个简单的经济考虑:如果对他们来说价值大于成本,他们就会逆向工程;但提高他们的成本也会大大提高你的成本,所以尽量降低他们的价值。

既然我已经告诉过你,混淆是困难和昂贵的,我要告诉你,无论如何,它不适合你。你写

目前我正在研究的协议绝不能被检查或理解,为了各种人的安全

这是一个危险的信号。它是通过默默无闻来保证安全的,而默默无闻的记录非常糟糕。如果协议的安全性依赖于人们不知道协议,那么你已经输了。

推荐阅读:

安全圣经:Ross Anderson的《安全工程》 混淆的圣经:由Christian Collberg和Jasvir Nagra开发的Surreptitious软件