Description
The fourth assembly dump loads 0x9fe1a, then conditionally subtracts 0x65 (the value exceeds the 0x2710 threshold, so the SUB branch is taken instead of the ADD branch). Convert the result to decimal for the flag.
Setup
Fetch the dump and focus on the subtraction at <+31>.
wget https://artifacts.picoctf.net/c/511/disassembler-dump0_d.txtcat disassembler-dump0_d.txtSolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Track the operations
ObservationThere is a compare against 0x2710, a conditional jump, and two arithmetic branches. Evaluate the actual value against that threshold to see which branch runs before working out what EAX ends up holding.The stack slot [rbp-0x4] is assigned 0x9fe1a, then the dump compares that slot against 0x2710 and jumps to an ADD 0x65 branch if the value is less-than-or-equal; because 0x9fe1a (654874) exceeds 0x2710 (10000), the jle is not taken and the SUB 0x65 path runs instead. The final MOV then loads the updated slot into EAX just before the return, and nothing else touches it.Learn more
The SUB instruction subtracts a value from a register or memory location in place.
sub DWORD PTR [rbp-0x4],0x65means [rbp-0x4] = [rbp-0x4] - 0x65, and the value only reaches EAX through the load that follows. Like ADD, SUB modifies flags (carry, overflow, zero, sign) that conditional branches can test - but since this function just returns after the subtract, the flags are irrelevant here.A key skill this challenge reinforces is verifying that nothing between the arithmetic and the RET disturbs the value on its way into EAX. In a longer function there might be other instructions that modify the slot or the register - a second store, a CALL that clobbers EAX, or a conditional MOV. Confirming that the final value is indeed the post-subtraction result requires scanning every subsequent instruction for writes to either location.
This kind of careful instruction-by-instruction analysis is exactly what reverse engineers do when tracing through license-key validation routines, cryptographic transformations, or anti-debugging checks. The habit of asking "does anything modify this value before it reaches the point I care about?" prevents mistakes that could waste hours during a real engagement.
Step 2Compute the result
ObservationThe subtract branch is the one taken. Let Python do the arithmetic so the hex borrows take care of themselves and the decimal answer comes out clean.Evaluate 0x9fe1a - 0x65 = 654,773 and wrap it with picoCTF{...}.pythonpython3 - <<'PY' print(0x9fe1a - 0x65) PYExpected output
654773
What didn't work first
Tried: Subtract in the other direction: 0x65 - 0x9fe1a, expecting the smaller constant to be the minuend.
You get a large negative number because the operand order is reversed. The instruction subtracts the constant from the stored value, not the other way round. Keep the destination operand on the left.
Tried: Take the ADD branch result instead (0x9fe1a + 0x65 = 654,975) because the challenge description mentions both ADD and SUB paths.
The jump is not taken, because 654874 is greater than 10000, so control falls through to the subtract. The add path runs only when the value is at or below the threshold.
Learn more
Subtraction in hex follows the same rules as in decimal, but carries propagate in powers of 16 instead of 10.
0x9fe1a - 0x65: the low byte1a(26 decimal) minus65(101 decimal) would go negative, triggering a borrow, givingb5(181 decimal) in the result's low byte. Letting Python handle this avoids manual borrow tracking.Notice that 0x65 is the ASCII code for 'e'. While this is coincidental here, it illustrates how the same number carries different meanings depending on context - always ask whether a constant is meant to be an integer, a character, a flag bitmask, or something else. In this series the constants are pure integers, but in real binaries this ambiguity appears constantly.
Completing all four Bit-O-Asm challenges builds the core loop of assembly reading: locate the relevant instructions, trace the data flow, apply any arithmetic, and convert to the required representation. This loop scales directly to reading real compiler output, whether you are auditing a closed-source binary, analyzing a firmware image, or studying how a C compiler optimizes a particular expression.
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{...}
Double-check the direction of the subtraction: the stored value minus 0x65, not the other way around.