首页
社区
课程
招聘
[原创]Windows PE 文件签名的解析与验证
发表于: 2024-9-23 16:22 6059

[原创]Windows PE 文件签名的解析与验证

2024-9-23 16:22
6059

为了方便在 mac 和 Linux 下解析与验证 PE 签名,我开发了一个跨平台工具 https://github.com/0xlane/pe-sign。安装和使用方法可以参考项目中的 README_zh.md。本文分享的是开发该工具之前做的一些签名研究内容。

具体的 PE 格式可以参考 MSDN

签名证书的位置在 Certificate Table 里(也称为 Security Directory):

可以从 Optional Header 的 Data Directories 里找到 Security Directory 的文件偏移:

如图表示,ProcessHacker.exe 文件的签名数据在 0x1A0400 位置,长度 0x3A20。

导航到这个偏移位置即可看到这里就是签名数据:

参考 MSDN, 签名数据的结构如下:

所以,bCertificate 是实际的证书内容,wCertificateType 表示签名证书类型,根据这个字段可知支持三种证书类型:PKCS #1、PKCS #7、X509,我看到过的文件都是使用 PKCS #7 签名。

找到 Security Directory 偏移之后,跳过前面的 8 字节就是实际的 PKCS #7 证书内容,DER 格式,代码示意:

使用项目中的 pe-sign 工具可以直接导出:

使用 --pem 参数可以将 DER 格式转换为 PEM 格式:

解析导出的证书,如果是 PEM 格式,-inform DER 改为 -inform PEM

这里有个小疑问,从属性里看 ProcessHacker.exe 文件有两个签名,一个是 sha1,另一个是 sha256:

openssl 打印的证书信息只有 sha1 证书的,使用 -print 参数打印 pkcs7 结构也可以看到是有 sha256 证书内容的但是没正确解析。

看了下微步沙箱也只解析到了 1 个签名:https://s.threatbook.com/report/file/bd2c2cf0631d881ed382817afcce2b093f4e412ffb170a719e2762f250abfea4

经过一番观察,发现 sha256 这个证书是在 sha1 证书属性里内嵌的,并不是平级:

