Library / SDK
zhkl0228/unidbg avatar
zhkl0228/unidbg

unidbg: Emulating Android Native Libraries on the JVM

Allows you to emulate an Android native library, and an experimental iOS emulation

5,232 stars1,185 forksJavaApache-2.0

At a glance

What is it?
unidbg loads an Android .so or an iOS Mach-O into a Java process, emulates the JNI Invocation API and syscalls, and exposes the guest through a console debugger, a gdb stub, and an MCP server for AI-assisted analysis. It is an educational project with a real debugger attached, and its release cadence is uneven.
Who is it for?
Adopt unidbg if you need to run an ARM32 or ARM64 native library inside a JVM process for analysis, hooking, tracing, or feeding symbol and memory data to an AI tool over MCP. Do not adopt it if you need a supported product with a predictable release train: v0.9.7 shipped in 2022, v0.9.8 in 2024, and v0.9.9 in 2026, so pin a tag and read the diff between them.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What unidbg actually replaces

unidbg exists so that an ARM native library can execute without an Android device or an iOS device in the loop. The README describes it as a way to emulate an Android native library, with experimental iOS emulation, and frames the whole thing as an educational project for learning the ELF and MachO formats and ARM assembly. That framing matters when you evaluate it: the target user is someone who wants to step through a .so in a debugger, not someone who wants a managed mobile testing cloud.

The practical use case is a Java test harness that loads a native library, calls JNI_OnLoad, and then invokes exported functions with controlled arguments. Because the emulator implements JavaVM and JNIEnv, the guest library can call back into Java, which is what makes instrumented analysis possible at all. The README also lists memory leak detection for emulated native code with guest backtrace and host stack trace, which is the kind of feature you only build after spending a lot of time staring at a crashed guest.

It is not a general Android emulator. There is no Android framework, no Activity lifecycle, no UI. If your problem is running an app, unidbg is the wrong layer.

Backends, hooks and the shape of the emulation

The architecture is a Java core in unidbg-api with platform modules in unidbg-android and unidbg-ios, sitting on top of interchangeable CPU backends. The README names four: Unicorn, dynarmic, Linux KVM, and the Apple M1 hypervisor, with the hypervisor described as the fastest ARM64 backend and KVM support listed for a Raspberry Pi B4. Choosing a backend is not cosmetic. The README states that next_block and step_until_mnemonic are Unicorn only, so a debugging workflow built around those two tools constrains you to that backend.

Hooking is layered by platform rather than unified. Android import hooking uses xHook, inline hooking uses Dobby, and iOS gets fishhook, substrate, and whale. That means the same conceptual operation, intercepting a call, has a different implementation and a different set of edge cases depending on which family you are emulating.

The debugger surface is where the project has invested most visibly. The README lists a simple console debugger, a gdb stub, instruction trace, and memory read/write trace on the Unicorn backend. The MCP integration is newer and is the part most likely to change how people work with the tool: when the debugger is active, typing mcp in the console starts a server that AI tools such as Cursor can connect to.

Installing and running your first emulated library

The repository is a Maven multi-module build. The top level contains pom.xml, mvnw, mvnw.cmd, and the three modules: unidbg-api, unidbg-android, unidbg-ios. There is no published install step in the README beyond the build files themselves, so the entry point is the wrapper scripts.

Build the project with the Maven wrapper:

bash
./mvnw install

On Windows the repository ships mvnw.cmd, and there are also test.cmd and test.sh at the top level for running the test suite. After the build, add the module you need as a dependency in your own project.

For an Android target, the first real use is attaching the debugger and setting a breakpoint before running your emulation logic. The README gives exactly this example:

java
Debugger debugger = emulator.attach();
debugger.addBreakPoint(address);
// run your emulation logic - debugger pauses when breakpoint is hit

When the breakpoint is hit, Breaker.debug() pauses the emulator. At that console you type mcp to start the MCP server, or mcp 9239 to specify the port. The README then shows the Cursor configuration:

json
{
  "mcpServers": {
    "unidbg-mcp-server": {
      "url": "http://localhost:9239/sse"
    }
  }
}

If you want the AI to re-run a function repeatedly with different inputs rather than stop once, the README describes a second mode built on McpToolkit, where you subclass McpTool, return a name, description and paramNames, and implement execute. The native library is loaded once and the process stays alive between runs.

The MCP toolkit is powerful and the least settled part

The MCP tool list in the README is long: register read and write, disassembly with branch targets annotated with symbol names, assemble, callstack, memory read and write, C string and C++ std::string reads with SSO detection, pointer chain reads with symbol resolution, typed reads, memory search with permission filters, memory map listing, allocation tracking, patching, breakpoints by address, symbol or module offset, stepping, tracing of code and of memory reads and writes, and function calls by address or by symbol. iOS-only additions cover objc_msgSend inspection, class name lookup, class dumping, and GPB protobuf schema dumping.

That breadth is the selling point and also the risk. The README states that next_block and step_until_mnemonic are Unicorn only, and the iOS tools are gated on Family=iOS, so the tool surface you actually get depends on backend and platform. The custom tool interface is described in prose, and the README section on it is truncated mid-sentence in the published text, which is a fair signal of how fresh this area is. Treat the MCP path as usable but moving.

