找回密码
 注册
搜索
系统gho:最纯净好用系统下载站投放广告、加入VIP会员,请联系 微信:wuyouceo
查看: 565|回复: 9

[分享] PECMD 枚举 PE 文件中的证书名和 EFI 中的某些变量中的证书名

[复制链接]
发表于 5 天前 | 显示全部楼层 |阅读模式
本帖最后由 Bluebells 于 2026-7-18 17:52 编辑

枚举 PE 文件中的数字证书的颁发者名称
  1. ;此封装函数用于枚举目标 PE 文件中的数字证书的颁发者名称
  2. ;第一个参数为目标文件(此参数路径支持 Win32 文件命名空间), 第二个参数用于接收返回信息(证书颁发者名称列表)
  3. _SUB EnumPEFileCertIssuer
  4.     TEAM ENVI$ &NL=0d 0a| ENVI &PEFile=%~1| ENVI &CertIssuerList=
  5.     ENVI-ptr &phCertStore=0
  6.     CALL $--qd --bool --ret:&ret Crypt32.dll,CryptQueryObject,#1,$%&PEFile%,#0x400,#2,#0,#0,#0,#0,*&phCertStore,#0,#0
  7.     IFEX #%&ret%=0,!
  8.     {
  9.         ENVI?ptr &phCertStore=&hCertStore
  10.         IFEX #%&hCertStore%>0,
  11.         {
  12.             ENVI &CERT_CONTEXT=0
  13.             LOOP #1=1,
  14.             {
  15.                 CALL $--qd --ret:&CERT_CONTEXT Crypt32.dll,CertEnumCertificatesInStore,#%&hCertStore%,#%&CERT_CONTEXT%
  16.                 IFEX #%&CERT_CONTEXT%=0,EXIT LOOP!
  17.                 {
  18.                     ENVI$ &NameString=*208 0
  19.                     CALL $--qd --ret:&ret Crypt32.dll,CertGetNameStringW,#%&CERT_CONTEXT%,#4,#1,#0,*&NameString,#208
  20.                     IFEX #%&ret%>0,ENVI &CertIssuerList=%&CertIssuerList%%&NameString%%&NL%
  21.                 }
  22.             }
  23.         }
  24.         CALL $--qd --bool Crypt32.dll,CertCloseStore,#%&hCertStore%,#0
  25.     }
  26.     ENVI-ret %~2=%&CertIssuerList%
  27. _END

  28. ;示例
  29. EnumPEFileCertIssuer "\\?\HarddiskVolume1\EFI\Microsoft\Boot\bootmgfw.efi" &CertList
  30. MESS %&CertList%@Certificates Issuer#OK
