# pe_emu

> **Tool `tools/emu/pe_emu.py`** (library, Emulators). Call functions inside a Windows x64 game's EXE and DLLs under Unicorn, without running the game.

A library: other tools and your own scripts import it. [Source on GitHub](https://github.com/tanepiper/game-frame/blob/main/tools/emu/pe_emu.py).

## Its own help

This is the help text in the tool itself, as `./gameframe tool pe_emu` prints it.

```text
Call functions inside a Windows x64 game's EXE and DLLs under Unicorn, without running the game.

This is how you get *ground truth*: the exact outputs of an original function for inputs you
choose, to test a reimplementation against bit for bit.

    from pe_emu import Emu, F32
    emu = Emu('game.exe', ['engine.dll'])          # load, relocate if needed, link imports
    emu.hook_export('engine.dll', 'mem_alloc', lambda a: emu.malloc(a[0]))
    out = emu.malloc(4 * 600)
    emu.call(emu.export('game.exe', 'simulate'), 1234, 600, out)
    print(emu.f32s(out, 600)[-1])

What it does:

- maps every module at its preferred base (or relocates it when two overlap) and writes the
  image as the Windows loader would;
- links each import to an export of another loaded module by name or ordinal; any other import
  becomes a stub that runs a Python handler (common C runtime and kernel32 functions have
  working handlers in `CRT_STUBS`; an import with no handler stops the run with its name, so you
  know exactly what to stub next);
- gives the emulated code a stack, a bump-allocator heap and a TEB (GS segment), so thread-local
  reads and stack checks work;
- `call(addr, *args)` uses the Windows x64 convention: the first four integer or pointer
  arguments in rcx, rdx, r8, r9, floats wrapped in `F32` in xmm0-xmm3, the rest on the stack
  above 32 bytes of shadow space. It returns rax; `call_f32` returns xmm0 as a float.

What it does not do: run DllMain or TLS callbacks, create threads, open files or windows, or
talk to Direct3D. Hook or stub anything like that (`hook_function`). Needs `unicorn` and
`pefile` (scripts/setup.sh puts them in .venv).
```

## Named by

Skills: [re-observe](/skills/re-observe), [re-emulate](/skills/re-emulate).
