Rating: 5.0
Upon reverse engineering the 32-bit binary `runme`, you will notice that all of the assembly instructions are `mov` instructions, which makes the machine incredibly difficult to decipher with decompilers or debuggers. In other words, this binary was obfuscated using the [movfuscator](https://github.com/xoreaxeaxeax/movfuscator) tool. Running the binary will print out two questions that need to be answered, as the flag consists of the answers to the two questions:
```
Question 1: How many instructions does this binary execute?
Question 2: What is the hidden message generated by this binary?
Flag format: texsaw{answer1_answer2}
```
In the hints folder are two binaries and two text files. The names of the hint binaries (`isuggestIDAfree1` and `isuggestIDAfree2`) suggests that they should be opened in the free version of IDA.
prisoner.txt contains the following message:
```
Grrr... first they have the gall to make a mov-ridden mess of my binary, and then they have the nerve to trap me in this text file!
Oh, if only there was a way to undo this whole mess.
I wonder if the person who made that stupid tool has any others up their sleeve...
```
This hints you to look up how to deobfuscate movfuscated binaries (which we will get to later when we look at the demovfuscator). It also hints you to search for the author of the movfuscator tool, who is Christopher Domas. If you find Domas's GitHub account and look through his other repos, you will find the tool [REpsych](https://github.com/xoreaxeaxeax/REpsych), which was used to create the two hint binaries.
wise_person.txt contains the following message:
```
Sometimes, if you find your banging your head against a wall in frustration, it may help to zoom out for a little perspective, and mayb change the colors of your lenses too.
```
~~I just now realized the typos...~~
It basically suggests that, for each hint binary opened in IDA Free, you must zoom out the control flow graph (CFG) view of the binary to see the entire graph (which may require increasing the number of allowed graph nodes and changing your graph color in your settings), which ends up revealing a hidden image.
### Part 1: Counting the Number of Instructions *Executed*
The hint image in isuggestIDAfree1's CFG is shown below:
It says "PERHAPS THIS BINARY INSTRUMENTATION TOOL WILL HELP YOU", followed by an image of a pin. If you look binary instrumentation tools that have "pin" in their name, you will quickly find a binary instrumentation framework called `Intel Pin` (aka Pintools). You can use Pintools to answer question 1 by creating a C++ program that counts the number of instructions executed by `runme`. You can either write, compile, and run your own program, or you can compile and run the sample program icount (which comes with your download of Pintools), whose source code is shown below:
```
/*
* Copyright (C) 2004-2021 Intel Corporation.
* SPDX-License-Identifier: MIT
*/
/*! @file
* This file contains an ISA-portable PIN tool for counting dynamic instructions
*/
#include "pin.H"
#include <iostream>
using std::cerr;
using std::endl;
/* ===================================================================== */
/* Global Variables */
/* ===================================================================== */
UINT64 ins_count = 0;
/* ===================================================================== */
/* Commandline Switches */
/* ===================================================================== */
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
cerr << "This tool prints out the number of dynamic instructions executed to stderr.\n"
"\n";
cerr << KNOB_BASE::StringKnobSummary();
cerr << endl;
return -1;
}
/* ===================================================================== */
VOID docount() { ins_count++; }
/* ===================================================================== */
VOID Instruction(INS ins, VOID* v) { INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END); }
/* ===================================================================== */
VOID Fini(INT32 code, VOID* v) { cerr << "Count " << ins_count << endl; }
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char* argv[])
{
if (PIN_Init(argc, argv))
{
return Usage();
}
INS_AddInstrumentFunction(Instruction, 0);
PIN_AddFiniFunction(Fini, 0);
// Never returns
PIN_StartProgram();
return 0;
}
/* ===================================================================== */
/* eof */
/* ===================================================================== */
```
##### Alternative Solution
You could use the `perf` command in Linux by running the command `perf stat -e instructions ./runme`, which will give you a similar instruction count via its own binary instrumentation. However, I still think that knowing how to do binary instrumentation on your own is a good skill to have.
### Part 2: Uncovering the Hidden Message
The hint image in isuggestIDAfree2's CFG is shown below (zooming out on this page should make the messsage esaier to read):
It says "YOU CANNOT REPAIR ALL THE DAMAGES. HOWEVER, RESTORE THE CONTROL FLOW YOU MUST.", followed by a picture of Yoda. After doing some Googling, you will realize that the hint points you to a tool called the [demovfuscator](https://github.com/leetonidas/demovfuscator), which recovers the explicit control flow of a movfuscated binary and resubtitutes some instructions in the movfuscated binary to create a patched version of the binary. You must use the demovfuscator to generated a patched version of the `runme` binary and an image containing the control flow graph of the patched runme, which is done by running the command `./demov -o runme_patched -g cfg.dot runme` (to generate a patched version of `runme` called `runme_patched` and a CFG file), followed by the command `cat cfg.dot | dot -Tpng > cfg.png` (to convert the CFG file into a viewable image). Below is an example of the CFG image generated for runme:
If you look for symbols in the `runme` binary, you will find tht the binary is not stripped. You will find a series of functions called `letter1`, `letter2`, `letter3`, ..., `letter16` that are called by the main function.
Each letter function computes and returns a letter of the hidden message requested by question 2, but the letters are not stored in any char or buffer variables, though you will not be able to easily discern that from reading the assembly or decompiled code. If you run `runme_patched` in gdb and set breakpoints at the addresses specified in the control flow graph image, you will eventually find that at the breakpoints after a letter function has "returned," the char that the function returned will be stored on the stack. In my case, the characters returned by each letter function were always located at `$esp+72` on the stack at the respective breakpoints. Putting these 16 characters together will give you the message "miles_to_my_home", which is the answer to question 2. Bonus points if you can figure out how to solve this part using Pintools or another binary instrumentation framework.
### The Flag
Due to the variance in instruction counts between different environments and due to the slight differences in how Pintools and perf count instructions, any flag with an instruction count between 320,000 and 390,000 instructions is considered valid. This is modeled by the following regex that was used to parse and accept valid flags for the competition: `texsaw{3[2-8][0-9],?[0-9]{3}_miles_to_my_home}`
Below are some examples of flags that are valid for this challenge:
`texsaw{356074_miles_to_my_home}`
`texsaw{326692_miles_to_my_home}`
`texsaw{356,074_miles_to_my_home}`
`texsaw{326,692_miles_to_my_home}`