我一直在思考如何保护我的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)

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


当前回答

安全网哨兵(原阿拉丁)。不过要注意的是——他们的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提供的保护是可以规避的。

其他回答

Take, for example, the AES algorithm. It's a very, very public algorithm, and it is VERY secure. Why? Two reasons: It's been reviewed by lots of smart people, and the "secret" part is not the algorithm itself - the secret part is the key which is one of the inputs to the algorithm. It's a much better approach to design your protocol with a generated "secret" that is outside your code, rather than to make the code itself secret. The code can always be interpreted no matter what you do, and (ideally) the generated secret can only be jeopardized by a massive brute force approach or through theft.

我认为一个有趣的问题是“为什么你想让你的代码变得模糊?”你想让攻击者难以破解你的算法?让他们更难在你的代码中发现可利用的漏洞?如果代码一开始就不可破解,那么您就不需要混淆代码。问题的根源在于易破解的软件。解决问题的根源,不要只是混淆它。

而且,你的代码越混乱,你就越难找到安全漏洞。是的,这对黑客来说很难,但你也需要找到漏洞。从现在开始,代码应该很容易维护,即使是编写良好的清晰代码也很难维护。不要让事情变得更糟。

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

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.

传统的逆向工程技术依赖于智能代理使用反汇编程序回答关于代码的问题的能力。如果你想要更强的安全性,你必须做一些事情,可以证明阻止代理得到这样的答案。

您可以通过依赖停止程序(“程序X停止吗?”)来做到这一点,这通常是无法解决的。向程序中添加难以推理的程序,会使程序难以推理。构建这样的程序要比拆解它们容易。你也可以在程序中添加推理难度不同的代码;一个很好的候选程序是关于别名(“指针”)的推理程序。

Collberg等人有一篇论文(“制造廉价、弹性和隐形的不透明结构”)讨论了这些主题,并定义了各种“不透明”谓词,这些谓词会使对代码的推理变得非常困难:

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.39.1946&rep=rep1&type=pdf

我还没有看到Collberg的具体方法应用于产品代码,尤其是C或c++源代码。

DashO Java混淆器似乎使用了类似的想法。 http://www.cs.arizona.edu/~collberg/Teaching/620/2008/Assignments/tools/DashO/

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

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

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

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软件

通过不公开来保证安全并不像比他聪明得多的人所证明的那样有效 我们两个。如果你必须保护你的客户的通信协议,那么你是 道德上有义务使用最好的代码,这些代码是公开的,并由专家全面审查。

这适用于人们可以检查代码的情况。如果您的应用程序是在嵌入式微处理器上运行的,那么您可以选择一个具有密封功能的微处理器,这使得在运行时不可能检查代码或观察更多的琐碎参数,例如当前使用情况。(是的,除了硬件入侵技术,你要小心地拆卸芯片,使用先进的设备来检查单个晶体管上的电流。)

我是x86逆向工程汇编程序的作者。如果你准备感冒的话 惊喜,寄给我你竭尽全力的结果。(通过我的网站联系我。) 在我所看到的答案中,很少有人会给我带来实质性的障碍。如果你想看的话 如何复杂的逆向工程代码工作,你真的应该研究网站 逆向工程挑战。

你的问题需要澄清一下。你怎么能保守协议的秘密,如果 计算机代码可以进行逆向工程吗?如果我的协议是发送一个RSA加密消息(甚至是公钥),通过保持协议的秘密,你能得到什么? 出于所有实际目的,检查器将面对一系列随机比特。

问候阿尔伯特