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

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


当前回答

为了避免逆向工程,您不能将代码提供给用户。也就是说,我建议使用在线应用程序……然而(因为你没有给出背景),这对你来说可能是毫无意义的。

其他回答

我不认为任何代码都是牢不可破的,但奖励必须非常棒,才能让人们愿意尝试它。

话虽如此,你还是应该做以下事情:

Use the highest optimization level possible (reverse engineering is not only about getting the assembly sequence, it is also about understanding the code and porting it into a higher-level language such as C). Highly optimized code can be a b---h to follow. Make structures dense by not having larger data types than necessary. Rearrange structure members between official code releases. Rearranged bit fields in structures are also something you can use. You can check for the presence of certain values which shouldn't be changed (a copyright message is an example). If a byte vector contains "vwxyz" you can have another byte vector containing "abcde" and compare the differences. The function doing it should not be passed pointers to the vectors but use external pointers defined in other modules as (pseudo-C code) "char *p1=&string1[539];" and "char p2=&string2[-11731];". That way there won't be any pointers pointing exactly at the two strings. In the comparison code you then compare for "(p1-539+i)-*(p2+11731+i)==some value". The cracker will think it is safe to change string1 because no one appears to reference it. Bury the test in some unexpected place.

尝试自己破解汇编代码,看看哪些是容易的,哪些是困难的。您可以尝试一些想法,使代码更难进行反向工程,并使调试更加困难。

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

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.

很多时候,担心你的产品被逆向工程是多余的。是的,它可以被逆向工程;但它是否会在短时间内变得如此出名,以至于黑客们会发现它值得逆转。它吗?(对于大量的代码行来说,这项工作不是一个小时间活动)。

如果它真的能赚钱,那么你就应该筹集足够的资金,通过专利或版权等合法途径来保护它。

恕我直言,采取你将要采取的基本预防措施,然后释放它。如果它成为逆向工程的一个点,这意味着你已经做得非常好,你自己会找到更好的方法来克服它。祝你好运。

最好的反反汇编技巧,特别是在可变字长指令集上,是在汇编程序/机器代码中,而不是在c中

CLC
BCC over
.byte 0x09
over:

The disassembler has to resolve the problem that a branch destination is the second byte in a multi byte instruction. An instruction set simulator will have no problem though. Branching to computed addresses, which you can cause from C, also make the disassembly difficult to impossible. Instruction set simulator will have no problem with it. Using a simulator to sort out branch destinations for you can aid the disassembly process. Compiled code is relatively clean and easy for a disassembler. So I think some assembly is required.

I think it was near the beginning of Michael Abrash's Zen of Assembly Language where he showed a simple anti disassembler and anti-debugger trick. The 8088/6 had a prefetch queue what you did was have an instruction that modified the next instruction or a couple ahead. If single stepping then you executed the modified instruction, if your instruction set simulator did not simulate the hardware completely, you executed the modified instruction. On real hardware running normally the real instruction would already be in the queue and the modified memory location wouldnt cause any damage so long as you didnt execute that string of instructions again. You could probably still use a trick like this today as pipelined processors fetch the next instruction. Or if you know that the hardware has a separate instruction and data cache you can modify a number of bytes ahead if you align this code in the cache line properly, the modified byte will not be written through the instruction cache but the data cache, and an instruction set simulator that did not have proper cache simulators would fail to execute properly. I think software only solutions are not going to get you very far.

上面这些都是老的和众所周知的,我对当前的工具了解不够,不知道它们是否已经围绕这些事情工作了。自修改代码可能/将使调试器出错,但是人类可以/将缩小问题范围,然后看到自修改代码并解决它。

It used to be that the hackers would take about 18 months to work something out, dvds for example. Now they are averaging around 2 days to 2 weeks (if motivated) (blue ray, iphones, etc). That means to me if I spend more than a few days on security, I am likely wasting my time. The only real security you will get is through hardware (for example your instructions are encrypted and only the processor core well inside the chip decrypts just before execution, in a way that it cannot expose the decrypted instructions). That might buy you months instead of days.

另外,读读凯文·米特尼克的《欺骗的艺术》。这样的人可以拿起电话,让你或同事把秘密交给系统,以为那是公司其他部门的经理、其他同事或硬件工程师。你的安全系统也被破坏了。安全不仅仅是管理技术,还要管理人。

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

您可以通过依赖停止程序(“程序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/