Skip to content

Instantly share code, notes, and snippets.

@0xdevalias
Last active November 8, 2024 15:17
Show Gist options
  • Save 0xdevalias/4e430914124c3fd2c51cb7ac2801acba to your computer and use it in GitHub Desktop.
Save 0xdevalias/4e430914124c3fd2c51cb7ac2801acba to your computer and use it in GitHub Desktop.
Some notes, tools, and techniques for reverse engineering Golang binaries

Reverse Engineering Golang

Some notes, tools, and techniques for reverse engineering Golang binaries.

Table of Contents

Go Reverse Engineering Tool Kit (go-re.tk)

  • https://go-re.tk/
    • A Reverse Engineering Tool Kit for Go, Written in Go.

    • The Go Reverse Engineering Tool Kit (go-re.tk) is a new open-source toolset for analyzing Go binaries. The tool is designed to extract as much metadata as possible from stripped binaries to assist in both reverse engineering and malware analysis.

    • https://go-re.tk/gore/
      • GoRE is the core of Go Reverse Engineering Tool Kit. It is a library written in Go that provides functionality to analyze binaries produced by the Go compiler.

      • https://github.com/goretk/gore
        • GoRE - Package gore is a library for analyzing Go binaries

    • https://go-re.tk/libgore/
      • Libgore

      • Libgore is a dynamic C-library for interacting with GoRE. It is using cgo to produce a translation layer between the code written in Go and the exported C functions. With this library, it is possible to write bindings for other languages that have C foreign function interface (FFI) support. PyGoRE uses this dynamic library to provide a Python library that can be used to write tools in Python.

      • https://github.com/goretk/libgore
        • Libgore - Open up GoRE to other languages

    • https://go-re.tk/pygore/
      • PyGoRE

      • Python library for analyzing Go binaries

      • PyGoRE is a simple to use Python library for analyzing Go binaries compiled with Go compiler.

      • https://github.com/goretk/pygore
        • pyGoRE - Python library for analyzing Go binaries

    • https://go-re.tk/redress/
      • Redress

      • A tool for analyzing stripped binaries

      • The redress software is a tool for analyzing stripped Go binaries compiled with the Go compiler. It extracts data from the binary and uses it to reconstruct symbols and performs analysis. It essentially tries to “re-dress” a “stripped” binary.

      • https://github.com/goretk/redress

GoReSym

  • https://github.com/mandiant/GoReSym
    • GoReSym is a Go symbol parser that extracts program metadata (such as CPU architecture, OS, endianness, compiler version, etc), function metadata (start & end addresses, names, sources), filename and line number metadata, and embedded structures and types. This cross platform program is based directly on the open source Go compiler and runtime code.

      The upstream Go runtime code is extended to handle:

      • stripped binaries
      • malformed unpacked binaries, such as from UPX
      • binaries that split single data ranges across multiple sections
      • the location of the moduledata structure
    • mandiant/GoReSym#44
      • Build release packages for linux/windows/macOS + add to homebrew package manager (macOS)

      • Homebrew/homebrew-core#155716
        • goresym 2.6.3 (new formula)

    • mandiant/GoReSym#45
      • add a 'strings' command

  • https://www.mandiant.com/resources/blog/golang-internals-symbol-recovery
    • Ready, Set, Go — Golang Internals and Symbol Recovery

    • Golang (Go) is a compiled language introduced by Google in 2009. The language, runtime, and tooling has evolved significantly since then. In recent years, Go features such as easy-to-use cross-compilation, self-contained executables, and excellent tooling have provided malware authors with a powerful new language to design cross-platform malware. Unfortunately for reverse engineers, the tooling to separate malware author code from Go runtime code has fallen behind.

      Today, Mandiant is releasing a tool named GoReSym to parse Go symbol information and other embedded metadata. This blog post will discuss the internals of relevant structures and their evolution with each language version. It will also highlight challenges faced when analyzing packed, obfuscated, and stripped binaries.

    • In addition to the runtime code, the compiler also embeds metadata about the source code and its binary layout to support language features, the runtime, and debug tooling.

      Some of this embedded information has been thoroughly documented, namely the pclntab, moduledata, and buildinfo structures. Each of these structures has seen major changes as Go has evolved. This evolution, combined with common obfuscator or packing tricks, can make type recovery trickier than expected. To effectively handle ever-changing runtime structures, GoReSym is based on the Go runtime source code to transparently handle all runtime versions. This makes supporting new Go versions trivial. We can also be more confident in edge cases since GoReSym uses the same parsers as the runtime.

    • The pclntab structure is short for “Program Counter Line Table”. The table is used to map a virtual memory address back to the nearest symbol name to generate stack traces with function and file names. For symbol recovery purposes, the pclntab is important because it stores function names, function start and end addresses, file names, and more.

    • When a Go binary is stripped, the .symtab symbol table is zeroed out or not present. This removes the ability to find symbols such as runtime.pclntab. However, the data those symbols point to, such as the pclntab itself, is still present in the binary. For ELF and Mach-O files, the named sections (e.g., .gopclntab) are also still present and can be used to locate the pclntab. Therefore, manual location of the pclntab` for both stripped and unstripped binaries can be performed

    • The moduledata structure is an internal runtime table that stores information about the layout of the file as well as runtime information used to support core features such as garbage collection and reflection. Unlike the pclntab, this structure cannot be found via symbols. Its layout also changes much more frequently.

    • Starting in Go 1.18, additional metadata is provided in a table named buildinfo. This table is emitted by default but can be easily omitted with compiler flags. When present, the table can provide the following: compiler and linker flags, values of the environment variables GOOS and GOARCH, git information, and information about the package name of both the main and dependency packages.

    • GoReSym is a standalone application that can be executed on the command line or incorporated into a larger batch processing script. It doesn’t perform additional binary analysis outside of Go’s symbols. As a result, data extraction typically finishes in 1-5 seconds for even the most complex binaries.

      By default, GoReSym prints concise output instead of all extracted information. Various flags can be used to alter GoReSym's behavior. The -t flag instructs GoReSym to emit type and interface lists, which are useful when reversing channels and other routines that accept types.

    • There are public and commercial tools that support some, or perhaps all, of the type parsing logic addressed in GoReSym. Prior works such as Redress and IDAGolangHelper are excellent and should be celebrated. The primary difference between GoReSym and existing tools is that GoReSym is based on the Go runtime source code. This helps counter the rapid pace of Go internal structure evolution. Additionally, because the runtime is already cross-architecture, GoReSym is too. All new parsing logic takes care to correctly support 32 and 64-bit big and little-endian architectures. Care was also taken to handle unpacked or partially corrupted samples where possible, something other tools may struggle with. Overall, GoReSym is designed to work in cases where other tools fail and offers a way to ease tool maintenance as Go evolves.

Unsorted

See Also

My Other Related Deepdive Gist's and Projects

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment