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.
Setup
Open the dump and focus on the MOV/IMUL/ADD sequence in main.
wget https://artifacts.picoctf.net/c/530/disassembler-dump0_c.txtcat disassembler-dump0_c.txtSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Translate each constant
ObservationA MOV loads a constant into EAX and an IMUL and an ADD follow. Walk the instructions in order and treat EAX as an accumulator that changes at every step.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 + 501into 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 likemov 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.Step 2Output the decimal flag
ObservationThe answer wants decimal and every constant in the dump is hex. Let Python evaluate the literals and print the result.Compute (0x9fe1a * 4) + 0x1f5 = 2,619,997. Wrap picoCTF{...}.pythonpython3 - <<'PY' print((0x9fe1a * 4) + 0x1f5) PYExpected 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 runs line by line: the multiply happens first, then the add. Swap them and you get a different number entirely. The order in the dump is the order that ran.
Learn more
Python is an excellent calculator for this kind of arithmetic because it understands hex literals natively. Writing
0x9fe1a * 4 + 0x1f5directly 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.