Speakeasy supports interactive debugging of emulated binaries via the GDB Remote Serial Protocol. When enabled, the emulator pauses before the first instruction and waits for a GDB client to connect. You can then set breakpoints, inspect registers and memory, single-step, and continue execution — all through a standard GDB interface.
This uses the udbserver library, which hooks directly into the Unicorn emulation engine.
The GDB server support is an optional dependency. Install it with:
pip install speakeasy-emulator[gdb]Or if installing from source:
pip install -e ".[gdb]"speakeasy -t sample.exe --gdbThis starts the GDB server on the default port (1234). Speakeasy will print a message and block until a GDB client connects:
GDB server listening on port 1234, waiting for connection...
To use a different port:
speakeasy -t sample.exe --gdb --gdb-port 9999Note:
--gdbautomatically enables--no-mp(in-process emulation). This is required because the GDB server hooks are bound to a specific Unicorn engine instance and cannot cross process boundaries.
In another terminal, connect using gdb-multiarch (or your platform's GDB):
For a 32-bit x86 binary:
$ gdb-multiarch
(gdb) set architecture i386
(gdb) target remote localhost:1234For a 64-bit x86-64 binary:
$ gdb-multiarch
(gdb) set architecture i386:x86-64
(gdb) target remote localhost:1234Once connected, GDB will show the current stop position. From here you can debug normally.
Standard GDB commands work:
(gdb) info registers
(gdb) x/10i $pc
(gdb) break *0x10001000
(gdb) continue
(gdb) stepi
(gdb) x/32xb $esp
speakeasy -t malware.dll --gdb --gdb-port 1234$ gdb-multiarch
(gdb) set architecture i386
(gdb) target remote localhost:1234
(gdb) break *0x10001000
(gdb) continue
Breakpoint 1, 0x10001000 in ?? ()
(gdb) info registers
(gdb) x/10i $pcspeakeasy --target shellcode.bin --raw --arch x86 --gdb$ gdb-multiarch
(gdb) set architecture i386
(gdb) target remote localhost:1234
(gdb) stepi
(gdb) info registersspeakeasy -t rootkit.sys --gdb --gdb-port 4444$ gdb-multiarch
(gdb) set architecture i386:x86-64
(gdb) target remote localhost:4444
(gdb) continueIDA Pro's built-in GDB debugger can connect to the speakeasy GDB stub:
- Start speakeasy with
--gdb - In IDA, go to Debugger > Select debugger > Remote GDB debugger
- Set Hostname to
localhostand Port to1234(or your chosen port) - Click Debugger > Attach to process or Start process
The GDB server can also be enabled when using speakeasy as a library:
import speakeasy
se = speakeasy.Speakeasy(gdb_port=1234)
module = se.load_module("sample.dll")
# This will block waiting for GDB to connect before emulating
se.run_module(module)The GDB integration uses udbserver, which installs Unicorn hooks for breakpoints, watchpoints, and single-stepping. When gdb_port is set:
- Speakeasy loads the binary and sets up all its emulation hooks normally
- Speakeasy initializes the first run context (stack/arguments/registers), including setting PC to the run entry point
- Before the first
emu_start()call,udbserver()is called withstart_addr=0 - This blocks on a TCP accept, waiting for a GDB client
- The GDB client connects, sets breakpoints, and issues
continue udbserver()returns and emulation proceeds under GDB control- The udbserver hooks persist across all emulation runs (DllMain, exports, etc.)
- one session per process: udbserver uses global state internally, so only one GDB server can be active per process
- breakpoints persist across runs: Speakeasy executes multiple runs (for example DllMain and exports), and breakpoints remain active across run boundaries
- platform support: if your platform is unsupported by udbserver binaries,
--gdbfails with an import error