Bit-O-Asm-3 picoGym Exclusive Solution

Published: March 5, 2024

Description

Trace the arithmetic in the third disassembly file: move 0x9fe1a into EAX, multiply by 4, and add 0x1f5. Convert the final value into decimal.

Open the dump and focus on the MOV/IMUL/ADD sequence in main.

bash
wget https://artifacts.picoctf.net/c/530/disassembler-dump0_c.txt
bash
cat disassembler-dump0_c.txt

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1
    Translate each constant
    Observation
    I noticed the disassembly dump contains a MOV instruction loading 0x9fe1a into EAX followed by IMUL and ADD instructions, which suggested tracing each instruction in sequence and treating EAX as an accumulator whose value changes with every operation.
    EAX first becomes 0x9fe1a, then is multiplied by 0x4, and finally 0x1f5 is added. Perform the arithmetic exactly as shown.
    Learn more

    This step introduces multi-instruction arithmetic tracing. Compilers routinely decompose high-level expressions like result = x * 4 + 501 into a sequence of assembly instructions, each modifying the same register. Reading the dump requires treating the register as an accumulator that changes with every instruction and tracking its value through the entire sequence.

    IMUL (Integer Multiply) multiplies the register by an immediate value and stores the product back in the same register. ADD adds an immediate value to the register. Both instructions modify EAX in place, so the order matters: multiply first, then add - not the other way around.

    This pattern mirrors the way compilers implement array indexing and struct field access. For instance, accessing array[i] where each element is 4 bytes compiles to something like mov eax, i; imul eax, 4; add eax, base_address. Recognizing these idioms lets you reconstruct the original high-level logic from the raw assembly, which is the core skill of reverse engineering.

  2. Step 2
    Output the decimal flag
    Observation
    I noticed the challenge asks for the final value in decimal and all constants in the dump are in hexadecimal, which suggested using Python to evaluate the hex literals directly and print the decimal result without any manual conversion.
    Compute (0x9fe1a * 4) + 0x1f5 = 2,619,997. Wrap picoCTF{...}.
    python
    python3 - <<'PY'
    print((0x9fe1a * 4) + 0x1f5)
    PY

    Expected output

    2619997
    What didn't work first

    Tried: Manually converting 0x9fe1a to decimal first, then doing all arithmetic in base 10

    Intermediate rounding or transcription errors accumulate when you convert each hex constant separately before multiplying. Python accepts hex literals directly, so writing 0x9fe1a * 4 + 0x1f5 avoids any conversion step and removes the opportunity for off-by-one mistakes from manual hex-to-decimal lookups.

    Tried: Adding 0x1f5 before multiplying by 4, reversing the instruction order

    Assembly executes line by line: IMUL runs first and produces 0x9fe1a * 4 = 0x27f868, then ADD appends 0x1f5. Swapping the operations yields (0x9fe1a + 0x1f5) * 4 = 2,621,500, a different number that does not match the flag. The order of instructions in the dump is authoritative.

    Learn more

    Python is an excellent calculator for this kind of arithmetic because it understands hex literals natively. Writing 0x9fe1a * 4 + 0x1f5 directly in Python gives the correct result without any manual conversion - you work in the same notation as the assembly listing.

    The here-document syntax (<<'PY' ... PY) passes a multi-line script to Python from the command line without needing a temporary file. This is a useful shell technique for quick computations in CTF work and scripting generally. Alternatively, python3 -c "print((0x9fe1a * 4) + 0x1f5)" achieves the same result on one line.

    Choosing the right tool for arithmetic conversions matters when time is limited in a CTF. Python handles arbitrarily large integers, understands hex and binary literals, and is available on virtually every Linux system - making it the default choice for quick calculations in competitive security contexts.

Interactive tools
  • Hex ViewerView text or raw hex bytes as a xxd-style hex dump with byte offset, hex columns, and ASCII sidebar. Highlights printable characters and null bytes.
  • Number Base ConverterConvert numbers between binary, octal, decimal, and hexadecimal instantly. Enter any value and see all four bases update in real time.

Flag

Reveal flag

picoCTF{...}

The dump intentionally includes unused instructions; only the highlighted arithmetic matters for the flag.

Key takeaway

Compilers translate high-level arithmetic expressions into sequences of IMUL and ADD instructions that each modify a register in place, and the order determines the result. This same multiply-then-add pattern appears in array index calculations, struct field offsets, and hash functions, so recognizing it lets you reconstruct the original source logic from raw assembly. In reverse engineering, the critical habit is treating a general-purpose register as a running accumulator: record its value after every instruction and never assume you know what it holds until you have traced the entire sequence.

Related reading

Want more picoGym Exclusive writeups?

Useful tools for Reverse Engineering

Do these first

What to try next