「随着物联网时代的开启,需要解决的安全问题会愈来愈多,而代码安全是其他安全方案的底层支撑。面对芯片架构繁多,运行环境复杂的嵌入式物联网设备,传统的代码安全方案都将会失效,LLVM 编译器为我们带来了终极代码安全解决方案。」
日前,几维安全 CTO 刘柏江在 2018 ISC 互联网安全大会“网络安全技术创新及应用论坛”上发表了题为《 IoT 时代 LLVM 编译器防护的艺术》的主题演讲。
图
移动互联网、万物互联网,归根结底都是硬件组成,软件驱动。软件代码承载着我们生活的方方面面,利用 App 打车、购物、支付、聊天等无一不是通过代码来实现具体的服务功能。然而由于黑灰产的存在,裸奔的代码将会给我们的生活带来各种糟糕的体验和危险。尤其是随着物联网时代的开启,需要解决的安全问题会愈来愈多,而代码安全是其他安全方案的底层支撑。面对芯片架构繁多,运行环境复杂的嵌入式物联网设备,传统的代码安全方案都将会失效,LLVM 编译器为我们带来了终极代码安全解决方案。架构无关、函数粒度、强度可调,堪称代码安全防护的艺术,也是今天要分享的实操性非常强的技术。
万物互联,代码安全先行
安全圈的同仁们最近几年都提到一个观点:万物互联,安全先行。但这里的安全是一个宽泛的概念,它可能是指设备的物理安全,防止丢失或者被盗;也可能指芯片以及操作系统安全,防止底层漏洞被恶意利用;还可能指物联网设备承载的业务安全,防止用户隐私数据泄漏。
图
这些安全我称之为策略安全,它们是通过设计完备的规则以及良好的代码实现来达到保护的目的。但是这类安全问题我们绝大多数人是遇不到的,它们属于 Intel、ARM、Apple、Google 这类芯片和操作系统巨头公司的考虑范畴。
软件代码是科技公司最宝贵的财富之一,代码安全是我们每位 IT 从业者都可能会遇到的问题,也是很有必要去解决的问题。代码加密能带来如下好处:第一,防止核心算法被重构,保护软件资产;第二,提升策略安全的强度;第三,加大破解难度,延长破解时间,为运营争取更多的有利窗口期;第四,提高破解成本,将逆向菜鸟拒之门外。
物联网时代已经来临
从 2007 年 iPhone 的诞生到现在,移动互联网已趋于成熟,万物互联网也已打响军备竞赛,比如 Google 的 Android Things、阿里的 AliOS Things,他们都在为新一轮的物联网平台布局。可以预见,未来我们身边将有数不清的与生活息息相关的智能终端设备。作为对策略安全的一个强力补充,代码安全也将会继续为整个生态安全贡献力量。
芯片体系多
在 PC 时代,三大主流的桌面操作系统均跑在 x86 体系下面。而到了移动互联网时代,我们主要面对的芯片体系是 arm,但是 arm 有 thumb、arm、arm64 三种不同的指令集,这已经开始有点让咱们这些做安全和逆向的人感到心力交瘁了。然而到了物联网时代,鉴于成本、使用场景、性能要求等因素,物联网设备所使用的微处理器芯片体系可能会多到让人难以置信,足以让安全开发者们癫狂。
运行内存小
不像 PC 或者手机动不动就是几个 G 的内存容量,物联网设备的运行内存容量相较 PC 或手机要小得多的,它们的内存可能只有少得可怜的几十几百 K。
运行环境复杂
物联网操作系统运行的环境有如下特点:第一,跑在种类繁多的芯片架构上;第二,运行在内存一般偏小的环境;第三,受限于功耗硬件性能低下。这些特性给我们做代码安全提出了不小的挑战。在引入我们新型的代码加密方案之前,我们先看看历史方案的做法以及缺陷。
图
传统黑盒代码加密及局限
首先,我们科普两个简单的概念。黑盒代码加密处理的对象是最终的软件执行体,它们都是以二进制的方式存在,比如 Windows 的 exe、Android 的 so 以及 dex ;白盒代码加密处理的对象是源代码,它们都是以文本的方式存在,需要用对应的编译器才能转换成二进制,比如 C/C++/Objective-C / Swift 源文件。
图
黑盒代码加密的应用
黑盒代码加密的典型应用有四种场景。第一种是加壳,一般是对执行体压缩或加密,然后运行的时候动态解密,比如适用于 Windows、Linux、Android 的 UPX 壳。第二种是加花指令,比如 x86 架构下面利用指令的可变长特性增加误导反汇编程序的垃圾指令。第三种是加虚拟机,这种是直接把对应的指令集转换成自定义的指令集,比如 Windows 平台非常著名的 VMProtect,它就是把 x86 指令集转码为私有的指令集格式。第四种是劫持运行时,比如 Android 平台的 Dex 加固就属于这一类。
图
黑盒代码加密的局限
从黑盒代码加密的实现原理来看,它们针对的操作系统以及芯片架构都是特定于一个很小的集合,这样带来一些很明显的限制和缺陷,一个是可移植性差,另一个是兼容性差。可移植性差主要体现在以下两点:一是很难对多端且同源的代码做一致性的保护;二是芯片架构不兼容、内存需求显著增加,很难适应新的像 IoT 这样的平台。兼容性差主要体现在黑盒方案往往需要干预正常的 App 运行时(专业的叫法称之为 Hook 技术)。但是对于像 Android 这类高碎片化的平台,干预运行时意味着很难把方案做到完备;而对于像 iOS 这类完全封闭的平台,干预运行时意味着方案没法工作,因为苹果基于安全的考虑不允许很多底层的操作比如动态分配代码内存。
图
新型代码加密方案 - LLVM 编译器
下面我们看看怎样利用 LLVM 来重新定义代码安全的实现思路。LLVM 是模块化、可复用的编译器工具链集合,它提供了非常完整的 API 操作接口,可以自定义整个编译过程。它的编译流程可以抽象为源文件通过编译器前端生成架构无关的 IR ( IR 是中间表示的英文缩写), 然后被编译器后端生成架构相关的目标文件。从这个抽象的编译流程我们可以看到,架构无关的 IR 给了我们设计代码安全方案的机会。
图
LLVM-IR 的抽象结构
IR 的抽象结构如下图所示,去除一些数据和描述信息,IR 由函数构成,函数由基本块构成,基本块由 IR 指令构成。LLVM 提供了完整的 IR 指令操作 API,让我们可以对 IR 模块做修改,这是我们基于 LLVM 编译器做代码安全的基础和核心,也是我们能克服黑盒方案缺陷的关键。
图
LLVM-IR 的潜能
基于 LLVM-IR 做代码安全能带来的好处众多且方案的设计思路灵活,它能完美的处理移动互联网和物联网操作系统环境下的代码安全问题。第一,在架构无关的 IR 级别做防护,可以适应任意芯片架构;第二,能做到以函数为单位进行防护,可以适应低内存运行环境;第三,可以根据不同的需求,定制化实现不同级别的安全防护。
基于 LLVM 编译器的代码安全方案
初级防护 - 混淆编译器
Obfuscator-LLVM,这是 2013 年开源的一个混淆编译器,也是我们国产安全编译器的鼻祖。很多友商的安全编译器都是从这个项目衍生而来。它能实现代码膨胀、块乱序等功能。
图
这是两张汇编代码反编译流程图 ,图中的白色部分代表着一个最小单位的指令块。左边是正常的流程图,右边是混淆之后的流程图。从流程图中我们可以看到,混淆之后把代码量增大了,执行逻辑也做了转换。从逆向分析的角度看,代码量的增加在一定程度提高了逆向的难度。但由于这个方案比较初级,因此强度不是很高,现在也已经有了针对混淆的自动化反混淆脚本。
高级防护 - 块调度编译器
Obfuscator-LLVM 给了我们一个好的开头,同时也是一个重要的启示。基于 LLVM,我们还能做得更多。从逆向分析的角度看,只要函数逻辑是连贯的,那么我们总是可以做分析,不管你如何膨胀,代码就在那里。所以,切断函数逻辑,是一个代码防护的方向。基于该方向的思考,我们做出了块调度编译器,它完美的掐断了原始函数的逻辑,让逆向的人没法分析。
图
块调度编译器的实现原理是这样的,比如一个函数里面有三个基本的代码块 A、B、C,A 执行完成之后会根据不同的条件跳转到 B 或者 C。正常的执行流程我们通过专业的反编译程序可以一眼就能看出这三者的逻辑关系,进而分析它的实现原理将变得易如反掌。而块调度呢,会把 A 跳转到 B 或者 C 这个跳转过程加密,这样出来的效果呢就像右边的图一样,各个基本的关键代码块成为了彼此独立的实体,静态反编译工具将没法做代码的连续性分析,这将使得逆向分析无法进行。另外,块调度还会把函数调用加密,那么我们常用的通过函数调用了哪些函数来猜测函数逻辑将变得不可能。因此,块调度的强度远远高于普通的混淆,如果将混淆和块调度叠加使用,那么效果将会出奇的好,让逆向分析的人无比痛苦。
旗舰防护 - KiwiVM 代码虚拟化
一直以来,在外挂、反外挂最激烈的 Windows 网络游戏攻防战场,虚拟机防护往往是最后一道防线,也是强度最高的一道防线。高水平的逆向分析者往往需要花费数月甚至数年才能大致搞明白被虚拟机保护的代码,而一般的逆向分析者几乎没法展开虚拟机的分析。因此,虚拟机是代码安全的最高堡垒。
作为国内专业的白盒代码安全方案提供商,几维安全于 2016 年就基于 LLVM 研发出了全平台全架构支持的代码虚拟化产品 KiwiVM。它小巧精致,不仅适用于移动互联网,同时也天生适应物联网,这是基于 LLVM 的顶级艺术品。
由于 LLVM-IR 的平台无关性,因此 KiwiVM 也能平台无关的实现函数级的虚拟化,可以在性能和安全两方面取得良好的平衡。KiwiVM 代码虚拟化属于静态代码加密技术,一旦成功虚拟化,配合虚拟 CPU 的运行时即可完整的实现原始代码的功能,不存在干预运行时的 Hook 操作,因此兼容性可以达到 100%。
图
KiwiVM 的中心思想是利用 LLVM-IR 编码成自定义虚拟 CPU 的指令集和元数据,包括指令集数据、重定位数据、函数调用签名数据等。转换过程是源码转源码,比如 C/C++/ObjC 源代码通过 LLVM 前端编译为 BC 文件( IR 模块的载体),然后 KiwiVM 核心算法把该 BC 文件做自定义的编码生成功能等价的标准 C 源代码文件,最后再编译为目标平台需要的二进制文件。前面我们提到物联网设备的芯片可能会是非常冷门的,甚至其编译工具链都是完全私有定制的,和常规的 GCC 交叉工具链都不一样。面对这种冷门环境,由于 KiwiVM 拥有源代码转源代码的能力,所以可以完美的兼容它的代码安全需求。
图
原始函数被虚拟化之后代码逻辑完全变为单一的虚拟机入口,不管多么复杂的函数成功虚拟化之后,最终出来都是这样一个无比“单纯”的白板。
结语
至此,我们分享了基于 LLVM 编译器做的不同防护级别的三种代码安全方案。从下图我们可以清楚的看出混淆、块调度、代码虚拟化三者之间的区别。
图
几维安全已经在 LLVM 编译器代码安全方面有了完整的产品布局,所有的安全编译器产品都支持 iOS、Android、IoT 三大平台。
图
其中初级防护产品混淆编译器能实现代码膨胀、乱序执行、字符串加密等功能。高级防护产品块调度编译器能实现逻辑断链、函数调用隐藏、字符串加密等功能,并且可以和混淆编译器叠加使用,强度更高。几维安全旗舰防护产品代码虚拟化编译器能实现虚拟 CPU 执行,完全隐藏函数逻辑,让逆向工程彻底无法进行。
原文地址: https://www.kiwisec.com/news/detail/5b987d94db30c341099f2600.html