First Look: Ghidra 10.3 Emulator

Craig Young
5 min readMay 13, 2023

--

Ghidra 10.3 dropped this week with a dedicated Emulator tool! I’ve been eagerly anticipating such a feature and so I am very excited that it is available in time for Black Hat USA this year. I’ve spent the morning tinkering and I’m pleasantly surprised with how performant and intuitive it is to use. In this post, I’ll share a little of what I have learned by walking you through analysis of a reversing challenge.

UPDATE 3/2/24: Registration is currently open for “A Basic Guide to Bug Hunting with Ghidra” at Black Hat USA 2024. The two day class will be offered August 3–4 and again August 5–6.

The example this week is called sneaker and you can download the binary from https://secur3.us/GhidraFiles/sneaker to follow along.

After importing and analyzing the binary, you should end up with a Ghidra main() decompilation that looks like:


undefined8 FUN_00101352(void)

{
char *__s;
int iVar1;
ulong uVar2;
undefined8 uStack_a0;
undefined4 local_98 [4];
undefined4 local_88;
undefined4 local_84;
undefined4 local_80;
undefined4 local_7c;
undefined4 local_78;
undefined4 local_74;
undefined4 local_70;
undefined4 local_6c;
undefined4 local_68;
undefined4 local_64;
undefined4 local_60;
undefined4 *local_50;
long local_48;
int local_3c;

local_98[0] = 5;
local_98[1] = 6;
local_98[2] = 0xffffffff;
local_98[3] = 4;
local_88 = 6;
local_84 = 9;
local_80 = 0xfffffffc;
local_7c = 0xffffffff;
local_78 = 10;
local_74 = 0xfffffffc;
local_70 = 0xfffffffa;
local_6c = 9;
local_68 = 0xfffffffc;
local_64 = 0xb;
local_60 = 10;
local_3c = 0xf;
uStack_a0 = 0x1013fe;
FUN_0010122e(local_98,0xf,8);
iVar1 = local_3c;
local_48 = (long)(local_3c + 1) + -1;
uVar2 = ((long)(local_3c + 1) + 0xfU) / 0x10;
local_50 = local_98 + uVar2 * -4;
(&uStack_a0)[uVar2 * -2] = 0x10146d;
FUN_001012b8(local_98,local_98 + uVar2 * -4,iVar1);
__s = (char *)local_50;
(&uStack_a0)[uVar2 * -2] = 0x101479;
puts(__s);
return 0;
}

Reading over this, we see various stack variables initialized and then passed to two functions before some result is printed with puts. Looking over the Function Call Graph, we can see that the program is structured with a few layers of functions:

Ghidra Function Call Graph of sneaker
Function Call Graph

Similar to the Debugger lesson, we could work through the code to decipher what is being printed, but it will be tedious. Instead, we will let Ghidra do the heavy lifting by running this in an emulated trace and then inspecting the memory before the puts call.

Ghidra 10.3 or newer is required to use this feature. In this version, you can open Emulator tool by clicking the new tool icon shown below between the Debugger and Version Tracker tools:

Emulator is the middle icon between Debugger and Version Tracker

Open sneaker in the Emulator by dragging it to this icon:

Ghidra Emulator Tool
Default Layout of Emulator Tool

Proceed to find main by scrolling down in entry and locating the call to __libc_start_main:

Entry point
__libc_start_main invocation

FUN_004007af is the main function. Double-click that symbol to jump the cursor to the start of main:

main()
main() from sneaker

At this point, we can start emulating the program from here in a new trace by clicking the Emulator icon on the toolbar or using the menu option at Debugger->Emulate Program in New Trace.

The Dynamic view will now come alive as Ghidra starts emulating the program:

Ghidra Emulator Started
Emulating sneaker

From here, things work similar to being in the Debugger with a trace being recorded. We can scroll to the end of the function and set a breakpoint immediately at the puts to make short work of deciphering this mess:

Target for breakpoint

Press ‘k’ to load the ‘Toggle Breakpoint’ window and accept the defaults:

Toggle a Breakpoint by pressing ‘k’

After setting the Breakpoint, the Breakpoints plugin should show that it is set in the program (top) and assigned within the emulator (bottom).

Breakpoints Debugger View

With the breakpoint in place, you can click the ‘Resume’ button (or F5 on Windows) to run the emulation. The Emulator tool should look similar to the following when it hits the breakpoint:

Breakpoint reached

Switching to the ‘Registers’ plugin from the Debugger views, we can see the address in RDI and jump to it in the emulated RAM by right-clicking as shown below:

Registers view shows the emulated CPU state

Doing so brings us to the Dynamic view where the output of the secret functions can be viewed with ease:

Dynamic view of data pointed from RDI

Using the keyboard shortcut (‘) you can retype this to a char and then to a defined string to make it more readable:

Using ‘ allows us to retype this as a defined string

And there you have it, Ghidra’s emulator has run the program and computed it’s output!

Join Me At Black Hat To Learn More

As always, I hope you have enjoyed reading this post. If you found this interesting and want to learn more, please consider joining me in Vegas this summer for ‘A Guide to Reversing with Ghidra’. The class is offered twice, Saturday/Sunday and Monday/Tuesday. Early-bird pricing is still available but spaces are limited so please reserve your space today!

Weekend Class Registration

Monday/Tuesday Registration

--

--

Craig Young

I’m a 15-year veteran of the infosec industry with 200+ CVEs, two USENIX papers, a Pwnie award, and a bunch of bounties to my name. Currently teaching Ghidra.