复制代码
枚举 EFI 变量中的证书的使用者名称
  1. ;此封装函数用于枚举 EFI 固件中的 db, dbx, PK, KEK 变量中的证书的使用者名称
  2. ;第一个参数为 EFI 变量名(db, dbx, db, dbx, PK, KEK), 变量名是区分大小写的;
  3. ;第二个参数为 EFI 变量名对应的 GUID 字符串, GUID 字符串字符不区分大小写
  4. ;db & dbx => {d719b2cb-3d3a-4596-a3bc-dad00e67656f}; PK & KEK => {8be4df61-93ca-11d2-aa0d-00e098032b8c}
  5. ;第三个参数用于接收返回信息(证书使用者名称列表)
  6. _SUB EnumEFIVariableCertName
  7.     TEAM ENVI$ &NL=0d 0a| ENVI &VariableName=%~1| ENVI &GUID=%~2| ENVI &CertNameList=
  8.     ENVI ?&Buffer=FVAR,%&VariableName%;%&GUID%
  9.     ;ENVI$# &tmp=*1 0
  10.     ;CALL $--qd ntdll.dll,RtlAdjustPrivilege,#22,#1,#0,*&tmp
  11.     ;ENVI$# &Buffer=*4194304 0
  12.     ;CALL $--qd Kernel32.dll,GetFirmwareEnvironmentVariableW,$%&VariableName%,$%&GUID%,*&Buffer,#4194304
  13.     ENVI-addr &BufAddr;&BufLen=&Buffer
  14.     IFEX [ #%&BufAddr% > 0 & #%&BufLen% > 0 ],
  15.     {
  16.         LOOP #%&BufLen%>0,
  17.         {
  18.             ENVI?int %&BufAddr%=&SignatureListSize:16
  19.             ENVI?int %&BufAddr%=&SignatureHeaderSize:20
  20.             ENVI?int %&BufAddr%=&SignatureSize:24
  21.             IFEX #%&SignatureListSize%=0,EXIT LOOP
  22.             CALC #&SignatureDataAddr = %&BufAddr% + 28 + %&SignatureHeaderSize% + 16
  23.             CALC #&SignatureDataSize = %&SignatureSize% - 16
  24.             CALL $--qd --ret:&CERT_CONTEXT Crypt32.dll,CertCreateCertificateContext,#0x10001,#%&SignatureDataAddr%,#%&SignatureDataSize%
  25.             IFEX #%&CERT_CONTEXT%>0,
  26.             {
  27.                 ENVI$ &NameString=*208 0
  28.                 CALL $--qd --ret:&ret Crypt32.dll,CertGetNameStringW,#%&CERT_CONTEXT%,#4,#0,#0,*&NameString,#208
  29.                 IFEX #%&ret%>0,ENVI &CertNameList=%&CertNameList%%&NameString%%&NL%
  30.                 CALL $--qd --bool Crypt32.dll,CertFreeCertificateContext,#%&CERT_CONTEXT%
  31.             }
  32.             CALC #&BufAddr = %&BufAddr% + %&SignatureListSize%
  33.             CALC #&BufLen = %BufLen% - %&SignatureListSize%
  34.         }
  35.     }
  36.     ;CALL $--qd ntdll.dll,RtlAdjustPrivilege,#22,#0,#0,*&tmp
  37.     ENVI-ret %~3=%&CertNameList%
  38. _END

  39. ;示例
  40. CALL EnumEFIVariableCertName db {d719b2cb-3d3a-4596-a3bc-dad00e67656f} &CertList
  41. MESS %&CertList%@Signature Database (db)#OK
复制代码
从 EFI 变量中的证书中提取其使用者名称部分参考了 527104427 老大在隔壁论坛提供的开源代码;
PS: 527104427 老大的源代码所返回的信息非常详细, 如果你需要更详细的信息, 建议使用他的源代码

发表于 5 天前 来自手机 | 显示全部楼层
感谢分享
回复

使用道具 举报

发表于 5 天前 | 显示全部楼层
谢谢分享
回复

使用道具 举报

发表于 5 天前 | 显示全部楼层
了解一下,感谢分享!
回复

使用道具 举报

发表于 5 天前 | 显示全部楼层
回复

使用道具 举报

发表于 4 天前 | 显示全部楼层
感谢大神的分享
回复

使用道具 举报

发表于 4 天前 | 显示全部楼层
一款很实用的脚本,看看性能如何
回复

使用道具 举报

发表于 4 天前 | 显示全部楼层
感谢分享!
回复

使用道具 举报

发表于 4 天前 | 显示全部楼层
不明觉厉
回复

使用道具 举报

发表于 4 天前 | 显示全部楼层
本帖最后由 Anson4 于 2026-7-18 12:05 编辑

楼主可否费点时间下写脚本用 API 实现:
1. 重设VHD/VHDX父子磁盘关系
2. 合并VHD/VHDX子磁盘与父磁盘
3. 压缩VHD/VHDX磁盘文件

其中第一点,DiskPart 实现不了,PowerShell 需要 HyperV 的支持,应该是用 API 通用性强一点。

AI 是这样描述的:

在 Windows 中,针对 VHD/VHDX 虚拟磁盘的这三类操作,主要通过 virtdisk.h 头文件中的原生 API 以及基于这些 API 的更高级管理工具(如 PowerShell cmdlet)来实现。

[td]
操作
原生 Windows API
对应的 PowerShell 或其他工具
重设父子关系SetVirtualDiskInformation 函数Set-VHD
合并磁盘MergeVirtualDisk 函数Merge-VHD
压缩磁盘CompactVirtualDisk 函数compact vdisk (DiskPart命令) 或 Optimize-VHD

下面是每个 API 的详细信息和使用要点。
🔗 重设VHD/VHDX父子磁盘关系

  • 原生 API: SetVirtualDiskInformation。此函数位于 virtdisk.h,可以设置虚拟磁盘的多种属性。要修改父子关系,需要传入一个 SET_VIRTUAL_DISK_INFO 结构,并将其 Version 成员指定为 SET_VIRTUAL_DISK_INFO_PARENT_PATH 或 SET_VIRTUAL_DISK_INFO_PARENT_PATH_WITH_DEPTH,在对应的 ParentFilePath 字段中填入新的父磁盘路径。
  • PowerShell 命令: Set-VHD。此命令提供了更方便的操作方式,通过 -ParentPath 参数指定新的父磁盘路径即可。对于不安全的操作,它还可以通过 -IgnoreIdMismatch 参数跳过父子磁盘的标识符匹配检查,但微软警告这可能导致数据丢失,需谨慎使用。

🔗 合并VHD/VHDX子磁盘与父磁盘

  • 原生 API: MergeVirtualDisk。此函数是执行合并操作的核心。使用时,需要先通过 OpenVirtualDisk 函数并指定 VIRTUAL_DISK_ACCESS_METAOPS 标志来打开子磁盘句柄。合并的深度通过 MERGE_VIRTUAL_DISK_PARAMETERS 结构的 MergeDepth 字段控制,例如深度为1时,数据从子磁盘移入其直接父磁盘。
  • PowerShell 命令: Merge-VHD。这是一个更高级的命令,使用起来更直观。通过 -Path 指定子磁盘路径,-DestinationPath 指定合并目标(父链中的一个磁盘),即可完成操作。请注意,合并是离线操作,执行前必须确保虚拟磁盘链未被附加(未挂载)。

🔗 压缩VHD/VHDX磁盘文件

  • 原生 API: CompactVirtualDisk。此函数用于减小动态扩展或差异磁盘的物理文件大小。与合并类似,操作前需要通过 VIRTUAL_DISK_ACCESS_METAOPS 标志打开磁盘句柄。压缩有两种模式:

    • 文件系统感知:将 VHD 附加为只读设备后执行,能更有效地回收空间。
    • 文件系统无关:直接操作 VHD 文件,仅回收全零数据块所占用的空间。

  • DiskPart 命令: compact vdisk。这是一个命令行工具,操作前需先用 select vdisk 命令选中目标动态扩展 VHD。



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1|闽公网安备35020302032614号 )

GMT+8, 2026-7-22 00:15

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表