Ghidra – Part 1

The NSA has graciously released their long-awaited reverse engineering framework. Called Ghidra, this software reverse engineering suite comes complete with installation and support documentation, a quick-start guide, and multiple decompilers (including x86-64). This is a game changer. Better yet, since Ghidra is open source, the community has already kicked into gear developing new plugins and supporting new architectures. No longer will IDA Pro be the de-facto tool for professional and personal reverse engineering. With the cost of IDA being the primary issue, most students and non-professional practitioners of reverse engineering/exploitation did not have access to a solid decompiler. Now, the world is their oyster. This changes the game for CTF as well, I believe many more competitive teams will rise to the top in the coming years now that the cat is out of the bag. While discussing the implications of this release with a co-worker, he brought up a great point. Ghidra will become part of academia! RPISEC will probably incorporate Ghidra into their Modern Binary Exploitation course, Florida State University will probably incorporate Ghidra into their Offensive Security course, etc. This release is huge for the community, thank you NSA (and thank you USA taxpayers).

In this post, I’ll run through decompiling a CTF challenge from Boston Key Party 2016. The challenge will be solved in Part 2 of this series. The pwnable is called Simplecalc and can be downloaded here. Booting up Ghidra, you are greeted with a nice graphic and a Tip of the Day. Next up is creating a new project. Ghidra asks if you want to create a Non-Shared Project or a Shared Project. Ghidra supports collaborative reversing; multiple engineers can work on the same project simultaneously. From what I understand, the shared project feature works similar to git. You would reverse some functionality, add some comments, then “commit” your updates to the shared project. Then, the other engineers would be able to pull your changes. I haven’t confirmed this yet since today I’ll be creating a Non-Shared Project. In the new project, open the CodeBrowser, indicated by the dragon icon:

Clicking this, the giant dragon expands within the Ghidra window, the CodeBrowser launches, and you’re ready to start reversing. Importing the simplecalc pwnable in CodeBrowser, Ghidra auto-detects the architecture and we’re good to go:

After a few moments, I was greeted with an import result summary with lots of useful information as well as a prompt asking if I wanted to perform further analysis:

Selecting yes for more analysis, here are the offered options. I will get into these in a future post:

The analysis finishes very quickly for this small binary and I’m presented with a program tree, symbol tree, data type manager, assembly listing, decompile listing, and scripting console. This is the view after navigating to main():

Look at that decompile! Having done this challenge in the past and seen the IDA decompile, I attest that it looks accurate at first glance. Here is the decompile text:

undefined8 main(void)

{
  undefined local_48 [40];
  int local_20;
  int local_1c;
  void *local_18;
  int local_c;
  
  local_1c = 0;
  setvbuf((FILE *)stdin,(char *)0x0,2,0);
  setvbuf((FILE *)stdout,(char *)0x0,2,0);
  print_motd();
  printf("Expected number of calculations: ");
  __isoc99_scanf(&DAT_00494214,&local_1c);
  handle_newline();
  if ((local_1c < 0x100) && (3 < local_1c)) {
    local_18 = malloc((long)(local_1c << 2));
    local_c = 0;
    while (local_c < local_1c) {
      print_menu();
      __isoc99_scanf(&DAT_00494214,&local_20);
      handle_newline();
      if (local_20 == 1) {
        adds();
        *(undefined4 *)((long)local_c * 4 + (long)local_18) = add._8_4_;
      }
      else {
        if (local_20 == 2) {
          subs();
          *(undefined4 *)((long)local_c * 4 + (long)local_18) = sub._8_4_;
        }
        else {
          if (local_20 == 3) {
            muls();
            *(undefined4 *)((long)local_c * 4 + (long)local_18) = mul._8_4_;
          }
          else {
            if (local_20 == 4) {
              divs();
              *(undefined4 *)((long)local_c * 4 + (long)local_18) = divv._8_4_;
            }
            else {
              if (local_20 == 5) {
                memcpy(local_48,local_18,(long)(local_1c << 2));
                free(local_18);
                return 0;
              }
              puts("Invalid option.\n");
            }
          }
        }
      }
      local_c = local_c + 1;
    }
    free(local_18);
  }
  else {
    puts("Invalid number.");
  }
  return 0;
}

Seriously, what a tool. This has been a quick overview of Ghidra. Next post, we will use Ghidra to find the bug and pwn this challenge. After that, we’ll explore Shared Project and the analysis options.

Leave a Reply