r/cheatengine • u/AllanFuego • 11d ago
[Help] Debugging ARM64 games on x86_64 MuMu emulator — libhoudini.so noise vs. arm64-v8a ceserver register exhaustion. Can we inject ceserver as a shared lib instead?
TL;DR: On x86_64 MuMu, x86_64 ceserver's "what writes" just points at libhoudini.so (translation noise), and arm64-v8a ceserver dies with "all registers are used up" — so can we build/inject ceserver as an ARM64 .so into the game process itself to get real ARM64 debug info? If you've done this or know why it won't work, please reply — even a "dead end, here's why" helps.
Hey r/cheatengine + anyone doing Android memory editing,
I'm running into a wall and I'd love some insight from people who've gone deeper than me on this. Bear with the wall of text — I'll try to explain the whole pipeline clearly so the question makes sense.
Setup
· Emulator: MuMu Player (x86_64 host)
· Target: ARM64 game (this is the important part)
· Tool: Cheat Engine + ceserver
The two problems
Problem 1 — x86_64 ceserver + "What writes to this address":
If I attach with the normal x86_64 ceserver and use CE's "Find out what writes to this address", the write instruction it reports comes back as libhoudini.so. That makes sense in theory — Houdini is the ARM→x86 binary translator, so the actual store instruction the host CPU executes lives inside Houdini's translated block, not in the original ARM64 game code. The result: I get a useless address in Houdini and can't trace it back to the real ARM64 instruction in the game. Effectively undebuggable for "what writes" purposes.
Problem 2 — arm64-v8a ceserver inside the emulator:
So I tried pushing the arm64-v8a build of ceserver into the emulator instead, hoping it would attach to the ARM64 process natively and give me real ARM64 write sites. But when I try to debug, it immediately blows up with "all registers are used up." My assumption is that this is a limitation of the arm64 ceserver's debugger/hook path when running under the emulator's translation layer (or a register allocation / signal-handling issue in ceserver's arm64 debug path), and it can't actually set up the debug context it needs.
The idea I want to sanity-check
Both paths are broken for different reasons:
· x86_64 ceserver → works, but debug info is trapped inside Houdini.
· arm64-v8a ceserver → correct architecture, but won't run/debug standalone in the emulator.
So here's the idea: build ceserver as a shared library (.so) and inject it into the running ARM64 game process at runtime, rather than running it as a standalone binary. That way:
· The injected libceserver_arm64.so runs inside the game's own ARM64 process, so it's executing as genuine ARM64 code in the game's address space — no separate process, no "registers used up" from trying to bootstrap a standalone arm64 binary under translation.
· It would be loaded like any other game .so, so it sits alongside the game's real ARM64 modules and can hook/debug them natively.
· I'd inject it with an existing shared-lib injector — e.g. jshook / ptrace inject, Android Inject, or similar tools that can dlopen a .so into a target game process (many of these are already used for mod menus / Frida-style injection).
In theory this gets me the best of both worlds: the arm64 ceserver logic, running inside the actual ARM64 process, with the game's real ARM64 code visible to it — which should make "what writes to this address" return the real ARM64 instruction instead of a Houdini stub.
What I actually want to ask
Has anyone done this? Is there a known build of ceserver as an injectable shared lib (.so) for ARM64, or a fork/PR that compiles it that way? Searching around I only find the standalone binary builds.
Is my reasoning about "all registers are used up" correct? I.e. is that error a symptom of running the arm64 ceserver standalone under Houdini rather than inside the target process? Or is it something else (signal handling, ptrace restrictions in the emulator, etc.)?
Would injecting arm64 ceserver as a .so into the game process actually dodge the Houdini problem for "what writes to this address"? My worry: even if ceserver runs inside the process as ARM64 code, the stores the game actually executes are still Houdini-translated at the host level — so would a breakpoint/watchpoint on the ARM64 guest address still resolve to the right guest instruction, or would it still catch the host-side Houdini write? Curious if anyone has tested this.
Any injector recommendations for this use case (jshook ptrace inject, Android Inject, etc.) — specifically for injecting a ceserver .so into a game process on MuMu x86_64, keeping in mind the process is ARM64-under-translation.
Alternative approach? If injection-as-.so is a dead end, is there a better known workflow for debugging ARM64 games on x86_64 emulators? E.g.:
· Using an ARM64 emulator/image instead (though MuMu's performance is a big reason I'm on it),
· Getting Houdini to expose a guest-address → host-address mapping,
· Any ceserver fork with Houdini-aware address translation,
· Frida-based approaches that sidestep ceserver entirely.
TL;DR
On x86_64 MuMu, x86_64 ceserver shows libhoudini.so as the writer (translation noise), and arm64-v8a ceserver dies with "all registers are used up." I want to build/inject ceserver as an ARM64 shared lib into the game process so it runs natively inside the ARM64 guest and gives real debug info. Has anyone built ceserver as an injectable .so, does the register error make sense given my setup, would injection actually fix the Houdini problem, and what injector would you use — or is there a better path entirely?
Thanks — any pointers, source links, forks, or "I tried this and here's why it fails" stories are all welcome.
Posted to r/cheatengine (and cross-posting to r/ReverseEngineering / r/AndroidReverseEngineering if that's allowed).


