Version: 0.6.8
Language: AutoHotkey v1 HTTP REST API Bridge: Java 18
Core idea: Hook an emulator’s process once, resolve the emulated console’s base RAM addresses, and expose a single, consistent API for reading/writing real-time game memory across many systems. Extension: Language agnostic HTTP, WebSocket & TCP interop with base lib.
Important
EmuHook is not public yet, however I will be posting updates and demos here.
My free time IRL has gone quite tighter than I expected and I am not 100% comfortable having this out with no free time to keep track/support it.
- TL;DR
- Emulator - System Support
- Why I built it
- Feature highlights
- Quick start
- API (practical)
- Address-space detection
- Real examples
- Performance & design choices
- Building overlays & Twitch plugins
- Changelog
- Supplementary Examples & Variants
- TO-DOs
- Final notes
- Demo images and Videos
- My projects using EmuHook
- Tools used
EmuHook lets you:
-
Attach once to an emulator (by EXE or PID) and keep a persistent handle for fast memory I/O.
-
Auto-resolve base addresses (WRAM, IRAM, SRAM…) per system/emulator.
-
Read/write memory in little- or big-endian (e.g., GC/Wii on Dolphin).
-
Follow multi-level pointer chains.
-
Use a common address model for your overlays, automated race trackers, autosplitters, crowd-control plugins, real-time event dispatchers, data mining tools, bot automation frameworks, debugging tools and many more.
Emulator | GB | SGB | GBC | GBA | PSX | NDS | NES | SNES | GC | Wii | SMS | MD | 32x | SG1000 | PS2 | N64 | WiiU | PSP | PS3 | 3DS |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
mGBA | ✔ | ✔ | ✔ | ✔ | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
VisualBoyAdvance-Link | ✔ | ✔ | ✔ | ✔ | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
VBA-H | ✔ | ✔ | ✔ | ✔ | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
VBA-rr | ✔ | ✔ | ✔ | ✔ | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
BGB | ✔ | ✔ | ✔ | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
Gambatte Speedrun | ✔ | ✔ | ✔ | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
GSE (Game Boy Speedrun Emulator) | ✔ | ✔ | ✔ | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | ||
BizHawk (EmuHawk) | ✔ | ✔ | ✔ | ✔ | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
DuckStation | — | — | — | — | ✔ | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
MelonDS | — | — | — | — | — | ✔ | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
FCEUX | — | — | — | — | — | — | ✔ | — | — | — | — | — | — | — | — | — | — | — | — | — |
SNES9x | — | — | — | — | — | — | — | ✔ | — | — | — | — | — | — | — | — | — | — | — | — |
Dolphin | — | — | — | — | — | — | — | — | ✔ | ✔ | — | — | — | — | — | — | — | — | — | — |
Kega Fusion | — | — | — | — | — | — | — | — | — | — | ✔ | ✔ | ✔ | ✔ | — | — | — | — | — | — |
PCSX2 | — | — | — | — | — | — | — | — | — | — | — | — | — | — | ✔ | — | — | — | — | — |
Project64 | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | ✔ | — | — | — | — |
Cemu | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | ✔ | — | — | — |
PPSSPP | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | ✔ | — | — |
RPCS3 | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | ✔ | — |
Azahar | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | — | 🔶 |
Supported emulators (as of 0.6.7):
- mGBA (GB/GBC/GBA)
- VisualBoyAdvance-Link (GB/GBC/GBA)
- VBA-H (GB/GBC/GBA)
- VBA-rr (GB/GBC/GBA)
- BGB (GB/GBC)
- Gambatte Speedrun (GB/GBC)
- GSE (Game Boy Speedrun Emulator) (GB/GBC)
- BizHawk (EmuHawk) (GB/GBC/GBA)
- DuckStation (PSX)
- MelonDS (NDS)
- FCEUX (NES)
- SNES9x (SNES)
- Dolphin (GC/Wii)
- Kega Fusion (Sega: SMS, MD/Genesis, 32x, SG-1000)
- PCSX2 (PS2)
- Project64 (N64)
- Cemu (WiiU)
- PPSSPP (PSP)
- RPCS3 (PS3)
- Azahar (3DS) (preliminar, help needed)
Supported Systems (as of 0.6.7):
- Nintendo Game Boy
- Nintendo Super Game Boy
- Nintendo Game Boy Color
- Nintendo Game Boy Advance
- Sony PlayStation 1
- Sony PlayStation 2
- Sony PlayStation 3
- Sony PlayStation Portable
- Nintendo DS
- Nintendo 3DS (preliminar, help needed)
- Nintendo Entertainment System
- Super Nintendo Entertainment System
- Nintendo GameCube
- Nintendo Wii
- Nintendo WiiU
- Nintendo 64
- Sega Master System
- Sega Mega Drive / Genesis
- Sega 32x
- Sega SG-1000
- Native PC Games
Emulator memory tooling is traditionally per-emulator and per-system. That fractures tooling for overlays, routing, races, or Twitch integrations. EmuHook normalizes those differences behind a single AHK class, TCP sockets, WebSockets or HTTP REST API (Java), so your higher-level code (events, UI, networking) doesn’t care which emulator or system you’re using.
-
One class to hook them all:
EmuHook
manages PID discovery, base module resolution, and a long-lived process handle. -
Per-emulator base address resolution: Internals know where each emulator keeps the emulated RAM (pointer chains or offsets).
-
Dynamic address-space detection (
detectAddressSpace
): Pass a console address like0x02000000
(GBA WRAM) and EmuHook maps it to the real process address automatically. -
Endianness toggle (
setEndian
): Global big/little endian handling; Dolphin is auto-set to big-endian. -
Address conversion for GC/Wii (
addrCnv
): Transparently converts0x80000000..
style addresses to process addresses (including Wii’s dual block0x8E000000
segment). -
Pointer helpers:
rmp/rmpd
(read-multi-pointer),wmp/wmpd
(write-multi-pointer), with final-byte-size support. -
Hex helpers:
rmwh/rmwhd
return 0-padded hex strings for UI/debug output. -
Multi-instance support via PID: pass
"ahk_pid 1234"
to target a specific emulator window.
#Include <EmuHook>
; Attach to mGBA (GBA)
emu := new EmuHook("ahk_exe mGBA.exe", "gba")
; Read a GBA WRAM address directly by console address
; GBA WRAM: 0x02000000..0x02FFFFFF (EmuHook maps this for you)
hp := emu.rmd(0x02037D00, 2, "wram") ; read 2 bytes
ToolTip, HP := %hp%
; Write a byte (e.g., set flag)
emu.wmd(1, 0x0203A120, 1, "wram")
; Clean up when done
emu.Destroy()
ExitApp
Attach by PID instead:
emu := new EmuHook("ahk_pid 12345", "gba")
Or auto-detect one running emulator:
exe := checkRunningEmulator() ; returns e.g. "ahk_exe mGBA.exe", "" or "multiple"
emu := new EmuHook(exe, "gba")
Tip: Some emulators—BizHawk, DuckStation, Dolphin, melonDS, PCSX2, RPCS3, Cemu, Azahar, PPSSPP—require AutoHotkeyU64 due to 64-bit pointers.
emu := new EmuHook("ahk_exe mGBA.exe", "gba")
emu := new EmuHook("ahk_pid 1234", "gbc")
-
romType
recognized in code paths: gbc, gb, gba, nds/ds, nes, snes/sfc, gc, wii, ps2, psx, sg-1000, sms, md, pc (exact checks vary per emulator). -
On construct:
-
Resolves PID and window handle.
-
Opens a persistent process handle (
OpenProcess
). -
Resolves
ram
, and when relevant,wram/sram
. -
For GC/Wii, flips global endian to big and enables address conversion.
-
; Raw read/write (process address) – use when you already know the resolved process address
val := emu.rm(addr, bytes := 1)
emu.wm(value, addr, bytes := 1)
; Auto address-space detected versions
val := emu.rmd(consoleAddr, bytes := 1, ramBlock := "ram|wram|sram")
emu.wmd(value, consoleAddr, bytes := 1, ramBlock := "ram|wram|sram")
; Hex helpers (0-padded)
hex := emu.rmwh(addr, bytes := 1) ; raw
hex := emu.rmwhd(consoleAddr, bytes := 1, "wram") ; detected
; Read through pointers: base -> +o1 -> +o2 ... -> value
val := emu.rmp(base, [o1, o2, ...], byt := 4, finalByt := "")
; Auto-detected address space
val := emu.rmpd(consoleAddr, [o1, o2, ...], byt := 4, finalByt := "")
; Write via pointer chains
emu.wmp(value, base, [o1, o2, ...], byt := 4, finalByt := "")
emu.wmpd(value, consoleAddr, [o1, o2, ...], byt := 4, finalByt := "")
emu.setEndian("l") ; little (default)
emu.setEndian("b") ; big (auto-set for GC/Wii)
emu.Destroy() ; closes handle
; or automatic via __Delete
detectAddressSpace(targetAddr, ramBlock := "ram")
transforms a console address into the real process address based on the system:
-
GBC
-
0xA000..0xBFFF
→ SRAM -
0xC000..0xCFFF
→ RAM -
0xD000..0xEFFF
→ WRAM
-
-
GBA
-
0x02000000..0x02FFFFFF
→ WRAM -
0x03000000..0x03FFFFFF
→ IRAM (exposed asram
)
-
-
Other systems
If you specifyramBlock
("ram" | "wram" | "sram"
) and that base exists, EmuHook just adds it and you’re done. This greatly shortens overlay code.
For Dolphin (GC/Wii), addrCnv()
auto-converts the 0x80000000
(and Wii’s 0x8E000000
) spaces to process addresses.
; Follow base + [0x28, 0x30, 0x43] then read a 4-byte value at the final address
val := emu.rmp(emu.baseProc + 0x275CFC4, [0x28, 0x30, 0x43], 4)
; Same idea but from a console address and auto-detected space
val := emu.rmpd(0x02000000, [0x1C, 0x8], 4, 2) ; e.g., final 2-byte value
emu := new EmuHook("ahk_exe Dolphin.exe", "gc")
; For Dolphin, endian is auto "b" and 0x8000_0000 space is auto converted.
emu.wmd(0x0032, 0x8034A0B2, 2) ; write big-endian halfword
-
OpenProcess once, reuse: handle stays open until
Destroy
/script exit → lower overhead for high-frequency reads (>~300.000 reads per second on a Intel i7 8700K). -
No repeated PID lookups: resolved once in
__New
. -
Endian handling centralized**: write path builds a byte array for big-endian writes; reads recompose integers properly.
-
Auto-mapping:
detectAddressSpace
reduces boilerplate and mismatches when you switch emulators.
-
Overlay UI: Use AHK GUIs or offload to a browser source via local WebSocket/HTTP (e.g., AHK ↔ Node/WS).
-
Event system: Wrap reads in a tiny dispatcher.
-
Races/crowd control: Expose a simple command bus (e.g., read chat → translate into
wmd()
writes).
-
0.6.8 - Add text extraction/injection support.
-
0.6.7 - Add support for Nintendo 3DS via Azahar (preliminar, help needed).
-
0.6.6 - Add support for Sony PlayStation 3 via RPCS3.
-
0.6.5 - Add support for Nintendo WiiU via Cemu.
-
0.6.4 - Add support for Sony PlayStation Portable via PPSSPP.
-
0.6.2 - 0.6.3 - Add support for Nintendo64 via Project64 & add functions to handle module base address resolution & dynamic n64 address resolution.
-
0.6.1 - Add support for Sony PlayStation 2 via PCSX2.
-
0.6.0 — Add support for Sega Mega Drive, 32x. Minor improvements to dynamic read system.
-
0.5.9 — Add support for some Sega systems through Kega Fusion (SG-1000, SMS)
-
0.5.8 — PC game hooking (not just emulators)
-
0.5.7 — Major GC/Wii upgrades; inner pointers usable with unconverted addresses
-
0.5.5 — Endianness is global and auto-set for GC/Wii
-
0.5.4 — Dynamic address-space fallback shortens commands
-
0.5.1 — GC/Wii support for Dolphin 2506a + endian toggle
-
0.5.0 — Keep handles open until destroyed (perf boost)
-
0.4.x — DuckStation (PSX), melonDS (NDS), GSE (Gambatte), FCEUX (NES), SNES9x (SNES), pointer-chain helpers, BizHawk fixups
-
0.3.x — BizHawk, Gambatte, VBA variants; multi-instance; SRAM tracking
These examples are built on the EmuHook core library described above, demonstrating practical applications and integrations.
Purpose:
A standalone real-time memory viewer for Game Boy Color titles, using EmuHook’s address-space detection to read live game data.
Key points:
- Targets GBC emulators supported by EmuHook (
mGBA
,VBA
, etc.). - Uses
rmd()
to fetch memory in console address space. - Displays values in a scrolling or fixed window for debugging/hacking.
- Auto-refresh loop for live updates.
Usage:
Great for reverse-engineering games, finding health/score addresses, or monitoring event triggers.
Purpose:
Extends EmuHook into a local HTTP API, allowing overlays, scripts, or remote services to query/write emulator memory without running AHK on the same machine.
Key points:
-
Wraps EmuHook calls inside a lightweight HTTP server.
-
Responds with JSON for memory reads, accepts POST for writes.
-
Can be polled by OBS browser sources, Node.js servers, or Twitch bots.
-
Supports multiple endpoints like
/read?addr=...
and/write
.
Usage:
Ideal for cross-language integrations (e.g., JS overlays), race coordinators, or crowd-control tools.
Purpose:
A centralized service that runs EmuHook and exposes its capabilities over the network, acting as a hub for multiple tools to interact with the emulator simultaneously.
Key points:
-
Built on
Socket.ahk
providing:-
TCP/WebSocket handling
-
Config parameter (addresses, update interval...)
-
Persistent memory watchers
-
-
Acts as a bridge between local emulator memory and multiple remote subscribers.
-
Reads config from a file and exposes those RAM addresses via a specific TCP port.
Usage:
Perfect for multi-user setups (e.g., a Twitch channel with both an overlay and a chat bot reading/writing memory in real time).
-
Finish SRAM mappings across all emulators.
-
Improve support for 3DS.
-
Add support for Dreamcast, Sega Saturn, WonderSwan, NeoGeo.
-
Add support for (low-priority) Atari: (Lynx, Jaguar, 2600...), Amstrad CPC, ZX Spectrum, Vectrex, Commodore 64.
-
Create search tool example.
-
Unify GBC/GBA on all capable emulators.
-
Migrate to AHK v2 ?.
EmuHook’s power lies in its consistency: once you target an address for one emulator, you can usually switch emulators without changing your overlay logic. It’s a solid foundation for interactive, real-time tooling—speedrunning races, Twitch crowd-control, data mining, automation frameworks or just deep game debugging.
[Wii, GBC, PSX, NDS & SNES] 🎬Real-Time RAM Viewer & Editor
[Game Boy Color] Pokemon Crystal - Multiplayer Proof of Concept
Tracks player positions and shares them between concurrent emulators so that you can see other players on your game.
I made a long video explaining and testing this here.
[Super Nintendo] Super Mario World - Web Tracker (Java branch of EmuHook)
Tracks player data and displays it in a transparent web panel that you can add to OBS.
This example runs on the Java branch of EmuHook and has JavaScript routines that periodically calls each endpoint for collecting and displaying data.
[Game Boy Color] Kirby's Dream Land 2 - OBS Overlay + Godot
This overlay is made in the Godot game engine, EmuHook exposes a TCP socket / WebSockets endpoint and then Godot receives data periodically for updating the UI.
[GameCube] Eternal Darkness: Sanity's Requiem - SRT
Tracks player data and shows a simple UI. This is what got me into inner pointers + big-endian settings being added to EmuHook!
I have a small demo video here:
[Game Boy Advance] Wario Land 4 - Multiplayer & Touch Controls
Tracks player positions and shares them between concurrent emulators so that you can see other players on the Real-Time map, similar to Super Mario 64 DS.
[Game Boy Advance] Pokemon Fire Red - Spinda Pattern Generator (Real-Time)
A web connected to an EmuHook backend via WebSockets allow you to draw a Spinda and will force the next encounter to find the desired Spinda that you just drew.
I have a small demo video here
I have a full explanation + live programming session here (long)
[Game Boy Color] Pokemon Crystal - Data Mining & Automation Framework
Where do I start?
There is a Trainer Card Tracker that tracks player data, such as casino coins, badges, play time, player id, name, money, current map name, current bgm name, repel steps...
There is a Real-Time map that will change depending on the area you are in.
There is an enemy team tracker + enemy pokemon stats viewer with all sorts of info.
There is a player team tracker + active pokemon stats viewer.
There is a little Cheat Menu for debugging and quick testing.
There is a Daycare Viewer with info on compatibility, steps, egg management, shinyness...
There is a Real-Time Pokedex viewer showing what you have seen, not seend and captured.
There is a Pokemon Announcer system made in Godot that gives alerts on certain events.
And lastly an Active Pokemon's possible movepool so you don't have to search a guide on what your Pokemon will learn next.
I have a few demo videos on this one:
[Nintendo DS] Metroid Prime Hunters - Player Health & Points Tracker
A tracker made for online matches because the netcode in MPH is not really good, this way you can predict lag seeing when you actually hit a player.
Actually this only works for bot matches because health data is not shared in online matches, but it doesn't stop anyone from creating a middleware server for upgraded clients that do share this data using EmuHook (I am too lazy to do that right now but it should be a rather simple task, commissions are open here I guess hehe).
[Game Boy Color] Pokemon Crystal - HTTP REST API Pokemon Home/Bank
I don't like to depend on third party services like the actual Pokemon Home, so I made my own.
I can store my pokemons on the cloud, trade them back to the game and so on.
There is a full video explaining each and every step I did for making this project here:
I made an Unofficial Pokemon Home Cloud Storage without Nintendo
[PC & PSX] Resident Evil 1 (1996) - Real Time Map, Health Overlay & AutoSplitter
This is a set of tools I have made for RE1, it features a Real-Time map, just like the DS version, a health hud and an autosplitter.
[Game Boy Advance] Wario Land 4 - Speedrun Tracker
It tracks A LOT of data, it also calculates the completion percentage for 100% speedruns.
[Game Boy Color] Pokemon Pinball - Adding Rumble Feature to unsupported emulators
This example reads constantly the status of the rumble and then through the XInput.dll library it makes your controller vibrate, no matter if the emulator supports vibration or not.
[PC & PSX] Resident Evil 1 (1996) - Entity Radar, IGT, Inventory Viewer
This overlay has a custom, from scratch IGT tracker, inventory tracker, autosplitter, entity radar and a health hud.
[Game Boy Advance] Wario Land 4 - Web Tracker
This is one of my first Java branch testing that expose a REST API and via timed calls it does HTTP queries to the backend for gathering game info.
[PSX] Parasite Eve 2 - SRT (Commission)
This is pretty much the one that started it all when dealing with emulators. I was commissioned to do this for practicing the Parasite Eve II speedrun, it tracks current enemy HP.
[PC] Resident Evil 1 (1996) - Twitch Crowd Control
This scripts hooks onto Twitch chat via IRC and then translates commands into in-game actions, like playing with your inventory, health, enemies, status effects and so on.
There are programmable cooldowns and multi language support.
I also made some achievement systems using EmuHook similar to Retro Achievements like in this demo.
Here is a PS2 demo video using PCSX2 and Haunting Ground.
Here is a N64 demo video using Project64 and Super Mario 64.
Here is a WiiU and PSP demo video using Cemu and PPSSPP on Zelda Breath of the Wild and God of War.
-
Pokémon Crystal: Multiplayer (You can see other players online real-time on the map)
-
Metroid Prime Hunters: Online Player Health + Points Tracker.
-
Kirby's Dream Land 2: Animated Real-Time Overlay (Godot).
-
Resident Evil 1: Auto Splitter for speedrunning.
-
Pokémon Crystal: Pokemon Home Implementation (MySQL + REST API Cloud Pokémon Storage System)
-
Resident Evil 1: Real-Time Map.
-
Resident Evil 2: Health + Inventory HUD.
-
Pokémon Crystal: Data Mining Tools.
-
Wario Land 4: Multiplayer + Touch Controls (Similar to Mario Maker)
-
Resident Evil 2: Achievement System.
-
Pokémon Crystal: 3D Pokémon Web Overlay.
-
Parasite Eve 2: Enemy Health Tracker (Commission).
-
Pokémon Pinball, Perfect Dark: Emulator Rumble Support.
-
Super Mario World: Real-Time Web Stats Tracker for OBS Overlays.
-
Pokémon Fire Red: Speedrun Tracker.
-
Dino Crisis 2: Health HUD.
-
Call of Cthulhu Dark Corners of the Earth: Health + Inventory HUD.
-
Resident Evil 1: IOT Tuya Home RGB Light Automation based on in-game Health Status.
-
Pokémon Fire Red: Spinda Pattern Generator.
-
Eternal Darkness: Real-Time Player Stats Tracker.
-
Pokémon Crystal: Multi-Instance Shiny Hunting BOT.
-
Resident Evil 1: Enemy Radar (Godot).
-
Wario Land 4: Speedrun Tracker.
-
Resident Evil 1: Twitch Crowd Control (Twitch chat can manage inventory, player health, enemies, camera status...)
-
Use a Wii Balance Board to control the Shinyness of Wild Pokémons.
-
Use a TV Remote to set in-game values for speedrun practice.
This project would be nothing without people contributing to theese tools.
- Each and every emulator.
- Cheat Engine.
- Ghidra.
- AutoHotkey & theese libs:
- Java, specially JNI.
- Websockify.
- Scite4Autohotkey.
Some parts of this article have been auto-generated with AI because of lack of free time, however I have revised that the information given here meets the current version specification.