Ghidra Printf String Inliner

August 21, 2025 · View on GitHub

Inline printf-style messages directly into Ghidra's decompiled view, with smart detection for Go and C, variable cleanup, and readable formatting.

Features

  • Go-aware printf inlining: detects fmt.Printf/friends, even when format strings are concatenated in a single large constant
  • Splits a large banner of messages into individual lines and assigns them to calls in code order
  • Rejects Go-internal garbage (e.g., reflect.Value, runtime.) and binary noise
  • Rewrites decompiled code preview with:
    • Clean printf("…", args); lines
    • Blank line before and after each inserted printf, preserving indentation
    • Removal of temporary Go variables like format_XX.* and a_XX.*
    • Removal of varX = fmt_Printf(...); assignment forms
  • Adds informative comments for each call (e.g., “safe operation”, “vulnerability warning”)
  • Batch mode across all functions

Requirements

  • Ghidra 11.4.1
  • Java 21

Build

We use a standalone builder script that auto-discovers Ghidra JARs.

cd ghidra-printf-inliner
./compile.sh

Artifacts created:

  • dist/StringInliner.zip – generic extension zip
  • dist/StringInlinerVXX_*.zip – versioned zips for convenience

Install

  1. Open Ghidra
  2. File → Install Extensions → select a zip from dist/
  3. Restart Ghidra
  4. File → Configure → Plugins → search “StringInliner” and enable

Usage

  • Single function: open a function and run the action “Inline Printf Strings” (toolbar or Analysis menu). A results window shows:

    • Original decompiled code
    • Found calls with resolved messages
    • Modified code preview with clean printf lines and variable cleanup
  • Batch: Analysis → “Batch Inline Printf Strings” to process all functions.

Example transformation

Before:

  format.len = in_stack_ffffffffffffff60;
  format.ptr = puVar10;
  a_00.len = in_stack_ffffffffffffff70;
  a_00.ptr = (runtime._interface *)uVar12;
  a_00.cap = uVar14;
  sVar9 = fmt.Printf(format,a_00);

After (clean preview in results):

printf("Testing index: %d, value: %dn", index, value); // CALL 1: shows test parameters

Limitations

  • The decompiler output is read-only. The plugin presents a cleaned “Modified code” preview, adds comments, and may rename symbols/locals, but cannot rewrite the true decompiler output.
  • Extremely obfuscated or optimized binaries may hide format strings in ways this tool won’t catch.

Troubleshooting

  • No strings found: ensure string blocks are present and not stripped
  • Extension not visible: check the zip layout is ExtensionName/lib/*.jar and restart Ghidra
  • Java/API errors: verify you’re on Ghidra 11.4.1 and Java 21

License

Apache 2.0