One design decision worth noting: get_objc_class_name is documented as pure memory parsing with no state change. That is the right default for an analysis tool, and it suggests the author is thinking about tool calls that must not perturb the guest.

Where unidbg is the wrong tool

The README opens with a warning: use it at your own risk, and describes the project as educational. Take that literally. There is no support contract, no compatibility matrix, and no documented rollback path if a version change breaks your harness. The release history shows the shape of the risk: v0.9.7 in July 2022, v0.9.8 in September 2024, v0.9.9 in March 2026. A two-year gap between minor versions means a fix you need may sit on master for a long time before it reaches a tag, and the last push was on 2026-09-08, so master moves between releases.

Backend selection is a real constraint rather than a preference. If your debugging workflow depends on next_block or step_until_mnemonic, you are on Unicorn, and you cannot simply switch to dynarmic or the M1 hypervisor for speed without losing those tools. Conversely, if you need the fastest ARM64 path, the README points at the hypervisor, which is Apple M1 specific.

Finally, if what you actually need is to test an app end to end, including framework behaviour, unidbg will not get you there. It emulates a native library and the JNI boundary around it, not Android.

Compared with angr and Qiling

The closest alternatives are binary analysis frameworks that also emulate code, and the difference is where the abstraction sits. Tools like angr and Qiling are built around a Python analysis workflow: you script the emulation, define hooks, and drive symbolic or concrete execution from Python. unidbg is a Java library with a JNI emulation layer, so the guest library behaves as if it were loaded by an Android runtime, with JavaVM and JNIEnv available and JNI_OnLoad callable.

That difference decides the choice. If your goal is to call a specific exported function with specific arguments and inspect the result, including callbacks into Java, unidbg's JNI emulation is doing work the Python frameworks do not attempt. If your goal is broad symbolic exploration of many code paths, the Python ecosystem is the more natural fit, and unidbg's MCP tools, useful as they are, are aimed at interactive debugging rather than automated search.

Note that the README's related tooling, Dobby, xHook, fishhook, whale, capstone and keystone, are components unidbg integrates rather than competitors.

Maintenance, licensing and what a version bump costs

The repository is not archived, and the last push was on 2026-09-08, so the project is being touched, but the release tags tell a slower story than the commit log. Between v0.9.7 and v0.9.9 there are roughly three and a half years, and the MCP integration appears to have landed in that window. Anyone pinning a version should read the diff rather than assume a patch-level bump is inert, because the debugger and MCP surfaces are where recent work is concentrated.

unidbg is licensed under Apache-2.0. That is a permissive licence, and the practical implication for most adopters is that you can use and redistribute it, including in commercial analysis tooling, provided you keep the licence and notices intact. It also includes an explicit patent grant. This is not legal advice; if you are shipping a product that embeds unidbg, have counsel confirm the notice requirements and check the licences of the bundled components, since Dobby, xHook, fishhook, whale, capstone and keystone carry their own terms. The README does not document an upgrade or migration procedure, so budget for reading the source when you move between tags.

Editorial conclusion

Adopt unidbg if you need to run an ARM32 or ARM64 native library inside a JVM process for analysis, hooking, tracing, or feeding symbol and memory data to an AI tool over MCP. Do not adopt it if you need a supported product with a predictable release train: v0.9.7 shipped in 2022, v0.9.8 in 2024, and v0.9.9 in 2026, so pin a tag and read the diff between them. Before committing, verify that your target library's imported symbols resolve on the backend you plan to use, since the hook and syscall paths differ between Unicorn, dynarmic, KVM and the Apple M1 hypervisor.

Frequently asked questions

What is the purpose of an emulator in the context of unidbg?

unidbg uses emulation to execute an ARM32 or ARM64 native library inside a JVM process, so you can run and inspect Android .so files, or experimental iOS code, without a device. It emulates the JNI Invocation API, JavaVM, JNIEnv and syscall instructions so the guest library behaves as if it had been loaded normally.

What are Android native libraries, and how does unidbg handle them?

unidbg targets compiled native libraries rather than the Android framework. The README states it emulates an Android native library and supports Android import hooking through xHook plus inline hooking through Dobby, which is how calls into and out of the guest library are intercepted.

Is unidbg an Android emulator?

No. unidbg emulates a native library and the JNI boundary around it, not an Android system. There is no Android framework, Activity lifecycle or UI in the repository layout, which contains unidbg-api, unidbg-android, unidbg-ios and backend modules.

How to use unidbg for the first time?

Build the Maven multi-module project with the wrapper script, then attach the debugger to your emulator and add a breakpoint before running your emulation logic. The README shows emulator.attach() followed by debugger.addBreakPoint(address); execution pauses when the breakpoint is hit, and you can type mcp at the console to start the MCP server for AI-assisted analysis.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. README
  4. Releases
  5. zhkl0228/unidbg on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/zhkl0228-unidbg.svg)](https://hysenlabs.com/projects/zhkl0228-unidbg)