今天简单说一下“壳”的历史,最早的“壳”的概念是 DOS 时代,我只在中学时用过 UCDOS 和 WPS,在编程这方面并没有深入进去,所以还是从后面开始聊吧。以下主要内容来自来于搞壳的小伙伴(网名 tick,tock),我只是稍微整理了一下。
纯压缩时代
Win95 之后三年时间,几乎没有壳,程序大多都裸奔,可能大家还没有从 DOS 中转过弯来,直到 Win 98 发布之后,到2000 年左右,是共享软件的大发展的时期,那个年代谁的浏览器书签里没有几个“下载站”都不好意思见人。现在我们知道的著名的壳,很多都是那个时期出现的,像 UPX(98年发布的第一版),AsPack 具体查不到了,应该也是差不多的时候,还有 VMProtect 也是 2000 年成立的公司(这个后面再介绍)。
这个时期的壳基本上都是压缩壳,也就是把源程序压缩再包起来,确实是个很形象的“壳”。压缩壳可以解决程序很容易被反汇编和反编译的问题,也能防止文件补丁,但随着脱壳技术的发展,以及内存补丁的破解方式盛行,压缩壳的保护效果越来越不尽人意。到现在,几乎所有的压缩壳都有对应的“脱壳”工具。
发展到现在,“压缩”只成了保护工具的一个功能,在安全上几乎没有贡献了。
虚拟机时代
“对抗”会促进技术进步,大到战争对科技影响,小到破解技术对加壳技术的影响,都一样。因为压缩壳安全性不行,后来的加壳技术开始将重点放在了代码逻辑的保护上。虚拟机壳就应运而生了,而且一直发展到了今天。这个时候“壳”已经不那么形象了,但是这个叫法也一直延用了下来,我们不用过于纠结了。
虚拟机装系统大家都玩过,虚拟机壳,顾名思义,就是借荐了传统虚拟机的实现思路,将可执行程序的二进制翻指令机器码翻译为自定义的虚拟机字节码,使逆向分析变得极其困难,即使破解也无法形成“通解”(也就是不存在全自动脱壳机),代码保护技术从此迈向了新的台阶,直到现在,也还是在这条技术路线上不断深入。
VMProtect 公司是 2000 年成立的,产品应该在 03 年到 05 年之间成熟,是虚拟机壳的代表,一段时间“VMP”几乎成为“壳”的代名词,可见其影响力。2010 年之前学逆向的人还不少,多多少少都会拿个老版本的 VMP 来练练手的,不过现在这种盛况已经不复存在了,一方面大家都转向了移动,再一方面这种辛苦活越来越少年轻人愿意干了。
话说回来,VMP 这老毛子的东西确实是好,这么些年也一直在进步,到今天,在 PE 壳江湖上也一直有统治地位。当然后来出了 SafeEngine, Themida 等更多的虚拟机壳,SafeEngine 是国产的,核心就一两个人,团队应该也是被某巨头收了,现在也不怎么做了。
移动时代
2007 年苹果发布了 iPhone,2008 年 Android 1.0 发布,2010 年苹果发布了 App Store 之后(Jobs 确实是个天才),移动应用真正开始的兴起。由于苹果生态相对封闭,苹果有强大的控制力,所以“安全”就一直集中在 Android 身上。因为移动的传播性强很多,所以利益也更大,因此加密和解密较量的激烈程序比 2000 年 PC 上有过之而无不及。
Android 应用是 Java 写的(或者说通常是 Java写的),而 Java 的字节码是出了名的容易被反编译,国内就出现了一些应用“加固”厂商,在移动上,“加固”确实比“加壳”更形象。大家一开始的技术,都主要集中在加密 dex 上。时势造英雄,最先出的几家都赚到了不少钱。
但由于性能和安全性的问题,一些复杂应用的代码逻辑需要实现在 so 库上,只加密 dex 很快就不能满足需求了,出现了 so 库加固,这里的“加固”就是 PC 上的“加壳”,在移动领域一直沿用了“加固”这个说法,我觉得确实比“加壳”更贴切。
而 Android 上对 so 库的“加固”,技术上出现了与 PC 不同的发展路径:
- 一开始,也是使用压缩壳的方式,国内有不少加固厂商是以 UPX 为原型实现了压缩壳,但前面说了压缩壳最大的问题是不安全,在 PC 上是已经被淘汰的加密技术,运行时代码会解密还原,可以被 dump 分析……后来虽出现了一些像“自定义 linker”的技术对 so 库的格式做了处理,但是本质上还是换汤不换药,也只是对 ELF 格式做了一点处理,真正的代码逻辑并没有得到保护。
- 后来国外开源的一些基于 LLVM 的代码混淆框架在国内开始流传使用,如 ollvm。各大加固厂商也借此纷纷推出了自己的“安全编译器”(这个说法有点把“搬运工”说成是“生产水”的感觉,有点那啥……),以解决 Android so 库和 iOS 应用的代码逻辑保护问题。(在这里不得不提一下,LLVM 确实是个好东西!)
所谓的“安全编译器”听着很高端,但是相对 PC 上的虚拟机壳更安全吗?其实并不是的,至少在以下几个方面,要逊色很多:
- 基于 LLVM 的保护方案,可以直接适配其前端支持的语言和后端支持的平台架构,但也同样会受限于这一特性,比如 Go 语言就无法支持,在大厂切换技术栈时,就非常被动了。
- 基于 LLVM 的保护方案,在使用时需要更换已有的编译环境,替换编译器,调整编译选项等,这么做先不说易用性,反正对于我来说,让我换个编译器,在内心深处是怀有深深恐惧的。
- 从保护效果上看,基于 LLVM 的保护方案,受限于编译器框架,生成的代码只能做逻辑上的混淆变换,仍然可以被反编译,对控制流的混淆效果有限,且边界清晰,更容易被分析。关于这一点,可以上个图直观感受一下:
那为什么移动端不采用 PC 上虚拟机壳的技术思路呢?因为难,“不经济”,搬一个总是会容易很多!ARM 指令的编码格式远比 x86 复杂(千万不要被“精简指令集”这个名字给误导了),保护过程中的解析、反汇编、汇编、链接,要处理的问题比 x86 架构复杂了不是一点半点。那目前有没有这样的壳?肯定是有的,但今天不是写软文,所以就不说了。
未来 -- 多“端”融合
现在的应用形态越来越丰富,Javascript 也大行其道,像小程序、Electron 等,都很成熟了,苹果从 macOS 11 开始也要融合进 iPadOS 和 iOS 平台的应用、微软也要在Windows上支持原生Android应用了……我们会发现,以前“应用程序”这个概念的边界越来越不清晰。
可以相信,未来,“传统”可执行程序、移动 APP、基于浏览器的各种应用、小程序、各种设备上、甚至浏览器里的网页等等都是“应用程序”,各种端的界限将进一步模糊直到融合。
到时候可能“盗版”的需求就很小了,但是只要“程序端”还有逻辑,只要人性不变,那么就有安全需求存在,相信能看到这里的小伙伴一定能懂的。
(全文完)