Backdoor CTF 2014 - Binary 200

A heavily obfuscated C++ program that hides a message. The trick is to follow the hint literally: preprocess, compile, execute — and remove a dead conditional along the way.

Task

Jill was high after consuming 2³ glasses of alcohol. In this state, he wrote a C++ program to hide a message, but he doesn't remember it now. Help him recover it. He managed to write a single line of comment.

We receive a file called obfuscated.cpp.

Source Code

The source is a mess of #define macros that rename everything — int, void, printf, main, even namespace. Trigraph sequences (??<, ~??~~>) are used in place of curly braces, which is a rarely-seen C/C++ feature.

#include<cstdio>
#include<cstdlib>
#define l101(a) rand()%a
#define zlz1 bbb
#define zz mmm
// ... (many more defines)
#define mlm printf
#define cfc int
#define fff main

ads aa bub;
bbbb fff() {
  l10l ll01 = l101((0x00f1b00>>4)+0x08ff08-354);
  mlm("%f%l%lld\n"+4, ffffff);
  f++;
  if(ll01<(ll01&-0x1))??<ff(); ggg();??~~>
}
// oops subtracted by 1 not keeping my base in mind

The hint at the bottom is: Preprocess → Compile → Execute.

Solution

Following the hint, first preprocess the file without compiling. The -trigraphs flag is needed to handle the trigraph sequences, and -E runs only the preprocessor:

g++ -trigraphs -E obfuscated.cpp > new.cpp
g++ new.cpp
./a.out
# 8243101811275816809

That number comes from this line after preprocessing:

printf("%f%l%lld\n" + 4, f);

Looking at new.cpp more carefully, there are calls to ff() and ggg() that never execute because they're inside a dead conditional — ll01 < (ll01 & -0x1) is always false. Remove the if so those functions run:

int main() {
  int ll01 = rand()%((0x00f1b00>>4)+0x08ff08-354);
  printf("%f%l%lld\n"+4, f);
  f++;
  // removed the if — ff() and ggg() now execute
  ff(); ggg();
}

Recompile and run:

g++ new.cpp
./a.out
# 8243101811275816809
# just_another_FLaG

The comment in the source said "oops subtracted by 1 not keeping my base in mind" — a nudge that something needed adjusting, which turned out to be removing the impossible conditional.

Encode just_another_FLaG with MD5 for the final flag.

Flag

Flag: a38834db6eb9d31e3c7e878bae3da748