简体   繁体   English

被 Python 的 ctypes LittleEndianStructure 弄糊涂了

[英]Confused by Pythons ctypes LittleEndianStructure

I'm experimenting with using the ctypes module to parse packets captured using the socket module and I'm confused by what I see when using the LittleEndianStructure .我正在尝试使用 ctypes 模块来解析使用 socket 模块捕获的数据包,我对使用LittleEndianStructure时看到的内容感到困惑。

Using Python 3.6.8 on a CentOS 7 64bit VM, I'm capturing a UDP packet with the payload 0x8401在 CentOS 7 64 位 VM 上使用 Python 3.6.8,我正在捕获带有有效负载0x8401的 UDP 数据包

I then want to parse the payload into the following structure, and print out the field values.然后我想将有效负载解析为以下结构,并打印出字段值。

class MSG(BigEndianStructure):
    _fields_ = [
        ("A", c_ubyte, 4),
        ("B", c_ubyte, 3),
        ("C", c_ubyte, 1),
        ("D", c_ubyte, 4),
        ("E", c_ubyte, 4)
    ]

when I use BigEndianStructure , I get the results I expect当我使用BigEndianStructure时,我得到了我期望的结果

MSG
  A: 8
  B: 2
  C: 0
  D: 0
  E: 1 

I then try using LittleEndianStructure where I expected the payload to be swapped to 0x0184 and produce the following然后我尝试使用LittleEndianStructure我希望有效载荷被交换到0x0184并产生以下

MSG
  A: 0
  B: 0
  C: 1
  D: 8
  E: 4 

However I instead get the following, and I don't understand why.但是,我却得到以下信息,但我不明白为什么。

MSG
  A: 4
  B: 0
  C: 1
  D: 1
  E: 0 

here's the full code.这是完整的代码。 I appreciate any help.我很感激任何帮助。

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()

The actual little-endian result is fetching bits from the lowest first.实际的 little-endian 结果是从最低的第一个获取位。

Bytes: 84 01字节:84 01

Big endian word 8401 16 (1000010000000001 2 ) and divide the bits starting with high bit:大端字 8401 16 (1000010000000001 2 ) 并除以高位开始的位:

A    B   C D    E
1000 010 0 0000 0001 so ABCDE = 82001

Little endian word 0184 16 (0000000110000100 2 ) and divide the bits starting with the low bit:小端字 0184 16 (0000000110000100 2 ) 并除以低位开始的位:

E    D    C B   A
0000 0001 1 000 0100 so ABCDE = 40110

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM