$ Rev: gcc

BITSCTF 2026 By TaklaMan
Flag: BITSCTF{n4n0m1t3s_4nd_s3lf_d3struct_0ur0b0r0s}

Summary

The binary is a stripped 64-bit PIE ELF that behaves like a wrapper around gcc, but it contains a self-modifying/self-erasing mechanism.

A hidden 64-byte region in the binary (.data, file offset 0x3020) is decrypted at runtime with a key derived from the binary contents itself. The first 8 decrypted bytes must match BITSCTF{ to pass an internal check.

By reimplementing the same logic offline on a fresh copy from chall.zip, the flag can be recovered directly.

High-Level Behavior

  1. ghost_compiler scans its own file for an 8-byte marker pattern stored at runtime in .data.
  2. It computes a hash of the file while skipping a 64-byte window starting at that marker offset.
  3. A key is derived from the hash.
  4. The 64-byte hidden block is XOR-decrypted with a rotating key stream.
  5. If decrypted prefix is BITSCTF{, execution continues.
  6. It then zeroes (memset) the same 64-byte region and writes the file back, so later runs lose the embedded secret material.

Important Reversed Components

  1. Marker search function (.text+0xe9 at 0x1349)
  • Opens target file in rb mode.
  • Searches for an 8-byte sequence beginning with first byte at 0x4020.
  • Returns the first match offset.
  1. Hash/key derivation (.text+0x265 at 0x14b5)
  • Implements FNV-1a style hashing:
    • init: 0xcbf29ce484222325
    • prime: 0x100000001b3
  • Skips bytes in [offset, offset+0x3f].
  • Returns: hash ^ 0xcafebabe00000000.
  1. Decryption & prefix check (.text+0x333 at 0x1583)
  • For 64 bytes:
    • out[i] = enc[i] XOR (key & 0xff)
    • rotate key right by 1 each byte (ror 64-bit, 1)
  • Validates first 8 output bytes as:
    • 42 49 54 53 43 54 46 7b -> BITSCTF{
  1. Self-erase step (.text+0x5c0 onward)
  • If checks pass, it wipes 64 bytes at found offset with zeros.
  • Rewrites the input file and continues to build a gcc ... command.

Why Fresh Binary Matters

The binary modifies itself. If executed once, the secret block may be overwritten, preventing later extraction. Recovering from a clean copy in chall.zip is essential.

Reproduction Script Logic (used)

  • Extract fresh ghost_compiler.
  • Locate marker at 0x3020.
  • Recompute hash while skipping 64-byte protected window.
  • Derive 64-bit key: hash ^ 0xcafebabe00000000.
  • Decrypt 64 bytes with rolling XOR/rotate.
  • Read plaintext flag.