We continue to observe both crimeware and advanced persistent threat (APT) malware variants found in the wild and during active targeted campaigns that are compiled in more non-traditional languages including Golang (Go) and Delphi programming languages.
The goal of this lesson is to investigate and obtain necessary malware analysis and valuable intelligence from two specific Golang compiled binaries that we increasingly see leveraged by various adversaries.
The compiled executables of both of these languages are to an extent a kind of “kryptonite” to malware analysts. Historically, malware analysis and reverse engineering practitioners have focused mainly on C compiled malware; therefore, the majority of custom and commercial malware analysis tools have aimed to assist with such C compiled binaries.
Golang executable malware introduces some challenges for the traditional anti-virus detection model, which has mainly focused on more traditional C-programmed malware. These kind of engines tend to have lower static detections for samples written in this language. As an additional benefit to attackers, Golang binaries are fast and efficient and have a high operational performance due to Golang’s concurrency features and garbage collection.
Such features allow various malware operators to achieve the desired malware state of “fully undetectable” (FUD). On the general cybercrime underground, such FUD malware means the malware developer can market and sell their wares more effectively; as a result, they make more profit when they can demonstrate that their malware samples really are FUD.
In addition, various nation-state APT actors have also began adopting the Golang programming language for their payloads. This has been seen, for example, with the Russian state-sponsored group known as APT28, Sofacy, Fancy Bear, STRONTIUM, Pawn Storm, and Sednit. Such changes in threat actor methodology necessitate that we examine the internals of the Golang binaries closely in order to derive both more malware analysis and greater intelligence value.
Introduction to Golang Journey
Initially developed at Google, Golang is an open source programming language with extensive community support. Golang might be thought of as analogous to a healthy mix of the high-programming ease-of-use Pythonic syntactic “sugar”, with a dose of lower-level C++ compiled features. The standout feature of this language is concurrency with its “goroutines.”
When analyzed, some of the quirks of the compiled Golang executables include more complicated control flow graph (CFG) calls as well as garbage collection.
The positive side for analysts is that Golang binaries include a plethora of metadata and compilation artifacts. These can often be used to derive additional intelligence about the possible source path.
Golang Binaries: From RobbinHood Ransomware to APT28 Zebrocy
For the purpose of reviewing Golang binaries, we will focus on two prominent Golang malware variants:
- Crimeware: RobbinHood Ransomware
- APT: APT28 Zebrocy loader
Both of these binaries were linked to the major outbreaks that made media headlines. RobbinHood ransomware is widely known for holding hostage the City of Greenville and more recently disrupting major local government operations in the City of Baltimore. The APT28 Zebrocy loader is a malware tool widely deployed by the purported Russian-based intelligence agencies in targeting various government and political entities to deliver another malware of choice as needed.
Golang Malware Executables Share Common Features
- The RobbinHood ransomware is a Golang executable consisting of 2.8 MB (2855424 bytes) with 2724 functions.
- The APT28 Zebrocy loader is a Golang executable consisting of 4.5 MB (4508672 bytes) with 5459 functions.
We are assessing the similarities and differences of the two using the popular Diaphora binary diffing IDA plugin tool and CFF Explorer.
The Diaphora plugin showed the following results between the two Golang binaries:
- Best Matches: 1158 functions
- Partial Matches: 1091 functions
- Unreliable Matches: 109 functions
- Unmatched in APT28 Loader: 396 functions
- Unmatched in RobbinHood Ransomware: 3077
It demonstrates that the separate Golang binaries share at least some similarities and best matches by either the same function hash, bytes hash, equal assembly and others.
Another similarity between the two Golang samples are the sections as follows:
- .rdata
- .text
- .idata
- .symtab
Both of the Golang binaries share the exact same import table with three static Windows dynamically linked libraries (DLL):
- winmm.dll
- ws2_32.dll
- kernel32.dll
Main Functions of Golang Malware
Leveraging IDA Golang Helpers tool, we assess and parse the Golang binaries trying to rename them. Then, based on the version, we try to add standard Go types and parse types by module data.
We make various attempts to parse the Golang section called “gopclntab”, which contains a function table routinely starting with the { FF FF FF FB 00 00 }
bytes and containing the size of the table and offsets to the location of the first function, through which we can resolve the names of the functions.
The code from the helper functions demonstrates the parsing of the “gopclntab” table for module data and function renaming as well as version find.
The relevant parser code is as follows:
def getGopcln(self): gopcln_addr = self.getVal("gopcln") if gopcln_addr is None: gopcln_addr = Gopclntab.findGoPcLn() self.setVal("gopcln", gopcln_addr) return gopcln_addr def findModuleData(self): gopcln_addr = self.getGopcln() fmd = Firstmoduledata.findFirstModuleData(gopcln_addr, self.bt_obj) self.setVal("firstModData", fmd) return def renameFunctions(self): gopcln_tab = self.getGopcln() Gopclntab.rename(gopcln_tab, self.bt_obj)
The possible output reveals the oftentimes necessary structure definition and type assignment as follows, for example:
According to moduleData struct it should be go1.8 or go1.9 or go1.10
Creating structure string Creating structure slice Creating structure __iface Creating structure type Creating structure arrayType Creating structure chanType Creating structure ptrType Creating structure sliceType Creating structure uncommonType Creating structure method__ Creating structure structField Creating structure structType Creating structure imethod Creating structure interfaceType Creating structure funcType Creating structure mapType 539d60 53ad6c 4df000 Processing: 4e9d00 PTR
1. The RobbinHood ransomware contains, for example, 2754 functions with only 26 main functions that affect the malware operation beyond static linking. Notably, Golang executables often preserve the original function names as developed by the developer.
The function names are descriptive of the ransomware encryption processes (for example, “main_RsaEncrypt”) and help navigate the malware analysis to locate the functions of interest.
2. The APT28 Zebrocy loader contains, for example, 5459 functions with only 16 main functions that affect the malware operation beyond static linking. Again, we see that the Golang executable likewise preserves the original function names as developed by the developer.
One of the key interesting analysis insights is the APT28 Golang executable relies heavily on various Golang open source code templates from GitHub including iamacarpet/go_win64api (ProcessList, InstalledSoftwareList, ListLoggedInUsers,SessionDetails/FullUser), shirou_gopsutil (host_Info), and kbinani/screenshot (NumActiveDisplays, GetDisplayBounds, CaptureRect) for its processes as noted with the function parsed prefixes “github_com” and the source paths above.
Golang Metadata Artifacts
1. The RobbinHood ransomware contained the original source “main.go” path data stored in “.rdata” section as follows:
C:/Users/valery/go/src/oldboy/config.go
C:/Users/valery/go/src/oldboy/functions.go
C:/Users/valery/go/src/oldboy/main.go
2. The APT28 Zebrocy loader contained the original source “main.go” data stored in “.rdata” section as follows:
C:/!Project/C1/ProjectC1Dec/main.go
Conclusion
The Golang programming language has become a language of choice and adoption for some of the most notable crimeware and APT groups. Being able to recognize the primary features of Golang executables is increasingly important for malware analysis and reverse engineering. Some of the key elements of malware analysis of Golang executables involve locating “main” functions within the binary that affect the flow of the program as well as understanding the importance of “gopclntab”.
Additionally, developing good RE habits through coding in Golang assists with gaining malware analysis. Programming in Golang allows the analyst to understand and identify patterns, types, and module data that would assist in future during Golang malware analysis and reverse engineering.
Referenced Malware Samples
APT28 Zebrocy UPX Packed Sample
SHA-256: 93680d34d798a22c618c96dec724517829ec3aad71215213a2dcb1eb190ff9fa
RobbinHood Ransomware Sample
SHA-256: 3bc78141ff3f742c5e942993adfbef39c2127f9682a303b5e786ed7f9a8d184b