2

In my networking class a lab i have is to make a client to receive 5 familiar 32-bit integers in big endian order and to intemperate them. I decided to use python and everything works well enough but i am receiving strange hex code.

\x00\x00\x00o\x00\x00\x00\xe4\x00\x00\x01\xb3\x00\x00\x01\xdb\x00\x00\x01\xec

I can convert most of it easily but the x00o is really confusing me, 228 435 475 492 where the 4 after that I believe. Can you help me intemperate the server message?

import socket 
import sys
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
    print('Failed to create socket')
    sys.exit()
print('Socket Created')

host = 'localhost'
port = 5071

try:
    remote_ip = socket.gethostbyname(host)

except socket.gaierror:
    #could not resolve
    print('Hostname could not be resolved. Exiting')
    sys.exit()

s.connect((remote_ip , port))

print('Socket Connected to ' + host + ' on ip ' + remote_ip)

reply = s.recv(4096)

print(reply)
Community
  • 1
  • 1
Will
  • 29
  • 1
  • 5
  • 2
    If the value of a byte in the buffer corresponds to a printable character, Python shows it as that character when printing the buffer as a string. If the value does not match a printable character, Python shows the byte as two hex digits after a `\x` prefix. So your `\x00o` represents a byte with value zero followed by a byte whose value is the value of the character 'o'. The numeric value of that byte is `ord('o')` which is 111 decimal, 6f hexadecimal. – ottomeister Jan 30 '18 at 00:27

1 Answers1

0

code.py:

import sys
import struct


def convert_data_to_ints(data, big_endian=True):
    int_count = len(data) // 4  # Assuming uint is 4 bytes long !!!
    fmt = ">" if big_endian else "<"
    fmt += "I" * int_count
    return struct.unpack(fmt, data[:int_count * 4])


def main():
    print("Python {} on {}\n".format(sys.version, sys.platform))
    data = b"\x00\x00\x00o\x00\x00\x00\xe4\x00\x00\x01\xb3\x00\x00\x01\xdb\x00\x00\x01\xec"
    ints_be = convert_data_to_ints(data)
    print("Big endian: {}".format(ints_be))
    ints_le = convert_data_to_ints(data, big_endian=False)
    print("Little endian: {}".format(ints_le))


if __name__ == "__main__":
    main()

Notes:

  • convert_data_to_ints:
    • Uses [Python]: struct.unpack(fmt, buffer) to perform the conversion (might also check [SO]: Python struct.pack() behavior for more details on how integers are being represented in memory - and also in the server response)
    • Conversion is done to unsigned int ("I" format). Check the "Format Strings" section in on the (1st) above page
    • Relies on the fact that int is 4 bytes long (I didn't want to hardcode the "IIIII", wanted to make it more general). If the string length is not a multiple of 4 (an integral number of ints), the incomplete int at the end (at most 3 bytes) is discarded (of course, a nicer way to pad the string and also convert the "incomplete" data, but that's outside the question scope)
    • Returns a tuple containing the converted integers
  • main:

Output:

E:\Work\Dev\StackOverflow\q048508018>"c:\install\Python\3.4.3\x86\python.exe" code.py
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:43:06) [MSC v.1600 32 bit (Intel)] on win32

Big endian: (111, 228, 435, 475, 492)
Little endian: (1862270976, 3825205248, 3003187200, 3674275840, 3959488512)
CristiFati
  • 38,250
  • 9
  • 50
  • 87