编译原理在安全领域的应用
什么是编译原理
上图是我从《编译系统透视:图解编译原理》里面扣出来的,基本包括编译原理的各个主要方面,从中可以对编译原理有个大体认识。
专业点来讲,编译原理就是介绍编译程序构造的一般原理和基本方法,内容包括语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成、存储管理、代码优化和目标代码生成。
之前在知乎上看到过一份视频,讲的是程序员编写的代码如何被计算机识别,并在CPU上运行,如果你未曾学习编译原理,推荐观看一下(视频时长11:34)。
每个信安学生总有一份叫“污点分析”的毕业设计
污点分析是指将程序从外部获取的数据标记为污点,然后观察污点在程序执行过程中的传播,从而得到程序中的信息流等信息,里面涉及编译原理中的词法语法分析会多一些,主要被应用于恶意软件分析、攻击代码检测等软件安全性分析研究中。
记得刚参加工作那会,经常到网上搜索安全论文,发现很多信息安全专业的学生大多有做过一份关于“污点分析”的毕业设计,你现在上CNKI就可以搜索到很多,尤以硕士毕业论文居多。
当时我几乎翻遍网上所有能找到的“污点分析”论文,最后我得出几点结论:
不求效果,但求理论高深。之前搞flash xss检测,花了几天时间用一堆grep实现的检测工具,挖不了不到大厂的漏洞,包括淘宝、京东这些电商;但也有同学花几个月搞flash actionscript污点分析,虽然有点作用,但从工作效率和结果看,有时高深的理论不见得适合工业界,虽然我的几行grep没法拿来写论文。
千篇一律,天下文章一大抄。下载了一堆同主题方向的论文,发现有的内容改都没改,互相乱抄。
以漏洞挖掘的主题居多,但最后总要以挖洞效果结尾,有0day自然最好,没0day就找几个历史漏洞重现下(很多可能是特例化处理的),没历史漏洞就对比几个主流开源的挖洞工具,对比效率、性能等等,最挫的就是连效果都没有就收尾了。
有过此般经历后,我已很少再去翻国内的安全论文了,学术论文可能还是以翻阅国外的为主。
成熟的技术 ≠ 成熟的产品
污点分析技术最早是在1976被提出的,2005年左右开始,污点分析应用于二进制漏洞挖掘的研究火了好多年,其实技术已经相对成熟。
确实有一些人通过污点分析挖掘到不少有价值的主流软件漏洞,但这项技术要落地为一款安全产品还是有很多问题的。
首要问题就是误报率,之前有同学开发出基于污点分析的源码审计工具,每次外部报告漏洞的时候,复盘时总说能检测出来,只是没人工跟进。但是,检测出来的有成千上万条告警,需要消耗大量人力去排查这又有什么价值呢,本质上,还是没发现嘛!
这也算是安全运营的问题,深以为,凡是能检测到,但无法人工或自动跟进推动问题解决的,都是徒劳的。
相信有很多公司都有出过污点分析的安全审计工具,收费的或者开源的,国内的此类安全产品很多最后都不了了之,所以说成熟的技术不等于成熟的产品。
国外比较著名的商业源码审计工具就是Coverity和Fortify SCA,算做得最好的业界同款产品,但用过的人都知道,检测出来的问题,还是需要投入很多人工成本的。
反编译与加固
搞逆向的同学都知道IDA、JEB这些著名的逆向工具,平时在无源码的情况下,我们直接通过它们来分析程序逻辑,无需知晓其中涉及各类反编译技术。
反编译算是编译的逆过程,即将可执行程序转换成程序源码的过程,如果是转换成汇编语言,我们通常称为反汇编;如果是其它语言的(比如C、Java、C#等等),我们统称为反编译。
不同语言的编译过程还不一样,比如Java是通过JVM虚拟机将字节码转换成CPU认识的指令,而C是直接由编译器转换机器码供CPU执行的,因此它们的反编译过程也不一样。
所以如果不懂编译原理,又如何开发反编译工具呢?
有了反编译,自然就有了防反编译的工具,因此造就了各种加壳工具的出现。
未知攻,焉知防。要开发加固工具,就需要知道反编译原理,要知道反编译原理,又需要知道编译原理。
编译原理 <---> 反编译原理 <---> 加固原理
编译原理在漏洞攻防中的应用
搞文件Fuzzing,我们可以在样本(收集、筛选、精简)和Fuzzer(策略、方向等)上面下功夫,甚至简单地暴力fuzzing文件都可以挖到漏洞。
但对于JavaScript、CSS、Flash ActionScript这些脚本呢,直接简单地暴力变异文件根本无法进入正常的解析,做的大多是无用功。
因此我们需要一个能够准确生成代码的语法生成器,再用它生成fuzzing样本,这里主要涉及编译原理中的语法分析。这方面有著名的开源工具funfuzz(https://github.com/MozillaSecurity/funfuzz)、domato(https://github.com/google/domato),下图就domato生成js代码的语法模板片段:
除此之外,通过对clang/gcc等开源的编译工具对目标源码进行插桩,以帮助监控fuzz样本的代码覆盖率,反馈给fuzzer作改进,以进一步提高代码覆盖率,这块叫“驱动反馈(feedback-driven),比如著名工具就是afl、libfuzzer、honggfuzz,以后有机会可以专篇讲解此技术。
还有通过编译器增加防漏洞利用的机制,比如GS、CFG等安全机制,在对抗漏洞攻击上也起到了不小的作用。
所以通过研究llvm、gcc等编译项目,对漏洞攻防领域也是有一些可作为的地方。
总结
编译原理在逆向工程、漏洞攻防、软件开发等诸多领域有所应用,有时就看你怎么使用,也并不是每个人在安全工作领域中有机会运用到,但技多不压身,不妨多储备点知识,以免到了“书到用时方恨少”的地步。
若干年前,挖洞不用污点追踪都不好意思写论文; 现在搞安全不用人工智能都不好意思装逼,能用机器学习的,坚决不用正则;能用DNN的,坚决不用LR回归;能用无监督学习的,坚决不用有监督学习……但你不试下,怎么就知道grep不行呢?