Disassemble a Go binary

Simple program

The example project uses the following files:

secret/secret.go:

package secret

import "log"

func ILoveTrains() {
    log.Println("secret")
}

cmd/test/main.go:

package main

import "github.com/xtuc/example/secret"

func main() {
    secret.ILoveTrains()
}

Disassembly

You actually don't need to disassemble the binary. For the sake of simplicity, I'll only use strings against the binary.

$ cd cmd/test
$ go build
$ strings ./test | grep secret

github.com/xtuc/example/secret.ILoveTrains
[]

Note that Go won't include can that you don't use. All the imports are used.

We can clearly see that github.com/xtuc is loving trains and even see the file structure. It makes no sense to include such information in the final binary, it's what we call a disclosure.

You might have noticed that I didn't stripped the binary. Let's try again with a stripped binary.

$ cd cmd/test
$ go build -ldflags="-s -w"
$ file ./test
test: ELF 64-bit LSB executable [] stripped
$ strings ./test | grep secret

github.com/xtuc/example/secret.ILoveTrains
[]

Even with a stripped (it's meant for distribution) we can still see them.

Since the binary is stripped we don't have debugging symbols anymore:

$ nm ./test
nm: ./test: no symbols

Stack Overflow, what's the solution?

Stack Overflow can be useful in many cases, but not this time. This is the answer I read:

Why do you need even that? Don't distribute Golang binaries.

Definitely not helpful.

Golang, what's the solution?

I didn't ask, so this is not their answer: as many things in Golang, it's highly opinionated and specific to Google's needs.

Since they don't distribute any Go binary, why would they invest time in an obfuscation process.

What's the real solution?

Since the Golang compiler won't mangle function names, I decided to mangle them before passing it to the compiler.

It's a source mangler: https://github.com/xtuc/manglo.

Alternative compiler backends

My example uses the default Go compiler. I tried the gccgo compiler (GCC with a Go fronted) but it refused to compile because the imports weren't quite the same (might have changed somewhere around Go1.9).

GCC mangles all names.

Packing?

Packing the binary will indeed removing the clear strings. Anyone having disassemble skills will notice it immediately and revert the process (unpack). I'm not sure if it works cross-platform.

Reach out

Say hello: [email protected].

Ping me on Twitter: @svensauleau.