Search code examples
pythonudphexasciiscapy

Convert HEX string that contains ASCII characters


I'm having trouble with decoding data (or maybe encoding on send) from scapy.

I'm attempting to send some UDP HEX data with scapy then decode it back to the original form, but the HEX string received has ASCII characters in it.

from scapy.all import *
from scapy.layers.l2 import Ether
from scapy.layers.inet import IP, UDP

test_data = ["000ad74340b81e4941002900020202000200"]  # This is actually read from a file.
source_ip = "192.168.1.12"
destination_ip = "192.168.1.4"
source_mac = "70:85:c2:f3:18:8e"
destination_mac = "80:ce:62:f2:94:22"
source_port = 5005
destination_port = 5005
tmp = []

byte_str = [(test_data[0][i:i + 2]) for i in range(0, len(test_data[0]), 2)]

for i in range(len(byte_str)):
    tmp.append(int(f"0x{byte_str[i]}", 16))

data_to_send = bytearray(tmp)
print("b'" + ''.join(f'\\x{c:02x}' for c in data_to_send) + "'")

pkt = Ether(dst=destination_mac, src=source_mac)/\
      IP(dst=destination_ip, src=source_ip, flags=2)/\
      UDP(dport=destination_port, sport=source_port)/data_to_send

del pkt[IP].chksum
del pkt[UDP].chksum

pkt.show2()
sendp(pkt)

Whats being sent

###[ Ethernet ]### 
  dst       = 80:ce:62:f2:94:22
  src       = 70:85:c2:f3:18:8e
  type      = IPv4
###[ IP ]### 
     version   = 4
     ihl       = 5
     tos       = 0x0
     len       = 46
     id        = 1
     flags     = DF
     frag      = 0
     ttl       = 64
     proto     = udp
     chksum    = 0xb75d
     src       = 192.168.1.12
     dst       = 192.168.1.4
     \options   \
###[ UDP ]### 
        sport     = 5005
        dport     = 5005
        len       = 26
        chksum    = 0xaeed
###[ Raw ]### 
           load      = '\x00\n\\xd7C@\\xb8\x1eIA\x00)\x00\x02\x02\x02\x00\x02\x00'

.
Sent 1 packets.

Whats received is \x00\n\\xd7C@\\xb8\x1eIA\x00)\x00\x02\x02\x02\x00\x02\x00, and i'm trying to figure out how i get back to 000ad74340b81e4941002900020202000200 or something like this \x00\x0a\xd7\x43\x40\xb8\x1e\x49\x41\x00\x29\x00\x02\x02\x02\x00\x02\x00.

When i convert 000ad74340b81e4941002900020202000200 to a list of hex values ['00', '0a', 'd7', '43', '40', 'b8', '1e', '49', '41', '00', '29', '00', '02', '02', '02', '00', '02', '00'], then convert them to a list ints [0, 10, 215, 67, 64, 184, 30, 73, 65, 0, 41, 0, 2, 2, 2, 0, 2, 0] to create a bytearray bytearray(b'\x00\n\xd7C@\xb8\x1eIA\x00)\x00\x02\x02\x02\x00\x02\x00'), i can then convert that back to b'\x00\x0a\xd7\x43\x40\xb8\x1e\x49\x41\x00\x29\x00\x02\x02\x02\x00\x02\x00'.

But when i read the payload info from the scapy UDP packet i get the following string "b'\\x00\\n\\xd7C@\\xb8\\x1eIA\\x00)\\x00\\x02\\x02\\x02\\x00\\x02\\x00'", which when i convert it to a bytestring, it still has the \\ and i can't convert ot back to the original hex data above.

How can i convert str "\\x00\\n\\xd7C@\\xb8\\x1eIA\\x00)\\x00\\x02\\x02\\x02\\x00\\x02\\x00" to b'\x00\n\xd7C@\xb8\x1eIA\x00)\x00\x02\x02\x02\x00\x02\x00' with a single \ so i can then use print("b'" + ''.join(f'\\x{c:02x}' for c in bytearray(RECEIVED_DATA) + "'") to get the original hex data back?


Solution

  • Use bytes.hex() and str.fromhex() to convert between representations:

    >>> s = "000ad74340b81e4941002900020202000200"  # ASCII string of hex digits
    >>> s
    '000ad74340b81e4941002900020202000200'
    >>> b = bytes.fromhex(s)
    >>> b  # Default *display* representation of bytes.
    b'\x00\n\xd7C@\xb8\x1eIA\x00)\x00\x02\x02\x02\x00\x02\x00'
    >>> list(b)  # decimal values of the bytes are correct
    [0, 10, 215, 67, 64, 184, 30, 73, 65, 0, 41, 0, 2, 2, 2, 0, 2, 0]
    >>> # Display a custom way (no ASCII).  This is *just* for display.
    >>> print("b'" + ''.join(f'\\x{n:02x}' for n in b) + "'")
    b'\x00\x0a\xd7\x43\x40\xb8\x1e\x49\x41\x00\x29\x00\x02\x02\x02\x00\x02\x00'
    >>> b.hex()  # display bytes as hexadecimal string again
    '000ad74340b81e4941002900020202000200'
    >>> b.hex(sep=' ')  # with a separator if desired.
    '00 0a d7 43 40 b8 1e 49 41 00 29 00 02 02 02 00 02 00'
    

    Note that the type of a bytes object element is int so you can iterate over them and perform calculations if needed:

    >>> type(b[0])
    <class 'int'>
    >>> for n in b:
    ...  print(f'{n:3d} {n:02X}')
    ...
      0 00
     10 0A
    215 D7
     67 43
     64 40
    184 B8
     30 1E
     73 49
     65 41
      0 00
     41 29
      0 00
      2 02
      2 02
      2 02
      0 00
      2 02
      0 00