论坛首页 逆向工程技术区 阅读主题

[推荐][原创]细说软件保护:从应用保护到算法保护

190 浏览 17 回复
#1 楼主 2026-06-01 21:09:14
其实不太细,QAQ~随着计算机与互联网相关技术的蓬勃高速发展,计算机已不再是“专业人员”的独有工具软件应用也逐渐与人们的日常生活深度绑定。如何妥善的保护软件,让软件安全运行在用户/客户的设备上,更好的服务大众助力业务稳定发展,软件保护自始至终都是一个重要的问题。从软件保护的视角来看,可以笼统的分为应用保护、代码保护、算法保护,本文也将从这 3 个纬度进行阐述软件保护相关的问题应用加壳:压缩壳、加密壳、抽取壳、保护壳应用保护(也称应用加壳),主要是为了保护软件的著作信息、关键资源和关键实现等资产的一种有效措施。“加壳”与自然界和生物界中动植物为了保护关键“种子”非常相似,当然这壳有先天的(譬如蛋壳,天生自带保护壳),也有后天的动物的羽毛、古时的铠甲盔甲。应用保护历史悠远,从 DOS 时代起就出现了反编译相关技术,而应用保护在那个时期已初见雏形。 壳的初始作用是保护软件,但后来发展的方向不一就出现了各种各样的壳,一般有压缩壳、加密壳、抽取壳、保护壳、虚拟执行壳几个阶段,具体如下所示:软件加壳除了保护软件的著作信息、关键资源和关键实现外,还为了隐藏了程序真实的 程序入口点(OEP,Original Entry Point。或者用了假的 OEP ), 对于隐藏了 OEP 的保护,需要先寻找应用真正的 OEP,才可以完成 OEP 脱壳。应用加壳和脱(解)壳彼此互为逆运算(类比于密码学中的加密与解密的思路与流程)。无非是在具体过程中采用的措施和思路并不相同,大致流程分为如下三个步骤:从而达到应用保护的目的,但又不干扰实际的逻辑。当然,代码或者抽取出的代码加载方式也可以做做文章(譬如懒加载、不落地加载“直接加载到内存不保留代码文件”)一般来说获取到抽取后的信息、解壳的逻辑后,然后由逆向工程师去“模拟”壳中脱壳逻辑即可完成脱壳(参考上述步骤 3)。【当然壳类型不同,模拟的过程也不相同。 譬如在虚拟执行壳中需要定位壳的解释器和自定义字节码的映射关系,才可还原】。上述,“模拟”是个较为笼统的讲述(或者说是一种思想, 加解(脱)壳与加解密流程上大同小异)。而实际的脱壳方式可以通过dump、Hook或者主动调用。这个就需要具体情况具体分析了,再次不再过多赘述实际的脱壳。btw: 未知攻 焉知防? 应对加壳与脱壳, 或许你需要了解程序的runtime(正向跟踪结合逆向分析). 譬如Android中Java层的加壳与脱壳, 那么就不得不说说classloader及双亲委派、Native层的加壳与脱壳就不得不说ELF文件结构、加载机制等。除此之外加密壳、虚拟壳亦是如此。如果说应用保护是给应用程序的大门加上了一把“大锁”,那么代码保护就是针对组成应用程序的源码加了多个“小锁”。在实际的代码保护中由于代码的粒度更细,组成更为分散,那么保护措施相对来说更多。在实际应用中,代码保护通常无法完整且长期的保护,也仅只能给对应的逆向人员延长分析与调试的时间。在实际的应用中引入代码保护会需要消耗更多的计算资源和存储资源的消耗,所以对于性能损耗和阻碍逆向人员的资源投入,需要在实际场景中进行相关的权衡取舍。 对于代码保护有如下几种分类方式:从应用程序组成的视角来看应用程序由代码(逻辑代码和控制代码)和信息数据组成。那么从组成方式,可以将应用程序的代码保护和数据保护。所谓的静态分析是在不运行代码的情况下,对代码的静态特征和功能模块进行分析的方法。静态分析代码的优势在于它能描绘程序的轮廓,包括控制流和数据结构。静态混淆是指保留代码原有功能上的代码等价转换,使其难以阅读、分析和理解。难以阅读,分析是混淆的目的,“等价转换”是确保混淆后代码和源代码的功能保持一致。对于代码混淆的分类,通常以 Collberg 的理论为基础,细分为布局混淆、数据混淆、控制混淆和预防混淆(反反混淆)。布局混淆原是指删除或混淆与执行无关的辅助文本信息,增加攻击者阅读和理解代码的难度,具体到高级语言中就是指源代码中的注释文本、调试信息、代码命名和格式等。布局混淆能够在引入更多计算的同时进行代码,虽然单独布局混淆保护强度并不强,但通常在实际应用中都会用到布局混淆。布局混淆也包括采用技术手段处理代码中的常量名、变量名、函数名等标识符,增加逆向工作者对代码理解的难度。具体有如下 2 种体现数据是构成语言代码的基本元素(注意:此数据并非应用程序的数据,而是代码中原有的数据),同时也是语义分析的重要依据。在数据混淆的过程中通常会引入更多的计算,不过好在数据混淆较于布局混淆会有更好保护的效果。数据混淆较于布局混淆是个更大的话题,一方面是数据类型种类更多,另一方面类型不同可引入的保护措施也更多。所以将在下述中对于基础数据类型进行分别讨论其混淆方式。基础类型包含:字符(串)类型、数值类型、布尔类型、对象类型等字符是最常见的常量数据(在此,将字符、字符串和文本统一称之为字符)。而字符中通常包含重要信息,如类名、方法名、变量名、异常,错误甚至是关键文本。而字符混淆便是将有“业务语义”的代码通过编码、加密的方式,将包含关键语义的信息进行保护。数字混淆即通过数字计算拆分、进制转换、公式拆解的方式,对代码中的数字进行保护。虽然数字本身包含的业务语义,并非像字符中体现的那么敏感。但数字又是在代码中随处可见,譬如循环迭代的索引、数组取值。对数字进行混淆保护有助于代码防护强度更上一层楼。布尔类型在底层直接由 0、1和其他 构成,所以使得既可以使用数字混淆的技巧,也可通过类型转换等方式完成布尔混淆。代码块都是按照逻辑顺序有序划分与组合,并且将相关的代码放在一起。在不改变程序功能的前提下,可以通过拆分重组代码等方式打破这种常规逻辑,使代码间的关系变得模糊,以此来保护程序的源码。控制混淆即改变控制流或将原有控制流复杂化,通常的方式有不透明谓词、插入冗余代码和控制流平坦化预防混淆的目的不是通过混淆代码增加分析调试代码的复杂度,而是提高现有的反混淆技术破解代码的难度或检测现有的反混淆器中存在的问题,并针对现有的反混淆器中的漏洞设计混淆算法,增加其破解代码的难度。譬如花指令、调试器检测动态混淆是指在程序运行时对代码进行修改,使其难以被静态分析工具分析和理解。动态混淆的目的是为了防止逆向人员在分析代码时发现代码的结构和逻辑,从而提高代码的安全性和可读性。
动态混淆的实现方式主要包括以下几种:动态混淆,主要应对动态分析。技术在实现上主要包括自修改代码(SMC)、代码虚拟化(VM)、指令虚拟化(VMP)。通过将源代码进行编译,并对字节码文件进行修改,然后在运行时在代码中运行标准的解释器。如dart VM通过自定义指令集、解释器的一种保护方式。其主要特性是自定义的指令集(也称虚拟指令集),由于实际的代码均是 VMP 动态运行后得到的。故无法直接有效的动态调试VM保护与VMP保护有些师傅认为同一个东西有些认为不是. 笔者认为不是同一个东西,其区别主要在于使用官方/标准的虚拟机还是使用自定义的指令集与解释器. 自修改代码(SMC,Self-Modified Code)是一类特殊的代码技术,即在运行时修改自身代码,从而使得程序实际行为与反汇编结果不符,同时修改前的代码段数据也可能非合法指令,从而无法被反汇编器识别,这加大了软件

...(已截断)

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-284629.htm
#2 2026-06-01 21:09:14
学习一下
#3 2026-06-01 21:09:14
学习学习
#4 2026-06-01 21:09:14
多多学习
#5 2026-06-01 21:09:14
感谢分享
#6 2026-06-01 21:09:14
学习一下
#7 2026-06-01 21:09:14
谢谢分享
#8 2026-06-01 21:09:14
很全面,学习一下。
#9 2026-06-01 21:09:14
很全面,学习一下。
#10 2026-06-01 21:09:14
能写这么多字 不容易啊!
#11 2026-06-01 21:09:14
感谢分享
#12 2026-06-01 21:09:14
感谢分享,很全面。
#13 2026-06-01 21:09:14
非常支持你的观点!
#14 2026-06-01 21:09:14
都是师傅们教的好,萌新第一次发文。请多指点

最后于 2024-11-30 23:53
被Payne-Wu编辑

,原因:
#15 2026-06-01 21:09:14
感谢分享!
#16 2026-06-01 21:09:14
感谢分享!
‹ 上一页 1 2 下一页 ›

请登录后参与讨论

立即登录 注册账号