究竟是谁动了我的代码?
关键要点
- 确保程序或技术安全比以往任何时候都更加重要。综合措施、保护层和各种方法总是需要建立良好的保护屏障。
- 混淆是一种重要的实践,通过使源代码难以理解来保护源代码,从而防止未经授权的各方轻松反编译或反汇编它。
- 混淆经常被误认为是加密,但它们是不同的概念。加密将信息转换为隐藏信息真实含义的密码,而混淆使信息模糊不清。
- 有多种方法可以混淆代码,例如使用随机随机播放、用公式替换值、添加“垃圾”数据等。
- 混淆与其他安全措施配合得很好,本身并不是一个足够强大的措施。
在我们生活的两极世界中,一方面技术、开源软件和知识是自由共享的,另一方面,防止攻击者对专有技术进行逆向工程的需求也在增长。
Hide the needle in the haystack
最好的安全专家会告诉您,保护您的知识产权从来都不是一个简单的解决方案,并且始终需要综合措施、保护层和方法来建立良好的保护盾。在本文中,我们重点介绍源代码保护中的一个小层:代码混淆。
虽然这是一种强大的安全方法,但混淆经常被忽视,或者至少被误解。当我们混淆时,我们的代码变得难以理解,从而防止未经授权的各方轻松反编译或反汇编它。混淆使我们的代码无法(或几乎不可能)被人类阅读或解析。因此,混淆是一种很好的保护措施,用于保护源代码的所有权并保护我们的知识产权。
为了更好地解释混淆的概念,让我们以“沃尔多在哪里”为例。沃尔多是一个著名的插图人物,总是穿着他的红白条纹衬衫和帽子,以及黑框眼镜。挑战在于在数十甚至数百人中找到沃尔多,在双页插图中做各种有趣的事情,充满了情况、人物、物体和事件。这并不总是那么容易,解析插图可能需要一些时间,但由于他独特的外表,沃尔多最终总会被发现。
现在想象一下,沃尔多没有他标志性的条纹衬衫、帽子或眼镜——相反,他每次都穿不同的衬衫、不同的帽子和假发。有时他甚至会打扮成女人。找到他有多容易?可能几乎不可能。
图 1 想象一下,寻找没有他标志性的条纹衬衫、眼镜和帽子的沃尔多。相反,他将穿着普通衣服和口罩。
使用相同的概念,当我们混淆时,我们隐藏了程序代码、流程和功能的一部分,使它们难以理解——我们屏蔽它们,我们“扭曲”,加扰,重命名,更改,隐藏,转换它们,最重要的是,我们倒了一层垃圾。
好的混淆将使用所有这些方法,同时保持我们的混淆代码与原始的、非混淆的源代码无法区分。生成看起来像真实事物的代码会让任何攻击者感到困惑,同时使逆向工程成为一个难以进行的命题。
请记住,与任何其他安全措施一样,混淆并不能提供 100% 的保证,但如果做得好,它可以尽可能接近它,尤其是在与其他安全措施结合使用时。
Obfuscation != encryption
区分混淆和加密很重要,尽管它们不是,但经常被误认为是相同的。混淆和加密是两个不同的概念,一个不能取代另一个 - 如果有的话,它们相互补充。
当我们加密时,我们将信息转换为隐藏信息真实含义的密码。当我们混淆时,信息保持原样,但格式模糊,因为我们将其复杂程度提高到不可能(或几乎不可能)阅读或解析的程度。
强加密是一种强大的安全措施,但我们必须记住,任何锁都会在某个时候打开。任何加密的东西都必须解密才能使用,这就像打开堡垒的大门——无论多么强大,它仍然是一个弱点。这就是混淆的优势所在:当我们混淆时,我们不会加密,我们只是将代码隐藏在众目睽睽之下。将混淆视为将针头藏在大海捞针中——如果做得好,攻击者将需要不合理的时间和资源才能找到您的“针”。
根据我们多年作为程序员和混淆倡导者的经验,我们发现混淆有点像英国脱欧——专家们要么完全支持它,要么强烈反对它。但是,让我们记住,安全性始终需要几种方法相互结合使用 - 如果一种失败,另一种仍然存在 - 这正是混淆和加密成为一对好方法的原因。混淆应该始终排在最后,即在添加加密层并完全调试程序之后,是时候进行混淆了。
虽然本文重点介绍如何创建字符串混淆工具,但重要的是要指出,在现实生活中,商业混淆工具比字符串混淆更多 - 它们包括混淆函数、API 调用、变量、库、值等等。
字符串混淆的幕后花絮
有多种方法可以混淆代码,因为混淆本身应该在多个级别或层上实现 - 无论是语义结构,词汇结构,控制流,API调用等。为了创建强大的保护,我们必须使用多种技术。由于本文的重点是字符串混淆,因此让我们探讨四个子方法。
随机的重要性
当我们想到随机数时,我们可以想象一台彩票机:该机器在鼓底部使用旋转桨,并在腔室周围随机旋转球。然后将一个球射入管子,这意味着每个球都是随机挑选的。
你可能会问:为什么我们需要在代码中使用随机元素?答案是,解码混淆数据的方法之一是检查你期望的事物的逻辑顺序,一旦我们随机化这个顺序,就很难猜测混淆数据首先是什么。
最大的问题是:计算机程序能否在没有任何隐藏逻辑的情况下生成真正的随机数,从而将随机数转换为,嗯,不是那么随机?毕竟,没有旋转的球拍,没有射击球,只是一个由计算机运行的人造程序。
例如,C++提供了<random>库头文件和 rand() 函数。这个库旨在帮助我们生成一个随机数,或者我们称之为“伪随机数”。为什么是伪的?好吧,因为使用 rand() 生成的“随机”输出并不是真正的随机输出。如果我们使用 rand() 在创建随机数的同时进行迭代,然后对结果进行统计测试,我们可以看到,在过去的几次迭代中,生成的数字未通过统计测试,因为一些“随机”结果可以很容易地预测。
Shuffle ‘em like a deck of cards
当我们混淆时,我们会打乱各种元素,例如字符串、函数等,以便它们的顺序(几乎)是随机的,这使得分析是否有人试图破解你的代码变得更加困难。把洗牌数据想象成拿一副牌,然后按随机顺序混合它们。我们对将要生成的函数执行相同的操作。
随机播放是以随机方式(或几乎随机)改变某些元素的顺序,这使得入侵者更难分析和逆向工程我们的代码。解码混淆数据的方法之一是检查您期望的逻辑顺序以及何时打乱该顺序,但很难猜测混淆数据的顺序是什么。当然,目的不是改变行为代码,而只是在一个单独的模块上工作,该模块处理洗牌的元素,因为它们应该在调用后进行处理。
- 点赞
- 收藏
- 关注作者
评论(0)