Skip to content

About

External memory read/write for Android apps under BlueStacks Air on macOS. Header C++. Reads and writes by the app's own virtual addresses via ARM64 page-table walking from the host.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

memory.h - external memory read/write for BlueStacks on macOS

Single-header C++17 library for reading and writing the memory of an Android app running under BlueStacks Air on macOS — by the app's own virtual addresses, entirely from the host.

Nothing is injected. No agent runs in the guest. The guest is never modified. The host process walks the guest's ARMv8 page tables directly out of the VM's RAM.

Built with the help of Claude.

#include "memory.h"

mem::Target T;
T.attach();                                 // find the BlueStacks Air VMM process
T.discover("libil2cpp.so");                 // locate the app, resolve its modules

uintptr_t base = T.moduleBase("libil2cpp.so");
int hp = T.read<int>(base + 0x1234);
T.write<int>(base + 0x1234, 999);

No dependencies, nothing to link, no build system. Copy memory.h into your project and include it.

Install

curl -O https://raw.githubusercontent.com/ankitrawatgit/Bluestacks-external-memory-rw-macos/main/memory.h

That's the whole library. example.cpp and build.sh in this repo exist only to demonstrate and verify it.

./build.sh && sudo ./memtest

Requirements

  • macOS on Apple Silicon
  • BlueStacks Air running an ARM64 Android guest with a 4 KB page granule
  • csrutil enable --without debug, set from Recovery
  • Your process running as root

Nothing else — no code signing, no entitlements. task_for_pid on another process is gated by SIP's debugging restriction, so lifting that and running as root is sufficient.

Set the SIP flag from Recovery — hold the power button at boot, then Utilities > Terminal:

csrutil enable --without debug

That weakens a real security boundary on your machine. Understand the trade before doing it, and put it back with csrutil enable when you're done.

Usage

#include "memory.h"

static mem::Target T;

// --- one-time setup -------------------------------------------------------
if (!T.attach())                      { puts(T.error().c_str()); return 1; }
if (!T.discover("libil2cpp.so"))      { puts(T.error().c_str()); return 1; }

uintptr_t base = T.moduleBase("libil2cpp.so");

// --- reads and writes -----------------------------------------------------
int   hp  = T.read<int>(base + 0x1234);        // 0 if unmapped
float pos = T.read<float>(addr, -1.0f);        // or your own default
T.write<int>(addr, 999);

int out;
if (T.tryRead<int>(addr, out)) { /* checked form */ }

API

Method Notes
attach(pid) / attach(name = "BlueStacks") Opens the VMM task, locates guest RAM
discover(anchorModule) One-time setup, a few seconds. Matches a substring of a SONAME
moduleBase(name) Substring match on SONAME; 0 if not loaded
modules() Every resolved module as {name, base}
read<T>(va, def = T{}) Returns def on failure
tryRead<T>(va, out) Returns false on failure
write<T>(va, v) Goes live immediately
readBytes / writeBytes Bulk; one syscall regardless of size
readString(va, max) NUL-terminated, bounded
chain(base, {…}, &ok) Dereferences between offsets, not after the last
readChain<T>(base, {…}, def) Chain then read
alive() Anchor still an ELF header — detects app restart
invalidate() / setCache(bool) Translation cache control
setProgress(fn) void(const char* stage, float frac) for discover()
error() Why the last failure happened
regions() / splitRamSuspected() Diagnostics, see limitations
pid(), gpaBase(), pgd(), vaBits(), ramSize(), hostBase() Introspection

T requires POD types (static_asserted). Every public method is mutex-guarded, so a polling thread and a render thread can share one Target.

Limitations

  • 4 KB page granule only. Level count, index width, and the output-address mask are hardcoded for it. Android 15+ images may ship 16 KB pages, which needs real code changes rather than tuning.

Intended use

This is memory-forensics tooling. Reverse engineering your own applications, malware analysis inside a disposable emulator, debugging a process you can't attach to, and learning how ARMv8 address translation actually works.

Pointing it at software you don't own is your call and your risk. Modifying an online game's memory violates essentially every such game's terms of service and gets accounts banned — external tooling is not invisible, and anomalous values are visible server-side regardless of how they were produced. It also degrades the experience for other players, which is worth weighing separately from whether you get caught.

Don't use this to interfere with systems you don't own or have permission to test.

About

External memory read/write for Android apps under BlueStacks Air on macOS. Header C++. Reads and writes by the app's own virtual addresses via ARM64 page-table walking from the host.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages