ChatGPT解决这个技术问题 Extra ChatGPT

保护可执行文件免受逆向工程?

我一直在考虑如何保护我的 C/C++ 代码免受反汇编和逆向工程的影响。通常我自己不会在我的代码中宽恕这种行为。但是,为了各种人的安全,我一直在研究的当前协议不能被检查或理解。

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

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

代码注入(在实际函数调用之前和之后调用虚拟函数)

代码混淆(破坏二进制文件的反汇编)

编写我自己的启动例程(调试器更难绑定) void startup(); int _start() { 启动( ); exit (0) } void startup() { /* 这里的代码 */ }

运行时检查调试器(如果检测到则强制退出)

函数蹦床 void trampoline(void (*fnptr)(), bool ping = false) { if(ping) fnptr();否则蹦床(fnptr,真); }

无意义的分配和释放(堆栈变化很大)

毫无意义的虚拟呼叫和蹦床(反汇编输出中的大量跳跃)

吨铸件(用于混淆拆卸)

我的意思是这些是我想到的一些事情,但它们都可以在正确的时间范围内由代码分析师解决和/或弄清楚。我还有其他选择吗?

“但是,为了不同人的安全,我一直在研究的当前协议不能被检查或理解。” ——祝你好运。
您可以使您的应用程序难以逆向工程。你不能让它成为不可能,只要对方手里有你的大部分东西。小心保证完全的安全,尤其是在生命受到威胁的情况下——你无法交付。
如果您的计算机可以理解代码,那么人也可以。
将代码开源,没有人会对其进行逆向工程。
“默默无闻的安全从未奏效。”

A
Amber

但在正确的时间范围内,它们都可以通过代码分析来解决和/或计算出来。

如果你给人们一个他们能够运行的程序,那么他们也将能够在给定足够的时间的情况下对其进行逆向工程。这就是程序的本质。一旦二进制文件可供想要破译它的人使用,您就无法阻止最终的逆向工程。毕竟,计算机必须能够破译它才能运行它,而人类只是一台速度较慢的计算机。


+1。去看看 Apple II 上复制保护的辉煌岁月,混淆器和破解者之间不断升级的战争,软盘步进电机的疯狂技巧和无证 6502 指令等等......然后让自己哭泣睡觉,因为你不会实现任何如此复杂的东西,它们最终都被破解了。
与尝试在视觉上或使用反汇编程序进行逆向工程相比,使用模拟器更容易并获得更好的可见性。如果您使用的硬件中没有内置安全性,我认为世界平均需要两天到两周的时间来逆向工程并击败几乎所有出现的东西。如果您需要两天以上的时间来创建和实施它,那么您已经花费了太多时间。
今天唯一合理运作的 DRM 是密钥和互联网服务器的组合,以验证在某个时间只有一个密钥实例处于活动状态。
@Rotsor:计算机无法理解它,因为我们(还)无法将这种智能简化为算法,而不是因为存在某种物理或技术障碍。人类可以理解它,因为他可以做任何计算机可以做的事情(尽管速度较慢)以及推理。
此时有人会尝试对计算机进行逆向工程,除非它仅在您控制的环境中可用。
i
ivan_pozdeev

琥珀说的完全正确。你可以让逆向工程变得更难,但你永远无法阻止它。您永远不应该相信 "security" that relies on the prevention of reverse engineering

也就是说,我见过的最好的反逆向工程技术并不专注于混淆代码,而是打破人们通常用来理解代码如何工作的工具。找到破解反汇编程序、调试程序等的创造性方法可能比仅仅生成大量可怕的意大利面条代码更有效,也更能满足智力。这对阻止一个坚定的攻击者没有任何帮助,但它确实增加了 J Random Cracker 走神并转而从事更容易的事情的可能性。


我理解这一点,并且我已经阅读了几篇关于 Skype 安全性解释的论文,并且我一直在考虑 Skype 已经尝试过的相同想法,作为一种不阻止而是保护我的协议的方法。鉴于 Skype 的明显情况,这已被证明是值得的。
Skype 实际上是我想到的第一个例子,所以我很高兴你已经在研究模仿他们的方法。
R
RyanR

Safe Net Sentinel(以前的阿拉丁)。不过需要注意的是——他们的 API 很烂,文档很烂,与他们的 SDK 工具相比,这两者都很棒。

我多年来一直使用他们的硬件保护方法 (Sentinel HASP HL)。它需要一个专有的 USB 密钥卡,作为软件的“许可证”。他们的 SDK 加密和混淆您的可执行文件和库,并允许您将应用程序中的不同功能与刻录到密钥中的功能联系起来。如果没有许可方提供和激活的 USB 密钥,软件将无法解密,因此无法运行。 Key 甚至使用定制的 USB 通信协议(在我的知识范围之外,我不是设备驱动程序专家),以使构建虚拟密钥或篡改运行时包装器和密钥之间的通信变得困难。他们的 SDK 对开发人员不太友好,并且将添加保护与自动构建过程集成起来非常痛苦(但可能)。

在我们实施 HASP HL 保护之前,有 7 名已知的盗版者从产品中剥离了 dotfuscator“保护”。我们在对软件进行重大更新的同时添加了 HASP 保护,该软件实时对视频执行一些繁重的计算。从分析和基准测试中我可以看出,HASP HL 保护仅将密集计算减慢了约 3%。自从该软件大约 5 年前发布以来,没有发现任何新的盗版产品。它保护的软件在其细分市场中的需求量很大,并且客户知道有几个竞争对手正在积极尝试逆向工程(迄今为止没有成功)。我们知道他们曾试图向俄罗斯的一些宣传服务以破坏软件保护的团体寻求帮助,因为各种新闻组和论坛上的许多帖子都包含受保护产品的较新版本。

最近,我们在一个较小的项目上尝试了他们的软件许可解决方案 (HASP SL),如果您已经熟悉 HL 产品,这很简单,可以开始工作。它似乎有效;没有报告盗版事件,但该产品的需求量要低得多。

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


版主注意:由于偏离了对立的噪音,此答案下的评论已被删除。
+1 经验,但我想重申它并不完美。 Maya(3D 套件)使用了硬件加密狗(不确定它是否是 HASP),这并没有阻止海盗很长时间。有志者事竟成。
AutoCAD 使用了类似的系统,该系统已被破解无数次。 HASP 和其他类似的方法将使诚实的人保持诚实,并防止随意盗版。如果您正在构建下一个价值数十亿美元的设计产品,那么您将始终面临挑战。这一切都与收益递减有关——破解软件保护而不是仅仅为它付出多少小时的努力是值得的。
我也想从使用过 HASP 安全软件的人的角度来谈谈。 HASP 对最终用户来说是一件非常痛苦的事情。我处理了一个 Dallas iButton 和一个 Aladdin HASP,两者都非常有问题,导致软件随机停止工作,需要断开并重新连接 HASP。
此外,值得注意的是,HASP 安全措施不一定比代码混淆更安全 - 当然它们需要不同的方法来进行逆向工程,但很可能会逆向它们 - 请参阅:flylogic.net/blog/?p=14 flylogic.net/blog/?p=16 flylogic.net/blog/?p=11
G
Gilles 'SO- stop being evil'

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

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

为了有效地混淆,您需要使程序的行为依赖于正在执行的无用位。例如,而不是这样做:

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;

如果您认真对待混淆,请在计划中增加几个月;混淆并不便宜。并且要考虑到目前为止,避免人们对您的代码进行逆向工程的最佳方法是使其无用,这样他们就不会打扰。这是一个简单的经济考虑:如果对他们来说价值大于成本,他们就会进行逆向工程;但是提高他们的成本也会大大增加你的成本,所以试着降低他们的价值。

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

为了不同人的安全,我一直在研究的当前协议不能被检查或理解

这引发了一个危险信号。它是 security by obscurity,它的记录很差。如果协议的安全性取决于不了解协议的人,you've lost already

推荐阅读:

安全圣经:Ross Anderson 的安全工程

混淆圣经:Christian Collberg 和 Jasvir Nagra 的秘密软件


@Gilles,那是您的陈述,非常有力,因此举证责任在您身上。但是,我将提供一个简单的示例:2+2 可以被编译器简化为 4,但反编译器无法将其恢复为 2+2(如果它实际上是 1+3 怎么办?)。
@Rotsor 42+2 在观察上是等效的,因此它们相同用于此目的,即弄清楚程序在做什么。是的,当然,反编译器无法重构源代码,但这无关紧要。这个问答是关于重构行为(即算法,更准确地说是协议)。
您不必做任何事情来重建行为。你已经有程序了!您通常需要了解协议并更改其中的某些内容(例如将 2+2 中的 2 替换为 3,或将 + 替换为 *)。
如果您认为所有行为等效的程序都相同,那么是的,编译器无法做任何事情,因为它只执行一个缩进转换。反编译器也是无用的,因为它又是一个身份转换。但是,如果您不这样做,那么 2+2 -> 4 是编译器执行的不可逆转换的有效示例。它是否使理解更容易或更困难是一个单独的论点。
@Gilles我无法将您与苹果的类比扩展,因为我无法想象结构上不同但行为上相同的苹果。 :)
O
Oded

最好的反汇编技巧,特别是可变字长指令集是汇编/机器代码,而不是 C。例如

CLC
BCC over
.byte 0x09
over:

反汇编器必须解决分支目标是多字节指令中的第二个字节的问题。不过,指令集模拟器不会有问题。可以从 C 中引起的分支到计算地址也使反汇编变得困难甚至不可能。指令集模拟器不会有问题。使用模拟器为您整理分支目的地可以帮助反汇编过程。对于反汇编程序来说,编译后的代码相对干净且容易。所以我认为需要一些组装。

我认为这是 Michael Abrash 的汇编语言禅的开始,他展示了一个简单的反反汇编器和反调试器技巧。 8088/6 有一个预取队列,您所做的是有一条指令修改了下一条指令或前面的几条指令。如果单步执行,则执行修改后的指令,如果您的指令集模拟器没有完全模拟硬件,则执行修改后的指令。在正常运行的真实硬件上,真实指令已经在队列中,只要您没有再次执行该指令串,修改后的内存位置就不会造成任何损坏。今天,当流水线处理器获取下一条指令时,您可能仍然可以使用这样的技巧。或者,如果您知道硬件有单独的指令和数据缓存,您可以提前修改多个字节,如果您正确对齐缓存行中的此代码,则修改后的字节不会通过指令缓存写入,而是通过数据缓存写入,并且没有适当缓存模拟器的指令集模拟器将无法正确执行。我认为纯软件解决方案不会让你走得太远。

以上是旧的和众所周知的,我对当前的工具知之甚少,不知道它们是否已经解决了这些问题。自修改代码可以/将会使调试器出错,但是人类可以/将缩小问题范围,然后查看自修改代码并解决它。

过去,黑客需要大约 18 个月的时间才能解决问题,例如 dvd。现在他们平均大约需要 2 天到 2 周(如果有动机的话)(蓝光、iphone 等)。这对我来说意味着如果我在安全方面花费的时间超过几天,我很可能会浪费我的时间。您将获得的唯一真正的安全性是通过硬件(例如,您的指令是加密的,并且只有芯片内部的处理器内核在执行前会解密,从而无法暴露解密的指令)。这可能会给你带来几个月而不是几天的时间。

另外,请阅读凯文·米特尼克 (Kevin Mitnick) 的《欺骗的艺术》一书。这样的人可能会拿起电话,让您或同事将秘密分发给系统,以为它是公司另一部分的经理或其他同事或硬件工程师。你的安全被炸毁了。安全不仅仅是管理技术,还必须管理人员。


此外,您无需访问源代码(甚至反汇编源代码)即可找到安全漏洞。这可能是偶然的,也可能是由于大多数漏洞来自代码中的相同问题(如缓冲区溢出)。
自修改代码存在很大问题。大多数现代操作系统/硬件不会让您在没有非常高权限的情况下执行此操作,可能存在缓存问题并且代码不是线程安全的。
对于现代 x86 处理器,此类技巧通常不利于性能。使用相同的内存位置作为多条指令的一部分可能会产生类似于错误预测分支的效果。自修改代码导致处理器丢弃高速缓存行以保持指令和数据高速缓存之间的一致性(如果您执行修改后的代码比修改它的频率高得多,它可能仍然是一个胜利)。
我在 20 年前遇到过这个问题。我们花了将近半个小时才弄清楚发生了什么。如果您需要更长的保护,这不是很好。
“真正的指令已经在队列中,修改后的内存位置不会造成任何损坏”直到中间发生中断,刷新指令流水线,并导致新代码变得可见。现在你的混淆已经给你的合法用户带来了一个错误。
P
Phil

AES algorithm 为例。这是一个非常非常公开的算法,而且非常安全。为什么?两个原因:它已经被很多聪明人审查过,“秘密”部分不是算法本身 - 秘密部分是密钥,它是算法的输入之一。这是一种更好的方法来设计你的协议,在你的代码之外生成一个“秘密”,而不是让代码本身成为秘密。无论您做什么,代码总是可以被解释,并且(理想情况下)生成的秘密只能通过大规模的暴力方法或通过盗窃来危害。

我认为一个有趣的问题是“你为什么要混淆你的代码?”您想让攻击者难以破解您的算法吗?让他们更难在您的代码中找到可利用的错误?如果代码一开始就无法破解,您就不需要混淆代码。问题的根源在于可破解的软件。解决问题的根源,不要只是混淆它。

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


常识+1:当您可以设计一个更好的系统时,为什么要让自己变得更难。
正如我常说的,如果你把所有东西都保留在服务器端,它会更安全
i
iammilind

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

如果它真的成为一个赚钱的人,那么你应该已经收集了足够的钱来使用专利和/或版权等合法方式来保护它。

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


我的意思是,这是一个可行且适用的答案,但是您在保护和赚取数百万收入以让其他人为您保护您的产品之间划定的界限真的很长。
a
asmeurer

阅读 http://en.wikipedia.org/wiki/Security_by_obscurity#Arguments_against。我敢肯定,其他人也可能会提供更好的资料来说明为什么默默无闻的安全性是一件坏事。

使用现代密码技术,完全有可能让你的系统开放(我不是说它应该是开放的,只是它可能是开放的),并且仍然具有完全的安全性,只要密码算法不有一个漏洞(如果您选择一个好的,则不太可能),您的私钥/密码仍然是私有的,并且您的代码中没有安全漏洞(这是您应该担心的)。


我同意这一点。我认为您可能有概念或设计问题。是否有具有私钥-公钥对解决方案的模拟?您永远不会泄露私钥,它由安全客户端处理它的所有者保留。您可以将安全代码保留在他们的计算机之外,并且只将结果返回给用户吗?
t
tne

自 2013 年 7 月以来,人们对加密稳健的混淆(以 Indistinguishability Obfuscation 的形式)重新产生了兴趣,这似乎是源自 Amit Sahai 的原始研究。

Sahai、Garg、Gentry、Halevi、Raykova、Waters,所有电路的候选不可区分性混淆和功能加密(2013 年 7 月 21 日)。

Sahai,Waters,如何使用不可区分性混淆:可否认加密等。

Sahai、Barak、Garg、Kalai、Paneth,保护混淆免受代数攻击(2014 年 2 月 4 日)。

您可以在这个 Quanta Magazine article 和那个 IEEE Spectrum article 中找到一些提炼的信息。

目前使用这种技术所需的资源量使其不切实际,但 AFAICT 的共识是对未来相当乐观。

我很随意地这么说,但对于每个习惯于本能地摒弃混淆技术的人来说——这是不同的。如果它被证明是真正有效的并且变得实用,那么这确实很重要,而不仅仅是为了混淆。


N
Norman Ramsey

要了解自己,请阅读有关代码混淆的学术文献。亚利桑那大学的 Christian Collberg 是该领域的著名学者;哈佛大学的 Salil Vadhan 也做了一些很好的工作。

我落后于这篇文献,但我知道的基本思想是,您无法阻止攻击者看到您将执行的代码,但您可以用未执行的代码包围它,而且成本很高攻击者的指数时间(使用最知名的技术)来发现你的代码的哪些片段被执行,哪些没有被执行。


B
Brian Makin

如果有人想花时间反转您的二进制文件,那么您绝对无法阻止他们。你可以使难度适中,但仅此而已。如果您真的想了解这一点,请获取 http://www.hex-rays.com/idapro/ 的副本并反汇编一些二进制文件。

CPU 需要执行代码的事实是您的撤消。 CPU 只执行机器代码……而程序员可以读取机器代码。

话虽这么说......你可能有一个不同的问题,可以通过另一种方式解决。你想保护什么?根据您的问题,您可能会使用加密来保护您的产品。


B
Black

为了能够选择正确的选项,您应该考虑以下几个方面:

“新用户”是否可能不想付费但使用您的软件?现有客户是否可能需要比他们拥有的更多的许可证?潜在用户愿意支付多少?您想为每个用户/并发用户/工作站/公司授予许可证吗?您的软件是否需要培训/定制才能有用?

如果问题 5 的答案是“是”,则不必担心非法复制。反正它们也没有用。

如果问题 1 的答案是“是”,那么首先考虑定价(见问题 3)。

如果您回答问题 2“是”,那么“按使用付费”模式可能适合您。

根据我的经验,按使用付费 + 定制和培训是对您的软件的最佳保护,因为:

新用户被定价模式吸引(很少使用 -> 很少付费)

几乎没有“匿名用户”,因为他们需要培训和定制。

没有软件限制会吓跑潜在客户。

现有客户源源不断的资金流。

由于长期的业务关系,您从客户那里获得了宝贵的发展反馈。

在您考虑引入 DRM 或混淆之前,您可能会想到这些要点以及它们是否适用于您的软件。


非常好的建议(我赞成),但它并没有真正解决这个特定问题
M
Mohammad Alaggan

最近有一篇名为“Program obfuscation and one-time programs”的论文。如果您真的很想保护您的应用程序。这篇论文一般通过使用简单和通用的硬件来绕过理论上的不可能结果。

如果您负担不起需要额外的硬件,那么还有另一篇论文给出了理论上最好的混淆“On best-possible obfuscation”,在所有具有相同功能和相同大小的程序中。然而,该论文表明,信息论的最佳可能意味着多项式层次结构的崩溃。

如果这些结果不能满足您的需求,那么这些论文至少应该为您提供足够的参考文献来浏览相关文献。

更新:一种新的混淆概念,称为不可区分混淆,可以减轻不可能结果(paper)


S
SSpoke

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

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

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


L
Lukasz Madon

没有骰子,你不能保护你的代码不被反汇编。您可以做的是为业务逻辑设置服务器并使用 web 服务为您的应用程序提供它。当然,这种情况并不总是可能的。


说得好,避免人们反汇编您的代码的唯一方法是根本不让他们物理访问它,这意味着您的应用程序专门作为 SAAS 提供,接受来自远程客户端的请求并返回处理后的数据。将服务器放置在一个被鳄鱼沟和 5m 高的带电剃刀线包围的地下掩体中的一个上锁的房间中软件系统以防止网络入侵。
我希望我永远不会得到维护你服务器的合同
G
Gallium Nitride

为避免逆向工程,您不得将代码提供给用户。也就是说,我建议使用在线应用程序......但是(因为你没有给出上下文)这对你来说可能毫无意义。


这是真正的解决方案......即将您的皇冠上的珠宝放入您自己的 VPS 机器上的服务器中,并且只将 API 调用从客户端(浏览器或 api 客户端)公开到该服务器中
A
Aaron Mason

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

关键是你不会得到终极保护,因为没有这种东西,如果有的话,它不会持续很长时间,这意味着它一开始就不是终极保护。

无论人组装什么,都可以拆卸。

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

如果你想保护某些东西免受 RE 的攻击,你必须至少知道 RE 使用的常用技术。

