文章目录
- 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, 也不见得就和原始文件相同.