Go is now supported in LLEF!

13 Nov 2025 - FoundryZero

We are announcing experimental support for the Go programming language in LLDB Enhanced Features (LLEF), an in-house tool to improve LLDB for reverse engineering and vulnerability research.

TL;DR

We’ve added new functionality to make LLEF Go-aware. LLEF can now recover Go function names and data types, unwind the Go call stack, and display the contents of complex Go data types such as arrays, structs, and maps on stripped binaries!

LLEF Go Logo

Why?

When doing security research on modern platforms, there’s an increasing requirement to reverse engineer binaries written in memory-safe languages. One of the most popular “new” programming languages is Go, also known as Golang.

Under the covers, compiled Go binaries look very different from those written in C or C++. For example, Go strings are not usually null terminated, functions can return multiple values, and Go has a custom, unstable ABI for function calls. However, metadata stored in Go binaries presents exciting opportunities for function symbol and data type recovery not possible with stripped binaries written in other languages.

To date, lots of research has been published about reversing Go binaries, but the current state-of-the-art has mostly focused on ‘static’ analysis techniques that do not involve running the target program. Many of our favourite dynamic analysis tools wouldn’t work with Go binaries at all! We realised with its ability to parse binary metadata and apply inline markup, LLEF could become a great tool for reverse engineering Go binaries dynamically. It was also the perfect project for one of our talented summer placement students.

What?

LLEF now supports Go binaries. A lot of work has been done behind the scenes to extract as much value as possible from Go metadata and automatically display it to the analyst in LLEF. This feature is considered experimental, and may have some rough edges, but we’re excited about the benefits it provides for dynamically reverse engineering Go binaries.

Consider a (contrived) example where a JSON string is unmarshalled into a Go map object:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
    "encoding/json"
    "fmt"
)

type Tool struct {
    Name string `json:"name"`
    Developer string `json:"developer"`
    Score int `json:"score"`
}

func main() {
    tools := []Tool{
        {Name: "LLEF", Developer: "Foundry Zero", Score: 10},
        {Name: "Binder Trace", Developer: "Foundry Zero", Score: 10},
    }
    jsonData, _ := json.Marshal(tools)
    fmt.Println(string(jsonData))
}

We can find main.main by using the command go find-func main

1
2
3
4
5
6
7
(lldb) go find-func main 
0x43f9c0 - runtime.main (file address = 0x43f9c0) 
0x43fde0 - runtime.main.func2 (file address = 0x43fde0) 
0x46be60 - runtime.main.func1 (file address = 0x46be60) 
0x4b8de0 - main.main (file address = 0x4b8de0) 
0x4b8ee0 - type:.eq.main.Tool (file address = 0x4b8ee0) 
0x4b8f80 - type:.eq.[2]main.Tool (file address = 0x4b8f80) 

This allows us to set a breakpoint on main.main using the matched address:

1
2
(lldb) b * 0x4b8de0 
Breakpoint 1: where = maps`___lldb_unnamed_symbol0 + 753120, address = 0x00000000004b8de0 

Stepping through, we can observe the call to json.Marshal. LLEF has recognised that rax contains a pointer to the type definition for []main.Tool, and has guessed that rbx is a pointer to an instance of []main.Tool, displaying the data in the object:

LLEF displaying Go structs

In the screenshot, the data is truncated due to the terminal width. To view the whole object, a command has been added to unpack a data pointer using a type definition. In this case, the type is the custom type []main.Tool:

LLEF Go Type Unpacking

Other notable features are:

  • Support for dumping all data type definitions in the binary (including stripped binaries).
  • Support for dumping all function symbols in the binary (including stripped binaries).
  • Go call backtrace on x86 and x86_64 targets.
  • Support for most versions of Go, with most features available on Go versions above 1.7 (2016).

If you’d like to try out the new LLEF Go features, it can be downloaded on our GitHub: github.com/foundryzero/llef

Comparison of Before and After

Before

LLEF Go Type Unpacking

After

LLEF Go Type Unpacking

Thanks

As ever, we stand on the shoulders of giants and the inspiration for LLEF’s Go support came from existing static tools such as GoReSym and Redress. If you want to know more about Go symbol recovery, this blog from Google is an excellent resource: https://cloud.google.com/blog/topics/threat-intelligence/golang-internals-symbol-recovery/.