如何为带强制完整性检查的用户态二进制签名(微软交叉签名已弃用)
问题根因
带/integritycheck编译选项的PE文件会在头中写入IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY标识,Windows加载这类文件时会走内核级强制代码完整性校验,校验逻辑不会认可用户手动导入到系统受信任存储区的非微软信任链证书,必须满足签名链最终锚定到微软内置的受信任根证书才能通过校验。
你目前排查到的几个现象完全符合这个校验逻辑:
- 开启测试签名模式后程序正常运行,是因为测试模式默认跳过强制完整性的根链校验环节,仅验证签名本身格式有效性
- 签名时加了
/ph页哈希参数只是满足强制完整性签名的格式要求,不代表签名链会被认可 - 手动导入新证书到受信任存储无效,是因为内核态的完整性校验逻辑不读取用户手动添加的第三方根证书信任项
交叉签名废弃后的方案现状
微软2021年已全面停止代码签名交叉证书的签发服务,旧的交叉签名证书链陆续到期后已经无法为新证书提供信任锚定,用户态程序使用/integritycheck标志的机制本身没有失效,只是原有的交叉签名签名路径已经彻底不可用。
可落地的替代方案
- 公网分发场景:走微软官方签名通道
先申请EV级别的代码签名证书,将编译好的二进制提交到微软合作伙伴中心做官方签名,拿到微软签发的签名后,程序即可正常通过强制完整性校验,这是目前公网发布场景下唯一符合微软规范的正式方案。 - 企业内部部署场景:配置WDAC/组策略信任
如果程序仅在企业内部可控设备上运行,可以通过部署Windows Defender应用程序控制(WDAC)策略或者域组策略,将你的新代码签名证书添加到内核级代码信任列表中,策略生效后对应设备即可正常运行用该证书签名的带强制完整性标识的程序,不需要提交微软签名。 - 无强制完整性需求场景:移除对应编译选项
如果当初开启/integritycheck没有强需求,可以直接在VC++编译配置中去掉该链接选项,重新编译生成的二进制移除了FORCE_INTEGRITY头标识,此时只要用有效代码签名(哪怕是自签名证书导入受信任存储)即可正常运行,不会触发内核级完整性校验拦截。如果需要防篡改能力,可以替换为用户态的签名校验、文件哈希校验等方案实现。
避坑说明
- 不存在新的可用交叉证书,所有2021年之后签发的第三方代码签名证书都没有对应的微软交叉签名根,不要在这上面浪费时间
- 测试签名模式仅适用于开发调试环节,开启后系统安全等级会下降,桌面会持续显示测试模式水印,绝对不能用于生产环境
- 直接修改已编译二进制的PE头擦除
FORCE_INTEGRITY标识的做法容易触发安全软件的篡改告警,不推荐使用。
内容的提问来源于stack exchange,提问作者DawidW
相关产品推荐
相关产品推荐

