如何从文件中读取 ctypes 结构
how to read ctypes structures from file
我想了解更多关于 PE 文件结构和 ctypes 结构的信息。我有几个问题:
给出这个简单的声明:
from ctypes import *
class ImageDosHeader(Structure):
_fields_ = [
('e_magic', c_uint8, 2),
('e_cblp', c_uint8, 2),
('e_cp', c_uint8, 2),
('e_crlc', c_uint8, 2),
('e_cparhdr', c_uint8, 2),
('e_minalloc', c_uint8, 2),
('e_maxalloc', c_uint8, 2),
('e_ss', c_uint8, 2),
('e_sp', c_uint8, 2),
('e_csum', c_uint8, 2),
('e_ip', c_uint8, 2),
('e_cs', c_uint8, 2),
('e_lfarlc', c_uint8, 2),
('e_ovno', c_uint8, 2),
('e_res', c_uint8, 2),
('e_oemid', c_uint8, 2),
('e_oeminfo', c_uint8, 2),
('e_res2', c_uint8, 2 * 10),
('e_lfanew', c_uint8, 4),
]
问题1:得到ValueError: number of bits invalid for bit field
的原因是什么?
如果我尝试阅读这样的简化结构:
class ImageDosHeader(Structure):
_fields_ = [
('e_magic', c_uint8, 2),
]
filename = 'example1_crinkler.exe'
with open(filename, 'rb') as f:
record = ImageDosHeader()
f.readinto(record)
print(record.e_magic)
print('-' * 80)
with open(filename, 'rb') as f:
content = f.read()
print(binascii.hexlify(content))
print(len(content))
我得到这个输出:
1
--------------------------------------------------------------------------------
b'4d5a3230504500004c01000001db617f10d017737547ebf9080002000b0111c94585c0791f01d350f7e2903d5c000000f7f339c119dbeb480000400004000000040000000fa32d320140008d0400ebce00000000ebb64206400000005331edbb0300000090be1c0140006a0158bf00004200b1009057eb1200000000000000005a72079229d1040029d060ad01f8742c6a0a5a89145489542410ad31ed4d4501c072fb74af60ac88c232076bc06f028700000000484f00d272ef75f9bf16104200b923e91f03730cf366ab0a06618d760e7bb7c3f7f18d3c5789e931c0ae74040007750241410fb61407d3e201548434487af385db7f0dd02c1f7503d0141ff7d3fe041f6146eb95e86aa6384b0b237bc66f82e9197a11121b13094ff4efbdfffeff7d96008180c090caeaefbdffffffffff44bec48b813eee1868379da18dcb827772cd7a49fe835cc82cc3850cb06603a8fff8e2d9becd3629b3268d3d6cb5ce9fd714516822c6dcc349482dc1e6868f92ed3df97e79469ad174b79b0479d9afb758dd7dd85c9218edef5ca0b47d5dd8aa46494ef4242201baeb2853c31d6f5ac630668462c5543f23a23616db595d1cd08993fce7231e8716b5f79480a1cacd10498fe4864843e744ae3e124c00e74af0173c8346860d98fb9882688c896737e07d3f16ee0d08238b0f0ed89553dbe2b177b64249ca712b9051e88c73'
510
问题2:为什么print(record.e_magic)
打印的是1?我希望它是 "MZ",或 0x4d5a,或 19802...但不是 1,我在这里缺少什么?
NS:我知道 pefile pypi 包或类似的包,那个包很棒,但我想在这里使用 ctypes 重新发明轮子来学习它,只是为了记录:)
这两个问题似乎表明了同样的误解。引用自 the ctypes documentation for Structure._fields_
:
For integer type fields like c_int, a third optional item can be given. It must be a small positive integer defining the bit width of the field.
这意味着第三个字段是位数,而不是值的数量。因此,您已指示 e_magic
是 uint8
中的 2 位宽字段。 ValueError
源于试图从 e_res2
中的 8 位值中提取 20 位。 1
值来自 'M'
的最低两位:ord('M')&0b11 == 1
。
您可以通过选择更匹配的数据类型来调整您的数据类型,例如 c_uint16
用于 16 位字段,或者创建其他结构类型,例如 2*c_char
。避免使用第三个条目,除非你真的在处理 bit field; ctypes 已经知道其类型的大小。
我想了解更多关于 PE 文件结构和 ctypes 结构的信息。我有几个问题:
给出这个简单的声明:
from ctypes import *
class ImageDosHeader(Structure):
_fields_ = [
('e_magic', c_uint8, 2),
('e_cblp', c_uint8, 2),
('e_cp', c_uint8, 2),
('e_crlc', c_uint8, 2),
('e_cparhdr', c_uint8, 2),
('e_minalloc', c_uint8, 2),
('e_maxalloc', c_uint8, 2),
('e_ss', c_uint8, 2),
('e_sp', c_uint8, 2),
('e_csum', c_uint8, 2),
('e_ip', c_uint8, 2),
('e_cs', c_uint8, 2),
('e_lfarlc', c_uint8, 2),
('e_ovno', c_uint8, 2),
('e_res', c_uint8, 2),
('e_oemid', c_uint8, 2),
('e_oeminfo', c_uint8, 2),
('e_res2', c_uint8, 2 * 10),
('e_lfanew', c_uint8, 4),
]
问题1:得到ValueError: number of bits invalid for bit field
的原因是什么?
如果我尝试阅读这样的简化结构:
class ImageDosHeader(Structure):
_fields_ = [
('e_magic', c_uint8, 2),
]
filename = 'example1_crinkler.exe'
with open(filename, 'rb') as f:
record = ImageDosHeader()
f.readinto(record)
print(record.e_magic)
print('-' * 80)
with open(filename, 'rb') as f:
content = f.read()
print(binascii.hexlify(content))
print(len(content))
我得到这个输出:
1
--------------------------------------------------------------------------------
b'4d5a3230504500004c01000001db617f10d017737547ebf9080002000b0111c94585c0791f01d350f7e2903d5c000000f7f339c119dbeb480000400004000000040000000fa32d320140008d0400ebce00000000ebb64206400000005331edbb0300000090be1c0140006a0158bf00004200b1009057eb1200000000000000005a72079229d1040029d060ad01f8742c6a0a5a89145489542410ad31ed4d4501c072fb74af60ac88c232076bc06f028700000000484f00d272ef75f9bf16104200b923e91f03730cf366ab0a06618d760e7bb7c3f7f18d3c5789e931c0ae74040007750241410fb61407d3e201548434487af385db7f0dd02c1f7503d0141ff7d3fe041f6146eb95e86aa6384b0b237bc66f82e9197a11121b13094ff4efbdfffeff7d96008180c090caeaefbdffffffffff44bec48b813eee1868379da18dcb827772cd7a49fe835cc82cc3850cb06603a8fff8e2d9becd3629b3268d3d6cb5ce9fd714516822c6dcc349482dc1e6868f92ed3df97e79469ad174b79b0479d9afb758dd7dd85c9218edef5ca0b47d5dd8aa46494ef4242201baeb2853c31d6f5ac630668462c5543f23a23616db595d1cd08993fce7231e8716b5f79480a1cacd10498fe4864843e744ae3e124c00e74af0173c8346860d98fb9882688c896737e07d3f16ee0d08238b0f0ed89553dbe2b177b64249ca712b9051e88c73'
510
问题2:为什么print(record.e_magic)
打印的是1?我希望它是 "MZ",或 0x4d5a,或 19802...但不是 1,我在这里缺少什么?
NS:我知道 pefile pypi 包或类似的包,那个包很棒,但我想在这里使用 ctypes 重新发明轮子来学习它,只是为了记录:)
这两个问题似乎表明了同样的误解。引用自 the ctypes documentation for Structure._fields_
:
For integer type fields like c_int, a third optional item can be given. It must be a small positive integer defining the bit width of the field.
这意味着第三个字段是位数,而不是值的数量。因此,您已指示 e_magic
是 uint8
中的 2 位宽字段。 ValueError
源于试图从 e_res2
中的 8 位值中提取 20 位。 1
值来自 'M'
的最低两位:ord('M')&0b11 == 1
。
您可以通过选择更匹配的数据类型来调整您的数据类型,例如 c_uint16
用于 16 位字段,或者创建其他结构类型,例如 2*c_char
。避免使用第三个条目,除非你真的在处理 bit field; ctypes 已经知道其类型的大小。