Skip to content

Architectural Considerations

jholowczak-cb edited this page Aug 14, 2019 · 2 revisions

Being a process emulator, Binee does not follow loading of processes exactly as the operating system would, but has its own way of setting up emulation. In most cases, every structure is built and stored in the emulator memory before execution starts, whereas in something like the Windows loader, it will create proper process structures and do the parsing as it starts the process.

Bitness and Platform

Binee currently supports only 32-bit Windows, but there is already much of the code that supports both 32-bit and 64-bit for this platform. There are plans to incorporate more 64-bit logic into Binee, but considering a large portion of malware still use 32 bit that became the priority for this tool. The core functionality of Binee relies on 64-bit primitive types, so most of what's needed is to add logic for handling 64 bit memory for various hooks and core functionality.

File Hierarchy

binee/config

This is where the default and example configuration files are located, packaged with the repository.

binee/core

./cpu.go

This is where we define the CPU manager we implemented for Binee. The CPU manager keeps track of heap and stack addresses and size, the bitness of the CPU (32 or 64 bit, represented as an integer counting the number of bytes). It also has references to the unicorn emulator itself. Register structures for handling 32 and 64 bit registers also exist in this file, along with supporting methods. It also has methods for printing out the Stack and Registers when in debug-verbose mode (-vv).

./heap.go

This where Binee's memory manager lives. Any heap operation that is done during emulation, whether hooked or otherwise (Heap Manager also deals with Windows HANDLEs), is done by the memory manager. This includes many of the malloc/free/etc. functions that you would expect for a heap.

binee/pefile

This folder contains the parsing code for PE files.

binee/scripts

This folder contains 2 python helper scripts. The first is bin2shellcode.py, which will convert shellcode to PE format to be ran in binee. The second is log_viewer.py, which is a curses frontend to the debug-verbose interface. Uses pseudo-vim bindings.

binee/tests

Testing executables are located here.

binee/util

./unicorn.go

This includes many helper functions for interfacing with the Unicorn emulator, typically to convert raw bytes to golang types. This list includes:

  • Writing structures to memory
  • Placing and getting pointers into/from memory
  • Pushing and Popping from the stack
  • Reading ASCII and widechar strings from memory
  • Reading raw PE files from emulator memory
  • Stack introspection

./util.go

  • Format string parser (for use with printing hooks)
  • ASCII to widechar conversion
  • GDT creation helper functions
  • File path searching
  • Random string creation

binee/windows

This is where most of the emulation code exists. Here is where the main loader code (loader.go), the windows emulation layer (winemulator.go), all hooks (typically the source file name coincides with the dll name where the hooks for functions reside, see here for more info), and subsystems reside (filesystem, registry, scheduler). Most of these are covered in the rest of this document or elsewhere in the wiki.

PE/DLL Parsing

Sample PE and associated DLL's (static, from headers) are parsed and loaded into emulator memory before emulation starts. This allows Binee to have everything prepared ahead of time, and then starting the emulation once is all that's needed. When parsing the PE, Binee will also recursively parse any DLL's that are listed in the headers of the PE (or subsequent DLL's), updating the Import Address Table for each parsed file to point to the right place in memory.

ApiSets

Since around Windows 7, Microsoft added an abstraction layer DLL function reference, called Apisets. These are included at compile time and add a resolution layer to any function calls. The parsing of these apisets to resolve the proper DLL does occur in Binee, source is located in pefile.go

Userland Structures

TIB/PEB

Much like PE and DLL parsing, the TIB and PEB are populated in Binee structures, then written to memory during initial setup of the emulator, before emulation begins. Typically a number of these values are null, and effectively hand-wave these structures until we run into a sample that requires them to be populated. As Binee is developed, we expect to have more of these populated (much like hooks). The setup of the TIB and PEB (and for the PEB, creating and populating the Ldr and associated structures) can be found in loader.go. The golang-styles structures also exist here, and there are 32 bit and 64 bit implementations of the Thread Information Block, Process Environment Block, and Ldr structures (plus any supporting structures). At this current time there are no helper functions to read these structures out of the emulator memory, but there are many examples of this operation occurring throughout Binee's code that can be used.

Note: Binee only runs the DllMain of a DLL (not by default, use the -l flag) to populate some of these fields for us.

Configuration Files

Typically we want as much of Binee to be configurable via configuration files. This allows us to make rapid changes to the mock OS so we can test against multiple windows versions and inputs. There are default/example YAML files (the format used for configuration) in binee/config. Using the -c flag you can specify a different configuration to use. Currently Binee can have a fully configurable

Threading

The thread manager in Binee is effectively a GIL implemented using a simple round-robin scheduler, where each thread has equal time slicing before changing contexts to another thread. The code can be found in scheduler.go

SubSystems

Handles

Much like Windows, we treat handles as the basic building block for many of the subsystems built into Binee's mock OS. We've abstracted away most of the Windows HANDLE implementation as a superstructure, yet we still store the atomic ID of this handle in the heap and it references these structures in the emulator memory.

type Handle struct {
	Path   string
	Access int32
	File   *os.File
	Info   os.FileInfo
	RegKey *RegKey
	Thread *Thread
}

(handles.go is where HANDLEs are implemented)

File Subsystem

More Soon

Registry Subsystem

More Soon

Next Steps and Goals

Increase Fidelity with High Quality Hooks

The primary goal of binee in it's early stages of release is to keep adding hooks to Binee so we have better code coverage and more successful emulations of samples

Single Step mode, debugger style

We have plans to add a gdb-style debugger functionality to Binee. This would allow us to have full introspection into a binary while it is being emulated, instead of waiting for it to emulate as far as possible.

Rundll behavior

Being able to load and run exports within a DLL is important for emulating certain emulating artifacts within Binee

Anti-Emulation Countermeasures

As emulation becomes more popular, we anticipate anti-emulation techniques to appear and become more prevalent.

Expanded Platform Support

We want to add Mach-o (macOS) and ELF (*nix) support to Binee, so it will not just be Windows PE emulation in the future. We designed this tool in mind for easy swapping of emulation layers depending on the type of input file.