【问题标题】:Confused by Pythons ctypes LittleEndianStructure被 Python 的 ctypes LittleEndianStructure 弄糊涂了
【发布时间】:2020-12-09 17:43:32
【问题描述】:

我正在尝试使用 ctypes 模块来解析使用 socket 模块捕获的数据包,我对使用 LittleEndianStructure 时看到的内容感到困惑。

在 CentOS 7 64 位 VM 上使用 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()

【问题讨论】:

    标签: python ctypes endianness


    【解决方案1】:

    实际的 little-endian 结果是从最低位先获取位。

    字节:84 01

    Big endian word 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
    

    【讨论】:

    • 啊,当然。我没有考虑从最不重要的位开始,即 Little Endian 的全部意义。所以我想如果我想按 ABCDE 顺序而不是 EDCBA 读取 0x0184,我必须使用 BigEndianStructure 并交换 __init__ 中的字节
    猜你喜欢
    • 2022-01-23
    • 2019-01-12
    • 1970-01-01
    • 2014-08-14
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 2017-07-24
    • 2011-08-02
    相关资源
    最近更新 更多