PeFile模块是Python
中一个强大的便携式第三方PE
格式分析工具,用于解析和处理Windows
可执行文件。该模块提供了一系列的API接口,使得用户可以通过Python
脚本来读取和分析PE文件的结构,包括文件头、节表、导入表、导出表、资源表、重定位表等等。此外,PEfile模块还可以帮助用户进行一些恶意代码分析,比如提取样本中的字符串、获取函数列表、重构导入表、反混淆等等。PEfile模块是Python中处理PE文件的重要工具之一,广泛应用于二进制分析、安全研究和软件逆向工程等领域。
由于该模块为第三方模块,在使用之前读者需要在命令行下执行pip install pefile
命令安装第三方库,当安装成功后即可正常使用,如下所示则是该模块的基本使用方法,读者可自行学习理解。
21.1.1 打开并加载PE文件
如下这段代码封装并实现了OpenPeFile
函数,可用于打开一个PE文件,在其内部首先判断了可执行文件是否被压缩如果被压缩则会通过zipfile
模块将压缩包读入内存并调用C2BIP3
函数将数据集转换为2字节,接着再执行pefile.PE()
函数,该函数可用于将可执行文件载入,至此读者可在主函数内通过pe.dump_dict()
的方式输出该PE文件的所有参数,由于输出的是字典,读者可以使用字典与列表的方式灵活的提取出该程序的所有参数信息。
import sys
import zipfile
import pefile
# 如果是Python3则转换为2字节
def C2BIP3(string):
if sys.version_info[0] > 2:
return bytes([ord(x) for x in string])
else:
return string
# 打开文件
def OpenPeFile(filename):
# 判断是否是ZIP压缩包
if filename.lower().endswith('.zip'):
try:
oZipfile = zipfile.ZipFile(filename, 'r')
file = oZipfile.open(oZipfile.infolist()[0], 'r', C2BIP3('infected'))
except Exception:
print(sys.exc_info()[1])
sys.exit()
oPE = pefile.PE(data=file.read())
file.close()
oZipfile.close()
# 如果是空则
elif filename == '':
oPE = False
return oPE
# 否则直接打开文件
else:
oPE = pefile.PE(filename)
return oPE
if __name__ == "__main__":
pe = OpenPeFile("d://lyshark.exe")
print(pe.FILE_HEADER.dump())
print(pe.dump_dict())
21.1.2 解析PE头部数据
如下代码实现了解析PE结构中头部基本数据,在GetHeader
函数内,我们首先通过pe.FILE_HEADER.Machine
成员判断当前读入的文件的位数信息,通过pe.FILE_HEADER.Characteristics
可判断PE文件的类型,通常为EXE可执行文件或DLL动态链接库文件,通过AddressOfEntryPoint
加上ImageBase
则可获取到程序的实际装载地址,压缩数据的计算可通过hashlib
模块对PE文件字节数据进行计算摘要获取,最后是附加数据,通过get_overlay_data_start_offset
则可获取到,并依次循环即可输出所有附加数据。
import hashlib
import pefile
# 计算得到数据长度,自动使用推荐大小
def NumberOfBytesHumanRepresentation(value):
if value <= 1024:
return '%s bytes' % value
elif value < 1024 * 1024:
return '%.1f KB' % (float(value) / 1024.0)
elif value < 1024 * 1024 * 1024:
return '%.1f MB' % (float(value) / 1024.0 / 1024.0)
else:
return '%.1f GB' % (float(value) / 1024.0 / 1024.0 / 1024.0)
# 获取PE头部基本信息
def GetHeader(pe):
raw = pe.write()
# 扫描基本信息
print("-" * 50)
print("程序基本信息")
print("-" * 50)
if (hex(pe.FILE_HEADER.Machine) == "0x14c"):
print("程序位数: {}".format("x86"))
if (hex(pe.FILE_HEADER.Machine) == "0x8664"):
print("程序位数: {}".format("x64"))
if (hex(pe.FILE_HEADER.Characteristics) == "0x102"):
print("程序类型: Executable")
elif (hex(pe.FILE_HEADER.Characteristics) == "0x2102"):
print("程序类型: Dynamic link library")
if pe.OPTIONAL_HEADER.AddressOfEntryPoint:
oep = pe.OPTIONAL_HEADER.AddressOfEntryPoint + pe.OPTIONAL_HEADER.ImageBase
print("实际入口: {}".format(hex(oep)))
print("映像基址: {}".format(hex(pe.OPTIONAL_HEADER.ImageBase)))
print("虚拟入口: {}".format(hex(pe.OPTIONAL_HEADER.AddressOfEntryPoint)))
print("映像大小: {}".format(hex(pe.OPTIONAL_HEADER.SizeOfImage)))
print("区段对齐: {}".format(hex(pe.OPTIONAL_HEADER.SectionAlignment)))
print("文件对齐: {}".format(hex(pe.OPTIONAL_HEADER.FileAlignment)))
print("区块数量: {}".format(in