Challenge Overview
The binary loops over a hidden 40-entry table in its .data section. Each inner iteration does:
imul rax, r8 ; A *= i
add rax, rax ; A += A
add rax, r8 ; A += i
add rax, 1 ; A += 1
mov rdx, [rip+DATA_TABLE@GOTPCREL]
mov rdx, [rdx+rcx*8] ; load DATA_TABLE[j]
add rax, rdx ; A += DATA_TABLE[j]
After each full inner loop for index i (0 ≤ j ≤ i), the low byte of A is taken as the flag byte.
Extracting the Table
Dump the raw .data section and copy the 320 hex bytes:
objdump -s -j .data the_old_way.exe > data_dump.txt
Copy the 40×8 bytes (no spaces) into the Python script below.
Python Recovery Script
#!/usr/bin/env python3
from struct import unpack
hexdata = (
"INSERT_ALL_320_HEX_BYTES_HERE"
)
data_bytes = bytes.fromhex(hexdata)
DATA_TABLE = list(unpack("<40Q", data_bytes))
flag_bytes = []
for i in range(40):
A = 0
for j in range(i+1):
# A = A * i + A + i + 1
A = A * i
A = A + A
A = A + i
A = A + 1
A = (A + DATA_TABLE[j]) & 0xFFFFFFFFFFFFFFFF
flag_bytes.append(A & 0xFF)
flag = bytes(flag_bytes).decode('ascii')
print(flag)
Explanation
-
Table Recovery
We useobjdump -sto grab the entire.datablock, then slice out the 320 bytes that form a 40-entry 64-bit table. -
Loop Emulation
The script re-implements the inner loop arithmetic and adds the corresponding table entry. -
Flag Extraction
For eachi, the script appends the low byte ofA. Joining these yields the ASCII flag.
Conclusion
By dumping the .data section and faithfully re-implementing the loop, we recover the 40-byte flag without patching or dynamic tracing.