Tuesday, October 13, 2026

Inside AetherVM: lifting AArch64 and x86_64 binaries into LLVM IR for emulation and deobfuscation

Inside AetherVM: lifting AArch64 and x86_64 binaries into LLVM IR for emulation and deobfuscation

AetherVM is an LLVM-native binary analysis and emulation platform that lifts AArch64 and x86_64 machine code into LLVM IR for authorized reverse engineering, instrumentation, and runtime recovery.

ToolAetherVM/AetherVM — LLVM-native binary analysis and emulation platform built around instruction lifting to LLVM IR
CategoryBinary analysis, emulation, and reverse engineering framework (C++, Apache-2.0)
Primary UseLifting, instrumenting, and emulating AArch64/x86_64 binaries and raw shellcode-style opcodes for deobfuscation and program understanding in a controlled environment
Safe UseAnalyzing malware samples, obfuscated code, and software you own or are explicitly authorized to assess, inside isolated research VMs and laboratory sandboxes
Telemetry NotePurely a local analysis engine; the notable observable is its integrated gdb-remote debug server (EventConfig::debug / dbgport) listening on TCP port 60807 when enabled — defenders should be aware that exposed instances indicate an analyst console

AetherVM positions itself in a specific and technically demanding niche: a binary analysis and emulation platform that is LLVM-native by design. Its core premise is instruction lifting — decoding raw AArch64 and x86_64 machine code and translating it into architecture-independent LLVM IR. Once in that intermediate representation, static, dynamic, and symbolic analysis stop being separate disciplines and become different passes over the same representation, which is what makes the tool interesting for deobfuscation, runtime recovery, and general program understanding. The project is motivated by and partially derived from ICPP and Remill, so readers familiar with the lifting-bits ecosystem will recognize the lineage immediately.

The repository metadata reinforces that scope: it is written in C++, licensed under Apache-2.0, and tagged with topics spanning llvm, llvm-ir, emulation, binary-analysis, dynamic-analysis, virtual-machine, and reverse-engineering, with target platforms including Windows, Linux/Android, macOS, and iOS. That cross-platform ambition is not incidental — it is baked into the architecture through a thin OS abstraction layer that we will come back to. At 22 stars the project is young and niche, but the README is unusually detailed about internals, which is a good sign for a research-grade tool.

The API design exposes two distinct entry points, and the distinction matters for how you would actually use the engine. The first constructs a BinaryEngine from a raw Machine architecture context, aimed at shellcode-style analysis or at driving an existing VCPU loop such as ICPP that already manages its own analysis context. The second constructs it from a loaded Binary, unlocking the full lifting, instrumentation, and analysis workflow for complete executables. This split lets an operator start small — a handful of raw opcodes — and graduate to full-binary emulation without changing tooling.

Register representation is unified across both architectures under a single Register enumeration, with x86_64 names aliased onto shared general-purpose slots (RIP = PC, RSP = SP, RBP = FP). The RegisterValue union supports all integer widths, floats, pointers, and architecture-specific flag layouts — NZCV for AArch64, rflags for x86_64 — while RegisterValueSIMD handles the 128-bit case with Q0-31 and XMM0-31. The README notes that even legacy x87 and MMX state is covered, which is the kind of detail that separates serious emulators from toys; plenty of obfuscated binaries deliberately reach into awkward corners of the ISA.

Instrumentation is where AetherVM earns its keep in an authorized workflow. EventConfig is a packed 64-bit bitfield selecting which event categories fire: lift, memory, func, block, insn, syscall, trap, bridge, and debug. Events arrive through a single registered EventCallback as variants (EventRuntime, EventLift, EventMemory, EventHyperCall), and the callback returns an EventResult of Continue, Processed, or Terminate to steer execution. For a malware analyst, this per-category opt-in model means you can trace only memory accesses or only syscalls without drowning in per-instruction noise, and you can terminate the moment a trap fires.