这样的话

互联网在预防逆向工程方面并没有真正的足智多谋,而是描述了大量关于如何逆向工程的信息

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

(有一些软件以错误的方式使用保护的例子,使得这种保护实际上不存在。为避免含糊其辞,我将在互联网上为您提供一个简要描述的示例:CD-ROM v4 上的牛津英语词典第二版。您可以阅读有关在以下页面中使用 SecuROM 失败:Oxford English Dictionary (OED) on CD-ROM in a 16-, 32-, or 64-bit Windows environment: Hard-disk installation, bugs, word processing macros, networking, fonts, and so forth

一切都需要时间。

如果您是该主题的新手,并且没有几个月甚至几年的时间来正确了解 RE 的内容,那么请使用其他人提供的可用解决方案。这里的问题很明显,它们已经存在,所以你已经知道它们不是 100% 安全的,但是制作你自己的新保护只会给你一种受到保护的错误感觉,除非你非常了解逆向工程和保护(但至少现在你没有)。

软件保护的重点是吓唬新手,阻止常见的 RE,并在经验丰富的 RE(希望很有趣)到达您的应用程序中心之后让她/他的脸上露出笑容。

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

(请查看 Philippe Biondi 和 Fabrice Desclaux 在 Black Hat 2006 上展示的精彩演示 Silver Needle in the Skype)。

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

我说的是虚拟化,所以我会给你一个链接,指向 EXETOOLS FORUM 中的一个示例线程:Best software protector: Themida or Enigma Protector?。它可能会对您进行进一步的搜索有所帮助。


R
Rotsor

与大多数人所说的相反,根据他们的直觉和个人经验,我不认为加密安全的程序混淆通常被证明是不可能的。

这是一个完全混淆的程序语句的示例,以证明我的观点:

printf("1677741794\n");

人们永远猜不到它的真正作用是

printf("%d\n", 0xBAADF00D ^ 0xDEADBEEF);

关于这个主题有一篇有趣的论文,它证明了一些不可能的结果。它被称为 "On the (Im)possibility of Obfuscating Programs"

尽管该论文确实证明了使程序无法与其实现的功能区分开来的混淆是不可能的,但以某种较弱的方式定义的混淆仍然是可能的!


1.您的示例与此处无关;您展示的两个程序在行为上是等效的,这个问题是关于弄清楚程序的行为,而不是重建它的源代码(这显然是不可能的)。 2.本文为理论论文;编写完美的混淆器是不可能的,但编写完美的反编译器也是不可能的(原因与编写完美的程序分析器的原因大致相同)。在实践中,这是一场军备竞赛:谁能写出更好的(去)混淆器。
@Gilles,(正确的)反混淆的结果在行为上总是等同于混淆的代码。我看不出这会如何削弱问题的重要性。
此外,关于军备竞赛:这不是关于谁在研究上投入更多,而是关于谁是正确的。正确的数学证明不会仅仅因为有人非常想要它们而出错。
好吧,也许你对实践中的军备竞赛是正确的。我想我误解了这一点。 :) 我希望某种加密安全的混淆是可能的。
对于一个有趣的混淆案例,请尝试智能卡,问题在于攻击者具有物理访问权限(白盒混淆)。部分回应是通过物理手段限制访问(攻击者无法直接读取密钥);但是软件混淆也起作用,主要是使像 DPA 这样的攻击没有给出有用的结果。我没有很好的参考,抱歉。我的回答中的示例模糊地受到该领域使用的技术的启发。
O
Olof Forshell

我不认为任何代码是不可破解的,但是对于想要尝试它的人来说,奖励需要很大。

话虽如此,您应该做一些事情,例如:

尽可能使用最高的优化级别(逆向工程不仅是获取汇编序列,还涉及理解代码并将其移植到更高级别的语言中,例如 C)。高度优化的代码可以遵循。

通过没有比必要更大的数据类型来使结构密集。在官方代码版本之间重新排列结构成员。您也可以使用结构中重新排列的位域。

