Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import path obfuscation #13

Closed
lu4p opened this issue Apr 1, 2020 · 16 comments · Fixed by #116
Closed

Import path obfuscation #13

lu4p opened this issue Apr 1, 2020 · 16 comments · Fixed by #116
Assignees

Comments

@lu4p
Copy link
Member

lu4p commented Apr 1, 2020

Add package name obfuscation similar to what gobfuscate does for GOPATH.

@mvdan
Copy link
Member

mvdan commented Apr 1, 2020

Unfortunately I don't think there is a way to do this with our design. We obfuscate one package at a time, while other tools like gobfuscate work on an entire GOPATH at once. When we're obfuscating a package foo/bar, it's already being built under that import path, because we are not in control of resolving dependencies and locating packages. We only control the compiler and linker's inputs.

I really don't want to take the "obfuscate the entire world" approach that gobfuscate takes, too. That requires a ton of upfront work and it's slow, so it doesn't scale to large builds at all. It's also much trickier to implement properly if one wants to support both GOPATH and modules.

@lu4p
Copy link
Member Author

lu4p commented Apr 2, 2020

Do you think it is possible to replace all paths in the resulting binary?

@mvdan
Copy link
Member

mvdan commented Apr 4, 2020

We control when the linker is called, so we could modify the resulting binary. But, how? I assume simple search and replace wouldn't work well at all. It's an interesting idea, but it requires some research.

mvdan added a commit that referenced this issue Apr 5, 2020
For #13, mainly, since that's a common concern.
@mvdan
Copy link
Member

mvdan commented Apr 5, 2020

I've expanded the README with current shortcomings of the tool, clarifying that many of them can probably be improved in the future.

@capnspacehook
Copy link
Member

I think modifying produced object files would be the best bet. As was mentioned in #44, modifying binaries would be more work as we'd have to support code to modify PE, ELF, MACH-O and more binary formats. Not to mention, most binary files would break if you replaced a string in the binary with a string of a different size, meaning we'd only be able to randomize the import paths such that they didn't change size, which is useful information to humans.

Also, are there any rules related to Go import paths that would prevent us from fully randomizing import paths? For example, would renaming github.com/foo/bar to a and github.com/foo/bar/baz to b break things, because github.com/foo/bar/baz is a subpackage of github.com/foo/bar? If not, I think fully randomizing import paths would be extremely beneficial.

@mvdan
Copy link
Member

mvdan commented Jul 2, 2020

Also, are there any rules related to Go import paths that would prevent us from fully randomizing import paths?

Before the build happens, there are definitely rules in place. For example, the internal package rules work on path element prefixes. However, as far as I can tell those rules are enforced at compile time only, and the linker shouldn't care if we replace the import paths.

That being said, the replacement should still be deterministic, just like the rest of the tool. If anyone wants to have a crack at this, patches are welcome, though it's a pretty difficult task to get started with. You should probably attempt a smaller PR first.

@capnspacehook
Copy link
Member

I'm interested in tackling this, what smaller patch do you suggest starting with? Also, my first step is going to be parsing the object files, does anyone know of any libraries to parse and get offsets of symbols in Go object files? goobj looks promising, but what's the difference between goobj and goob2? Does goobj2 deal with the new object format?

@lu4p
Copy link
Member Author

lu4p commented Jul 3, 2020

@capnspacehook Can you provide links to goobj and goobj2?

@lu4p
Copy link
Member Author

lu4p commented Jul 3, 2020

@capnspacehook Maybe have a go at #39 first, which should be relativly easy and helps you to understand the codebase.

@mvdan
Copy link
Member

mvdan commented Jul 3, 2020

@capnspacehook as a first patch, how about this TODO here? https://github.com/mvdan/garble/blob/3e4f3821ea8516068e6b3d87e89473d99825c060/main.go#L567

It's an optimization to save a bit of work when -literals isn't used. I reckon it should be under a dozen lines of code, and it shouldn't require any test changes as the tool already has tests with and without the flag.

does anyone know of any libraries to parse and get offsets of symbols in Go object files? goobj looks promising, but what's the difference between goobj and goob2? Does goobj2 deal with the new object format?

I don't have a good answer for you there, sorry. Perhaps check the Go repo's git log to see where they come from. It is true that Go has a new object format, though, and we only support the latest stable Go version, so you should completely ignore the old object (export) format.

@lu4p #39 is probably easier than this one, but I still wouldn't call it an easy first issue :)

@capnspacehook
Copy link
Member

@lu4p
Copy link
Member Author

lu4p commented Jul 3, 2020

@capnspacehook goobj2 is the one you want

@capnspacehook
Copy link
Member

@mvdan sounds good, I'll work on that small optimization first.

@capnspacehook
Copy link
Member

Hmm, looks like goobj will actually work just fine... it apparently works with both the old and new formats automatically

https://github.com/golang/go/blob/master/src/cmd/internal/goobj/read.go#L511

@lu4p
Copy link
Member Author

lu4p commented Jul 3, 2020

Ok

@mvdan
Copy link
Member

mvdan commented Jul 5, 2020

FYI both, I've started the #obfuscation channel over at the Gophers slack, so it could be a place to exchange short messages or questions about garble. I intend to keep using GitHub to track issues, but I understand that comments on here are generally asynchronous.

This was referenced Jul 12, 2020
@mvdan mvdan closed this as completed in #116 Sep 5, 2020
mvdan pushed a commit that referenced this issue Sep 5, 2020
Finally, finally this is done. This allows import paths to be obfuscated by modifying
object/archive files and garbling import paths contained within. The bulk of the
code that makes parsing and writing Go object/archive files possible lives at
https://github.com/Binject/debug/tree/master/goobj2, which I wrote as well.

I have tested by garbling and checking for import paths via strings and grep
(in order of difficulty) https://github.com/lu4p/binclude, garble itself, and
https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck.

This only supports object/archive files produced from the Go 1.15 compiler.
The object file format changed at 1.15, and 1.14 and earlier is not supported.

Fixes #13.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
3 participants