Skip to content

Architecture

Ezz Aldeen Bayoumi edited this page May 24, 2026 · 1 revision

Brovan's Architecture

Brovan is a multi-guest emulator, with some shared components between them. Currently it supports Unicorn as the only backend.

Main core components

  • BinaryFile.cs which is used to parse binary file formats, and it is used by the emulator in many places, either from the guest or from the core binary emulator to do various operations related to that specific guest, or is used for various analysis. (e.g. the windows guest uses it to parse other modules and add their information to WinModule)

  • BinaryEmulator.cs which is the main binary emulation interface, which can accept a guest directly or a BinaryFile class and based on that it will initialize the guest, it also contains the MLFQ Scheduler, in which the guests can use it as a callback (e.g. ExecuteThreadSlice, OnThreadContextLoaded, etc), which provides an easy way to manage threading without duplicate code. it also contains some callbacks for other hooks like CPUID, Syscall, Interrupts, etc.

  • GeneralHelper.cs which is a general-purpose helper, containing native imports for some winapi/linuxapi functions, the IO helper for sandboxed and cross-platform file access, and any utility functions in there can be found there.

  • StructSerializer.cs which is a general struct helper that can be used to parse structs from the emulator, get their size, as well as write them.

  • Unicorn folder which contains the main unicorn bindings, constants, and native imports.

Windows-specific core files

  • WindowsGuest.cs which contains the Windows guest implementation, handling Windows process setup, module loading, PEB/TEB creation, thread initialization, APC dispatching, and the Windows-specific emulation flow used at runtime.

  • BinaryEmulator.WindowsBridge.cs which connects BinaryEmulator to Windows-specific state and helpers, exposing Windows guest accessors and common Windows-facing emulator logic used by the core. this is legacy and will be removed later, it is only there because the Guest-style implementation was added and lots of syscalls already depended on the fact that BinaryEmulator.cs contained everything.

  • WinSyscallsHelper.cs which contains the shared Windows syscall support code, including handle/object management, shared buffers, device control helpers, and common logic reused across Windows syscall handlers.

  • WinStructs.cs which contains some windows structure definitions and related helpers used throughout the windows guest, syscall handlers, and runtime state setup. but some structs are written directly using the emulator memory, so you might not find everything here that is actually used by the emulator as some are written manually.

  • WinThreading.cs which contains Windows thread-state support, including APC tracking, exception state, worker-factory state, and other thread-related Windows runtime data.

  • WindowsFileStream.cs which provides the Windows file-stream implementation used by the Windows guest, with overlay-backed file IO that prefers the Windows VFS and falls back to allowed host files when appropriate.

  • WindowsVersionInfo.cs which contains the Windows version/build information written into guest memory and exposed to Windows programs during emulation.

  • Devices/ which contains Windows device emulation such as ConDrv, mount manager, physical disk, volume, WMI, and other Windows-specific device handlers.

  • Files/, Misc/, Process/, Registry/, RPC/, and Win32k/, etc, which contain the Windows syscall handlers grouped by subsystem, covering file operations, process and thread control, registry access, RPC, and win32k/user-mode GUI behavior.

Linux-specific core files

  • LinuxGuest.cs which contains the Linux guest implementation, handling ELF loading, module mapping, thread and signal state, Linux syscall dispatch, and the overall Linux-specific emulation flow.

  • LinuxSyscallsHelper.cs which contains shared Linux syscall support code, including errno values, stat helpers, socket and file helpers, memory and process utilities, and other common logic reused across Linux syscall handlers.

  • LinuxFileStream.cs which provides the Linux file-stream implementation used by the Linux guest, with overlay-backed file IO that prefers Linux VFS-backed paths before falling back to host files when appropriate.

  • LinuxStructs.cs which contains Linux-specific structure definitions and related helpers used throughout the Linux guest and syscall handlers.

  • SpecialPathsHandlers.cs which handles Linux special paths such as /dev, /proc, and /sys, providing emulated content and behavior for virtual files and device-like paths used by Linux programs.

  • Events/ which contains Linux event-related syscall handlers such as epoll, eventfd, and timerfd.

  • Files/ which contains Linux file-related syscall handlers such as open, read, write, stat, fcntl, lseek, mount, and directory enumeration.

  • Misc/ which contains Linux miscellaneous syscall handlers such as clock_gettime, poll, pselect6, getrandom, uname, and close.

  • network/ which contains Linux networking syscall handlers such as socket, bind, connect, accept, sendto, recvfrom, setsockopt, and socketcall.

  • Process/ which contains Linux process and memory syscall handlers such as clone, mmap, mprotect, mremap, munmap, prctl, futex, brk, and arch_prctl.

  • Signals/ which contains Linux signal-related syscall handlers such as kill, tgkill, tkill, rt_sigaction, rt_sigprocmask, rt_sigsuspend, and sigaltstack.

Flow

The usual flow for parsing and emulation is designed to keep the core emulator generic while letting each guest control its own behavior.

  1. A BinaryFile is created from the input file.

    • It parses the file format and extracts the information needed for analysis and loading.
    • This may include headers, sections, imports, exports, symbols, and other format-specific data.
  2. BinaryEmulator receives either the BinaryFile or a guest directly.

    • If a BinaryFile is provided, BinaryEmulator uses it to determine which guest should handle the file.
    • It then initializes the guest and prepares the emulation environment.
  3. The selected guest performs its own setup.

    • For example, the Windows guest may load modules, build its module list, initialize the PEB/TEB, and prepare memory layout.
    • The Linux guest perform its own process and memory initialization too.
  4. BinaryEmulator configures execution and backend state.

    • Memory mappings, registers, hooks, and backend-specific settings are applied here.
    • Shared helpers such as StructSerializer and GeneralHelper are used whenever needed.
  5. Execution begins through the emulator backend.

    • Unicorn handles instruction execution.
    • During execution, callbacks are forwarded to the guest when guest-specific handling is required.
  6. The guest and scheduler cooperate during runtime.

    • The MLFQ scheduler manages thread execution and slicing.
    • Callbacks such as ExecuteThreadSlice and OnThreadContextLoaded allow the guest to integrate with scheduling without duplicating logic.
  7. Runtime events are handled through shared emulator callbacks.

    • CPUID, syscalls, interrupts, exceptions, and other events are intercepted by BinaryEmulator.
    • The emulator forwards these events to the active guest or handles them through common logic when possible.

Clone this wiki locally