您可以检查是否存在不应更改的某些值(例如版权信息)。如果一个字节向量包含“vwxyz”,您可以拥有另一个包含“abcde”的字节向量并比较差异。执行此操作的函数不应传递指向向量的指针,而应使用在其他模块中定义为(伪 C 代码)“char *p1=&string1[539];”的外部指针和“char p2=&string2[-11731];”。这样就不会有任何指针准确地指向这两个字符串。然后在比较代码中比较“(p1-539+i)-*(p2+11731+i)==some value”。破解者会认为更改 string1 是安全的,因为似乎没有人引用它。将测试埋在某个意想不到的地方。

试着自己破解汇编代码,看看什么容易做,什么难做。应该会弹出一些想法,您可以尝试使代码更难进行逆向工程并使其更难调试。


你的第一点没有意义,优化的代码减少了麻烦,这使得更容易逆转(我根据经验说话)。您的第三点也是浪费时间,并且称职的逆向工程师知道如何进行内存访问断点。这就是为什么最好不要自己设计系统,而是我们尚未“破解”的第 3 方库,因为这可能比“新手”可以创建的任何东西都持续更长时间......
既然看起来我对这个主题一无所知,也许我应该求助于像你这样的专业人士来满足我的软件开发需求,而不是自己编写任何代码。
f
flolo

正如许多人已经说过的:在常规 CPU 上,您无法阻止它们执行,您可以延迟它们。正如我的老密码老师告诉我的:你不需要完美的加密,破解密码肯定比收益更昂贵。同样适用于您的混淆。

但还有 3 个附加说明:

有可能使逆向工程变得不可能,但是(这是一个非常非常大的但是),你不能在传统的 cpu 上做到这一点。我也做了很多硬件开发,经常使用FPGA。例如,Virtex 5 FX 上有一个 PowerPC CPU,您可以使用 APU 在您的硬件中实现自己的 CPU 操作码。您可以使用此工具真正解密外部或其他软件无法访问的 PowerPC 指令,甚至可以在硬件中执行命令。由于 FPGA 为其配置比特流内置了 AES 加密,因此您无法对其进行逆向工程(除非有人设法破坏 AES,但我想我们还有其他问题......)。通过这种方式,硬件 IP 供应商也可以保护他们的工作。你从协议中说话。您没有说它是哪种协议,但是当它是网络协议时,您至少应该保护它免受网络嗅探。您确实可以通过加密来做到这一点。但是如果你想保护软件所有者的加密/解密,你又回到了混淆。一定要让你的程序不可调试/不可运行。尝试使用某种调试检测并应用它,例如在某些公式或将调试寄存器内容添加到魔术常数中。如果您的程序在调试模式下看起来很困难,如果它运行正常,但会进行完全错误的计算、操作或其他操作。例如,我知道一些生态游戏,它有一个非常讨厌的版权保护(我知道你不想要版权保护,但它是相似的):被盗版本在玩了 30 分钟后改变了开采的资源,突然你只有一个资源。海盗刚刚破解了它(即对其进行逆向工程)-检查它是否运行,然后volia将其释放。这种轻微的行为变化很难被发现,尤其是。如果它们没有立即被发现,而只是延迟了。

所以最后我会建议:估计人们对您的软件进行逆向工程的收益是多少,将其转化为一些时间(例如通过使用最便宜的印度工资)并使逆向工程如此耗时以至于它更大。


I
Ira Baxter

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

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

Collberg 等人有一篇论文(“Manufacturing Cheap, Resilient and Stealthy Opaque Constructs”)讨论了这些主题,并定义了各种“不透明”谓词,这些谓词会使代码推理变得非常困难:

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
Albert van der Horst

正如比我们俩聪明得多的人所证明的那样,通过默默无闻的安全性是行不通的。如果您必须保护客户的通信协议,那么您在道德上就有义务使用公开且经过专家全面审查的最佳代码。

这是针对人们可以检查代码的情况。如果您的应用程序要在嵌入式微处理器上运行,您可以选择一个具有密封功能的微处理器,这样就无法在运行时检查代码或观察诸如当前使用情况等琐碎的参数。 (除硬件入侵技术外,您需要仔细拆卸芯片并使用先进设备检查单个晶体管上的电流。)

