← Back to Writeups
CUSTOMEasyReversing

s7.out

XESXOR9/10/20263 min read
#reversing#custom#easy#backward_solving#constraint_solving#decompilation#static_analysis

s7.out

Platform: spbctf | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2020-01-01 | Status: Solved Techniques: backward_solving, constraint_solving, decompilation, static_analysis

Summary

s7.out — spbctf (rev-kids20)

Description

Language: C. Download binary: s7.out (ELF 32-bit) or s7.exe (PE32). Flag is the correct serial number.

Classic keygen challenge: reverse engineer a serial validation function and find the correct input that passes all checks. The flag is the serial number itself (no wrapper).

Analysis

Binary Information

  • s7.out: ELF 32-bit LSB executable, Intel 80386, dynamically linked, not stripped (7444 bytes)
  • s7.exe: PE32 executable (console) Intel 80386 (2560 bytes)
  • Not stripped — function names visible including _Z5CheckPc (C++ mangled name for Check(char*)) ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Check Function Logic

Decompilation of the Check function revealed three validation constraints:

c
void Check(char* input) {
    int len = strlen(input);
    
    // Constraint 1: length must be 6
    if (len != 6) { fail; }
    
    // Constraint 2: last char must be 'x' (0x78)
    if (input[5] != 'x') { fail; }
    
    // Constraint 3: each char = previous char + index
    bool ok = true;
    for (int i = 1; i < len; i++) {
        if (input[i] != input[i-1] + i) {
            ok = false;
            break;
        }
    }
    
    PrintOK(ok);
    PrintError(!ok);
}

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

Constraints Summary

  1. Length check: strlen(input) == 6 — serial must be exactly 6 characters
  2. Last character check: input[5] == 0x78 — last character must be 'x' (ASCII 120)
  3. Recurrence relation: For i from 1 to 5: input[i] == input[i-1] + i — each character equals the previous one plus its index

Solution

The recurrence relation input[i] = input[i-1] + i combined with the known last character allows us to work backwards:

python
#!/usr/bin/env python3
# Solve s7.out serial validation
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

# Known: input[5] = 'x' (ASCII 120)
# Relation: input[i] = input[i-1] + i
# Therefore: input[i-1] = input[i] - i

serial = [0] * 6
serial[5] = ord('x')  # 120

# Work backwards
for i in range(5, 0, -1):
    serial[i-1] = serial[i] - i

# Convert to string
result = ''.join(chr(c) for c in serial)
print(f"Serial: {result}")

# Verify
print("\nVerification:")
print(f"Length = {len(result)} (expected 6)")
print(f"Last char = '{result[5]}' (expected 'x')")
for i in range(1, 6):
    diff = ord(result[i]) - ord(result[i-1])
    print(f"serial[{i}] - serial[{i-1}] = {ord(result[i])} - {ord(result[i-1])} = {diff} (expected {i})")

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

Manual Calculation

Working backwards from input[5] = 'x' (ASCII 120):

IndexCalculationASCIICharacter
5given120'x'
4120 - 5115's'
3115 - 4111'o'
2111 - 3108'l'
1108 - 2106'j'
0106 - 1105'i'

Verification

All checks pass:

  • Length = 6 ✓
  • Last char = 'x' ✓
  • serial[1] - serial[0] = 106 - 105 = 1 ✓
  • serial[2] - serial[1] = 108 - 106 = 2 ✓
  • serial[3] - serial[2] = 111 - 108 = 3 ✓
  • serial[4] - serial[3] = 115 - 111 = 4 ✓
  • serial[5] - serial[4] = 120 - 115 = 5 ✓ ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