Hackvent_2023/Day 24/decode.py

96 lines
3.4 KiB
Python
Raw Permalink Normal View History

2023-12-26 15:17:56 +01:00
import struct
from hackingscripts import util
from PIL import Image
from pyzbar.pyzbar import decode
def bit_stream_to_qr(bit_stream, qr_size=(29, 32), pix_size=10):
img = Image.new("RGB", (qr_size[1] * pix_size, qr_size[0] * pix_size))
pix = img.load()
columns = ["" for r in range(qr_size[1])]
for i, b in enumerate(bit_stream):
columns[i % qr_size[1]] += b
for ci, column in enumerate(columns):
for ri, b in enumerate(column):
color = (0,0,0) if b == "1" else (255,255,255)
for xi in range(pix_size):
for yi in range(pix_size):
pix[ci*pix_size+xi,ri*pix_size+yi] = color
return img
def apply_scramble(data, loop_count, shift_direction, shift_type_1, shift_type_2):
for i in range(loop_count):
if shift_direction == 0:
if shift_type_1 != -1:
offset = 0x70 + shift_type_1
value = data[offset]
for x in range(0x1c+1):
data[offset] = data[offset - 4]
offset -= 4
data[offset + 4] = value
if shift_type_2 != -1:
offset = shift_type_2 * 4
value = data[offset]
for x in range(3+1):
data[offset] = data[offset + 1]
offset += 1
data[offset - 1] = value
elif shift_direction == 1:
if shift_type_2 != -1:
offset = 3 + shift_type_2 * 4
value = data[offset]
for x in range(3+1):
data[offset] = data[offset - 1]
offset -= 1
data[offset + 1] = value
if shift_type_1 != -1:
offset = shift_type_1
value = data[offset]
for x in range(0x1c + 1):
data[offset] = data[offset + 4]
offset += 4
data[offset - 4] = value
else:
raise
return data
def bytes_to_bit_stream(data, qr_size=(29, 32)):
bit_stream = ""
for v in data:
bit_stream += util.lpad(bin(v)[2:], 8, "0")
bit_stream = bit_stream[0:qr_size[0] * qr_size[1]]
return bit_stream
if __name__ == "__main__":
with open("HV23", "rb") as f:
prog_data = f.read()
QR_DATA = bytearray(prog_data[0x8a3e:0x8a3e+0x70+7])
SCRAMBLE_DATA = prog_data[0x628:0x628+0x60]
NUM_SCRAMBLES = 0x18
assert len(SCRAMBLE_DATA) == NUM_SCRAMBLES * 4
scrambles = []
for scramble in range(0, NUM_SCRAMBLES*4, 4):
scramble_data = SCRAMBLE_DATA[scramble:scramble+4]
shift_type_2, shift_type_1, loop_count, shift_direction = struct.unpack("bbBB", scramble_data)
scrambles.append((loop_count, shift_direction, shift_type_1, shift_type_2))
data = QR_DATA
while True:
for scramble in scrambles:
data = apply_scramble(data, *scramble)
bit_stream = bytes_to_bit_stream(data)
# last 3 columns are all white? we might have a valid QR-code
if all(bit_stream[row*32+29:row*32+32] == "000" for row in range(29)):
img = bit_stream_to_qr(bit_stream)
decoded_objects = decode(img)
if decoded_objects:
img.save(f"qr_code.png")
print("[+] Flag:", decoded_objects[0].data.decode())
exit()