← Back to Writeups
CUSTOMEasyReversing

RE4_JoeFain

XESXOR9/10/20263 min read
#reversing#custom#easy#arithmetic_reconstruction#diophantine_system_solving#scanf_argument_order_analysis#trivial_root_recognition#windows

RE4_JoeFain

Platform: rev_kids20 | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: Windows | Author: XESXOR | Date: 2026-06-15 | Status: Solved Techniques: arithmetic_reconstruction, diophantine_system_solving, scanf_argument_order_analysis, trivial_root_recognition

Summary

Task: 32-bit PE32 console binary reads two integers via scanf and checks two integer polynomial constraints; flag is the input without spaces. Solution: reconstruct the two polynomials from radare2 disassembly, determine scanf argument order from cdecl push order, and solve the Diophantine system (sympy) to get the non-trivial root (a=-5, b=4) -> input '4 -5' -> flag 'REDACTED'.

RE4_JoeFain — rev_kids20

Description

Flag is your input without spaces

English summary: A 32-bit PE32 console executable JoeFain.exe (Intel 80386, MS Windows) prints Input complex number: >, reads two integers with scanf("%d %d"), evaluates two integer polynomial expressions of those inputs, and prints You are welcome! on success or Go out of here! otherwise. The flag is the accepted input with spaces removed.

Analysis

file JoeFain.exe → PE32 executable, Intel 80386, console subsystem. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Disassembling main with radare2 reveals:

  • scanf("%d %d", &v1, &v2) is called. Under cdecl, arguments are pushed right-to-left, so the push order maps the FIRST typed number to v2 (kept in ebx, call it b) and the SECOND typed number to v1 (kept in ecx, call it a).

  • Two integer polynomial expressions are computed from (a, b) via the usual imul / lea / neg / shl arithmetic sequences:

    edx = (b*b - a*a - 1) - 5*b - 6*a
    eax = 2*a*b - 5*a + 6*b - 9
    

‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

  • A special-case guard: if b == 1 AND a == -1, the program prints Almost. But the root is too simple. — this deliberately rejects the trivial root of the system.
  • Success (You are welcome!) requires edx == 0 AND eax == 0.

So we must satisfy the system while avoiding the rejected trivial root.

Solution

Solve the integer system:

b*b - a*a - 1 - 5*b - 6*a == 0
2*a*b - 5*a + 6*b - 9 == 0
python
#!/usr/bin/env python3
from sympy import symbols, Eq, solve

a, b = symbols('a b', integer=True)
sols = solve(
    [Eq(b*b - a*a - 1 - 5*b - 6*a, 0),
     Eq(2*a*b - 5*a + 6*b - 9, 0)],
    [a, b],
)
print(sols)   # [(-5, 4), (-1, 1)]

‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Two integer solutions exist:

  • (a=-1, b=1) — the trivial root, explicitly rejected by the binary.
  • (a=-5, b=4) — the valid root.

Recall the scanf order: FIRST number = b = 4, SECOND number = a = -5. So the input is 4 -5. The flag is the input without spaces: REDACTED.

A quick brute-force confirmation instead of sympy:

python
for a in range(-50, 51):
    for b in range(-50, 51):
        if (b*b - a*a - 1 - 5*b - 6*a) == 0 and (2*a*b - 5*a + 6*b - 9) == 0:
            print(a, b)   # (-5, 4) and (-1, 1)

‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

The "complex number" framing hints the two integers are the real/imaginary parts; concatenating them without the separating space yields the flag. The challenge also accepted equivalent encodings (-54, 4,-5, -5,4), but the canonical answer is REDACTED. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