EMU(3)

πŸ“¦ version 0.2.0, in epel 9, fedora 43, fedora 44

πŸ’– EMU(3) β€” Library Functions Manual πŸ’–

okay bestie, gather round, because we're about to talk about libemu, aka the little x86 emulator that could ✨ This is EMU(3), a Library Functions Manual page, and it's giving "I emulate x86 shellcodes and I'm not sorry about it." πŸ¦‹


🌸 NAME 🌸

libemu β€” emulate x86 shellcodes πŸ’…

no cap, that's the whole name section. short. iconic. periodt.


✨ SYNOPSIS ✨

first things first, you gotta pull in the headers, bestie:

#include <emu/emu.h>
#include <emu/emu_memory.h>
#include <emu/emu_cpu.h>

then here's the whole function lineup, and yes, every single one of them, we're not skipping a single one πŸ™ˆ

struct emu * emu_new ()
void emu_free (struct emu *e)
struct emu_memory * emu_memory_get (struct emu *e)
struct emu_logging * emu_logging_get (struct emu *e)
struct emu_cpu * emu_cpu_get (struct emu *e)
void emu_errno_set (struct emu *e, int err)
int emu_errno (struct emu *c)
void emu_strerror_set (struct emu *e,
        const char *format,...)
const char * emu_strerror (struct emu *e)

void emu_memory_clear (struct emu_memory *em)
int32_t emu_memory_read_byte (struct emu_memory *m,
        uint32_t addr, uint8_t *byte)
int32_t emu_memory_read_word (struct emu_memory *m,
        uint32_t addr, uint16_t *word)
int32_t emu_memory_read_dword (struct emu_memory *m,
        uint32_t addr, uint32_t *dword)
int32_t emu_memory_read_block (struct emu_memory *m,
        uint32_t addr, void *dest, size_t len)
int32_t emu_memory_read_string (struct emu_memory *m,
        uint32_t addr, struct emu_string *s, uint32_t maxsize)
int32_t emu_memory_write_byte (struct emu_memory *m,
        uint32_t addr, uint8_t byte)
int32_t emu_memory_write_word (struct emu_memory *m,
        uint32_t addr, uint16_t word)
int32_t emu_memory_write_dword (struct emu_memory *m,
        uint32_t addr, uint32_t dword)
int32_t emu_memory_write_block (struct emu_memory *m,
        uint32_t addr, void *src, size_t len)
void emu_memory_segment_select (struct emu_memory *m,
        enum emu_segment s)
enum emu_segment emu_memory_segment_get (struct emu_memory *m)
int32_t emu_memory_alloc (struct emu_memory *m,
        uint32_t *addr, size_t len)
uint32_t emu_memory_get_usage (struct emu_memory *m)
void emu_memory_mode_ro (struct emu_memory *m)
void emu_memory_mode_rw (struct emu_memory *m)

uint32_t emu_cpu_reg32_get (struct emu_cpu *cpu_p, enum emu_reg32 reg)
uint16_t emu_cpu_reg16_get (struct emu_cpu *cpu_p, enum emu_reg16 reg)
uint8_t  emu_cpu_reg8_get  (struct emu_cpu *cpu_p, enum emu_reg8  reg)
void emu_cpu_reg16_set (struct emu_cpu *cpu_p, enum emu_reg16 reg, uint16_t val)
void emu_cpu_reg32_set (struct emu_cpu *cpu_p, enum emu_reg32 reg, uint32_t val)
void emu_cpu_reg8_set  (struct emu_cpu *cpu_p, enum emu_reg8 reg,  uint8_t val)
uint32_t emu_cpu_eflags_get (struct emu_cpu *c)
void emu_cpu_eflags_set (struct emu_cpu *c, uint32_t val)
void emu_cpu_eip_set (struct emu_cpu *c, uint32_t eip)
uint32_t emu_cpu_eip_get (struct emu_cpu *c)
int32_t emu_cpu_parse (struct emu_cpu *c)
int32_t emu_cpu_step (struct emu_cpu *c)
int32_t emu_cpu_run (struct emu_cpu *c)
void emu_cpu_debug_print (struct emu_cpu *c)

int32_t emu_shellcode_test(struct emu *e, uint8_t *data, uint16_t size)

struct emu_env_w32 *emu_env_w32_new(struct emu *e)
void emu_env_w32_free(struct emu_env_w32 *env)
struct emu_env_w32_dll_export *emu_env_w32_eip_check(struct emu_env_w32 *env)
int32_t emu_env_w32_export_hook(struct emu_env_w32 *env,
        const char *dllname,
        const char *exportname,
        int32_t (*fnhook) (struct emu_env_w32 *env, struct emu_env_w32_dll_export *ex)
        );

