Pack, Unpack & C Structs
Pack, Unpack & C Structs
Built-in Pack/Unpack
ql.pack(value) / ql.unpack(data)
Architecture-width aware: automatically uses 16/32/64-bit variant based on ql.arch.bits.
1packed = ql.pack(value)
2value = ql.unpack(data)
Fixed-width variants
1# Unsigned
2ql.pack64(v) # Q — unsigned long long, 8 bytes
3ql.pack32(v) # I — unsigned int, 4 bytes (endian-aware)
4ql.pack16(v) # H — unsigned short, 2 bytes (endian-aware)
5
6ql.unpack64(d)
7ql.unpack32(d)
8ql.unpack16(d)
9
10# Signed
11ql.pack64s(v) # q — long, 8 bytes
12ql.pack32s(v) # i — int, 4 bytes (endian-aware)
13ql.pack16s(v) # h — short, 2 bytes (endian-aware)
14
15ql.unpack64s(d)
16ql.unpack32s(d)
17ql.unpack16s(d)
Python struct Module for C Structs
For complex or unknown structures, use Python’s struct module directly.
Format string prefix controls byte order:
<— little-endian>— big-endian=— native
Common format characters:
| Char | C type | Size |
|---|---|---|
b/B | signed/unsigned char | 1 |
h/H | signed/unsigned short | 2 |
i/I | signed/unsigned int | 4 |
q/Q | signed/unsigned long long | 8 |
s | char[] | n (prefix with count) |
p | pointer | arch-dependent |
Reference: https://docs.python.org/3/library/struct.html
Example: Parsing sockaddr_in from Memory
Target: Netgear R6220, MIPS32 little-endian, bind() syscall.
C structure:
1struct sockaddr_in {
2 sa_family_t sin_family; /* address family: AF_INET */
3 in_port_t sin_port; /* port in network byte order */
4 struct in_addr sin_addr; /* internet address */
5};
1import struct
2from qiling.os.const import UINT, POINTER
3
4def my_bind(ql, *args, **kw):
5 params = ql.os.resolve_fcall_params({
6 'fd': UINT,
7 'addr': POINTER,
8 'addrlen': UINT
9 })
10
11 data = ql.mem.read(params['addr'], params['addrlen'])
12
13 # sin_family: little-endian short (arch endian)
14 sin_family = struct.unpack("<h", data[:2])[0]
15
16 # sin_port + sin_addr: big-endian (network byte order)
17 port, host = struct.unpack(">HI", data[2:8])
Note: Network stack fields (sin_port, sin_addr) are always big-endian regardless of CPU architecture, as mandated by POSIX. The architecture endianness only affects the sin_family field.