然后就搜了一个这个属性名 1.3.6.1.4.1.311.2.4.1 有什么特殊的地方,从 MSDN 可知,这个值表示的是 szOID_NESTED_SIGNATURE 内容(实际就是一个 pkcs#7 格式证书),ChatGPT 是这么解释这个属性的:

szOID_NESTED_SIGNATURE 是一个表示嵌套签名的对象标识符(OID),其对应的 OID 是 1.3.6.1.4.1.311.2.4.1。在 PKCS7 或 CMS(Cryptographic Message Syntax)中,嵌套签名允许在签名数据中嵌套另一个签名数据块。这种机制用于实现多层次的签名或加密操作。

使用 openssl 的 asn1parse 命令可以找出嵌套签名的偏移位置:

SET 后面开始就是嵌入数据,7658 就是嵌套数据开始的文件偏移,hl 表示头大小,l 表示数据大小,所以总的嵌套数据大小为 4+7203=7207。使用 powershell 提取这个嵌套签名:

再次使用 openssl 就可以解析出这个嵌套签名证书:

代码解析的话,需要按 ASN.1 结构手动解析,因为这里找的内容算是个固定的,只需要定位 1.3.6.1.4.1.311.2.4.1 所在位置就可以。所以就需要研究一下 OID 在证书内是以怎么方式存储的,根据之前 openssl 的 asn1parse 命令的结果可以知道偏移位置 7642 + 2 处为 1.3.6.1.4.1.311.2.4.1,长度 10:

用下面的代码读取出来为 2b 06 01 04 01 82 37 02 04 01

可以发现有些数字是可以直接能和 1.3.6.1.4.1.311.2.4.1 对应上的:

不难看出,这里的 2b 就是表示的 1.382 37 表示的 311。但是 13 的十六进制表示为 D311 的十六进制表示为 137,所以这里并不是直接的10-16转换关系。查了一些 OID 的资料,在 这篇文章 中找到了一些关于 OID 编码方式的描述:

OID 的实质就是一串整数, 而且至少由两个整数组成。 第一个数必须是 0、1、2 三者之一, 如果是 0 或 1,则第二个数必须小于 40。 因此,前两个数 X 和 Y 可以直接用 40×X+Y 来表示,不会产生歧义。

以 2.999.3 的编码为例,首先要将前两个数合并成 1079(即 40×2+999),得到 1079.3。

完成合并后再用 Base 128 编码,左侧为高位字节。 也就是说,每个字节的最高位设为 1,但最后一个字节最高位设为 0,表示一个整数到此结束。各字节的其余七位从高到低依次相连表示数值。 例如数字 3 就用一个字节 0x03 表示, 而 129 则需要两个字节 0x81 0x01。 每个数字都如此转换成字节后,拼接在一起就形成了 OID 的编码。

无论是在 BER 还是 DER 中,OID 都必须用最短的方式编码。 所以其中每个数字编码时开头都不能出现 0x80 字节。

所以只有开头的 1.3 编码方式和后面不一样,后面都是 Base 128 编码。1.3 需要先按公式变成 40x1+3 = 43,再转换为十六进制就是 2b。反着推就是 2b 的十进制表示为 43,需要先确定第一位,因为只能是 0、1、2。

0 和 1 时第二个数不能超过 40,所以可以知道第一位:

所以 43 在 [40, 80) 之间,第一位应该是 1,第二位就是 43 - 40x1 = 3

后面每个数字都由 Base 128 编码方式存储,即数字在 128 (0x80) 以内(不包含 128)不需要转换直接存储,所以在上面能看到有些个位数的数字能直接对应上。128 之后就需要转成二进制从右向左每 7 位拆分一次,例如 311 的二进制表示为 100110111,每 7 位拆分 1 次变成:

前面补 0 变 8 位:

除最后 1 个字节(8 位)不需要动,前面每个字节最高位变成 1:

最后变成 十六进制看就是 82 37

现在对 2b 06 01 04 01 82 37 02 04 01 整体反向解析一下,开头两位前面说过了,2b 表示 1.3,后面的数字需要 1 个接 1 个字节换成二进制形式地看:

合起来最终得到 1.3.6.1.4.1.311.2.4.1

搞明白这个之后,可以直接通过 2b 06 01 04 01 82 37 02 04 01 定位到后 1 位再向后偏移 4 字节跳过 SET 块就是 SEQUENCE,此处便是内嵌证书的开头位置,一般直接读取到结尾就可以,严谨一点的话需要解析一下头部位置:

第 1 个字节是标签,30 表示 SEQUENCE 不用管,第二个字节最高位被设置为 1 的时候代表长编码,为 0 表示短编码,短编码时该字节就表示内容的长度,长编码时该字节表示存储长度的字节大小,0x82 最高位为 1,所以是长编码形式,去掉最高位的 1 就是 0x2,表示后面有 2 个字节用来表示 SEQUENCE 内容的长度,即 0x1c23,加上头的长度,这里是 4,内嵌证书长度就是 0x1c27

代码实现:

现在可以直接使用项目中的 pe-sign 工具的 --embed 参数直接导出:

也可以直接传递到 openssl 解析:

PKCS #7 证书的验证可以直接调用 PKCS7_verify,该函数原型:

根据参数可以知道验证证书需要准备的东西:

里面比较特殊的是 indata 参数,根据资料显示如果证书为 detached 证书,即签名独立证书,此时证书内不包含被签名的原始数据内容,需要调用 PKCS7_verify 时传入 indata 参数,否则可以为空。

这样的话,PE 中提取的证书内必然包含被签名的原始数据,所以看似不需要传入 indata,使用这个函数对应的 openssl 命令快速验证一下:

验证失败了,导致失败的报错信息是 digest failuresignature failure,看起来是签名和原始数据内容并不匹配。大概查了一下,PKCS #7 SignedData 结构用 ASN.1 描述为:

ContentInfo 中保存的原始数据,encryptedDigest 中是消息摘要,验签时需要使用签名者的 publickey 解开 encryptedDigest 得到一个 hash,然后如果存在 authenticatedAttributes,里面能再提取出一个消息摘要,这个消息摘要的 hash 如果和 encryptedDigest 中的一致说明可信,验证 authenticatedAttributes 可信后,从 authenticatedAttributes 中又可以得到一个 hash,这个 hash 是 ContentInfo 中原始内容的 hash,最终通过该 hash 验证原始数据内容是否可信。假如没有 authenticatedAttributesencryptedDigest 的消息摘要 hash 就是 ContentInfor 原始内容的 hash。

调用 PKCS7_verify 时,会自动进行上面的验证,但是当解析 ContentInfo->content 的时候,根据 ContentInfo->contentType 类型解析,只有类型为 dataASN1_OCTET_STRING 才能被正确解析到 content(参考源码位置 pk7_doit.c#L48)。

根据 Authenticode_PE.docx 中的描述,Authenticode 相当于 PE 文件的 hash,保存在 ContentInfo->content 中,ContentInfo->contentType 必须是 SPC_INDIRECT_DATA_OBJID (1.3.6.1.4.1.311.2.1.4),所以 PKCS7_verify 并不能解析出 content 内容,需要自行解析后通过 indata 参数传入。

以下是 SpcIndirectDataContent 的 ASN.1 定义:

对应的 asn1parse 解析结果:

下面是 pe-sign 工具中关于提取 indata 的代码:

由于 openssl 解析出的证书信息只是一些证书通用的信息,有些关键字段还需要单独解析一下:

签名时间大多数时候存储在副署签名里,少数直接在认证属性里就可以找到,在副署签名里的时候有两种情况:

第一种情况,当 unauth_attrs 直接存在副署(countersignature)属性时,该内容为 PKCS7_SIGNER_INFO 结构,表示副署签名者信息,该信息作为副署(countersignature)签名展示:

第二种情况,不存在副署(countersignature)属性,寻找 unauth_attrs 中的 1.3.6.1.4.1.311.3.3.1 属性作为副署签名,该内容为 Timestamping signature:

该属性内容被作为副署(countersignature)签名展示:

签名时间一般保存在副署签名中名为 signingTime 的 auth_attrs 里:

如果 signingTime 属性不存在(案例),签名时间保存在 contentInfo->content 中。

把案例文件的 1.3.6.1.4.1.311.3.3.1 属性内容导出:

从结果中可以看到,contentInfo->content 内容类型为 id-smime-ct-TSTInfo,里面也是一段 ASN.1 序列化数据:

从右侧可以看出,20240801004644.617Z 就是签名时间。程序中需要解析 TSTInfo 结构:

提取出 contentInfo->content,并通过 openssl 解析 asn1 结构:

没有找到能快速解析 TSTInfo 结构的方法,所以代码里直接通过搜索第一个 GENERALIZEDTIME 作为签名时间。在 ASN.1 序列化数据中 0x18 表示 GENERALIZEDTIME,后跟一个字节表示长度,因为 GENERALIZEDTIME 时间格式大多数时候为 YYYYMMDDHHMMSSZYYYYMMDDHHMMSS.sssZ,其他情况遇到再改代码吧,s 可以减少不一定是 3 个,所以长度在 15 - 19 这个范围,找 18 [15, 19] 序列即可。

Authenticode 信息在 indata 里,需要根据 SpcIndirectDataContent 结构解析:

SpcIndirectDataContent->messageDigest->digest 就是 authenticode,indata 数据开头的 sequence 表示的是 SpcIndirectDataContent->data,跳过这个 sequence 就是 messageDigest

提取代码:

通过 pe-sign 工具验证证书并打印证书信息:

Authenticode_PE.docx 中有详细的 authenticode 计算步骤:

可以通过 pe-sign 工具计算 authenticode,支持 sha1、sha256、md5 三种算法:

使用 pe-sign 工具验证文件签名时,status 如果是 InvalidSignature 表示证书中的 authenticode 与实际不符,文件被篡改:

大多数工具只提供了公钥验签,不提供公钥解密功能。可以使用类似 https://www.lddgo.net/en/encrypt/rsa 的在线解密工具,对签名数据解密。

打开 cerlm.msc 证书管理窗口,导航到“受信任的根证书颁发机构->证书”,全选后导出为 p7b。

然后通过 openssl 可以转换 p7b 证书为 pem:

不过这种方式,不知道什么原因导出的证书有时候并不全,可能有缺失。

所以改用 python 的 wincertstore 库枚举系统根证书然后导出为 PEM:

typedef struct _WIN_CERTIFICATE {
  DWORD dwLength;
  WORD  wRevision;
  WORD  wCertificateType;
  BYTE  bCertificate[ANYSIZE_ARRAY];
} WIN_CERTIFICATE, *LPWIN_CERTIFICATE;
typedef struct _WIN_CERTIFICATE {
  DWORD dwLength;
  WORD  wRevision;
  WORD  wCertificateType;
  BYTE  bCertificate[ANYSIZE_ARRAY];
} WIN_CERTIFICATE, *LPWIN_CERTIFICATE;
fn extract_pkcs7_from_pe(file: &PathBuf) -> Result<Vec<u8>, Box<dyn Error>> {
    // ...
    let image = VecPE::from_disk_file(file.to_str().unwrap())?;
    let security_directory =
        image.get_data_directory(exe::ImageDirectoryEntry::Security)?;
    let signature_data =
        exe::Buffer::offset_to_ptr(&image, security_directory.virtual_address.into())?; // security_data_directory rva is equivalent to file offset
 
    Ok(unsafe {
        let vec = std::slice::from_raw_parts(signature_data, security_directory.size as usize).to_vec();    // cloned
        vec.into_iter().skip(8).collect()   // _WIN_CERTIFICATE->bCertificate
    })
}
fn extract_pkcs7_from_pe(file: &PathBuf) -> Result<Vec<u8>, Box<dyn Error>> {
    // ...
    let image = VecPE::from_disk_file(file.to_str().unwrap())?;
    let security_directory =
        image.get_data_directory(exe::ImageDirectoryEntry::Security)?;
    let signature_data =
        exe::Buffer::offset_to_ptr(&image, security_directory.virtual_address.into())?; // security_data_directory rva is equivalent to file offset
 
    Ok(unsafe {
        let vec = std::slice::from_raw_parts(signature_data, security_directory.size as usize).to_vec();    // cloned
        vec.into_iter().skip(8).collect()   // _WIN_CERTIFICATE->bCertificate
    })
}
pe-sign extract <input_file> > pkcs7.cer
pe-sign extract <input_file> > pkcs7.cer
pe-sign extract <input_file> --pem > pkcs7.pem
pe-sign extract <input_file> --pem > pkcs7.pem
openssl pkcs7 -inform DER -in .\pkcs7.cer -print_certs -text -noout
openssl pkcs7 -inform DER -in .\pkcs7.cer -print_certs -text -noout
PS C:\dev\windows_pe_signature_research> openssl asn1parse -i -inform DER -in \pkcs7.cer | Select-String -Context 1,3 1.3.6.1.4.1.311.2.4.1
 
   7638:d=6  hl=4 l=7223 cons:       SEQUENCE
>  7642:d=7  hl=2 l=  10 prim:        OBJECT            :1.3.6.1.4.1.311.2.4.1
   7654:d=7  hl=4 l=7207 cons:        SET
   7658:d=8  hl=4 l=7203 cons:         SEQUENCE
   7662:d=9  hl=2 l=   9 prim:          OBJECT            :pkcs7-signedData
PS C:\dev\windows_pe_signature_research> openssl asn1parse -i -inform DER -in \pkcs7.cer | Select-String -Context 1,3 1.3.6.1.4.1.311.2.4.1
 
   7638:d=6  hl=4 l=7223 cons:       SEQUENCE
>  7642:d=7  hl=2 l=  10 prim:        OBJECT            :1.3.6.1.4.1.311.2.4.1
   7654:d=7  hl=4 l=7207 cons:        SET
   7658:d=8  hl=4 l=7203 cons:         SEQUENCE
   7662:d=9  hl=2 l=   9 prim:          OBJECT            :pkcs7-signedData
$offset = 7658
$size = 7207
$fileStream = [System.IO.File]::OpenRead(".\pkcs7.cer")
$buffer = New-Object byte[] $size
$fileStream.Seek($offset, [System.IO.SeekOrigin]::Begin)
$fileStream.Read($buffer, 0, $size)
$fileStream.Close()
[System.IO.File]::WriteAllBytes(".\pkcs7_embed.cer", $buffer)
$offset = 7658
$size = 7207
$fileStream = [System.IO.File]::OpenRead(".\pkcs7.cer")
$buffer = New-Object byte[] $size
$fileStream.Seek($offset, [System.IO.SeekOrigin]::Begin)
$fileStream.Read($buffer, 0, $size)
$fileStream.Close()
[System.IO.File]::WriteAllBytes(".\pkcs7_embed.cer", $buffer)
PS C:\dev\windows_pe_signature_research> openssl pkcs7 -inform der -in .\pkcs7_embed.cer -print_certs -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            04:0c:b4:1e:4f:b3:70:c4:5c:43:44:76:51:62:58:2f
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert SHA2 High Assurance Code Signing CA
        Validity
            Not Before: Oct 30 00:00:00 2013 GMT
            Not After : Jan  4 12:00:00 2017 GMT
        Subject: C=AU, ST=New South Wales, L=Sydney, O=Wen Jia Liu, CN=Wen Jia Liu
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:97:a8:e8:af:59:2a:05:f3:d5:0e:36:66:eb:89:
                    95:52:1a:3b:dd:41:12:63:b2:81:b9:f4:d0:cb:3d:
                    df:7d:f5:9b:f1:55:35:c0:9b:0a:ae:39:f6:ed:d8:
                    da:58:dd:ab:0e:ca:ce:b2:de:de:f0:fd:9d:6d:77:
                    1e:9d:05:ae:51:e6:02:27:8d:a4:c2:43:2f:2b:07:
                    cf:04:0b:00:a0:46:5d:61:13:f6:a3:b6:ab:bd:04:
                    b3:e4:b6:a2:9e:bd:94:d6:95:cf:28:bb:d9:5f:dc:
                    fb:06:2c:52:00:3d:63:6c:64:f8:68:ca:02:5a:1f:
                    25:b8:1c:d5:af:6e:bb:11:61:c0:f5:72:97:32:c1:
                    66:af:41:b8:7b:59:b0:da:e5:5b:9b:25:db:56:b4:
                    44:fc:52:5f:44:40:3b:5f:b0:02:37:53:d1:9f:96:
                    a5:a0:a5:47:87:19:c8:3d:a6:5b:91:05:01:b1:d4:
                    00:96:14:31:80:04:8a:e0:a6:a3:a5:32:31:92:37:
                    1a:93:85:da:b1:e9:79:ec:1a:bb:a6:1a:34:c7:70:
                    80:2d:8a:d6:89:38:d3:8c:54:ae:6e:86:3d:3a:c5:
                    49:d6:72:7b:b7:94:b6:6b:ee:f0:d0:70:11:c2:f0:
                    a2:5d:d8:87:5c:47:a4:7e:8e:36:29:d5:64:cf:49:
                    79:85
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Authority Key Identifier:
                67:9D:0F:20:09:0C:CC:8A:3A:E5:82:46:72:62:FC:F1:CC:90:E5:40
            X509v3 Subject Key Identifier:
                13:86:9A:3B:EF:68:31:53:BC:6B:18:9B:34:C6:FF:0A:8B:4D:68:28
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage:
                Code Signing
            X509v3 CRL Distribution Points:
                Full Name:
                  URI:http://crl3.digicert.com/sha2-ha-cs-g1.crl
                Full Name:
                  URI:http://crl4.digicert.com/sha2-ha-cs-g1.crl
            X509v3 Certificate Policies:
                Policy: 2.16.840.1.114412.3.1
                  CPS: https://www.digicert.com/CPS
                Policy: 2.23.140.1.4.1
            Authority Information Access:
                OCSP - URI:http://ocsp.digicert.com
                CA Issuers - URI:http://cacerts.digicert.com/DigiCertSHA2HighAssuranceCodeSigningCA.crt
            X509v3 Basic Constraints: critical
                CA:FALSE
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        91:87:ac:23:c2:84:07:cb:c7:6a:c1:f8:1a:6c:78:3b:21:9f:
        c2:48:1b:08:e8:f5:e3:41:f7:eb:e2:d9:41:b1:48:e6:1b:ff:
        55:ab:79:c1:a2:d8:16:7a:2d:d2:94:f5:32:c8:00:5a:5f:dd:
        f2:f8:b2:19:86:47:fb:e7:aa:a7:16:e6:ff:0a:c3:37:f9:64:
        c0:5b:51:64:ef:8a:23:c4:7a:d0:8f:d7:37:b8:70:dd:35:6f:
        19:06:4e:a5:cd:ea:0a:ef:a4:f2:2a:1c:b3:49:f8:a6:89:ac:
        a5:67:f3:8b:b3:de:01:23:20:4f:9f:f5:56:0c:59:ec:e4:01:
        32:3f:2c:e5:84:be:e0:ea:5b:b7:39:31:26:ff:32:7f:eb:15:
        cc:82:d0:b0:16:f8:fc:6f:1d:c8:b2:1b:9c:85:68:27:7d:45:
        b0:e0:7a:7c:dd:26:f4:9a:d4:7d:0f:a6:ac:04:c1:48:65:1c:
        ef:49:33:0b:d2:c7:28:95:a7:26:51:09:cf:1a:f0:d2:ca:74:
        93:92:8c:e3:44:6e:24:5b:57:9f:b2:cc:df:01:e0:3d:b4:7f:
        41:cc:97:d6:ea:3d:1f:42:3d:fd:2b:75:82:0c:43:50:e9:d8:
        ac:d1:d9:e6:e4:08:97:05:75:29:55:be:2d:89:7d:ab:16:5e:
        be:32:e0:b5
 
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            0b:7e:10:90:3c:38:49:0f:fa:2f:67:9a:87:a1:a7:b9
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
        Validity
            Not Before: Oct 22 12:00:00 2013 GMT
            Not After : Oct 22 12:00:00 2028 GMT
        Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert SHA2 High Assurance Code Signing CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:b4:4a:5e:7d:07:0f:41:de:c4:f5:76:16:36:bd:
                    71:ff:cf:3f:4f:73:4b:9c:d1:0d:fe:4a:cb:57:58:
                    5e:85:16:dd:02:15:54:99:f0:8f:3c:2f:4d:02:78:
                    10:68:c8:d8:35:4b:3f:c1:f7:67:ce:98:1c:ae:33:
                    b9:2d:1d:a4:0a:54:93:c4:85:a2:df:35:b1:f5:f1:
                    3c:a7:b3:34:fb:5d:48:c9:46:c9:62:44:bc:48:99:
                    eb:28:49:53:c3:3d:8f:c0:0e:de:35:98:e9:62:51:
                    df:3d:6b:40:61:ee:04:41:da:cf:a7:5c:56:96:d1:
                    f9:4c:b7:44:84:87:98:69:e5:82:b9:13:e6:55:bf:
                    c8:92:70:92:0a:31:6f:7f:8b:32:ab:cf:6b:5a:9f:
                    62:c4:3e:ee:be:ed:59:a4:53:7f:0b:f1:52:88:8a:
                    7b:0a:67:24:cb:90:cd:ec:d2:4d:34:4c:b0:e1:b5:
                    9f:9c:c6:f6:6f:2c:cd:e6:ca:53:74:01:9f:67:35:
                    de:38:49:2d:ce:ed:39:44:82:19:79:4e:1a:b2:b5:
                    fb:bb:78:f0:49:66:a7:cf:fa:5c:96:75:92:8b:1a:
                    72:d9:ff:50:92:53:cc:3e:c2:43:32:09:1a:86:13:
                    69:3c:fb:81:32:33:32:64:75:73:28:26:1d:08:30:
                    3b:07
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:TRUE, pathlen:0
            X509v3 Key Usage: critical
                Digital Signature, Certificate Sign, CRL Sign
            X509v3 Extended Key Usage:
                Code Signing
            Authority Information Access:
                OCSP - URI:http://ocsp.digicert.com
                CA Issuers - URI:http://cacerts.digicert.com/DigiCertHighAssuranceEVRootCA.crt
            X509v3 CRL Distribution Points:
                Full Name:
                  URI:http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl
                Full Name:
                  URI:http://crl3.digicert.com/DigiCertHighAssuranceEVRootCA.crl
            X509v3 Certificate Policies:
                Policy: 2.16.840.1.114412.0.2.4
                  CPS: https://www.digicert.com/CPS
                Policy: 2.16.840.1.114412.3
            X509v3 Subject Key Identifier:
                67:9D:0F:20:09:0C:CC:8A:3A:E5:82:46:72:62:FC:F1:CC:90:E5:40
            X509v3 Authority Key Identifier:
                B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        6a:0e:ff:7e:13:7c:06:a5:4b:c0:2e:8c:f9:53:64:09:e2:ba:
        58:91:30:50:ec:cc:9f:e1:d3:a8:2f:48:46:36:18:29:d0:78:
        28:5f:98:56:40:0f:1e:ba:bd:b1:3b:87:5c:dc:5b:d8:20:0d:
        ed:1a:16:4d:d5:11:24:21:4b:f1:27:69:90:13:eb:11:a1:01:
        da:fd:b5:4e:79:59:75:bd:38:2a:6a:c3:f6:8e:41:2b:8a:a2:
        8b:d7:2c:51:51:d9:9c:a0:c8:e3:4e:ba:6c:a8:47:d2:4e:d1:
        68:1f:8c:02:57:3b:b3:29:6a:8e:6a:20:2a:b9:f2:00:62:64:
        ba:c8:e9:00:f9:cc:a4:d4:ba:9a:35:d8:af:2c:65:6c:16:7c:
        58:21:de:4a:30:d0:fa:eb:24:5d:06:c9:9d:16:b7:ad:4a:45:
        d3:25:e2:0c:f0:40:aa:5c:4d:ac:7e:cd:06:82:b9:76:46:69:
        08:d8:32:b6:82:fe:e3:a9:58:34:43:1b:8e:67:67:97:3f:68:
        31:16:36:38:95:3e:87:f7:c7:c3:af:9d:7a:77:19:d9:de:93:
        b5:fd:6e:2b:fc:94:f9:3d:b7:4c:12:35:2c:30:be:e8:8d:9e:
        05:70:9a:48:13:f4:8c:d6:e7:1e:ac:38:e7:a8:f3:ad:0c:b7:
        7a:ec:67:ed
PS C:\dev\windows_pe_signature_research> openssl pkcs7 -inform der -in .\pkcs7_embed.cer -print_certs -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            04:0c:b4:1e:4f:b3:70:c4:5c:43:44:76:51:62:58:2f
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert SHA2 High Assurance Code Signing CA
        Validity
            Not Before: Oct 30 00:00:00 2013 GMT
            Not After : Jan  4 12:00:00 2017 GMT
        Subject: C=AU, ST=New South Wales, L=Sydney, O=Wen Jia Liu, CN=Wen Jia Liu
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:97:a8:e8:af:59:2a:05:f3:d5:0e:36:66:eb:89:
                    95:52:1a:3b:dd:41:12:63:b2:81:b9:f4:d0:cb:3d:
                    df:7d:f5:9b:f1:55:35:c0:9b:0a:ae:39:f6:ed:d8:
                    da:58:dd:ab:0e:ca:ce:b2:de:de:f0:fd:9d:6d:77:
                    1e:9d:05:ae:51:e6:02:27:8d:a4:c2:43:2f:2b:07:
                    cf:04:0b:00:a0:46:5d:61:13:f6:a3:b6:ab:bd:04:
                    b3:e4:b6:a2:9e:bd:94:d6:95:cf:28:bb:d9:5f:dc:
                    fb:06:2c:52:00:3d:63:6c:64:f8:68:ca:02:5a:1f:
                    25:b8:1c:d5:af:6e:bb:11:61:c0:f5:72:97:32:c1:
                    66:af:41:b8:7b:59:b0:da:e5:5b:9b:25:db:56:b4:
                    44:fc:52:5f:44:40:3b:5f:b0:02:37:53:d1:9f:96:
                    a5:a0:a5:47:87:19:c8:3d:a6:5b:91:05:01:b1:d4:
                    00:96:14:31:80:04:8a:e0:a6:a3:a5:32:31:92:37:
                    1a:93:85:da:b1:e9:79:ec:1a:bb:a6:1a:34:c7:70:
                    80:2d:8a:d6:89:38:d3:8c:54:ae:6e:86:3d:3a:c5:
                    49:d6:72:7b:b7:94:b6:6b:ee:f0:d0:70:11:c2:f0:
                    a2:5d:d8:87:5c:47:a4:7e:8e:36:29:d5:64:cf:49:
                    79:85
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Authority Key Identifier:
                67:9D:0F:20:09:0C:CC:8A:3A:E5:82:46:72:62:FC:F1:CC:90:E5:40
            X509v3 Subject Key Identifier:
                13:86:9A:3B:EF:68:31:53:BC:6B:18:9B:34:C6:FF:0A:8B:4D:68:28
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage:
                Code Signing
            X509v3 CRL Distribution Points:
                Full Name:
                  URI:http://crl3.digicert.com/sha2-ha-cs-g1.crl
                Full Name:
                  URI:http://crl4.digicert.com/sha2-ha-cs-g1.crl
            X509v3 Certificate Policies:
                Policy: 2.16.840.1.114412.3.1
                  CPS: https://www.digicert.com/CPS
                Policy: 2.23.140.1.4.1
            Authority Information Access:
                OCSP - URI:http://ocsp.digicert.com
                CA Issuers - URI:http://cacerts.digicert.com/DigiCertSHA2HighAssuranceCodeSigningCA.crt
            X509v3 Basic Constraints: critical
                CA:FALSE
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        91:87:ac:23:c2:84:07:cb:c7:6a:c1:f8:1a:6c:78:3b:21:9f:
        c2:48:1b:08:e8:f5:e3:41:f7:eb:e2:d9:41:b1:48:e6:1b:ff:
        55:ab:79:c1:a2:d8:16:7a:2d:d2:94:f5:32:c8:00:5a:5f:dd:
        f2:f8:b2:19:86:47:fb:e7:aa:a7:16:e6:ff:0a:c3:37:f9:64:
        c0:5b:51:64:ef:8a:23:c4:7a:d0:8f:d7:37:b8:70:dd:35:6f:
        19:06:4e:a5:cd:ea:0a:ef:a4:f2:2a:1c:b3:49:f8:a6:89:ac:
        a5:67:f3:8b:b3:de:01:23:20:4f:9f:f5:56:0c:59:ec:e4:01:
        32:3f:2c:e5:84:be:e0:ea:5b:b7:39:31:26:ff:32:7f:eb:15:
        cc:82:d0:b0:16:f8:fc:6f:1d:c8:b2:1b:9c:85:68:27:7d:45:
        b0:e0:7a:7c:dd:26:f4:9a:d4:7d:0f:a6:ac:04:c1:48:65:1c:
        ef:49:33:0b:d2:c7:28:95:a7:26:51:09:cf:1a:f0:d2:ca:74:
        93:92:8c:e3:44:6e:24:5b:57:9f:b2:cc:df:01:e0:3d:b4:7f:
        41:cc:97:d6:ea:3d:1f:42:3d:fd:2b:75:82:0c:43:50:e9:d8:
        ac:d1:d9:e6:e4:08:97:05:75:29:55:be:2d:89:7d:ab:16:5e:
        be:32:e0:b5
 
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            0b:7e:10:90:3c:38:49:0f:fa:2f:67:9a:87:a1:a7:b9
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA
        Validity
            Not Before: Oct 22 12:00:00 2013 GMT
            Not After : Oct 22 12:00:00 2028 GMT
        Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert SHA2 High Assurance Code Signing CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:b4:4a:5e:7d:07:0f:41:de:c4:f5:76:16:36:bd:
                    71:ff:cf:3f:4f:73:4b:9c:d1:0d:fe:4a:cb:57:58:
                    5e:85:16:dd:02:15:54:99:f0:8f:3c:2f:4d:02:78:
                    10:68:c8:d8:35:4b:3f:c1:f7:67:ce:98:1c:ae:33:
                    b9:2d:1d:a4:0a:54:93:c4:85:a2:df:35:b1:f5:f1:
                    3c:a7:b3:34:fb:5d:48:c9:46:c9:62:44:bc:48:99:
                    eb:28:49:53:c3:3d:8f:c0:0e:de:35:98:e9:62:51:
                    df:3d:6b:40:61:ee:04:41:da:cf:a7:5c:56:96:d1:
                    f9:4c:b7:44:84:87:98:69:e5:82:b9:13:e6:55:bf:
                    c8:92:70:92:0a:31:6f:7f:8b:32:ab:cf:6b:5a:9f:
                    62:c4:3e:ee:be:ed:59:a4:53:7f:0b:f1:52:88:8a:
                    7b:0a:67:24:cb:90:cd:ec:d2:4d:34:4c:b0:e1:b5:
                    9f:9c:c6:f6:6f:2c:cd:e6:ca:53:74:01:9f:67:35:
                    de:38:49:2d:ce:ed:39:44:82:19:79:4e:1a:b2:b5:
                    fb:bb:78:f0:49:66:a7:cf:fa:5c:96:75:92:8b:1a:
                    72:d9:ff:50:92:53:cc:3e:c2:43:32:09:1a:86:13:
                    69:3c:fb:81:32:33:32:64:75:73:28:26:1d:08:30:
                    3b:07
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:TRUE, pathlen:0
            X509v3 Key Usage: critical
                Digital Signature, Certificate Sign, CRL Sign
            X509v3 Extended Key Usage:
                Code Signing
            Authority Information Access:
                OCSP - URI:http://ocsp.digicert.com
                CA Issuers - URI:http://cacerts.digicert.com/DigiCertHighAssuranceEVRootCA.crt
            X509v3 CRL Distribution Points:
                Full Name:
                  URI:http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl
                Full Name:
                  URI:http://crl3.digicert.com/DigiCertHighAssuranceEVRootCA.crl
            X509v3 Certificate Policies:
                Policy: 2.16.840.1.114412.0.2.4
                  CPS: https://www.digicert.com/CPS
                Policy: 2.16.840.1.114412.3
            X509v3 Subject Key Identifier:
                67:9D:0F:20:09:0C:CC:8A:3A:E5:82:46:72:62:FC:F1:CC:90:E5:40
            X509v3 Authority Key Identifier:
                B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        6a:0e:ff:7e:13:7c:06:a5:4b:c0:2e:8c:f9:53:64:09:e2:ba:
        58:91:30:50:ec:cc:9f:e1:d3:a8:2f:48:46:36:18:29:d0:78:
        28:5f:98:56:40:0f:1e:ba:bd:b1:3b:87:5c:dc:5b:d8:20:0d:
        ed:1a:16:4d:d5:11:24:21:4b:f1:27:69:90:13:eb:11:a1:01:
        da:fd:b5:4e:79:59:75:bd:38:2a:6a:c3:f6:8e:41:2b:8a:a2:
        8b:d7:2c:51:51:d9:9c:a0:c8:e3:4e:ba:6c:a8:47:d2:4e:d1:
        68:1f:8c:02:57:3b:b3:29:6a:8e:6a:20:2a:b9:f2:00:62:64:
        ba:c8:e9:00:f9:cc:a4:d4:ba:9a:35:d8:af:2c:65:6c:16:7c:
        58:21:de:4a:30:d0:fa:eb:24:5d:06:c9:9d:16:b7:ad:4a:45:
        d3:25:e2:0c:f0:40:aa:5c:4d:ac:7e:cd:06:82:b9:76:46:69:
        08:d8:32:b6:82:fe:e3:a9:58:34:43:1b:8e:67:67:97:3f:68:
        31:16:36:38:95:3e:87:f7:c7:c3:af:9d:7a:77:19:d9:de:93:
        b5:fd:6e:2b:fc:94:f9:3d:b7:4c:12:35:2c:30:be:e8:8d:9e:
        05:70:9a:48:13:f4:8c:d6:e7:1e:ac:38:e7:a8:f3:ad:0c:b7:
        7a:ec:67:ed
>  7642:d=7  hl=2 l=  10 prim:        OBJECT            :1.3.6.1.4.1.311.2.4.1
>  7642:d=7  hl=2 l=  10 prim:        OBJECT            :1.3.6.1.4.1.311.2.4.1
$offset = 7644
$size = 10
$fileStream = [System.IO.File]::OpenRead(".\pkcs7.cer")
$buffer = New-Object byte[] $size
$fileStream.Seek($offset, [System.IO.SeekOrigin]::Begin)
$fileStream.Read($buffer, 0, $size)
$fileStream.Close()
Write-Host $(($buffer | ForEach-Object { "{0:x2}" -f $_ }) -join " ")
$offset = 7644
$size = 10
$fileStream = [System.IO.File]::OpenRead(".\pkcs7.cer")
$buffer = New-Object byte[] $size
$fileStream.Seek($offset, [System.IO.SeekOrigin]::Begin)
$fileStream.Read($buffer, 0, $size)
$fileStream.Close()
Write-Host $(($buffer | ForEach-Object { "{0:x2}" -f $_ }) -join " ")
2b . 06 . 01 . 04 . 01 . 82 37 . 02 . 04 01
2b . 06 . 01 . 04 . 01 . 82 37 . 02 . 04 01
10  0110111
10  0110111
00000010  00110111
00000010  00110111
10000010  00110111
10000010  00110111
30 82 1C 23
30 82 1C 23
fn extract_pkcs7_embedded<'a>(cert_bin: &'a [u8]) -> Option<&'a [u8]> {
    match cert_bin.windows(EMBEDDED_SIGNATURE_OID.len()).position(|w| w == EMBEDDED_SIGNATURE_OID) {
        Some(pos) => {
            let sequence_pos = pos + EMBEDDED_SIGNATURE_OID.len() + 4;
            let mut header_len = 1;
 
            let size = if cert_bin[sequence_pos + 1] >= 0b10000000 {
                // 长编码
                let len = (cert_bin[sequence_pos + 1] & 0b01111111) as usize;
                header_len += 1 + len;
                let size_bin = &mut cert_bin[sequence_pos + 1 + 1 .. sequence_pos + 1 + 1 + len].to_vec();
                size_bin.reverse();     // big endian to little endian
                size_bin.resize(8, 0x0);    // align to usize
                usize::from_le_bytes(unsafe { *(size_bin.as_ptr() as *const [u8; 8]) })
            } else {
                // 短编码
                header_len += 1;
                cert_bin[sequence_pos + 1] as usize
            };
 
            Some(&cert_bin[sequence_pos.. sequence_pos + header_len + size])
        },
        None => None
    }
}
fn extract_pkcs7_embedded<'a>(cert_bin: &'a [u8]) -> Option<&'a [u8]> {
    match cert_bin.windows(EMBEDDED_SIGNATURE_OID.len()).position(|w| w == EMBEDDED_SIGNATURE_OID) {
        Some(pos) => {
            let sequence_pos = pos + EMBEDDED_SIGNATURE_OID.len() + 4;
            let mut header_len = 1;
 
            let size = if cert_bin[sequence_pos + 1] >= 0b10000000 {
                // 长编码
                let len = (cert_bin[sequence_pos + 1] & 0b01111111) as usize;
                header_len += 1 + len;
                let size_bin = &mut cert_bin[sequence_pos + 1 + 1 .. sequence_pos + 1 + 1 + len].to_vec();
                size_bin.reverse();     // big endian to little endian
                size_bin.resize(8, 0x0);    // align to usize
                usize::from_le_bytes(unsafe { *(size_bin.as_ptr() as *const [u8; 8]) })
            } else {
                // 短编码
                header_len += 1;
最后于 2024-9-23 17:24 被techliu编辑 ,原因:
收藏
免费 3
支持
分享
最新回复 (5)
雪    币: 335
活跃值: (2568)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
great job
2024-9-23 17:36
1
雪    币: 1134
活跃值: (2601)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2024-9-24 22:00
1
雪    币: 7786
活跃值: (4474)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
太精彩了 整篇连贯 太干了 !!感谢 , 辛苦码了这么多 
2024-9-24 23:52
1
雪    币: 917
活跃值: (1855)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
现在这么卷了吗?全用rust,大佬有c系列的工程吗
2024-9-25 10:54
0
雪    币: 5889
活跃值: (1402)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
6
wuxiwudi 现在这么卷了吗?全用rust,大佬有c系列的工程吗
哈哈,这篇主要写的是思路,用什么写其次,用c做这个事情也行的,不过如果不想依赖openssl,比较难找到一个合适的解析asn1结构的库,本来也是想尽快实现,还有想只写一套代码跨平台的话c差点意思有时候调底层API需要自己适配一下,我不太想在这上面耗费太多不必要的工夫。我不太清楚你找c项目做什么,如果只是学习c语言的话,可以找些别人写的不错的项目用c重构一下也能学到很多
2024-9-26 10:14
0
游客
登录 | 注册 方可回帖
返回
//