### Watch and Inject on Process Start Source: https://context7.com/mjx0/andkittyinjector/llms.txt Monitor for process restarts and inject a library with a specified delay. ```shell ./AndKittyInjector \ --package com.target.app \ --libs /data/local/tmp/libhook.so \ --watch \ --delay 500000 ``` -------------------------------- ### AndKittyInjector Command-Line Usage Source: https://github.com/mjx0/andkittyinjector/blob/main/README.md This example demonstrates how to launch the AndKittyInjector tool with specific arguments to inject libraries into a target package. It includes options for delayed injection and timeouts. ```shell ./AndKittyInjector --package com.target.package --libs path/to/lib1 path/to/lib2 --memfd --launch --delay 1000000 --timeout 3000 ``` -------------------------------- ### Show Help and Version Source: https://context7.com/mjx0/andkittyinjector/llms.txt Display the help message or the version of AndKittyInjector. ```shell ./AndKittyInjector --help ``` ```shell ./AndKittyInjector --version # Output: AndKittyInjector 5.2.1 ``` -------------------------------- ### Push Binary and Inject Library using ADB Source: https://context7.com/mjx0/andkittyinjector/llms.txt This sequence of ADB commands pushes the injector binary and a hook library to the device, makes the injector executable, and then runs it to inject the library into a target package. ```bash adb push build-arm64/AndKittyInjector /data/local/tmp/ adb push /path/to/libhook.so /data/local/tmp/ adb shell "chmod +x /data/local/tmp/AndKittyInjector" adb shell "su -c '/data/local/tmp/AndKittyInjector \ --package com.example.target \ --libs /data/local/tmp/libhook.so \ --launch --memfd --hide --timeout 3000'" ``` -------------------------------- ### Advanced Injection with Memfd and Launch Source: https://context7.com/mjx0/andkittyinjector/llms.txt Launch the application, inject multiple libraries using memfd for stealth, with specified delay and timeout. ```shell ./AndKittyInjector \ --package com.target.app \ --libs /data/local/tmp/libhook1.so /data/local/tmp/libhook2.so \ --launch \ --memfd \ --delay 1000000 \ --timeout 3000 ``` -------------------------------- ### Make Binary Executable Source: https://context7.com/mjx0/andkittyinjector/llms.txt Before running the injector, ensure the binary has execute permissions. ```shell chmod +x ./AndKittyInjector ``` -------------------------------- ### Initialize KittyInjector with Configuration Source: https://context7.com/mjx0/andkittyinjector/llms.txt Initializes the KittyInjector by resolving necessary symbols in the target process and preparing a remote buffer. Ensure the target process is attached and memory operations are initialized before calling this. Handles potential ABI mismatches and missing symbols. ```cpp #include #include "Injector/KittyInjector.hpp" int pid = KittyMemoryEx::getProcessID("com.example.target"); KittyMemoryMgr kmgr{}; // Seize and immediately interrupt the target thread kmgr.trace = KittyTraceMgr(pid, 0, /*autoStop=*/true); bool seized = kmgr.trace.seize(PTRACE_O_EXITKILL | PTRACE_O_TRACESYSGOOD); if (!seized) { seized = kmgr.trace.attach(PTRACE_O_EXITKILL | PTRACE_O_TRACESYSGOOD); } // On PTRACE_SEIZE the process is not stopped automatically if (seized && cfg.seize) kmgr.trace.stop(); // Initialize memory manager with syscall memory operations if (!kmgr.initialize(pid, EK_MEM_OP_SYSCALL, /*enable_mem_backup=*/true)) { KITTY_LOGE("Failed to initialize KittyMemoryMgr"); kmgr.trace.detach(); return false; } KittyInjector injector{}; if (!injector.init(&kmgr, cfg)) { // Reasons for failure: // - ABI mismatch between injector and target // - remote dlopen not found in target // - memfd_create unavailable but --memfd requested KITTY_LOGE("Injector init failed"); kmgr.trace.detach(); return false; } // injector is ready — proceed to validateElf / inject ``` -------------------------------- ### Compile AndKittyInjector using NDK Source: https://github.com/mjx0/andkittyinjector/blob/main/README.md This shell command sequence outlines the steps to clone the AndKittyInjector repository and compile it using NDK. Ensure NDK_HOME is set correctly. ```shell git clone --recursive https://github.com/MJx0/AndKittyInjector.git cd AndKittyInjector/AndKittyInjector ndk-build.bat ``` -------------------------------- ### KittyInjector::init() Source: https://context7.com/mjx0/andkittyinjector/llms.txt Initializes the KittyInjector by resolving necessary symbols in the target process and preparing a remote buffer on the target's stack for argument passing. This method must be called before any injection operations. ```APIDOC ## `KittyInjector::init()` — Initialize the Injector Resolves remote `dlopen`, `dlclose`, `dlerror`, `dlsym`, and `android_dlopen_ext` symbols inside the target process and prepares a remote buffer on the target's stack for passing arguments. ```cpp #include #include "Injector/KittyInjector.hpp" int pid = KittyMemoryEx::getProcessID("com.example.target"); KittyMemoryMgr kmgr{}; // Seize and immediately interrupt the target thread kmgr.trace = KittyTraceMgr(pid, 0, /*autoStop=*/true); bool seized = kmgr.trace.seize(PTRACE_O_EXITKILL | PTRACE_O_TRACESYSGOOD); if (!seized) { seized = kmgr.trace.attach(PTRACE_O_EXITKILL | PTRACE_O_TRACESYSGOOD); } // On PTRACE_SEIZE the process is not stopped automatically if (seized && cfg.seize) kmgr.trace.stop(); // Initialize memory manager with syscall memory operations if (!kmgr.initialize(pid, EK_MEM_OP_SYSCALL, /*enable_mem_backup=*/true)) { KITTY_LOGE("Failed to initialize KittyMemoryMgr"); kmgr.trace.detach(); return false; } KittyInjector injector{}; if (!injector.init(&kmgr, cfg)) { // Reasons for failure: // - ABI mismatch between injector and target // - remote dlopen not found in target // - memfd_create unavailable but --memfd requested KITTY_LOGE("Injector init failed"); kmgr.trace.detach(); return false; } // injector is ready — proceed to validateElf / inject ``` ``` -------------------------------- ### JNI_OnLoad Entry Point Pattern for Injected Libraries Source: https://context7.com/mjx0/andkittyinjector/llms.txt This C++ code demonstrates the expected structure for `JNI_OnLoad` within a shared library intended for injection by AndKittyInjector. It includes essential checks for the secret key to differentiate calls from the injector versus the Android runtime. ```cpp // In your injected shared library (e.g., libhook.so) #include #include #include #define TAG "HookLib" #define LOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##__VA_ARGS__) #define LOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##__VA_ARGS__) // Constructor runs before JNI_OnLoad — keep it minimal, no threads here __attribute__((constructor)) void on_load() { LOGI("Library constructor called."); } static void hook_thread() { LOGI("Hook thread started — performing work..."); // Place hooks, scan memory, etc. } extern "C" jint JNIEXPORT JNI_OnLoad(JavaVM* vm, void* key) { LOGI("JNI_OnLoad called. key=%p", key); // Verify the injector is the caller (secret key == 1337) if (key != (void*)1337) { LOGI("Called by Android runtime, not injector — skipping hook setup."); return JNI_VERSION_1_6; } LOGI("Called by AndKittyInjector — setting up hooks."); JNIEnv* env = nullptr; if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) == JNI_OK) { LOGI("Got JNIEnv: %p", env); } // Launch work on a detached thread — never block JNI_OnLoad std::thread(hook_thread).detach(); return JNI_VERSION_1_6; } ``` -------------------------------- ### Remote Syscall Helper with KittyRemoteSys Source: https://context7.com/mjx0/andkittyinjector/llms.txt Demonstrates using KittyRemoteSys to perform various Linux syscalls within a traced remote process via ptrace. Ensure kmgr is initialized and attached before using rsys.init(). ```cpp #include "Injector/KittyInjectorSyscall.hpp" KittyRemoteSys rsys; rsys.init(&kmgr); // kmgr must already be initialized and attached // Verify ptrace remote syscall is functional if (!rsys.testSyscall()) { KITTY_LOGE("Remote syscall not working: %s", rsys.lastError().c_str()); return false; } // Allocate anonymous RWX memory in the remote process uintptr_t rmem = rsys.rmmap(0, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); PITTY_LOGI("Remote mmap result: %p", (void*)rmem); // e.g. 0x7b3f400000 // Change protection of a remote region to RX rsys.rmprotect(rmem, 4096, PROT_READ | PROT_EXEC); // Create a memfd in the remote process (used for --memfd injection) // rname must be a pointer into remote process memory containing the name string // kmgr.writeMemStr(rbuffer, "myrandomname") first uintptr_t rname_ptr = /* pre-written into remote stack buffer */ 0; int rfd = rsys.rmemfd_create(rname_ptr, MFD_CLOEXEC | MFD_ALLOW_SEALING); PITTY_LOGI("Remote memfd fd: %d", rfd); // Seal the remote memfd against further writes rsys.rmemfd_seal(rfd, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL); // Free the remote memory rsys.rmunmap(rmem, 4096); // Query the remote PID (sanity check) int rpid = rsys.rgetpid(); PITTY_LOGI("Remote getpid(): %d == kmgr.processID(): %d", rpid, kmgr.processID()); // must match ``` -------------------------------- ### inject_elf_config_t Structure Source: https://context7.com/mjx0/andkittyinjector/llms.txt This structure holds all runtime configuration options for the KittyInjector. It should be populated and passed to `KittyInjector::init()` when embedding the injector into another C++ project. ```APIDOC ## `inject_elf_config_t` — Injection Configuration Struct This structure encapsulates all runtime injection options. When embedding `KittyInjector` into another C++ project, populate this struct and pass it to `KittyInjector::init()`. ```cpp #include "Injector/KittyInjector.hpp" #include #include // Build a configuration programmatically inject_elf_config_t cfg{}; cfg.sdk = KittyUtils::Android::getSDK(); // auto-detect API level cfg.seize = cfg.sdk >= 24; // use PTRACE_SEIZE on API 24+ cfg.rtdl_flags = RTLD_LOCAL | RTLD_NOW; // dlopen flags cfg.package = "com.example.target"; cfg.memfd = true; // hide library path via memfd cfg.hide = true; // remove from solist and remap segments cfg.free = false; // keep the library loaded after JNI_OnLoad cfg.bp = false; // do not wait for dlopen breakpoint cfg.launch = true; // launch the app cfg.delay = 500000; // 500 ms pre-injection delay (microseconds) cfg.timeout = 3000; // 3-second remote call timeout (ms) // Optional callbacks executed around JNI_OnLoad invocation cfg.beforeEntryPoint = [](inject_elf_info_t &info) { // Called after dlopen succeeds, before JNI_OnLoad is invoked // info.dl_handle — remote dlopen handle // info.elf.base() — loaded library base address in target KITTY_LOGI("Library loaded at %p, calling JNI_OnLoad next...", (void*)info.elf.base()); }; cfg.afterEntryPoint = [](inject_elf_info_t &info) { // Called after JNI_OnLoad returns KITTY_LOGI("JNI_OnLoad finished. Handle=%p", (void*)info.dl_handle); }; ``` ``` -------------------------------- ### Configure Injection with inject_elf_config_t Source: https://context7.com/mjx0/andkittyinjector/llms.txt Populate this struct with runtime options for KittyInjector. It allows customization of SDK detection, PTRACE flags, target package, memory file descriptor usage, library visibility, and execution delays/timeouts. Optional callbacks can be set for events before and after the entry point. ```cpp #include "Injector/KittyInjector.hpp" #include #include // Build a configuration programmatically inject_elf_config_t cfg{}; cfg.sdk = KittyUtils::Android::getSDK(); // auto-detect API level cfg.seize = cfg.sdk >= 24; // use PTRACE_SEIZE on API 24+ cfg.rtdl_flags = RTLD_LOCAL | RTLD_NOW; // dlopen flags cfg.package = "com.example.target"; cfg.memfd = true; // hide library path via memfd cfg.hide = true; // remove from solist and remap segments cfg.free = false; // keep the library loaded after JNI_OnLoad cfg.bp = false; // do not wait for dlopen breakpoint cfg.launch = true; // launch the app cfg.delay = 500000; // 500 ms pre-injection delay (microseconds) cfg.timeout = 3000; // 3-second remote call timeout (ms) // Optional callbacks executed around JNI_OnLoad invocation cfg.beforeEntryPoint = [](inject_elf_info_t &info) { // Called after dlopen succeeds, before JNI_OnLoad is invoked // info.dl_handle — remote dlopen handle // info.elf.base() — loaded library base address in target KITTY_LOGI("Library loaded at %p, calling JNI_OnLoad next...", (void*)info.elf.base()); }; cfg.afterEntryPoint = [](inject_elf_info_t &info) { // Called after JNI_OnLoad returns KITTY_LOGI("JNI_OnLoad finished. Handle=%p", (void*)info.dl_handle); }; ``` -------------------------------- ### Basic Library Injection Source: https://context7.com/mjx0/andkittyinjector/llms.txt Inject a single shared library into a running target application. ```shell ./AndKittyInjector --package com.target.app --libs /data/local/tmp/libmyhook.so ``` -------------------------------- ### Inject a Single Library with KittyInjector::inject() Source: https://context7.com/mjx0/andkittyinjector/llms.txt Performs the full injection pipeline for a single library. Use this to inject a library and retrieve post-injection metadata. Ensure the target process is correctly set up for tracing before calling. ```cpp // Inject one library and retrieve post-injection metadata inject_elf_info_t info = injector.inject("/data/local/tmp/libhook.so"); if (!info.is_valid()) { // dlopen failed — dlerror was already logged by the injector KITTY_LOGE("Injection failed!"); kmgr.trace.detach(); return false; } // Post-injection information KITTY_LOGI("is_native : %d", info.is_native); // false = injected via NativeBridge KITTY_LOGI("is_hidden : %d", info.is_hidden); // true = soinfo removed, segments remapped KITTY_LOGI("dl_handle : %p", (void*)info.dl_handle); KITTY_LOGI("base addr : %p", (void*)info.elf.base()); KITTY_LOGI("end addr : %p", (void*)info.elf.end()); KITTY_LOGI("pJvm : %p", (void*)info.pJvm); KITTY_LOGI("pJNI_OnLoad : %p", (void*)info.pJNI_OnLoad); KITTY_LOGI("secretKey : %d", info.secretKey); // always kINJ_SECRET_KEY (1337) // Detach — target process continues running with the library loaded kmgr.trace.waitSyscall(); kmgr.trace.detach(); ``` -------------------------------- ### Inject, Hide, and Unload Library Source: https://context7.com/mjx0/andkittyinjector/llms.txt Inject a library at the first dlopen breakpoint, hide it from maps and solist, and unload it after JNI_OnLoad execution. ```shell ./AndKittyInjector \ --package com.target.app \ --libs /data/local/tmp/libhook.so \ --launch --bp --hide --free \ --timeout 5000 ``` -------------------------------- ### Validate ELF Library Before Injection Source: https://context7.com/mjx0/andkittyinjector/llms.txt Verifies a library file's ELF header, checks bitness compatibility, and detects if emulation is needed. This step is crucial before injecting a library to ensure it's valid and compatible with the target architecture. Errors like file inaccessibility, invalid ELF format, or bitness mismatches are logged. ```cpp const std::string libPath = "/data/local/tmp/libhook.so"; KT_ElfW(Ehdr) hdr{}; bool needsEmulation = false; if (!injector.validateElf(libPath, &hdr, &needsEmulation)) { // Possible errors logged: // "not accessible" — file does not exist or no read permission // "not a valid ELF" — magic bytes check failed // "is 32bit but Injector is 64bit" — bitness mismatch KITTY_LOGE("ELF validation failed for %s", libPath.c_str()); return false; } KITTY_LOGI("ELF machine: 0x%x (%s)", hdr.e_machine, EMachineToStr(hdr.e_machine).c_str()); // needsEmulation == true → library is arm/arm64 on an x86/x86_64 device; // emuInject() path via NativeBridge will be used // needsEmulation == false → nativeInject() path will be used ``` -------------------------------- ### Build AndKittyInjector with CMake Source: https://context7.com/mjx0/andkittyinjector/llms.txt Builds AndKittyInjector using CMake for a specific Android ABI (arm64-v8a). Ensure NDK_HOME is set and the Android toolchain file is correctly referenced. The output binary will be located in the `build-arm64` directory. ```shell # Clone with submodules git clone --recursive https://github.com/MJx0/AndKittyInjector.git cd AndKittyInjector # --- NDK-build (ndk-build / Android.mk) --- # Set NDK_HOME, then inside AndKittyInjector/AndKittyInjector: export NDK_HOME=/path/to/ndk cd AndKittyInjector ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk # Outputs per-ABI binaries to libs/{arm64-v8a,armeabi-v7a,x86,x86_64}/AndKittyInjector # --- CMake (cross-compile for arm64-v8a) --- cmake -B build-arm64 \ -DCMAKE_TOOLCHAIN_FILE=$NDK_HOME/build/cmake/android.toolchain.cmake \ -DANDROID_ABI=arm64-v8a \ -DANDROID_PLATFORM=android-21 \ -DCMAKE_BUILD_TYPE=Release \ AndKittyInjector/ cmake --build build-arm64 --config Release # Output: build-arm64/AndKittyInjector ``` -------------------------------- ### Wait for dlopen Breakpoint with KittyInjector::waitBreakpoint() Source: https://context7.com/mjx0/andkittyinjector/llms.txt Waits for the `dlopen` or NativeBridge `loadLibrary` function to be called, ensuring the Android linker is initialized. This is crucial for early process startup injections. The function has a 5-second timeout. ```cpp bool emulate = false; // determined by validateElf() above if (cfg.bp) { KITTY_LOGI("Waiting for dlopen breakpoint..."); if (!injector.waitBreakpoint(emulate)) { // Possible reasons: // - dlopen/loadLibrary address could not be resolved // - breakpoint timed out (5-second hardcoded limit) KITTY_LOGE("Breakpoint wait failed!"); kmgr.trace.detach(); return false; } KITTY_LOGI("Breakpoint hit — linker is initialized, injecting now."); } // Now safe to inject even early in process startup (e.g., with --launch or --watch) inject_elf_info_t info = injector.inject("/data/local/tmp/libhook.so"); ``` -------------------------------- ### Android JNI_OnLoad for Library Injection Source: https://github.com/mjx0/andkittyinjector/blob/main/README.md This C++ code snippet shows the correct implementation of JNI_OnLoad within a shared library intended for injection by AndKittyInjector. It includes a check for a specific key passed by the injector and demonstrates logging and thread creation. ```cpp extern "C" jint JNIEXPORT JNI_OnLoad(JavaVM* vm, void *key) { // key 1337 is passed by injector if (key != (void*)1337) return JNI_VERSION_1_6; KITTY_LOGI("JNI_OnLoad called by injector."); JNIEnv *env = nullptr; if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) == JNI_OK) { KITTY_LOGI("JavaEnv: %p.", env); // ... } std::thread(thread_function).detach(); return JNI_VERSION_1_6; } ``` -------------------------------- ### KittyInjector::waitBreakpoint() Source: https://context7.com/mjx0/andkittyinjector/llms.txt Sets a hardware breakpoint on the target's `dlopen` or NativeBridge load library function and waits for it to be hit. This ensures the Android linker is fully initialized before proceeding with injection. ```APIDOC ## KittyInjector::waitBreakpoint() ### Description Waits for the `dlopen` or NativeBridge `loadLibrary` / `loadLibraryExt` function to be called by setting a hardware breakpoint. It waits for a maximum of 5 seconds. ### Method `bool success = injector.waitBreakpoint(bool emulate);` ### Parameters #### Path Parameters - **emulate** (bool) - Required - Set to `true` if waiting for NativeBridge functions, `false` for native `dlopen`. ### Response #### Success Response (true) - Returns `true` if the breakpoint was hit within the timeout period. #### Failure Response (false) - Returns `false` if the breakpoint address could not be resolved or if the breakpoint timed out. ### Request Example ```cpp bool emulate = false; // determined by validateElf() if (cfg.bp) { KITTY_LOGI("Waiting for dlopen breakpoint..."); if (!injector.waitBreakpoint(emulate)) { KITTY_LOGE("Breakpoint wait failed!"); kmgr.trace.detach(); return false; } KITTY_LOGI("Breakpoint hit — linker is initialized, injecting now."); } // Now safe to inject inject_elf_info_t info = injector.inject("/data/local/tmp/libhook.so"); ``` ``` -------------------------------- ### KittyInjector::inject() Source: https://context7.com/mjx0/andkittyinjector/llms.txt Performs the full injection pipeline for a single library. This includes backing up registers, allocating a remote stack buffer, calling native or emulated injection, invoking JNI_OnLoad, optionally hiding or unloading the library, and restoring registers. ```APIDOC ## KittyInjector::inject() ### Description Injects a single library into the target process, performing the full injection pipeline. ### Method `inject_elf_info_t info = injector.inject(const char* library_path);` ### Parameters #### Path Parameters - **library_path** (const char*) - Required - The absolute path to the library to inject (e.g., "/data/local/tmp/libhook.so"). ### Response #### Success Response - **inject_elf_info_t** - An object containing post-injection metadata. - **is_valid()** (bool) - Returns true if the injection was successful. - **is_native** (int) - Indicates if the injection was native (1) or via NativeBridge (0). - **is_hidden** (int) - Indicates if the library was hidden (1) or not (0). - **dl_handle** (void*) - The dlopen handle of the injected library. - **elf.base()** (void*) - The base address of the injected ELF. - **elf.end()** (void*) - The end address of the injected ELF. - **pJvm** (void*) - Pointer to the JavaVM instance. - **pJNI_OnLoad** (void*) - Pointer to the JNI_OnLoad function. - **secretKey** (int) - The secret key passed to JNI_OnLoad (should be kINJ_SECRET_KEY). ### Request Example ```cpp inject_elf_info_t info = injector.inject("/data/local/tmp/libhook.so"); if (!info.is_valid()) { KITTY_LOGE("Injection failed!"); kmgr.trace.detach(); return false; } KITTY_LOGI("is_native : %d", info.is_native); KITTY_LOGI("is_hidden : %d", info.is_hidden); KITTY_LOGI("dl_handle : %p", (void*)info.dl_handle); KITTY_LOGI("base addr : %p", (void*)info.elf.base()); KITTY_LOGI("end addr : %p", (void*)info.elf.end()); KITTY_LOGI("pJvm : %p", (void*)info.pJvm); KITTY_LOGI("pJNI_OnLoad : %p", (void*)info.pJNI_OnLoad); KITTY_LOGI("secretKey : %d", info.secretKey); kmgr.trace.waitSyscall(); kmgr.trace.detach(); ``` ``` -------------------------------- ### JNI_OnLoad Source: https://context7.com/mjx0/andkittyinjector/llms.txt The entry point for injected libraries. It must verify the caller using a secret key to distinguish between the injector and the Android runtime. ```APIDOC ## JNI_OnLoad — Injected Library Entry Point Pattern ### Description This is the entry point function that the injector calls within the target process after loading the shared library. It is crucial to verify the `key` parameter to ensure the call originates from the injector and not the Android runtime. ### Method Signature `extern "C" jint JNI_OnLoad(JavaVM* vm, void* key);` ### Parameters #### Path Parameters - **vm** (JavaVM*) - Required - A pointer to the Java Virtual Machine. - **key** (void*) - Required - A secret key passed by the injector. Must be `(void*)1337` for injector-initiated calls. ### Response #### Success Response (JNI_VERSION_1_6) - Returns `JNI_VERSION_1_6` upon successful initialization. ### Request Example (Injected Library) ```cpp #include #include #include #define TAG "HookLib" #define LOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##__VA_ARGS__) #define LOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##__VA_ARGS__) __attribute__((constructor)) void on_load() { LOGI("Library constructor called."); } static void hook_thread() { LOGI("Hook thread started — performing work..."); // Place hooks, scan memory, etc. } extern "C" jint JNIEXPORT JNI_OnLoad(JavaVM* vm, void* key) { LOGI("JNI_OnLoad called. key=%p", key); // Verify the injector is the caller (secret key == 1337) if (key != (void*)1337) { LOGI("Called by Android runtime, not injector — skipping hook setup."); return JNI_VERSION_1_6; } LOGI("Called by AndKittyInjector — setting up hooks."); JNIEnv* env = nullptr; if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) == JNI_OK) { LOGI("Got JNIEnv: %p", env); } // Launch work on a detached thread — never block JNI_OnLoad std::thread(hook_thread).detach(); return JNI_VERSION_1_6; } ``` ``` -------------------------------- ### KittyInjector::validateElf() Source: https://context7.com/mjx0/andkittyinjector/llms.txt Validates a given library file before injection. It checks if the file is a valid ELF, if its bitness matches the injector's, and determines if emulation is required (e.g., injecting ARM code on an x86 device). ```APIDOC ## `KittyInjector::validateElf()` — Validate a Library Before Injection Reads the ELF header of the library file, confirms it is a valid ELF, checks the bitness matches the injector, and optionally detects whether the library needs emulation (e.g., injecting an arm64 `.so` via libhoudini on an x86_64 device). ```cpp const std::string libPath = "/data/local/tmp/libhook.so"; KT_ElfW(Ehdr) hdr{}; bool needsEmulation = false; if (!injector.validateElf(libPath, &hdr, &needsEmulation)) { // Possible errors logged: // "not accessible" — file does not exist or no read permission // "not a valid ELF" — magic bytes check failed // "is 32bit but Injector is 64bit" — bitness mismatch KITTY_LOGE("ELF validation failed for %s", libPath.c_str()); return false; } KITTY_LOGI("ELF machine: 0x%x (%s)", hdr.e_machine, EMachineToStr(hdr.e_machine).c_str()); // needsEmulation == true → library is arm/arm64 on an x86/x86_64 device; // emuInject() path via NativeBridge will be used // needsEmulation == false → nativeInject() path will be used ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.