如何获取带数字签名PE文件的原始PE哈希值?
如何从带Authenticode签名的PE文件中提取原始PE哈希值
我完全懂你的痛点——要拿到签名绑定的原始PE哈希(而非整个文件的哈希),但微软没明确定义Authenticode PKCS#7块里ContentInfo的具体结构,直接重新计算哈希对篡改后的文件又毫无意义。下面是可行的解决方案,核心是解析PKCS#7签名结构里的特定属性:
核心原理回顾
Authenticode的PKCS#7签名块里,原始PE的哈希值其实存储在SignerInfo的AuthenticatedAttributes中的SpcPeImageData属性(OID: 1.3.6.1.4.1.311.2.1.15),而非ContentInfo的顶层字段——你提到的ContentInfo只是PKCS#7的外层容器,真正的关键数据在内部的签名属性里。
具体提取步骤
- 定位PE文件中的Authenticode签名块
PE文件的可选头目录项IMAGE_DIRECTORY_ENTRY_SECURITY会指向签名块的偏移和大小。这个块是DER编码的PKCS#7SignedData结构,直接提取这部分数据即可,不用处理整个PE文件的其他内容。 - 解析PKCS#7 SignedData结构
首先识别ContentInfo的OID(应该是1.3.6.1.4.1.311.2.1.4,对应Authenticode的SignedData),跳过外层容器,进入SignedData部分;然后找到SignerInfo数组(通常只有一个元素),遍历其中的AuthenticatedAttributes集合。 - 提取SpcPeImageData属性中的哈希值
在AuthenticatedAttributes中找到OID为1.3.6.1.4.1.311.2.1.15的属性,它的ASN.1编码内容包含哈希算法的OID(比如SHA-256对应2.16.840.1.101.3.4.2.1)和原始PE文件的哈希字节数组,直接提取这个字节数组并转成十六进制字符串,就是你要的原始PE哈希。
实现思路(工具/代码)
- Windows平台原生方案:使用
CryptQueryObjectAPI加载PE文件的签名,获取PKCS#7消息对象,再通过CryptMsgGetParam提取SignerInfo和对应的属性,最后解析ASN.1结构拿到哈希。 - 跨平台方案:用OpenSSL的
PKCS7_*系列函数解析签名块的DER数据,定位到SignerInfo的属性节点,手动解析SpcPeImageData的内容。
关键提醒
为什么重新计算哈希没用?因为篡改后的PE文件,重新计算的是当前修改后的文件哈希,而签名里的哈希是签名时原始PE的哈希——两者必然不一致,只有从签名块里提取的才是签名绑定的原始值。
内容的提问来源于stack exchange,提问作者dockd
相关产品推荐
相关产品推荐

