A Lightweight Native Instrumentation Library for Android Security Research
Android-Mem-Kit is a minimal-overhead, pure C library for Android native instrumentation. It provides memory patching, function hooking, and symbol resolution capabilities for security research, debugging, and educational purposes.
This library is intended for:
- β Security research (analyzing app security, reverse engineering)
- β Educational purposes (learning Android internals, hooking techniques)
- β Application debugging (understanding native code behavior)
- β Malware analysis (dynamic analysis of malicious apps)
- β Penetration testing (with proper authorization)
NOT intended for:
- β Game cheating or bypassing game protections
- β Circumventing security in production applications
- β Any illegal activities or unauthorized access
Always use responsibly and within legal boundaries.
| Feature | Implementation | Description |
|---|---|---|
| Memory Patching | Custom (mprotect-based) | Cross-page safe memory patching with XOM bypass |
| Function Hooking | ShadowHook | ByteDance's inline hook library with excellent stability |
| Symbol Resolution | XDL | Advanced symbol resolution bypassing Android 7+ linker restrictions |
| IL2CPP Support | Built-in | Unity app analysis and instrumentation |
- Small Binary Size: <100KB overhead (vs several MB for Rust)
- Simple NDK Integration: No FFI bridge or complex build setup
- Direct JNI/NDK Access: Native C integration with Android frameworks
- Modern Tooling: Leverages battle-tested libraries (ShadowHook, XDL)
# Android NDK (r25b or newer)
export ANDROID_NDK_HOME=/path/to/your/android-ndk-r29
# CMake 3.10+
cmake --versiongit clone https://github.com/HanSoBored/Android-Mem-Kit.git
cd Android-Mem-Kit
# Clone dependencies
./setup.shmkdir build && cd build
# Configure for Android ARM64
cmake .. \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a \
-DANDROID_PLATFORM=android-21
# Build
cmake --build .#include "memkit.h"
#include <android/log.h>
#define LOG_TAG "MyResearch"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
// Original function pointer
static int (*orig_SSL_read)(void* ssl, void* buf, int num) = NULL;
static void* ssl_hook_stub = NULL;
// Hooked function - log SSL reads for research
static int my_SSL_read(void* ssl, void* buf, int num) {
LOGI("SSL_read called with buffer: %p, size: %d", buf, num);
// Call original
int ret = orig_SSL_read(ssl, buf, num);
if (ret > 0) {
LOGI("Received %d bytes", ret);
// Analyze decrypted data (for research only!)
}
return ret;
}
// Initialize when library loads
__attribute__((constructor))
void init() {
// Initialize hooking
if (memkit_hook_init(SHADOWHOOK_MODE_UNIQUE, false) != 0) {
LOGE("Failed to init ShadowHook");
return;
}
// Hook SSL_read (example for security research)
ssl_hook_stub = memkit_hook_by_symbol(
"libssl.so",
"SSL_read",
(void*)my_SSL_read,
(void**)&orig_SSL_read
);
if (ssl_hook_stub) {
LOGI("SSL_read hooked successfully!");
}
}For detailed usage and examples, see:
- docs/USAGE.md - Complete API reference and examples
- docs/RECIPES.md - Common patterns and use cases
- docs/SECURITY_RESEARCH.md - Legitimate research examples
Android-Mem-Kit/
βββ CMakeLists.txt # Build configuration
βββ include/
β βββ memkit.h # Public API header
βββ src/
β βββ memory.c # Memory patching (mprotect-based)
β βββ hooking.c # ShadowHook wrapper
β βββ il2cpp.c # XDL wrapper for symbol resolution
βββ examples/
β βββ main.c # Complete usage example
βββ docs/
β βββ USAGE.md # Detailed documentation
β βββ RECIPES.md # Common patterns
β βββ SECURITY_RESEARCH.md # Research use cases
βββ setup.sh # Dependency setup script
βββ deps/
βββ xdl/ # XDL library (git submodule)
βββ shadowhook/ # ShadowHook library (git submodule)
// Get library base address
uintptr_t base = memkit_get_lib_base("libtarget.so");
// Create patch from hex string
MemPatch* patch = memkit_patch_create(base + 0x1234, "00 00 80 D2");
// Apply/restore/free
memkit_patch_apply(patch);
memkit_patch_restore(patch);
memkit_patch_free(patch);// Initialize (call once)
memkit_hook_init(SHADOWHOOK_MODE_UNIQUE, false);
// Hook by symbol
void* stub = memkit_hook_by_symbol("lib.so", "func_name", my_func, (void**)&orig);
// Hook by address
void* stub = memkit_hook(address, my_func, (void**)&orig);
// Unhook
memkit_unhook(stub);// Auto-cached function call
void* (*il2cpp_domain_get)(void) = IL2CPP_CALL(void*, "il2cpp_domain_get");
void* domain = il2cpp_domain_get();
// Resolve from .symtab for internal symbols
void* internal = memkit_il2cpp_resolve_symtab("_ZN6Player13InternalInitEv");// Hook SSL_verify_cert_chain to always return success
static int (*orig_SSL_verify_cert_chain)(void*) = NULL;
static int my_SSL_verify_cert_chain(void* cert_chain) {
LOGI("SSL certificate verification intercepted");
return 1; // Always succeed (for research only!)
}
memkit_hook_by_symbol("libssl.so", "SSL_verify_cert_chain",
my_SSL_verify_cert_chain, (void**)&orig_SSL_verify_cert_chain);// Hook signature verification to return valid
static int (*orig_verifySignature)(const char* data) = NULL;
static int my_verifySignature(const char* data) {
LOGI("Signature verification called with: %s", data);
return 1; // Always valid (for analysis only!)
}
memkit_hook_by_symbol("libtarget.so", "verifySignature",
my_verifySignature, (void**)&orig_verifySignature);// Trace all calls to a function
static void (*orig_targetFunc)(int param) = NULL;
static void my_targetFunc(int param) {
LOGI("targetFunc called with param: %d", param);
// Log stack trace, parameters, etc.
orig_targetFunc(param);
}
memkit_hook_by_symbol("libtarget.so", "targetFunc",
my_targetFunc, (void**)&orig_targetFunc);| Mode | Description | Use Case |
|---|---|---|
SHADOWHOOK_MODE_UNIQUE |
Same address can only be hooked once | Most research scenarios |
SHADOWHOOK_MODE_SHARED |
Multiple hooks allowed (recursion prevention) | When using multiple SDKs |
SHADOWHOOK_MODE_MULTI |
Multiple hooks allowed (no prevention) | Advanced use cases |
// If memkit_get_lib_base() returns 0:
// 1. Ensure library is loaded in target process
// 2. Use exact name (e.g., "libil2cpp.so" not "il2cpp")
// 3. Add retry loop to wait for loading
uintptr_t base = 0;
for (int i = 0; i < 30 && base == 0; i++) {
base = memkit_get_lib_base("libtarget.so");
if (base == 0) sleep(1);
}void* stub = memkit_hook_by_symbol("lib.so", "func", my_func, (void**)&orig);
if (stub == NULL) {
int err = shadowhook_get_errno();
const char* msg = shadowhook_to_errmsg(err);
LOGE("Hook failed: %d - %s", err, msg);
}Common errors:
SHADOWHOOK_ERRNO_HOOK_DLSYM- Symbol not foundSHADOWHOOK_ERRNO_HOOK_ENTER- Failed to enter hookSHADOWHOOK_ERRNO_UNINIT- ShadowHook not initialized
| Rust API | C Equivalent |
|---|---|
memory::get_lib_base() |
memkit_get_lib_base() |
MemoryPatch::from_hex() |
memkit_patch_create() |
hooking::attach() |
memkit_hook() / memkit_hook_by_symbol() |
il2cpp::resolve_export() |
memkit_il2cpp_resolve() |
il2cpp_call!() |
IL2CPP_CALL() |
This project utilizes excellent open-source libraries:
- ShadowHook by ByteDance - Inline hooking for Android
- XDL by HexHacking - Dynamic linker bypass
- Dobby - Lightweight hooking framework (original inspiration)
- KittyMemory - Memory patching library (original inspiration)
MIT License - See LICENSE file for details.
Contributions are welcome! Please read CONTRIBUTING.md first.
- π More documentation and examples
- π§ Additional utility functions
- π Bug fixes and improvements
- π§ͺ Test cases for different Android versions
If you find a security vulnerability, please see SECURITY.md for responsible disclosure guidelines.
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Built for the security research community. Use responsibly.