文章目录
- vs2019 - signtool签名和验签的手工操作
 - 概述
 - 笔记
 - 导入根证书
 - 时间戳服务器的选择
 - code sign - 签名
 - 文件在代码签名(code sign)前后的区别
 - 签名后, 查看属性, 是正常的.
 - 用signtool命令行进行验签
 - 移除签名
 - END
 
vs2019 - signtool签名和验签的手工操作
概述
signtool是进行code sign用的工具. 装了vs2019后自带(SDK中的工具).
 code sign 是代码签名, 是用证书对PE文件进行签名.
 前面实验用openssl已经生成了自签名的证书, 现在用vs2019自带的signtool试试code sign的签名和验签.
 对PE文件进行了代码签名后, 在程序中的逻辑, 就可以判断自己程序的PE有没有被第三方改过.
笔记
打开vs2019本地x64命令行, 可以直接运行signtool.
D:\my_dev\my_local_git_prj\study\openSSL\exp\signtool_case>signtool /?
Usage: signtool <command> [options]
  Valid commands:
    sign       --  Sign files using an embedded signature.
    timestamp  --  Timestamp previously-signed files.
    verify     --  Verify embedded or catalog signatures.
    catdb      --  Modify a catalog database.
    remove     --  Remove embedded signature(s) or reduce the size of an
                   embedded signed file.
For help on a specific command, enter "signtool <command> /?"
 
但是signtool没有看版本的命令行参数, 也不知道运行的是哪个版本的signtool, 只能从环境变量的包含路径去猜测.
 在vs2019x64本地命令行中查看PATH变量的值.
set path
 
整理PATH的值, 看看路径集合
Path=
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\\Extensions\Microsoft\IntelliCode\CLI;
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133\bin\HostX64\x64;
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\VC\VCPackages;
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow;
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\bin\Roslyn;
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Team Tools\Performance Tools\x64;
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Team Tools\Performance Tools;
C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\\x64;
C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\;
C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x64\;
C:\Program Files (x86)\HTML Help Workshop;
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools;
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\devinit;
C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64;
C:\Program Files (x86)\Windows Kits\10\bin\x64;
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\\MSBuild\Current\Bin;
C:\Windows\Microsoft.NET\Framework64\v4.0.30319;
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\;
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\;
C:\Program Files\Eclipse Foundation\jdk-8.0.302.8-hotspot\bin;
C:\Python311\Scripts\;C:\Python311\;
# ...
 
将everything找到的signtool.exe的列表导出为日志.
C:\Program Files (x86)\Microsoft SDKs\ClickOnce\SignTool\signtool.exe
C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\microsoft.windows.sdk.buildtools\10.0.19041.8\bin\10.0.19041.0\x64\signtool.exe
C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\microsoft.windows.sdk.buildtools\10.0.19041.8\bin\10.0.19041.0\x86\signtool.exe
C:\Program Files (x86)\Windows Kits\10\App Certification Kit\signtool.exe
C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\arm\signtool.exe
C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\arm64\signtool.exe
C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64\signtool.exe
C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86\signtool.exe
C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\arm\signtool.exe
C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\arm64\signtool.exe
C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\signtool.exe
C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86\signtool.exe
C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\arm\signtool.exe
C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\arm64\signtool.exe
C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\signtool.exe
C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x86\signtool.exe
C:\Windows\Prefetch\SIGNTOOL.EXE-229E1730.pf
C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\microsoft.windows.sdk.buildtools\10.0.19041.8\bin\10.0.19041.0\x64\signtool.exe.manifest
C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\microsoft.windows.sdk.buildtools\10.0.19041.8\bin\10.0.19041.0\x86\signtool.exe.manifest
C:\Program Files (x86)\Windows Kits\10\App Certification Kit\signtool.exe.manifest
C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\arm\signtool.exe.manifest
C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\arm64\signtool.exe.manifest
C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64\signtool.exe.manifest
C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86\signtool.exe.manifest
C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\arm\signtool.exe.manifest
C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\arm64\signtool.exe.manifest
C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\signtool.exe.manifest
C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86\signtool.exe.manifest
C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\arm\signtool.exe.manifest
C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\arm64\signtool.exe.manifest
C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\signtool.exe.manifest
C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x86\signtool.exe.manifest
 
结合这2个日志, 看看运行的是哪个路径中的signtool.exe
 看起来好像是 C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\signtool.exe
 自己写个exe, 换掉 C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\signtool.exe, 再运行signtool, 看看是不是这个exe.
// exe_show_path.cpp
#include <iostream>
int main(int argc, char** argv)
{
    int i = 0;
    printf("fake exe for test\n");
    for (i = 0; i < argc; i++)
    {
        printf("param[%d] = [%s]\n", i, argv[i]);
    }
    return 0;
}
 
D:\my_dev\my_local_git_prj\study\openSSL\exp\signtool_case>signtool
fake exe for test
param[0] = [signtool]
 
这就验证了, 在vs2019x64本地命令行中运行的signtool.exe确实是 C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\signtool.exe
看一下signtool.exe的版本信息, 版本为10.0.22000.832
 
导入根证书
如果是买的证书, 就不用导入根证书, win10证书库中就有大CA的根证书.
 像自己做实验的自签名根证书, 就需要自己导入win10, 否则验签不过.
 在win10中导入证书时, 说是只支持6种, 其实也支持*.PEM
 
 
 将文件过滤器改为*.*, 然后导入自己的自签名根证书.
 
