被 Pythons ctypes LittleEndianStructure 搞糊涂了
Confused by Pythons ctypes LittleEndianStructure
我正在尝试使用 ctypes 模块来解析使用 socket 模块捕获的数据包,但我对使用 LittleEndianStructure
.
时看到的内容感到困惑
在 CentOS 7 64 位虚拟机上使用 Python 3.6.8,我正在捕获一个带有负载 0x8401
的 UDP 数据包
然后我想把payload解析成下面的结构,然后打印出字段值。
class MSG(BigEndianStructure):
_fields_ = [
("A", c_ubyte, 4),
("B", c_ubyte, 3),
("C", c_ubyte, 1),
("D", c_ubyte, 4),
("E", c_ubyte, 4)
]
当我使用 BigEndianStructure
时,我得到了我期望的结果
MSG
A: 8
B: 2
C: 0
D: 0
E: 1
然后我尝试使用 LittleEndianStructure
,我希望负载交换到 0x0184
并生成以下内容
MSG
A: 0
B: 0
C: 1
D: 8
E: 4
然而我却得到了以下信息,我不明白为什么。
MSG
A: 4
B: 0
C: 1
D: 1
E: 0
这是完整的代码。感谢您的帮助。
import socket
import sys
import struct
from ctypes import *
class IP(Structure):
_fields_ = [
("ihl", c_ubyte, 4),
("version", c_ubyte, 4),
("tos", c_ubyte),
("len", c_ushort),
("id", c_ushort),
("offset", c_ushort),
("ttl", c_ubyte),
("protocol_num", c_ubyte),
("sum", c_ushort),
("src", c_uint32),
("dst", c_uint32)
]
def __new__(self, socket_buffer=None):
return self.from_buffer_copy(socket_buffer)
def __init__(self, socket_buffer=None):
pass
class UDP(BigEndianStructure):
_fields_ = [
("sport", c_ushort),
("dport", c_ushort),
("length", c_ushort),
("checksum", c_ushort)
]
def __new__(self, socket_buffer):
return self.from_buffer_copy(socket_buffer)
def __init__(self, socket_buffer):
pass
class MSG(LittleEndianStructure):
_fields_ = [
("A", c_ubyte, 4),
("B", c_ubyte, 3),
("C", c_ubyte, 1),
("D", c_ubyte, 4),
("E", c_ubyte, 4)
]
def __new__(self, socket_buffer):
return self.from_buffer_copy(socket_buffer)
def __init__(self, socket_buffer):
pass
def sniff():
eth_length = 14
ip_length = 20
udp_length = 8
msg_length = 2
try:
# Capture all packets
protocol = socket.ntohs(0x0003) # captures all packets
sniffer = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, protocol)
except KeyboardInterrupt:
sys.exit()
while True:
# read a packet
raw_buffer = sniffer.recvfrom(65535)[0]
eth_header = raw_buffer[:eth_length]
eth_payload = raw_buffer[eth_length:]
eth = struct.unpack('!6s6sH', eth_header)
eth_protocol = socket.ntohs(eth[2])
# IP packet
if eth_protocol == 8:
# create an IP header from the first 20 bytes
ip_header = IP(eth_payload[:ip_length])
ip_data = eth_payload[ip_length:]
# UDP packet
if ip_header.protocol_num == 17:
udp_header = UDP(ip_data[:udp_length])
udp_data = ip_data[udp_length:]
if udp_header.dport == 8001:
msg_header = MSG(udp_data[:msg_length])
print("MSG")
print(" A: %s" % msg_header.A)
print(" B: %s" % msg_header.B)
print(" C: %s" % msg_header.C)
print(" D: %s" % msg_header.D)
print(" E: %s" % msg_header.E)
if __name__ == '__main__':
sniff()
实际的小端结果是从最低位开始取位。
字节:84 01
大端字 840116 (10000100000000012) 并划分从高位开始的位:
A B C D E
1000 010 0 0000 0001 so ABCDE = 82001
little endian word 018416 (00000001100001002) 并从低位开始划分位:
E D C B A
0000 0001 1 000 0100 so ABCDE = 40110
我正在尝试使用 ctypes 模块来解析使用 socket 模块捕获的数据包,但我对使用 LittleEndianStructure
.
在 CentOS 7 64 位虚拟机上使用 Python 3.6.8,我正在捕获一个带有负载 0x8401
然后我想把payload解析成下面的结构,然后打印出字段值。
class MSG(BigEndianStructure):
_fields_ = [
("A", c_ubyte, 4),
("B", c_ubyte, 3),
("C", c_ubyte, 1),
("D", c_ubyte, 4),
("E", c_ubyte, 4)
]
当我使用 BigEndianStructure
时,我得到了我期望的结果
MSG
A: 8
B: 2
C: 0
D: 0
E: 1
然后我尝试使用 LittleEndianStructure
,我希望负载交换到 0x0184
并生成以下内容
MSG
A: 0
B: 0
C: 1
D: 8
E: 4
然而我却得到了以下信息,我不明白为什么。
MSG
A: 4
B: 0
C: 1
D: 1
E: 0
这是完整的代码。感谢您的帮助。
import socket
import sys
import struct
from ctypes import *
class IP(Structure):
_fields_ = [
("ihl", c_ubyte, 4),
("version", c_ubyte, 4),
("tos", c_ubyte),
("len", c_ushort),
("id", c_ushort),
("offset", c_ushort),
("ttl", c_ubyte),
("protocol_num", c_ubyte),
("sum", c_ushort),
("src", c_uint32),
("dst", c_uint32)
]
def __new__(self, socket_buffer=None):
return self.from_buffer_copy(socket_buffer)
def __init__(self, socket_buffer=None):
pass
class UDP(BigEndianStructure):
_fields_ = [
("sport", c_ushort),
("dport", c_ushort),
("length", c_ushort),
("checksum", c_ushort)
]
def __new__(self, socket_buffer):
return self.from_buffer_copy(socket_buffer)
def __init__(self, socket_buffer):
pass
class MSG(LittleEndianStructure):
_fields_ = [
("A", c_ubyte, 4),
("B", c_ubyte, 3),
("C", c_ubyte, 1),
("D", c_ubyte, 4),
("E", c_ubyte, 4)
]
def __new__(self, socket_buffer):
return self.from_buffer_copy(socket_buffer)
def __init__(self, socket_buffer):
pass
def sniff():
eth_length = 14
ip_length = 20
udp_length = 8
msg_length = 2
try:
# Capture all packets
protocol = socket.ntohs(0x0003) # captures all packets
sniffer = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, protocol)
except KeyboardInterrupt:
sys.exit()
while True:
# read a packet
raw_buffer = sniffer.recvfrom(65535)[0]
eth_header = raw_buffer[:eth_length]
eth_payload = raw_buffer[eth_length:]
eth = struct.unpack('!6s6sH', eth_header)
eth_protocol = socket.ntohs(eth[2])
# IP packet
if eth_protocol == 8:
# create an IP header from the first 20 bytes
ip_header = IP(eth_payload[:ip_length])
ip_data = eth_payload[ip_length:]
# UDP packet
if ip_header.protocol_num == 17:
udp_header = UDP(ip_data[:udp_length])
udp_data = ip_data[udp_length:]
if udp_header.dport == 8001:
msg_header = MSG(udp_data[:msg_length])
print("MSG")
print(" A: %s" % msg_header.A)
print(" B: %s" % msg_header.B)
print(" C: %s" % msg_header.C)
print(" D: %s" % msg_header.D)
print(" E: %s" % msg_header.E)
if __name__ == '__main__':
sniff()
实际的小端结果是从最低位开始取位。
字节:84 01
大端字 840116 (10000100000000012) 并划分从高位开始的位:
A B C D E
1000 010 0 0000 0001 so ABCDE = 82001
little endian word 018416 (00000001100001002) 并从低位开始划分位:
E D C B A
0000 0001 1 000 0100 so ABCDE = 40110