I am relatively a novice to decompiling other than jumping around and breaking and such. So a bit out of my depth but I have a binary file I am inspecting that came up recently on my radar from a developer on my team who was using it for work (which was unapproved but we're a small company and it's not like he is in trouble). However something didn't seem right about this file.
Inspecting it it appears to contain the working program he is using and others use but there is being attached a lot of Go code (which is easy enough with strings alone to see) and knowing this software this should not be the case. I am wondering what steps one might go to to extract just the Go file for further inspection. I'd rather not share the file here because it does contain licensed software with some funny business attached to it.
At my disposal I have the Swift binary which contains both an AARM and x86_64 payload to run for interoperability, Hooper, Binary Ninja, MacOView, and of course IDA all to assist with getting this thing down to it's guts. We are just all a bit in over our heads trying to yank this Go binary out of the file and I would rather take this on then have my developers deal with it.
Sorry if this may be the wrong forum for this discussion but it seemed the most apt being that this forum is for discussions at lower levels for Swift code. Thank you for some advice or links in advance.
Why do you want to extract it out?
It probably was a static library in go compiled with some sort of C compatiblity layer through which Swift accesses it.
There is no way you can remove "just the Go file" from this compiled binary because everything in the original source has been translated into the cpu-specific machine code; There's no way telling which was Swift or go
Thank you for your reply and questions; I was hoping to not have to give too much away but at this point I know the binary is nefarious and phoning a mothership, has private SSH keys I've extracted out (which I do or do not know yet are passwordless or not), and tcpdump of it proves it is a company I will not name that operates in multiple first world countries with impunity somehow(?).
I would like to isolate this activity from the Go at use from the software which is legitimate but somehow become entangled with the Swift code and I am so fairly novice at disassembling (but learning quickly as I go) that I do not want to implicate ourselves should it come about that someone here has done this or someone with the company authoring this Go code (which I understand much better in some sense) somehow takes action before fully analyzing it and turning it over to yet-to-be-researched agency(s) to handle legally.
Many of the opensource Go projects it is using are, or could be in the wrong hands tools in the toolset for an individual and/or company to assemble a botnet (reverse-proxy, centralized ssh manager suites, etc.)
There’s no easy answer here. If you’re thinking that the Go code is a malicious payload that’s been linked in, I’d start by figuring out what parts of the binary are Go and which are Swift. It’s probably not hard to come up with a function-by-function heuristic for that — compiled Swift functions are very likely to use a Swift runtime functions, and the same is probably true of Go. Functions from different translation units can be interleaved with each other by the linker, but that should be relatively uncommon, especially in cross-language scenarios. But one of the things that can trigger reordering is having a global constructor, which are also a pretty simple way to inject a payload: no need to modify any of the normal app code, just link a few malicious object files with a global constructor into the program and let that constructor set things up for bad behavior. So it’s not surprising that you do see some interleaving. Still, there’s probably only 2-3 ranges of Go code in the binary.
I see;
It is a bit tricky then; You said you extracted out some private ssh keys, have you nullified them in the binary? At least this way you can be sure the connection with the mothership won't succeed in these calls.
Have you guys analyzed the included Go projects yet (given they're opensource) to confirm that these ssh calls happen from one of them?
In theory you would have to replace calls to any suspicious Go function with no-ops in the binary but this is very difficult as you have to be really familiarized with the Go ABI (which is not stable) per cpu-type, to make sure you return the correct results in the correct registers or whatever places the code reads the result, err := #functionCall(..) result types; And you should also know which of the ~3 compilers was used (go, gccgo or gollvm) though most likely the default one compiled the code;
Not to mention you have to make sure the program-counter is updated correctly after these changes;
I would say the easiest steps to do is simply nullify any suspicious ip addresses / ssh hosts at this point.
It is a bit tricky then; You said you extracted out some private ssh keys, have you nullified them in the binary? At least this way you can be sure the connection with the mothership won't succeed in these calls.
This is a more complex answer but 2 of the 3 keys are retrieved from HTTP endpoints: one registered using a sketchy domain proxy service and the second is an AWS S3 Bucket. The third key is embedded and I have not tried nullifying that out no.
Have you guys analyzed the included Go projects yet (given they're opensource) to confirm that these ssh calls happen from one of them?
Beyond the basic Go projects (e.g. crypto, etc.) there are some public facing forks of repos or public repos themselves that this project is using that are again fairly nefarious in nature: distributed SSH key management, reverse-proxy service, one to manage .plist files on Macs. The bulk of the Go comes from a publicly inaccessible GitHub repository (private). I have tried with no avail to gain access to this repository to take a look at the source but I think the 3 keys I mentioned are simple SSH keys and not tied into GitHub that I can venture a guess at.
In theory you would have to replace calls to any suspicious Go function with no-ops in the binary but this is very difficult as you have to be really familiarized with the Go ABI (which is not stable) per cpu-type, to make sure you return the correct results in the correct registers or whatever places the code reads the result, err := #functionCall(..) result types; And you should also know which of the ~3 compilers was used (go, gccgo or gollvm) though most likely the default one compiled the code;
Not to mention you have to make sure the program-counter is updated correctly after these changes;
I would say the easiest steps to do is simply nullify any suspicious ip addresses / ssh hosts at this point.
I was curious further: does the Swift compiler (i.e. Xcode and it's suite in this case) have the ability to import a Go project and Swift project and so graciously interweave between the two at compilation at the C level? Or, like I was thinking is it basically imported as an internal binary to the project and the Swift wrapper code essentially says "while exit_status = 1: exit_status = run this code Go code; endwhile;" for this reason I have been persistent in seeing if there was a simple way to extract that linear section from the Swift binary... if that is how things work at all here...
Swift has no direct support for interacting with Go, and this payload probably has no special interaction with anything at the Swift level. Most likely, somebody added an extra link flag to the build which adds an extra object file to the linked binary, and that object file has a global constructor which causes some of its code to be run automatically.
I understand why you're reluctant to share this program publicly. However, I get the sense that you're missing a lot of the skills you'll need to make any real progress with this investigation, and it's asking a lot of us to walk you through the basics of building applications here. Please consider getting in touch privately with a security researcher who works with Mac apps; Apple's product security team may be able to help with that.
So extracting a standalone binary is a fools errand to attempt to pull out an executable Go binary because it won’t necessarily have a constructor?
Yeah, I’m certainly in over my head with it. I’ve done more talking about it on this thread than working on it of late. If there’s a safe way to pull this artifact from the surrounding Swift that was my objective to hand a researcher and/or authorities. As it stands I’d have to hand them the whole Swift executable which is licensed software and was wanting to avoid that ideally.
I’ll do some more thinking on this and report back.