like, look at that. a whole wardrobe. πŸ’…


🫢 DESCRIPTION 🫢

libemu provides basic x86 emulation including memory access and registers.

that's it. that's the description. lowkey humble of it, but go off king πŸ‘‘


πŸ”₯ ROUTINES πŸ”₯

🌟 setting up the whole vibe: emu_new() and friends

emu_new() is your girl for creating a brand new emulation entity πŸ’– and when you're done with it, emu_free() frees all the associated memory. (not me forgetting to free things... couldn't be me πŸ™ˆ)

then you've got the pointer-fetchers: emu_memory_get(), emu_logging_get() and emu_cpu_get() β€” these hand you pointers to different parts of the emulation, so you can poke at whatever piece you need ✨

for errorhandling, hit up emu_errno() or emu_strerror(), which return either a POSIX errno or a string describing the error. and when you're out here writing extensions, emu_errno_set() and emu_strerror_set() will come in handy too πŸŽ€


🧠 memory, but make it paged

The emu_memory is split up in pages, so there are functions to access the memory without taking care of page borders. that's the whole point, bestie β€” you don't gotta worry about it πŸ’…

  • emu_memory_read_byte(), emu_memory_read_word(), emu_memory_read_dword(), emu_memory_read_string() and emu_memory_read_block() β€” use these to read values out of the emu memory πŸ“

one tiny but crucial detail: emu_memory_read_string() will allocate the required memory for the string within the emu_string provided by itself, because you won't be able to know the string's length ahead of time. in all other cases, the pointer to the location has to provide enough space to write the data. so like, bring your own buffer, okay? πŸŽ€


πŸŽ€ getting the CPU ready for its main character moment

Once the emulation is created, code is written to the memory, and then we need to:

  1. set the registers to the initial values
  2. set the cpuflags to the start values
  3. set EIP to the point where code execution should start

emu_cpu provides functions to access all registers, the flags and EIP, for both read and write. iconic behaviour, honestly πŸ‘‘

here's the register situation:

  • 32bit registers β†’ emu_cpu_reg32_get() and emu_cpu_reg32_set(), where reg is one of eax, ecx, edx, ebx, esp, ebp, esi, edi
  • 16bit registers β†’ emu_cpu_reg16_get() and emu_cpu_reg16_set(), with ax, cx, dx, bx, sp, bp, si, di as valid values for reg
  • 8bit registers β†’ emu_cpu_reg8_get() and emu_cpu_reg8_set(), with al, cl, dl, bl, ah, ch, dh, bh as values for reg

and then:

  • flags β†’ emu_cpu_eflags_get() and emu_cpu_eflags_set()
  • EIP β†’ emu_cpu_eip_set() and emu_cpu_eip_get()

once everything is setup, parse the first instruction using emu_cpu_parse(). on success it will return 0, and on failure use emu_strerror() to get a description of the error 🌸 and if parsing was successfull, step the first instruction using emu_cpu_step().


πŸ¦‹ detecting shellcodes: emu_shellcode_test()

If you want to detect shellcodes in buffers, use emu_shellcode_test() β€” the emu will copy the buffer to it's pages and try to detect a shellcode. If a possible shellcode gets detected, the guessed starting offset is returned, else -1 πŸ’€


πŸͺŸ windows api vibes: emu_env_w32

To be able to run shellcodes using windows api, one has to provide parts of the windows process environment to the emulation, as well as some kind of emulation for the used api calls. yes, that's a lot. we know. πŸ’…

  • emu_env_w32_new() will created a minimalistic process environment in e
  • using emu_env_w32_eip_check() after step allows you intercepting calls to exported api
  • if the return value of emu_env_w32_eip_check() is not NULL, the dll exports information is returned, including the calls name and hook πŸ‘€
  • if you want to hook calls to api exports, use emu_env_w32_export_hook()
quick reminder bestie: that's the whole w32 situation, emu_env_w32_new(), emu_env_w32_free(), emu_env_w32_eip_check() and emu_env_w32_export_hook() β€” all four, accounted for, no skips 🫢

πŸ’œ AUTHOR πŸ’œ

Markus Koetter <nepenthesdev@gmail.com> β€” thank you for your service, king πŸ‘‘


and that's the whole page, bestie!! this one's from the EMU(3) manual, Library Functions Manual, and it's dated 04 September 2007 ⭐ like, a whole vintage moment. slay, honestly. now go emulate something πŸ’–βœ¨πŸ¦‹