在做Android逆向题时就遇到过对APK文件进行签名的题,奇安信面试官跟我说,无论是做哪个平台的逆向,它的大方向、学习路径总是相似的。比如Android逆向有签名、有Hook和注入技术,Windows逆向也是有的。所以这篇笔记就是学习PE文件的数字签名。
1. 基础概念
PE文件全称是Portable Executable,意为可移植的可执行文件,常见的EXE、DLL、OCX、SYS、COM等都是PE文件。
为什么要对PE文件进行数字签名呢?
- 防篡改:通过对数字签名的验证,保证文件未被非法篡改
- 降低误报:安全软件通过验证文件是否有正规厂商的数字签名来降低误报
PE文件数字签名信息存放在Certificate Table
位置,同时PE文件可选文件头DataDirectory
第5项记录文件偏移及大小。
使用PEView查看签名前后对比图,可以看到Certificate Table
存储相关签名信息。
1.1 PE文件数字签名及验证过程
签名:
- 软件发布者使用散列算法(如MD5或SHA)计算PE文件的散列值
- 软件发布者使用私钥对散列值进行签名得到签名数据
- 将签名私钥对应的公钥和签名数据等以证书的形式附加在PE文件中,形成经过数字签名的PE文件
- 软件发布者将经过数字签名的PE文件进行发布
验证:
- 从PE文件证书中提取软件发布者的公钥、使用的散列算法、签名算法、原始散列值的签名数据
- 使用提取的公钥和对应签名验证算法将签名数据还原为原始PE文件的原始散列值
- 对现有PE文件使用同样的散列算法计算出对应的散列值
- 对比两个散列值是否一致,从而判断数据是否被破坏或篡改
1.2 查看数字签名
1.2.1 PE文件数字签名证书
以toDesk.exe
为例,可以看到经过数字签名后的PE文件会多出一个“数字签名”属性,点击详细信息可以查看对应的证书。对应的证书信息包括签名算法、哈希算法、有效期、颁发者信息等。
1.2.2 微软数字签名证书
徽标键 + R -> 输入certmgr.msc
,可以看到这里面有2个系统默认的椭圆曲线加密(ECC)算法的根证书。随意选择一个导出,右键 -> 所有任务 -> 导出,选择Base64编码。
可以看到导出的ECC密钥证书如下图所示,包括证书的有效期等信息。这就是微软在实现椭圆曲线加密(ECC)算法的数字证书,位于CryptoAPI.dll
文件,也是被我们利用伪造可信任来源的签名漏洞。
1.3 数字签名常用算法及应用领域
数字签名常用算法包括:
- RSA数字签名算法:基于大整数分解问题,MD5、SHA
- DSA数字签名算法:基于离散对数问题
- ECDSA椭圆曲线数字签名算法:ECC+DSA,椭圆加密算法,属于DSA的一个变种,基于椭圆曲线上的离散对数问题
其应用领域包括:
- PE文件数字签名
- HTTPS数字签名
- 电子邮件数字签名
- Office文档数字签名
- 代码数字签名
2. Github网站证书验证过程
在Windows系统访问一个网站(如Github.com)时,该网站会向Windows系统发送由第三方权威机构(CA)签署的网站证书。
Windows系统则会验证该证书是否由CA颁发,若验证通过,则Windows系统与网站成功建立TLS连接。
为了方便下一次更快地访问,Windows将验证成功的证书放入内存中一块Cetificate Cache
(证书缓存)中。在下一次验证时,如果该证书存在于缓存中,则直接取缓存中的值进行验证。
微软证书漏洞(CVE-2020-0601)就是利用这一机制。在成功缓存证书数据后,根据Windows证书缓存机制,恶意网站可以伪造虚假的网站证书且通过Windows验证,将自身伪装成合法网站。
当Windows接受到新的证书时,Windows将新接收的证书与已缓存证书的证书公钥进行遍历对比,寻找匹配的值。
伪造的恶意证书与Windows系统中的缓存证书有同样的公钥,但Curve项没有在校验范围内,所以可以通过构造自定义Curve来伪造证书,使得证书验证流程依然成立,但通过验证的证书已经不是之前成功验证的安全证书。
3. Signtool签名PE文件
PE文件数字签名所使用的工具包括:
makecert.exe
:生成数字签名证书signcode.exe
:数字签名工具test.exe
:被数字签名的目标PE文件test.cer
:数字证书文件test.PVK
:数字签名的私钥文件
假设test.exe
是要被数字签名的PE文件,首先我们要通过makecert.exe
生成需要的证书,生成两个文件分别是test.cer
和test.PVK
。
1 | makecert -$ "individual" -r /sv "test.PVK" /n "CN=Windows,E=microsoft,O=微软" test.cer |
其中,通过makecert.exe
生成需要的证书常见参数如下:
- -r:自签名
- -n:证书名称,格式为
-n "CN=名称,E=Email,O=组织名称,C=国家,S=省份,P=县城"
- -a:指定散列算法,其值必须是MD5(默认值)或SHA1
- -$:指定证书的签名权限,其值必须是
commercial
(商业软件)或individual
(个人软件) - -b:证书有效期的开始时间,格式为mm/dd/yyyy
- -e:证书有效期的结束时间,格式为mm/dd/yyyy
创建过程中需要输入私钥密码,这里设置为“v5le0n9”。
查看证书信息,如果未信任则需要点击“安装证书”。
利用signcode.exe
工具进行数字签名,选择需要签名的test.exe
程序。
选择自定义选项,然后选择test.cer
文件。
点击浏览按钮,添加文件test.PVK
。哈希算法可以选MD5也可以选sha1。
数据描述可填可不填,时间戳服务器可填可不填,最后弹出签名成功框。
此时test.exe
文件完成数字签名,打开该EXE文件属性,可以看到签名相关信息。注意,该数字签名正常且颁发者为Windows。
最后使用PEView软件打开PE文件,可以看到签名前和签名后的结构存在CERTIFICATE Table
区别。
4. PE文件签名数据提取
4.1 PEView查看签名信息
使用PEView查看已经签名的test.exe
文件,可以看到Certificate Table
存储相关签名信息。
1 | typedef struct _WIN_CERTIFICATE |
文件开始位置:00000A00
- 表项长度:4字节,头部字段和签名数据的总长度,这里为0x4A0,所以0xA00+0X4A0-1=0xE9F为签名数据结束的位置
- 证书版本:2字节,常见0x0200表示
WIN_CERT_REVISION_2
- 证书类型:2字节,常见0x0002表示包含PKCS#7的
SignedData
结构 - SignedData:包含PE文件Hash值的签名数据、软件发布者公钥,选用的签名及散列算法等(在文件中为ASN.1编码)
在PE文件可选文件头DataDirectory
第5项查看文件签名信息的偏移及大小以验证上述起始地址与大小是否正确。
4.2 010Editor提取签名数据
Ctrl + G 定位到0xA00,从第9个字节开始一直复制到0xE9F,另存为test.dat
。
此时签名信息成功导出,后续需要进行数据分析。
5. PE文件签名数据分析
一个PKCS#7 SignedData
结构包括PE文件的哈希值、一个被软件出版厂商的私钥创建的签名 和 将软件出版厂商的签名密钥和法人代表进行绑定的X.509 v3证书。PKCS#7 v1.5规范定义了如下关于SignedData
的ASN.1(抽象语法符号)结构:
注意,导出的test.dat
签名数据为ASN.1抽象结构,需要采用ASN1View或ASN1Dump进行解析,其效果如下图所示:
用ASN1View导出会出现错误,可能是由于DAT文件后面的5个字节为0,在校验数据大小时出现错误。
5.1 ASN1Dump分析签名数据
调用ASN1Dump打开test.dat
解析基础数据,每个字段都有对应的flag,比如:
指定
SignedData
结构值为1.2.840.113549.1.7.2,表示采用PKCS#7结构
生成签名的哈希算法
MD5:1.2.840.113549.2.5
SHA1:1.3.14.3.2.26
SHA256:2.16.840.1.101.3.4.2.1
签名属性
SPC:1.3.6.1.4.1.311.2.1.4
获取证书颁发者信息,包括md5withRSA签名、证书颁发者、组织、国家及省份。每块数据通常有一个标记变量,标记变量对应有相关值,比如颁发者标记2.5.4.3和颁发者“Windows”、散列算法和散列值等。
还有其它相关信息,核心数据包括:散列算法、摘要数据、公钥数据、签名后数据。
注意,RSA签名后的数据和公钥值会还原出第一个hash值,摘要数据和散列算法将计算第二个hash值。如果两个值一致,则表示该PE文件在传输过程中违背篡改或破坏,且受信任;否则已经被破坏。
5.2 ASN1View提取证书及分析数据
回顾test.exe
的签名信息和证书信息。PE文件的签名算法是SHA1,加密算法是RSA,证书的签名算法是MD5,加密算法也是RSA。
使用ASN1View打开test.dat
。
由于ASN1View打开test.dat
失败,暂时还无法解决,所以后面的实验暂时做不了。
6. PE签名文件新增数据
由于010Editor导入PE模板时出现错误,所以这个实验也做不了。