我一直在思考如何保护我的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)
我的意思是,这些是我想过的一些事情,但它们都可以在适当的时间框架内由代码分析师解决。我还有别的选择吗?
与大多数人所说的相反,基于他们的直觉和个人经验,我不认为密码安全的程序混淆通常被证明是不可能的。
这是一个完美混淆的程序语句的例子,以证明我的观点:
printf("1677741794\n");
人们永远猜不到它真正的作用是什么
printf("%d\n", 0xBAADF00D ^ 0xDEADBEEF);
关于这个问题有一篇有趣的论文,它证明了一些不可能的结果。它叫做“关于混淆程序的(Im)可能性”。
尽管这篇论文确实证明了使程序与它实现的函数不可区分的混淆是不可能的,但以某种较弱的方式定义的混淆仍然是可能的!
传统的逆向工程技术依赖于智能代理使用反汇编程序回答关于代码的问题的能力。如果你想要更强的安全性,你必须做一些事情,可以证明阻止代理得到这样的答案。
您可以通过依赖停止程序(“程序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/
为了能够做出正确的选择,你应该考虑以下几个方面:
有没有可能“新用户”不愿意花钱而是使用你的软件?
现有客户是否有可能需要比他们拥有的更多的许可证?
潜在用户愿意支付多少钱?
你想按用户/并发用户/工作站/公司发放许可证吗?
你的软件需要培训/定制才能有用吗?
如果问题5的答案是“是”,那么就不用担心非法拷贝。反正也没用。
如果问题1的答案是“是”,那么首先考虑定价问题(见问题3)。
如果你回答问题2“是”,那么“按使用付费”模式可能会
适合你。
从我的经验来看,按使用付费+定制和培训是最好的保护
为您的软件,因为:
新用户被定价模式所吸引(很少使用->很少付费)
几乎没有“匿名用户”,因为他们需要培训和定制。
没有软件限制会吓跑潜在客户。
现有客户源源不断地提供资金。
由于长期的业务关系,您可以从客户那里得到有价值的发展反馈。
在您考虑引入DRM或混淆之前,您可能会考虑这些要点,以及它们是否适用于您的软件。