时间戳服务器的选择
code sign签名和验签时, 都需要时间戳服务器.
 选大厂的时间戳服务器即可(e.g. digicert的 http://timestamp.digicert.com)
code sign - 签名
signtool sign /v /f my_app_cert.p12 /p pwd_exp_333333 /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 case1.exe
 
D:\my_dev\my_local_git_prj\study\openSSL\exp\signtool_case>signtool sign /v /f my_app_cert.p12 /p pwd_exp_333333 /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 case1.exe
The following certificate was selected:
    Issued to: my_app
    Issued by: my_root_ca
    Expires:   Mon Feb 03 17:18:58 2025
    SHA1 hash: 83289266D9F2287F176A3D78FD292D9D36D297B9
Done Adding Additional Store
Successfully signed: case1.exe
Number of files successfully Signed: 1
Number of warnings: 0
Number of errors: 0
 
文件在代码签名(code sign)前后的区别
大概看, 就是签名数据在文件尾部附加的, 在PE文件头部好像改了一个签名数据的位置索引值.
 用BC4能大概看出来.
 
签名后, 查看属性, 是正常的.

用signtool命令行进行验签
必须要加/pa参数, 否则验签失败
signtool verify /all /debug /pa case1.exe
 
signtool verify /all /debug /pa case1.exe
Verifying: case1.exe
Signature Index: 0 (Primary Signature)
Hash of file (sha256): 4A247E0316FFE69969F1E764AF3B2C70913FC86F76B051A6F50F660BA5DA5EA3
Signing Certificate Chain:
    Issued to: my_root_ca
    Issued by: my_root_ca
    Expires:   Wed Feb 01 17:05:22 2034
    SHA1 hash: B9B9F8C9F2AD14D630244E672871B9BB6F9C40E0
        Issued to: my_app
        Issued by: my_root_ca
        Expires:   Mon Feb 03 17:18:58 2025
        SHA1 hash: 83289266D9F2287F176A3D78FD292D9D36D297B9
The signature is timestamped: Sun Feb 11 11:31:18 2024
Timestamp Verified by:
    Issued to: DigiCert Assured ID Root CA
    Issued by: DigiCert Assured ID Root CA
    Expires:   Mon Nov 10 08:00:00 2031
    SHA1 hash: 0563B8630D62D75ABBC8AB1E4BDFB5A899B24D43
        Issued to: DigiCert Trusted Root G4
        Issued by: DigiCert Assured ID Root CA
        Expires:   Mon Nov 10 07:59:59 2031
        SHA1 hash: A99D5B79E9F1CDA59CDAB6373169D5353F5874C6
            Issued to: DigiCert Trusted G4 RSA4096 SHA256 TimeStamping CA
            Issued by: DigiCert Trusted Root G4
            Expires:   Mon Mar 23 07:59:59 2037
            SHA1 hash: B6C8AF834D4E53B673C76872AA8C950C7C54DF5F
                Issued to: DigiCert Timestamp 2023
                Issued by: DigiCert Trusted G4 RSA4096 SHA256 TimeStamping CA
                Expires:   Sat Oct 14 07:59:59 2034
                SHA1 hash: 66F02B32C2C2C90F825DCEAA8AC9C64F199CCF40
Successfully verified: case1.exe
Number of signatures successfully Verified: 1
Number of warnings: 0
Number of errors: 0
 
可以看到, 用signtool验签也是成功的.
移除签名
对于已有签名的PE, 再进行签名, 在某些情况下可能有问题. 可以移除已有签名后, 再进行新的签名.
 移除签名再签名的场景(进行2进制patch后, 原始签名再验签是过不去的, 必须移除原始签名, 再重新签名才行)
signtool remove /v /s case1.exe
 
D:\my_dev\my_local_git_prj\study\openSSL\exp\signtool_case>signtool remove /v /s case1.exe
Removing signature on file: D:\my_dev\my_local_git_prj\study\openSSL\exp\signtool_case\case1.exe
Successfully committed changes to the file: D:\my_dev\my_local_git_prj\study\openSSL\exp\signtool_case\case1.exe
Number of files successfully processed: 1
Number of warnings: 0
Number of errors: 0
 

 移除签名后, 将cas1.exe和最开始的未签名的备份比较一下, 可以看到是相同的.
 
 用BC4比较, 可以看到还是有2进制区别, 不过那个不同的地方, 可能是签名数据位置偏移的残留.
 移除签名后, 应该和原始备份一样才对.
 重新做了一次实验, 将exe_for_sign_x64.exe.org的拷贝命名为case1.exe.
 对case1.exe进行code sign签名, 然后看看是否签名正常, 然后移除签名, 然后再2进制比较case1.exe和exe_for_sign_x64.exe.org.
 还是发现有2进制区别, 估计是signtool的bug.
 
 也不能算是signtool有bug, 假设有2进制区别的地方是签名数据的文件内部偏移. 签名移除后, 因为用不到签名数据了, 这个签名数据偏移位置写啥都行(反正都用不到了), signtool哪知道原始文件这个位置是什么值, 如果真的写成 0x 00 00 00, 也不见得就和原始文件相同.



















