A cyber security blog

What the Bin? Nim, Golang, C++

We've seen offensive tools and/or malware written in Golang and Nim, it's no new news. However, recently we've seen a lot of people in the infosec community discussing Nim and that sparked our interest.

We asked the following questions:

  1. How do the binaries differ during initial analysis?
  2. Is it possible to quickly detect if a binary was written in Nim or Golang?

We found that there was a Yara rule written by SentinelLabs on Github which detects Golang bins. We couldn't find anything for Nim binaries at the time of this writing and we attempt to see if we can build one.

Process

We will go into the following process shortly:

  1. Produce test binaries using default configs
  2. Analyze the binaries
  3. Attempt to produce Yara rule(s)
  4. Run rule(s) against test binaries and malware
  5. Additional Nim Testing:
    • Release Build
    • DLLs

Test Bins

Code

Test Bins Code

The picture above contains the code which was compiled to produce the test binaries. They achieve the same simple goal of printing "hello world".

Compilation

C++ 32bit compilation
C++ 64bit compilation

"The /EHsc command-line option instructs the compiler to enable standard C++ exception handling behavior.Without it, thrown exceptions can result in undestroyed objects and resource leaks. For more information, see /EH (Exception Handling Model)." - Microsoft docs

Golang compilation
Nim compilation

Analyzing the Binaries

Bin Sizes

Golang is known to produce large binaries, and that can be seen below:

Lang Arch Size
C++ 32bit 174KB
C++ 64bit 223KB
Go 64bit 1,848KB
Nim 64bit 181KB
C++ 32 & 64 bit
Golang
Nim

A Look at the Sections

We noticed that the Golang and Nim bins we produced contain much more sections than the C++ bin.

C++, 6 sections

While C++'s bin contained 6 sections the Nim bin contained 16 and Golang's contained 13:

Nim, 16 sections
Golang, 13 sections

A Look at the File Header

C++ helloworld64.exe
Nim helloworld.exe

We found that the "IMAGE_FILE_LINE_NUMS_STRIPPED" flag in the nim bin's characteristics field to be interesting and took note of it.

Golang helloworld.exe

A Look at the Imports

We noticed that only the Nim binary was importing the msvcrt.dll. Surely we can't use this for detection, it is just interesting.

A Look at Nim’s Strings

Nim helloworld.exe

That's a lotta Nims. Note that we used choosenim to install Nim.

Attempt to Produce Yara Rule

Putting everything interesting we found thus far which is:

  1. IMAGE_FILE_LINE_NUMS_STRIPPED flag in the characteristics field
  2. Multiple occurrences of ".nim" in the strings

We wrote and tested the following Yara rule

import "pe"

rule IsNim : Nim{
  meta:  
    desc = Identify windows Nim binaries (PE)"
    author = "Humoud Al Saleh"
    version = "1.0"
    last_modified = "11.06.2022"
  strings:
    $a1 = ".nim" ascii
  condition:
    pe.is_pe and $a1 and pe.characteristics & pe.LINE_NUMS_STRIPPED
}

We also added Sentinel Lab's rule from Github to our rules file, and added the "Go" tag to it:

// https://github.com/SentineLabs
rule TTP_GoBuildID : Go
{
	meta:  
		desc = "Quick rule to identify Golang binaries (PE,ELF,Macho)"
		author = "JAG-S @ SentinelLabs"
		version = "1.0"
		last_modified = "10.06.2021"

	strings:
		$GoBuildId = /Go build ID: \"[a-zA-Z0-9\/_-]{40,120}\"/ ascii wide
	
	condition:
		(
			(uint16(0) == 0x5a4d) or 
			(uint32(0)==0x464c457f) or 
			(uint32(0) == 0xfeedfacf) or 
			(uint32(0) == 0xcffaedfe) or 
			(uint32(0) == 0xfeedface) or 
			(uint32(0) == 0xcefaedfe) 
		)
		and
		#GoBuildId == 1
}

Run Rule Against Test Binaries and Malware

We gathered a collection of binaries written in Nim and Golang from:

Many thanks to them!

We threw all the bins in one directory in preparation for testing the rule:

Directory With Samples

Now, the directory contains C++ binaries, zip archives, Nim binaries, and Golang binaries.

For reference and convenience, the following image contains of a list of binaries in the directory:

Yara scan

Ran Yara Against Directory With Samples

We filtered the results to make them more readable:

TTP_GoBuildID [Go]:
all_bins\1c55d4144572be0ee5f5f95d9ce655549a7d0f55c74d576f649a85c323b31a63.go
all_bins\8b6d63b2b7829c89877231c11bbcb8984abab9a344e918780bea6d0cf4632bc5.go
all_bins\af5e6a5e0d4c63665c642e7c6f82345c77e05c67ea7efb8fc881c46117248765.go
all_bins\e6d6100cc97057cd00751ef5ac18261f7796868a420b4507144e9de0a7e80784.go
all_bins\golang_helloworld.exe

IsNim [Nim]:
all_bins\a3af3d7e825daeffc05e34a784d686bb9f346d48a92c060e1e901c644398d5d7.nim
all_bins\07e0b509288c501c57cc8f11b88ac8c06e379b01b74cd910d93cfdff1f9dd7ec.nim
all_bins\397e4dc12d48fb0c4d80980643581c9416a4bed022d4676f30218fb1f1e1811c.nim
all_bins\nim_helloworld.exe
all_bins\nim_shellexec.exe
all_bins\socket.exe

No misses or false positives.

Additional Nim Testing

Release Build

Compile options and arguments can be passed to the Nim compiler, we decided to take a look at the compilation options and generated a release build.

Nim Release Build

We noticed that it included less "nim"s in the strings:

strings

Characteristics field still had the IMAGE_FILE_LINE_NUMS_STRIPPED flag:

File Header

Thus the Yara rule would detect it as a Nim Bin.

DLL

Decided to test the Yara rule against a DLL release build. For the source code we went with byt3bl33d3r's offensive Nim repo on Github, we took the source code from the examples:

GitHub - byt3bl33d3r/OffensiveNim: My experiments in weaponizing Nim (https://nim-lang.org/)
My experiments in weaponizing Nim (https://nim-lang.org/) - GitHub - byt3bl33d3r/OffensiveNim: My experiments in weaponizing Nim (https://nim-lang.org/)
Compiled and Executed DLL (we renamed the dll with the correct ext after)

We noticed the generated DLL contained both the strings and the IMAGE_FILE_LINE_NUMS_STRIPPED flag.

DLL File Header

Running the Yara rule against Nim bins dir:

Yara Scan

Thus far the rule detected debug and release Nim Windows bins, exe's and dll's.

Concerns

We will list concerns in the form of questions:

  1. What if obfuscation was used?
  2. Can the IMAGE_FILE_LINE_NUMS_STRIPPED flag be unset during the compilation of a nim binary?

Sources

The following is a Github repo with the Yara rule and source code used to generate the test bins

Resource

This is a nice resource for those that wish to do further reading:

https://www.blackberry.com/content/dam/blackberry-com/asset/enterprise/pdf/direct/report-old-dogs-new-tricks.pdf


Author

Humoud Al Saleh:
- Twitter
- Github
- More posts...

Subscribe to Cyphur Blog

Sign up now to get access to the library of members-only issues.
Jamie Larson
Subscribe