关于可信代码数字签名如何计算PE文件哈希值的细节,参阅本文档后面的“Calculating the PE Image Hash”。
“数字签名”已成为黑客绕过安全防御措施的常用工具,例如臭名昭著的“勒索软件Petya”,他就是选用合法的“数字签名”应用于恶意软件中,以逃避基本的签名验证工具检测。针对如此热门的入侵技术,作为一个逆向工程师或者安全程序开发者,知道如何使用“数字签名”应用于那些未签名、攻击者代码的方法就显得非常重要。
下面亚信安全网络监测实验室将为大家解读“数字签名”如何应用于未签名的PE文件中,以及关于代码签名机制、数字签名二进制格式的背景知识。
什么是软件“数字签名”
首先呢,要了解下什么是PE文件!PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL)。
如何知道一个PE文件是否被签名?
对于许多人来说,简单的答案就是打开该PE文件的属性,如果存在“数字签名”选项卡,那么就意味着该文件是被签名的。当你看到“数字签名”标签存在于一个文件属性中时,它实际上是表示该PE文件是被验证签名过的,这也意味着该文件本身会存在一个由证书和签名组成的哈希文件的二进制数据,该验证签名的存储格式被记录在PE验证签名规范文档中。
然而,有一些文件是要求被签名的,另外有的文件(记事本程序)是没有“数字签名”标签的,这是否意味着文件没有签名,但微软实际上是在发布未签名的代码呢?这得看具体情况,虽然记事本程序没有验证签名被植入到本身,但是实际上,它是通过另一种方法进行被签名的---目录签名。
Windows包含一个由许多目录文件组成的目录储蓄,这些目录文件主要是验证签名哈希值的列表。每个目录文件然后去签署证实匹配来源于这些目录文件的签名任何文件的哈希值(这是微软在几乎所有的情况下),所以,浏览器UI并不试图去查找目录签名,但是几乎所有的验证签名工具都会执行目录签名查找,例如PowerShell和Sysinternals Sigcheck。
(说明:这个目录存储文件位于 %windir%System32CatRoot{F750E6C3-38EE-11D1-85E5-00C04FC295EE})
在上面的截图中,我们可以从签名属性中看出notepad.exe程序是目录签名,还有值得注意的是IsOSBinary属性,因为执行是不被记录的,所以他将会显示“true”以表明一个签名已经连接到微软的根证书。有兴趣了解是如何实现的应该逆向CertVerifyCertificateChainPolicy函数。
使用 Sigcheck “-i”这个命令可以执行目录证书验证和显示包含验证哈希值的目录文件路径,“-h”这个命令是计算和显示PE文件的验证哈希的SHA1和SHA256.
我们知道验证哈希是允许你查找目录文件,你也可以双击一个目录文件已查看其条目,我还写了catalogtools PowerShell模块解析目录文件。“hint”的元数据字段给出了notepad.exe相应的条目。
数字签名的二进制格式
现在你已经知道了一个PE文件被签名的方法(验证和目录),知道一些签名的二进制格式是非常有用的,无论是验证签名还是目录签名,这两个签名都是存储为PKCS #7签名数据,这种数据是ASN.1格式的二进制数据。ASN.1是一个标准,它说明了不同数据类型的二进制数据应该如何存储。在观察、解析数字签名的字节之前,你必须首先知道它是如何存储在文件中的。目录文件本身是由PKCS #7数据组成,在线有一个ASN.1解码器,可以解析出ASN.1数据并以直观的方式呈现。例如,尝试加载包含notepad.exe散列到解码器的目录文件,你会得到一个意义上的数据布局。
ASN.1的每一个属性的解码都开始于一个对象标识符(OID),该OID是一个唯一的数字序列。如下图所示:
花时间探索数字签名中包含的所有字段是值得的。然而,目前所有的字段不在这个博客文章的范围之内。额外的加密、签名相关的OID是列在这里。
嵌入到PE中的验证签名检索
验证签名的签名数据是被植入到PE文件的末尾,操作系统也需要更多的信息以便于可以得到精确的便宜,我们可以见一下kernel32.dll在我最喜欢的PE编辑工具的情况吧。(CFF Explorer)
被嵌入的验证签名的便宜和大小都存储在可选标头中的“数据目录”数组内的“安全目录”偏移中,该数据目录包含在PE文件中各种接受的偏移和大小,比如导入表、导出表和重定位等等,数据目录中的所有偏移都是相对虚拟地址偏移(RVA),意思是当加载到内存时,他们是PE中各个部分的偏移量,但是有一个反面的例子,安全目录将其偏移量作为文件偏移量存储。这样做的原因是Windows加载程序实际上不在加载安全目录中的内容到内存。
在安全目录中文件偏移二进制数据是一个win_certificate结构。
PE验证签名结构中总有一个字段wRevision,存在于WIN_CERT_TYPE_PKCS_SIGNED_DATA中,这个字节矩阵和PKCS #7是一样的,ASN.1编码的数据正是你在目录文件中看到的,仅仅不同的是你不会找到1.3.6.1.4.1.311.12.1.1 OID,而是显示存在目录哈希。
数字签名应用到无签名的PE中
现在你已经对数字签名的二进制格式和存储位置有了基本的概念,你可以开始将现有签名应用到未签名的代码中。
应用被植入的验证签名
将一个被植入的验证签名从一个签名文件应用到无签名的文件中是非常简单的,因为这个过程很明显是可以自动化的,接下来我将介绍如何使用hex editor 和CFF Explorer工具来进行操作。
步骤1:获取我们需要的一个验证签名,比如我用kernel32.dll的签名。
步骤2:获取该签证签名在安全目录中WIN_CERTIFICATE结构的偏移量和大小。
【由上图可知,该RVA是0x000A9600,大小是x00003A68】
步骤3:在二进制编辑器中打开kernel32.dll,选择从0x000A9600地址开始x00003A68个字节大小的内容,复制他们。
步骤4:在二进制编辑器中打开这个无签名的文件(如HelloWord.exe文件),调至最后位置,粘贴来自于上一步骤中的内容,注意现在的该内容的偏移量就是这个签名的偏移量(现在是0x00000E00),然后保存文件。
步骤5:用CFFExplorer文件打开HelloWorld.exe文件,然后更新安全目录中的偏移和大小(目前是RVA = 0x00000E00 大小不变)修改完成之后保存文件,忽略不合法的警告,这不会对其有影响的。
现在成功了,签名验证程序将可以解析和显示出该文件的验证签名证书,唯一要注意的是,他将会显示这个签名是不合法的,因为这个被计算出来的验证签名码和被保存在证书里的不匹配。
现在,如果你想知道为什么这个验证签名值是不匹配的,有人在想我们是使用的同一个验证签名,为何会出现不一样呢?
那是因为GetAuthenticodeSignature函数首先会尝试去kernel32.dll中查找目录文件。在这个案件中,他在kernel32.dll中找到了一个目录入口,并且显示了这个目录文件中的签名信息,为了让这个验证签名特征值是完全一样的变得合法,需要临时关闭CryptSvc service,这个服务的职责就是去执行哈希目录查询。现在你看到的则是匹配的,这个说明了目前这个被签名的哈希目录与之前kernel32.dll签名的是不同的。
在PE中应用目录签名
实际上,CryptSvc是一直运行的并且执行目录查询操作。假如你要记住OPSEC和匹配用于签署你的目标二进制文件的验证证书,事实证明,你可以通过交换WIN_CERTIFICATE结构体中的bCertificate内容和更新相应的dwlength的方式去申请一个目录文件到被植入签名的二进制中,同时你要注意,我们的目标是(在这个案件中)申请一个签名验证码到我们没有签名的二进制文件中,这种方式与我们签包含目录文件是一样的,在这个案件中,证书特征值为:
AFDD80C4EBF2F61D3943F18BB566D6AA6F6E5033.
步骤1:获取包含目标二进制验证码哈希的目录文件,在这个案件中是kernel32.dll,如果一个文件是被验证码签署过的,sigcheck实际上不能操获取这个目录文件,但是这个Signtool工具是可以的。
步骤2:使用二进制文件编辑器打开目录文件并且注释其大小:0x000137C7
步骤3:我们将在编辑器中手动地制作WIN_CERTIFICATE结构体,使用我们申请到的字段。
dwLength:这个是结构体的长度,fields = 4(size of DWORD) 2 (size of WORD) 2 (size of WORD) 0x000137C7(bCertificate - the file size of the .cat file) = 0x000137CF.
wRevision:0x0200
wCertificateType:0x0002
bCertificate:目录文件的原始字节。
当在十六进制编辑器制作时,谨记字段存储在小端格式。
步骤4:复制你手工制作的WIN_CERTIFICATE结构体的字节内容,追加到未签名的PE文件中并且更新相应的安全目录中的偏移量和大小。
现在,如果你的计算和操作步骤都正确的话,你应该可以看到一个目录文件的特征配了。
培养“异常”检测的思维
通过以上的解析,希望大家能思考关于二进制数字签名的滥用问题,大家可从以下几点去调查和编写潜在的异常签名的检测:
- PE时间戳与证书有效期之间是否存在相关性?
- 攻击者提供代码的PE时间戳是否与前面提到的相关性不符?
- 你对具有哈希不匹配的“签名”文件的信任程度是什么?
- 你将会如何去检测一个被植入签名的PE文件?
- 如果在数字签名之外有附加数据怎么办?
- 什么样的影响可能停止/禁用安全产品进行局部签名验证cryptsvc服务吗?