一、引言
密码学系列是我开的新系列,约13篇。本系列文章关注于Android SO逆向所涉及的密码学知识。
二、主题
开门见山,学密码学是为了避免扣代码。Android SO的对抗中,凡是涉及到密码学的,其攻防就在于是否要“扣代码”。
来看一下密码学方面,所涉及的攻防历史吧。
开发人员想通过加密算法来保护数据,这是根本需求。采用什么加密算法?总共两条路
-
现代加密算法
-
古典加密加密
现代加密和古典加密的区别主要在于两点
1是加密如何保证安全性,古典加密的安全性主要依赖于算法本身不公开,而现代加密算法其本身完全公开,安全性由密钥保证。但这并不是唯一判定,每个国家都会搞一些算法不公开的”国密“,用于军事和重要经济领域,但也算现代加密算法。
2是算法复杂度和原理,现代加密算法往往依托于某种数学结构或难题,典型的比如RSA、ECC。而古典加密则结构简单、设计也朴素。如果开发者设计个”自定义算法“,类似于凯撒密码或维吉尼亚密码,也应该归为古典加密算法,因为缺少复杂度。
从密码学的角度上讲,古典加密算法的安全性远不如现代加密算法,因此在加密数据时,必须选择现代加密算法或以其为主。
现在转到逆向分析的视角
对于Android逆向而言,分析者对运行环境有完全的控制权,可以进行充分的动静态分析,这被称为白盒环境。只需要掌握少量密码学知识,动静态分析出密钥等要素,就可以轻松搞定。
反而朴素的古典加密,只能老老实实扣代码。因为古典加密千千万,而且不依赖于密钥而依赖于算法保密,那么为了实现其功能,只能阅读汇编执行流,扣出加密算法程序。
换句话说,只要掌握一定的密码学知识,在白盒环境下,处理现代加密算法是比古典加密容易很多的。甚至都不必白盒环境,只要能访问设备的内存,很多时候就可以dump出AES等加密算法的密钥,相关技术我们后续再讲。
再次切回安全开发人员的视角,抛弃是不可能抛弃现代加密算法的,因为单纯用古典加密的话,算法所提供的安全强度太低了,隐患无穷。一个好的思路是使用不那么热门的现代加密算法。因为一个研究人员,除非是博学家,否则熟悉MD5/SHA1/AES/DES/RSA/SM国密系列/TEA/CRC32/RC4/Base64这么一些常见的算法和编码就差不多了。当遇到一个不熟悉的加密算法时,只能当作自定义加密去做trace、看F5、扣代码。现代加密算法的种类数十上百,经过安全验证的也很多。开发人员可以使用”非最知名的加密算法"。
扣代码耗费时间远超“理解加密算法”,后者只需要找到对应的加密算法和密钥,调用API,就大功告成了。
再次转到分析者视角,FIndcrypt的思想以及工具出现了(这在第二讲中介绍)。使用一个不那么热门的加密算法,来干扰分析者这一条路又基本走不通了。Findcrypt找到密码特征后,分析者迅速的找其资料进行学习,然后分析出密钥,调用该种算法库的API,问题就又解决了。
利用算法所固有的魔数和数组所研发的Findcrypt,让分析者可以很容易的明白二进制文件中存在什么算法,大量的算法都可被识别。那么只要开发人员不使用极其冷门的现代加密算法,分析者都可以先借助Findcrypt了解具体是什么算法,然后学习那种算法,最后“理解加密算法”,不必扣代码了。
问题在此来到了安全开发这边,在后续的很多尝试中,形成了三类行之有效的办法
- 不把加密函数作为一个单独的问题,视为一般化的代码程序去保护。得益于代码保护技术的发展与成熟,大量的加密与混淆技术可用于代码保护。比如SO整体加固、部分代码加密、花指令、OLLVM、VMP等。
- 对标准加密算法的魔改,除非对该种算法的原理与实现都熟稔于心,否则分析者又只能当作“自定义算法”去扣代码了。
- 白盒加密,将密钥与加密算法结合在一起,白盒加密本质上已并非原标准加密算法,只是功能上与标准加解密结果一致。分析者再次只能扣代码。
在实际分析中,这三类出现频率都很高,1+2或1+3同时出现也是常有的事。
我们顺着密码学的对抗史进行学习,学这么四类东西
首先就是算法本身,没有对算法本身的深度理解,后续学习便如无源之水,无本之木,是不可能行得通的。
其次是算法的识别,所谓识别,依算法不同,可能包括下面这几类
- 根据魔数/运算表,识别出算法
- 根据函数的输入和输出,识别出算法
- 根据代码结构或流程,识别出算法
- 根据执行流中所呈现出的内存信息
第二讲中先讲较为简单的部分,后续还有深入。
第三部分就是识别加密算法的关键要素,所谓关键要素,举个例子,我们分析出sub_137AD 是AES算法
那么所需识别的关键要素如下
- 加密 or 解密过程
- 明文内容
- 密钥长度及内容
- 分组模式
- IV
- 明文填充方式
第四部分即实例讲解,我们说的那三类,对加密算法的保护,其该如何分析。这是进阶者必看的精华内容。