我是 x86 逆向工程汇编程序的作者。如果您准备好迎接一个冷酷的惊喜,请将您尽最大努力的结果发送给我。 (通过我的网站与我联系。)我在答案中看到的很少会对我构成重大障碍。如果您想了解复杂的逆向工程代码是如何工作的,您应该真正研究具有逆向工程挑战的网站。

您的问题可以使用一些澄清。如果计算机代码可以进行逆向工程,您如何期望对协议保密?如果我的协议是发送 RSA 加密消息(甚至是公钥),那么通过保持协议的机密性可以获得什么?出于所有实际目的,检查员将面临一系列随机位。

格罗杰斯·阿尔伯特


M
MerchantProtocol.com

关于隐藏代码要记住的第一件事:并非所有代码都需要隐藏。

最终目标:对于大多数软件程序,我的最终目标是能够销售不同的许可证,这些许可证将打开和关闭我的程序中的特定功能。

最佳技术:我发现构建一个像 WordPress 提供的钩子和过滤器系统,是试图迷惑你的对手时绝对最好的方法。这允许您加密某些触发器关联,而无需实际加密代码。

您这样做的原因是因为您希望加密尽可能少的代码。

了解您的破解者:了解这一点:破解代码的主要原因不是因为恶意分发许可,而是因为需要更改您的代码,而他们并不真的需要分发免费副本。

开始:将您要加密的少量代码放在一边,其余代码应尽量塞进一个文件中,以增加复杂性和理解力。

准备加密:您将使用我的系统分层加密,这也将是一个非常复杂的过程,因此构建另一个负责加密过程的程序。

第一步:对所有内容使用 base64 名称进行混淆。完成后,base64 混淆代码并将其保存到一个临时文件中,该文件稍后将用于解密和运行此代码。说得通?

我会重复一遍,因为你会一次又一次地这样做。您将创建一个 base64 字符串并将其作为变量保存到另一个文件中,该变量将被解密和呈现。

第二步:您将把这个临时文件作为字符串读入并对其进行模糊处理,然后对其进行 base64 处理并将其保存到第二个临时文件中,该文件将用于解密并为最终用户呈现它。

第三步:根据需要重复第二步。一旦您在没有解密错误的情况下正常工作,那么您将要开始为您的对手建造地雷。

地雷一号:你会想要对你收到通知的事实保密。因此,为第 2 层构建破解者尝试安全警告邮件系统。如果出现任何问题,这将被触发,让您了解对手的详细信息。

地雷二:依赖。你不希望你的对手能够运行第 1 层,没有第 3 层、第 4 层或第 5 层,甚至没有为它设计的实际程序。因此,请确保在第一层中包含某种终止脚本,如果程序不存在或其他层则将激活该脚本。

我相信你可以想出你自己的地雷,玩得开心。

要记住的事情:您实际上可以加密您的代码,而不是使用 base64 对其进行加密。这样一个简单的base64就不会解密程序。

奖励:请记住,这实际上可能是你和你的对手之间的共生关系。我总是在第一层内发表评论,评论祝贺破解者并给他们一个促销代码,以便从你那里获得现金奖励。

在不涉及任何偏见的情况下,使现金奖励显着。我通常会说 500 美元。如果你的人是第一个破解密码的人,那就付钱给他,成为他的朋友。如果他是你的朋友,他不会分发你的软件。问问他他是怎么做到的,你可以如何改进!

祝你好运!


你甚至读过这个问题吗?我从来没有问过如何防止盗版的方法。该应用程序将是免费的,它是使用的底层协议,由于安全性的性质需要受到保护。
A
AareP

有没有人尝试过 CodeMorth: http://www.sourceformat.com/code-obfuscator.htm ?或 Themida:http://www.oreans.com/themida_features.php

后来的一个看起来更有希望。


我建议的第一件事是不惜一切代价避免使用商业混淆器!因为如果你破解了混淆器,你就可以破解所有被它混淆的应用程序!