The execution model, as the README's pipeline diagram describes, is a three-stage process. Raw opcodes are decoded and lifted into clean LLVM IR; each lifted instruction sequence is compiled and encoded into an executable runtime handler; and a threaded chained dispatcher then executes those handlers sequentially, with control flowing directly from one prebuilt handler to the next rather than paying full dynamic-compilation overhead per instruction. Execution yields to event hooks or hypercalls only when requested. This hybrid — JIT-compile once, chain thereafter — is a sensible performance compromise for long emulation runs.

Guest memory and host interop are handled with real pragmatism. mapMemory, readMemory, writeMemory, readUInt64, and mappedAddress cover guest memory management and binary-address-to-runtime-address translation. More interesting is makeExecutable(addr_t target), which turns any guest address into a real host-callable function pointer — effectively letting host tooling invoke guest code as if it were a native library. On the loading side, subclasses for Mach-O, ELF, and PE engines override recursiveLoad() to implement format-specific relocation binding, segment mapping, and dependent-library loading, with runMain() executing an attached executable's entry point.

Debugger integration is first-class. Enabling -debug starts an internal gdb-remote server on port 60807 (configurable via EventConfig::debug / dbgport), and the README shows lldb, Cutter, and IDA all connecting to it — with the practical note that IDA users should uncheck No-Ack mode in its GDB configuration. Per-VM-thread register access via getRegister/setRegister with a void *cpu argument supports multi-threaded guest debugging. For an analyst, this means emulation sessions become inspectable with familiar RE tooling rather than a printf-only experience.

The example tooling is concrete and, importantly, non-weaponized: it is sample-oriented scripting of the engine itself. The aevm.cc script takes -arch x64|arm64, -bin with raw hex opcodes, -reg register initialization lists, and -debug, and the README demonstrates it with literal nop sequences (909090, 1f2003d5) — deliberately inert test vectors. The emubin executable extends this to full binaries in PE/ELF/MachO format with -entry taking a hex RVA. Building requires ICPP, Ninja, CMake, and the sibling AetherBinary project, invoked through icpp build.cc after recursive cloning; on Windows you first initialize MSVC with vcvarsall x64.

The platform layer, exposed through Platform.h, is worth scrutiny from a defensive reading of the codebase. It provides page allocation and commit/decommit, process memory read/write optionally targeting another pid, dynamic library loading with symbol resolution, and process info helpers like self_path and current_pid. The README claims it abstracts Windows, Linux including Android, and Darwin including iOS. Process-memory primitives targeting arbitrary PIDs are inherently dual-use plumbing for any emulator of this class; anyone deploying AetherVM in production research infrastructure should treat it as privileged code and review how those primitives are guarded.

Where does this fit relative to alternatives? Compared to pure DBI frameworks, AetherVM's lifting-to-LLVM IR approach enables analysis passes that hook-based tools cannot easily do — you can run compiler-style transformations over lifted code for deobfuscation. Compared to full-system emulators, it is process-centric and library-like, embedding into host tooling rather than emulating hardware. The headers under the single aether namespace (AetherVM.h, Event.h, Register.h, Platform.h, Common.h, Utils.h) suggest the authors intend it as a foundation other tools build on, not a turnkey GUI product.

For authorized professionals — malware researchers, reverse engineers working on licensed targets, and defenders studying obfuscated samples in isolated labs — AetherVM is a technically credible addition to the lifting ecosystem. Watch the young codebase for maturity: register callbacks before executing guest code (the API is explicit that registerCallback is not thread-safe), keep the debug server bound to loopback rather than the default 0.0.0.0:60807 shown in the README transcript, and pin your build against the AetherBinary dependency it expects to sit alongside.

Official project repository for AetherVM/AetherVM.
Download Tool

Educational analysis for authorized security professionals. Use only in controlled, authorized environments.

Share articleFacebookXLinkedIn

Continue exploring

Browse all articles →

0 comentários:

Post a Comment

Note: Only a member of this blog may post a comment.