Binaries
Data
1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
0 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 |
0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 |
1 | 1 | 0 | 1 | 1 | 0 | 1 | 1 |
0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 |
1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 |
0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 |
0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
1 | 0 | 1 | 0 | 1 | 1 | 0 | 1 |
str, unicode & bytes
>>> napis = "zażółć gęślą jaźń"
>>> napis
'za\xc5\xbc\xc3\xb3\xc5...'
>>> print(napis)
zażółć gęślą jaźń
>>> napis[2]
'\xc5'
>>> unicode(napis, 'utf-8')[2]
u'\u017c'
Python 2
>>> napis = "zażółć gęślą jaźń"
>>> napis
'zażółć gęślą jaźń'
>>> print(napis)
zażółć gęślą jaźń
>>> napis[2]
'ż'
>>> unicode
NameError: name 'unicode'
is not defined
Python 3
str, unicode & bytes
>>> napis = b"zażółć gęślą jaźń"
SyntaxError: bytes can only contain ASCII literal characters.
>>> napis = b"zażółć gęślą jaźń".encode('utf-8')
>>> napis
b'za\xc5\xbc\xc3\xb3\xc5...'
>>> napis[2], hex(napis[2])
(197, '0xc5')
>>> napis = bytes.fromhex('3216d1509884b533248541792b877f98')
>>> napis
b'2\x16\xd1P\x98\x84\xb53$\x85Ay+\x87\x7f\x98'
>>> napis.hex()
'3216d1509884b533248541792b877f98'
>>> napis.hex().encode('ascii')
b'3216d1509884b533248541792b877f98'
>>> napis[0]
50
>>> chr(50)
'2'
>>> ord('2')
50
When I use a word,
it means just what I choose it to mean
numbers
1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
0 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 |
0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
3579670034
int('11010101'
'01011101'
'01101110'
'00010010', 2)
endians
1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
0 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 |
0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
309222869
int('00010010'
'01101110'
'01011101'
'11010101', 2)
arrays
1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
[18, 110, 93, 213]
[int('00010010', 2),
int('01101110', 2),
int('01011101', 2),
int('11010101', 2)]
0 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 |
0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
structures
1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
0 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
1 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
(54621, 110, 18)
(int('11010101'
'01011101', 2),
int('01101110', 2),
int('00010010', 2))
0 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
bit fields
(13, 21974, 3602)
(int('1101', 2),
int( '0101'
'01011101'
'0110', 2),
int( '1110'
'00010010', 2))
1 | 1 | 0 | 1 |
1 | 1 | 0 | 1 |
0 | 1 | 0 | 1 |
1 | 1 | 0 | 1 |
0 | 1 | 0 | 1 |
1 | 1 | 0 | 1 |
0 | 1 | 0 | 1 |
1 | 1 | 0 | 1 |
C: struct
typedef struct
{
unsigned version: 4;
unsigned header_length: 4;
unsigned services: 6;
unsigned congestion: 2;
uint16_t total_length;
uint16_t identification;
unsigned flags: 3;
unsigned fragment: 13;
uint8_t time_to_live;
uint8_t protocol;
uint16_t header_checksum;
uint8_t source[4];
uint8_t destination[4];
} __attribute__((packed)) IPv4Header;
C: struct
char *data = "\x45\x00\x00\x54\x17\x61\x40\x00"
"\x40\x01\x21\x37\xc0\xa8\x0b\x12"
"\xd4\x4d\x62\x09";
IPv4Header *header = (IPv4Header*)data;
printf("total length: %hu\n",
ntohs(header->total_length));
Python: struct
header = struct.unpack('!' # network endian
'B' # version, header_length
'B' # services, congestion
'H' # total_length
'H' # identification
'H' # flags, fragment
'B' # time_to_live
'B' # protocol
'H' # header_checksum
'4B' # source
'4B', # destination
data)
print("total length:", header[2])
Python: CTYPES
class IPv4Header(ctypes.BigEndianStructure):
_fields_ = (
('version', ctypes.c_uint, 4),
('header_length', ctypes.c_uint, 4),
('services', ctypes.c_uint, 6),
('congestion', ctypes.c_uint, 2),
('total_length', ctypes.c_uint, 16),
('identification', ctypes.c_uint, 16),
('flags', ctypes.c_uint, 3),
('fragment', ctypes.c_uint, 13),
('time_to_live', ctypes.c_uint, 8),
('protocol', ctypes.c_uint, 8),
('header_checksum', ctypes.c_uint, 16),
('source', ctypes.c_byte * 4),
('destination', ctypes.c_byte * 4)
)
header = ctypes.cast(data,
ctypes.POINTER(IPv4Header)).contents
print("total length:", header.total_length)
Python: bitstring
header = bitstring.Bits(data).unpack((
'uint:4 = version',
'uint:4 = header_length',
'uint:6 = services',
'uint:2 = congestion',
'uintbe:16 = total_length',
'uintbe:16 = identification',
'uint:3 = flags',
'uint:13 = fragment',
'uint:8 = time_to_live',
'uint:8 = protocol',
'uintbe:16 = header_checksum',
'bytes:4 = source',
'bytes:4 = destination',
)))
print("total length:", header[4])
a tale of one protocol
stream = bitstring.BitStream(network_pdu)
ivi, nid, ctl, ttl, seq, src, dst = stream.readlist(NET_HEADER_FORMAT)
NET_HEADER_FORMAT = (
'uint:1 = ivi',
'uint:7 = nid',
'uint:1 = ctl',
'uint:7 = ttl',
'uintbe:24 = seq',
'uint:16 = src',
'uint:16 = dst')
a tale of one protocol
a tale of one protocol
CTL 0
SEG 0
CTL 0
SEG 1
CTL 1
SEG 0
CTL 1
SEG 1
a tale of one protocol
UNSEGMENTED_ACCESS = ('uint:1 = 0',
'uint:1 = akf',
'uint:6 = aid',
'bits = upper_transport_pdu')
SEGMENTED_ACCESS = ('uint:1 = 1',
'uint:1 = akf',
'uint:6 = aid',
'uint:1 = szmic',
'uint:13 = seq_zero',
'uint:5 = seg_o',
'uint:5 = seg_n',
'bits = segment')
UNSEGMENTED_CONTROL = ('uint:1 = 0',
'uint:7 = opcode',
'bits = parameters')
SEGMENTED_CONTROL = ('uint:1 = 1',
'uint:7 = opcode',
'uint:1 = 0', # RFU
'uint:13 = seq_zero',
'uint:5 = seg_o',
'uint:5 = seg_n',
'bits = segment')
stream = bitstring.BitStream(network_pdu)
ivi, nid, ctl, ttl, seq, src, dst = stream.readlist(NET_HEADER_FORMAT)
seg = stream.peek('uint:1')
if ctl:
stream.readlist(SEGMENTED_CONTROL if seg else UNSEGMENTED_CONTROL)
else:
stream.readlist(SEGMENTED_ACCESS if seg else UNSEGMENTED_ACCESS)
a tale of one protocol
a tale of one protocol
privacyCounter = append(privacyCounter, ivindexL...) //+4
privacyCounter = append(privacyCounter, msgL[1 + 6 : 8 + 6]...) //+7
copy(dp.seq, packet[2:5])
copy(dp.src, packet[5:7])
dp.seqZero[0] = (dp.tcfBuffer[1] & 0x7f) >> 2
dp.seqZero[1] = dp.tcfBuffer[2]>>2 | ((dp.tcfBuffer[1] & 0x03) << 6)
dp.segO = dp.tcfBuffer[3]>>5 | ((dp.tcfBuffer[2] & 0x03) << 3)
dp.segN = dp.tcfBuffer[3] & 0x1f
var t uint32 = 0x00
t |= uint32(n - 1)
t |= uint32(i) << 5
t |= uint32(seq0[2]) << 10
t |= (uint32(seq0[1]) & 0x1F) << 18
dev_nonce = bitstring.pack('uint:8, uint:1, pad:7, uintbe:24, uintbe:16, uintbe:16, uintbe:32',
0x02, szmic, seq, src, dst, self.network.iv_index).bytes
access_payload = b'\x80\x05\x01' # health model attention set, timer = 1
encrypted_access_payload, trans_mic = aes_ccm(device.device_key.bytes, dev_nonce, access_payload)
transport_pdu = bitstring.pack('uint:1, uint:1, uint:6, bits, bits',
seg, akf, aid, encrypted_access_payload, trans_mic).bytes
net_nonce = bitstring.pack('pad:8, uint:1, uint:7, uintbe:24, uintbe:16, pad:16, uintbe:32',
ctl, ttl, seq, src, self.network.iv_index).bytes
encrypted_transport_pdu, net_mic = aes_ccm(encryption_key, net_nonce,
bitstring.pack('uintbe:16, bits',
dst, transport_pdu).bytes)
net_header = bitstring.pack('uint:1, uint:7, uintbe:24, uintbe:16',
ctl, ttl, seq, src).bytes
privacy_random = bitstring.pack('pad:40, uintbe:32, bits:56',
self.network.iv_index, encrypted_transport_pdu[:7]).bytes
pecb = aes_ecb(privacy_key, privacy_random)[:6]
net_header = bytes(map(operator.xor, net_header, pecb))
net_pdu = bitstring.pack('uint:1, uint:7, bits, bits, bits',
self.network.iv_index & 1, nid, net_header, encrypted_transport_pdu, net_mic).bytes
a tale of one protocol
THANK YOU
Binarki @ Silvair 11.2018
By Michał Lowas-Rzechonek
Binarki @ Silvair 11.2018
Processing binary and low-level data in Python
- 730