First steps with Ghidra: crackme01

Jean-Michel Amblat
5 min readApr 11, 2019

--

Unless you have been sleeping under a rock lately, you have likely heard about a new intriguing tool released by the NSA: Ghidra.

This open-source reverse engineering gem is quite refreshing, and I wanted to provide a quick overview by solving an entry-level crackme file.

A crackme (often abbreviated by cm[citation needed]) is a small program designed to test a programmer’s reverse engineering skills

Wikipedia

I do enjoy Capture-The-Flag (if this sounds like gibberish: pause here and check out https://ctftime.org/ctf-wtf) events even if it is harder to find the time lately . I recently had some fun with the binary section of a recent EncryptCTF. This post is about solving the crackme01 beginner challenge using Ghidra.

First things first: download the binary and try to get a basic idea of what we’re dealing with:

Simple ELF 64-bit binary — crackme01 from EncryptCTF

(*) Be cautious when working with untrusted binaries. At the minimum, you should always analyze them within a sandboxed and clean environment, ideally restored from a trusted snapshot or backup.

A quick check reveals that it appears to be a Linux 64-bit binary, stripped (no symbols or helpful debugging information).

Installing Ghidra is easy, as long as you follow the instructions at https://ghidra-sre.org/InstallationGuide.html and know your Java installation path.

Now, load Ghidra using ghidraRun create a project, and then import the crackme01 file (press 'I' or drag and drop the files directly).

Ghidra launch — you need to create a project and insert files for analysis

Double-click on the file, then, after using the default options and enabling Analysis, you will see the workspace below. You may notice that there is currently nothing listed on the right side.

Ghidra main interface after loading something

Now that we are ready to start, let’s hunt for the entry point and see what Ghidra can help us with: we first want to search for the main function, but as we can quickly see, there is no main function. Therefore, we start by looking at the entry function, which is the first function called during runtime.

When selecting “entry”, notice on the right side the decompiler window gets finally busy and gives us an approximate C code, quite easy to read:

This decompiled output is quite valuable and is a very compelling argument for using Ghidra.

For purists, according to http://refspecs.linuxbase.org/LSB_3.0.0/LSB-PDA/LSB-PDA/baselib---libc-start-main-.html: “The __libc_start_main() function shall initialize the process, call the main function with appropriate arguments, and handle the return from main()”.

In our case, double-click on the first argument: FUN_00101179, to enter our main function and see how really cool this decompiled view looks.

At this stage, if you know some C, you could easily figure out the flag by carefully examining the printf() statements while avoiding entering any block with exit(0).

The Ghidra way

Let’s push aside that temptation and get further into Ghidra’s features to discover and refine the C output we have obtained (the following process can be reused to have more fun next time when working on something more complex to reverse engineer):

  • Right click on the FUN_00101179 and change it to “main”;
  • Right click on undefined8 and use “Edit function signature” to change the return type to int (since you noticed “return 0” at the end of the code);
  • Based on fgets(&local_28,0x14,stdin) and man 3 fgets: “fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. […]”: right click and rename local_28 to user_input;
  • Based on local_26 == 1, change type from char local_26 to int_local_26 via right click:
change from char to int

Here is where we are now:

Now that the code is even easier to read, we could save it as crackme01.c. Then, we can inject two new lines at the top to have it almost ready for compilation:

#include <stdlib.h>
#include <stdio.h>

Lastly, let’s add some declarations to pass conditional branches:

  • char local_27 = ‘D’
  • int local_26 = 1
  • comment all the branch code sections leading to exit(0);

Final code should look like this:

Compile and run:

75 points

As a final note on interesting features, Ghidra allows us to patch instructions (using CTRL + SHIFT + G), transforming things like conditional jumps (think JNZ to JZ and so on) into simple jumps, and so on. This is an exciting feature to bypass protections, simplify the logic, and eventually provide less complex and more readable output in the decompiler view. Perhaps more on this in another post.

I hope this quick intro to Ghidra has sparked some interest. At the very least, it should equip you to solve entry-level binary challenges in most CTFs or even have a better way to look at this new binary you discovered during your last investigation.

--

--

Jean-Michel Amblat

#infosec #redteam #blueteam #privacy fun in NYC. @sourcefrenchy on Twitter.