### Complete lsplant::InitInfo Example in JNI_OnLoad Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-initinfo.md A comprehensive example demonstrating the initialization of lsplant::InitInfo within a JNI_OnLoad function. This snippet includes configurations for inline hooking, symbol resolution, and class generation. ```cpp #include #include #include extern "C" jint JNI_OnLoad(JavaVM *vm, void *) { JNIEnv *env; vm->GetEnv((void **)&env, JNI_VERSION_1_6); void *art_lib = dlopen("libart.so", RTLD_LAZY); lsplant::InitInfo init_info{ .inline_hooker = [](void *target, void *hooker) -> void * { void *backup = nullptr; if (DobbyHook(target, (void *)hooker, &backup) == DOBBY_NO_ERROR) { return backup; } return nullptr; }, .inline_unhooker = [](void *func) -> bool { return DobbyDestroy(func) == DOBBY_NO_ERROR; }, .art_symbol_resolver = [art_lib](std::string_view symbol_name) -> void * { return dlsym(art_lib, symbol_name.data()); }, .art_symbol_prefix_resolver = nullptr, // Optional .generated_class_name = "LSPHooker_", .generated_source_name = "LSP", .generated_field_name = "hooker", .generated_method_name = "{target}", .executable_memory_allocator = nullptr, // Use default .executable_memory_recycler = nullptr, // Use default }; if (!lsplant::Init(env, init_info)) { return JNI_VERSION_1_4; // Initialization failed } return JNI_VERSION_1_6; } ``` -------------------------------- ### Complete Hooking ART Functions Example Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-hook-helpers.md Demonstrates how to define Function wrappers for ART internals, set up a Hooker for a specific method, implement a hook replacement function, and initialize hooks using a HookHandler. This example shows the full lifecycle of setting up and applying a hook. ```cpp #include #include using namespace lsplant; // Define Function wrappers for ART internals Function<"_ZN3art6Runtime5ConstEv"_sym, Runtime*()> get_runtime; // Define Hooker for a method we want to hook Hooker<"_ZN3art11ClassLinker9FindClassEPNS_6ThreadE..."_sym, Class* (ClassLinker::*)(Thread*)> find_class_hooker; // Implement the hook replacement Class* hook_find_class(ClassLinker *self, Thread *thread) { // Custom logic __android_log_write(ANDROID_LOG_DEBUG, "MyApp", "FindClass called"); // Call original via backup function // (backup would be obtained during hooking) return nullptr; } extern "C" void initialize_hooks(JNIEnv *env, const InitInfo &init_info) { HookHandler handler(init_info); // Resolve get_runtime (no hooking) handler(get_runtime); // Resolve and hook find_class_hooker handler(find_class_hooker); if (get_runtime && find_class_hooker) { __android_log_write(ANDROID_LOG_INFO, "MyApp", "All hooks initialized"); } else { __android_log_write(ANDROID_LOG_ERROR, "MyApp", "Hook initialization failed"); } } ``` -------------------------------- ### Inline Unhooker Implementation Example Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-initinfo.md Provides an example of implementing the `inline_unhooker` callback using a lambda function. This function is responsible for removing previously installed hooks and must restore the original function to its pre-hooked state. It is compatible with the `inline_hooker` implementation. ```cpp lsplant::InitInfo init_info{ .inline_unhooker = [](void *func) -> bool { return DobbyDestroy(func); // Returns true on success }, // ... other fields }; ``` -------------------------------- ### Example Usage of Field Template Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-hook-helpers.md Provides a complete example of defining and using the Field template to access the ART Runtime singleton. It includes checking for resolution before accessing its members. ```cpp // Define a Field wrapper for a global or member field lsplant::Field<"_ZN3art6Runtime15..."(), lsplant::art::Runtime> runtime_singleton; // After resolution: if (runtime_singleton) { auto version = runtime_singleton->getVersion(); } ``` -------------------------------- ### Inline Hooker Implementation Example Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-initinfo.md Provides an example implementation for the `inline_hooker` field using the Dobby hooking framework. This function is required for initialization and must be capable of hooking both Java and native functions. ```cpp #include #include lsplant::InitInfo init_info{ .inline_hooker = [](void *target, void *hooker) -> void * { DobbyHook(target, (void *)hooker, &backup); return backup; // backup set by DobbyHook }, // ... other fields }; ``` -------------------------------- ### Create FixedString Instance Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-hook-helpers.md Example of creating a FixedString instance with a specified length and character sequence. ```cpp // FixedString with 10 characters FixedString<10, '_', 'Z', 'N', '3', 'a', 'r', 't', '.', '.', '.'> sym; ``` -------------------------------- ### Example Implementation of executable_memory_recycler Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-initinfo.md Provides a sample implementation for the executable_memory_recycler field, demonstrating how to unmap previously allocated executable memory. Note that the original size must be tracked separately. ```cpp lsplant::InitInfo init_info{ .executable_memory_recycler = +[](void *memory) { munmap(memory, /* original size */); }, // ... other fields }; ``` -------------------------------- ### Initialize LSPlant with Dobby Hooking Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/configuration.md Example of initializing LSPlant within JNI_OnLoad, providing a Dobby-based inline hooker. Ensure all required fields in InitInfo are populated. ```cpp #include #include extern "C" jint JNI_OnLoad(JavaVM *vm, void *) { JNIEnv *env; vm->GetEnv((void **)&env, JNI_VERSION_1_6); lsplant::InitInfo init_info{ .inline_hooker = [](void *target, void *hooker) -> void * { void *backup = nullptr; int ret = DobbyHook(target, (void *)hooker, &backup); if (ret == DOBBY_NO_ERROR) { return backup; // Success } return nullptr; // Failure }, // ... other fields }; if (!lsplant::Init(env, init_info)) { return JNI_VERSION_1_4; } return JNI_VERSION_1_6; } ``` -------------------------------- ### ScopedLocalRef Get Method Example Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Use the get method to retrieve the raw JNI reference without transferring ownership. The returned reference is still managed by the ScopedLocalRef, so do not delete it. ```cpp lsplant::ScopedLocalRef scoped(env, cls); jni::JClass raw = scoped.get(); // raw is still owned by scoped; do not delete ``` -------------------------------- ### Function Template Example: FindClass Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-hook-helpers.md An example defining and using a `Function` wrapper for the `ClassLinker::FindClass` method. The address is typically assigned later by `Hook()`. ```cpp #include // Define a Function wrapper for ClassLinker::FindClass lsplant::Function<"_ZN3art11ClassLinker9FindClassEPNS_6ThreadENS_6HandleINS_6mirror5ClassEEEPKcbPNS_6mirror9ClassLoaderE", lsplant::art::mirror::Class* (lsplant::art::ClassLinker::*)(lsplant::art::Thread*, ...)> find_class; // Later, after Hook() resolves and assigns the address: if (find_class) { auto cls = find_class(thread, handle, name, ...); } ``` -------------------------------- ### Working with Java Fields Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Demonstrates how to get and set integer fields of a Java object using JNI helper functions. Ensure the field ID is correctly obtained before access. ```cpp auto field_id = JNI_GetFieldID(env, my_class, "value", "I"); jint current = JNI_GetIntField(env, my_object, field_id); JNI_SetIntField(env, my_object, field_id, current + 10); ``` -------------------------------- ### LSPlant Stub Class Generation Example Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/project-structure.md Illustrates the basic structure of a generated stub class used for method hooking. It includes a field to hold the hooker object and a method to invoke the callback via reflection. ```java public class LSPHooker_0 { public Object hooker; // Holds the hooker object public Object length(Object[] args) { // Trampoline code return hooker.callback(args); } } ``` -------------------------------- ### Custom Executable Memory Allocator Implementation Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-initinfo.md Provides an example of implementing the executable_memory_allocator using mmap to allocate RWX memory. This function must not have a capture list and should return a page-aligned, executable address. Return nullptr on allocation failure. ```cpp lsplant::InitInfo init_info{ .executable_memory_allocator = +[](std::span data) -> void * { // Allocate from a custom code cache or mmap an RX region void *addr = mmap(nullptr, data.size(), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (addr == MAP_FAILED) return nullptr; memcpy(addr, data.data(), data.size()); return addr; }, // ... other fields }; ``` -------------------------------- ### Get Field ID and Instance Field Values Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Retrieve field IDs and get values from instance fields. Supports various primitive types and objects. ```cpp // Get field ID auto JNI_GetFieldID(JNIEnv *env, Class &&clazz, std::string_view name, std::string_view sig); // Get instance field values auto JNI_GetObjectField(JNIEnv *env, Object &&obj, jfieldID fieldId); auto JNI_GetBooleanField(JNIEnv *env, Object &&obj, jfieldID fieldId); auto JNI_GetByteField(JNIEnv *env, Object &&obj, jfieldID fieldId); auto JNI_GetIntField(JNIEnv *env, Object &&obj, jfieldID fieldId); auto JNI_GetLongField(JNIEnv *env, Object &&obj, jfieldID fieldId); // ... and more for float, double, char, short ``` -------------------------------- ### Deoptimize Method Example Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-core.md This C++ JNI function demonstrates how to use the lsplant::Deoptimize function to deoptimize a given Java Method object. It logs the success or failure of the deoptimization operation. ```cpp extern "C" JNIEXPORT void Java_com_example_Hook_deoptimizeMethod(JNIEnv *env, jobject method_obj) { if (lsplant::Deoptimize(env, method_obj)) { __android_log_write(ANDROID_LOG_INFO, "MyApp", "Deoptimization successful"); } else { __android_log_write(ANDROID_LOG_ERROR, "MyApp", "Deoptimization failed"); } } ``` -------------------------------- ### Method Operations Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Functions for getting method IDs and calling instance methods. ```APIDOC ## Method Operations ### `JNI_GetMethodID` Gets the method ID for a method within a class. #### Signature ```cpp auto JNI_GetMethodID(JNIEnv *env, Class &&clazz, std::string_view name, std::string_view sig); ``` ### `JNI_CallVoidMethod` Calls an instance method that returns void. #### Signature ```cpp auto JNI_CallVoidMethod(JNIEnv *env, Object &&obj, jmethodID method, Args &&...args); ``` ### `JNI_CallObjectMethod` Calls an instance method that returns an object. #### Signature ```cpp auto JNI_CallObjectMethod(JNIEnv *env, Object &&obj, jmethodID method, Args &&...args); ``` ### `JNI_CallBooleanMethod` Calls an instance method that returns a boolean. #### Signature ```cpp auto JNI_CallBooleanMethod(JNIEnv *env, Object &&obj, jmethodID method, Args &&...args); ``` ### `JNI_CallIntMethod` Calls an instance method that returns an integer. #### Signature ```cpp auto JNI_CallIntMethod(JNIEnv *env, Object &&obj, jmethodID method, Args &&...args); ``` *Note: Similar functions exist for other return types.* ``` -------------------------------- ### Example Usage of JArrayUnderlyingType Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/types.md Demonstrates how to use the JArrayUnderlyingType alias to deduce the element type of JNI arrays. ```cpp using IntElement = JArrayUnderlyingType; // jint using BoolElement = JArrayUnderlyingType; // jboolean ``` -------------------------------- ### Get Method ID and Call Instance Methods Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Retrieve method IDs and invoke instance methods. Supports methods returning void, objects, booleans, and integers, with extensions for other return types. ```cpp // Get method ID auto JNI_GetMethodID(JNIEnv *env, Class &&clazz, std::string_view name, std::string_view sig); // Call instance methods auto JNI_CallVoidMethod(JNIEnv *env, Object &&obj, jmethodID method, Args &&...args); auto JNI_CallObjectMethod(JNIEnv *env, Object &&obj, jmethodID method, Args &&...args); auto JNI_CallBooleanMethod(JNIEnv *env, Object &&obj, jmethodID method, Args &&...args); auto JNI_CallIntMethod(JNIEnv *env, Object &&obj, jmethodID method, Args &&...args); // ... and more for other return types ``` -------------------------------- ### ART Symbol Resolver Implementation Example Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-initinfo.md Demonstrates how to implement the `art_symbol_resolver` callback, which is required to resolve symbols within the libart.so library. This function uses `dlopen` and `dlsym` to find the memory address of a given symbol name. It handles both plain C and mangled C++ symbols and must resolve from both .dynsym and .symtab. ```cpp #include void *art_lib = nullptr; lsplant::InitInfo init_info{ .art_symbol_resolver = [](std::string_view symbol_name) -> void * { if (!art_lib) { art_lib = dlopen("libart.so", RTLD_LAZY); if (!art_lib) return nullptr; } return dlsym(art_lib, symbol_name.data()); }, // ... other fields }; ``` -------------------------------- ### ART Symbol Resolver using dlsym Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/configuration.md Example implementation for art_symbol_resolver using dlsym to find symbols in libart.so. It handles lazy loading of the library and basic error checking. Note that dlsym primarily searches .dynsym. ```cpp #include void *art_lib = nullptr; .art_symbol_resolver = [](std::string_view symbol_name) -> void * { if (!art_lib) { art_lib = dlopen("libart.so", RTLD_LAZY); if (!art_lib) { __android_log_write(ANDROID_LOG_ERROR, "TAG", dlerror()); return nullptr; } } dlerror(); // Clear previous error void *address = dlsym(art_lib, symbol_name.data()); if (!address) { // Try with other methods (e.g., ELF parsing for .symtab) // dlsym only searches .dynsym by default } return address; } ``` -------------------------------- ### Function Template Usage: Getting Raw Pointer Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-hook-helpers.md Illustrates obtaining the raw function pointer using the address-of operator (&) for manual invocation. ```cpp auto ptr = &func; ptr(arg1, arg2); // Call via pointer ``` -------------------------------- ### Example Usage of ScopeOrObject Concept Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Demonstrates how a function constrained by ScopeOrObject can accept both ScopedLocalRef wrappers and raw JNI jobject references. This highlights the flexibility provided by the concept. ```cpp // This function accepts raw or wrapped references: void func(auto &&obj) requires ScopeOrObject; ScopedLocalRef scoped(env, obj); func(scoped); // Accepted: ScopedLocalRef matches concept func(raw_jobject); // Accepted: raw jobject matches concept ``` -------------------------------- ### Array Creation and Access Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Create various types of Java arrays (int, byte, object) and get their lengths. Supports multiple array types. ```cpp auto JNI_NewIntArray(JNIEnv *env, jsize len); auto JNI_NewByteArray(JNIEnv *env, jsize len); auto JNI_NewObjectArray(JNIEnv *env, jsize len, Class &&clazz, const Object &init); // ... and more for other array types auto JNI_GetArrayLength(JNIEnv *env, const Array &array); ``` -------------------------------- ### ScopedLocalRef Constructor Example Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Use this constructor to create a ScopedLocalRef that automatically manages a JNI local reference. The reference is automatically deleted when the ScopedLocalRef goes out of scope. ```cpp JNIEnv *env = /* ... */; java::lang::String string_class = env->FindClass("java/lang/String"); lsplant::ScopedLocalRef scoped(env, string_class); // DeleteLocalRef called automatically when scoped goes out of scope ``` -------------------------------- ### Core LSPlant API Functions Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/README.md Reference for the main LSPlant API functions used for initializing, hooking, and managing method hooks. Each function includes its signature, parameter details, return type, threading notes, and code examples. ```APIDOC ## Core LSPlant API Functions This section details the core functions available in the LSPlant library for performing method hooking operations. ### `Init()` **Description**: Initializes the LSPlant library. This function must be called before any other LSPlant functions. **Signature**: `void Init(const InitInfo& info)` **Parameters**: - `info` (const `InitInfo&`): Structure containing initialization configuration. **Return Type**: void **Threading/Safety**: Must be called once during application startup, typically in `JNI_OnLoad`. ### `Hook()` **Description**: Redirects Java method calls to custom handlers. Supports various hooking modes. **Signature**: `HookHandle Hook(Symbol symbol, void* handler)` **Parameters**: - `symbol` (`Symbol`): Represents the method to be hooked. - `handler` (`void*`): Pointer to the custom handler function. **Return Type**: `HookHandle`: An opaque handle to the installed hook. **Threading/Safety**: Can be called from any thread after initialization. ### `UnHook()` **Description**: Removes a previously installed hook. **Signature**: `void UnHook(HookHandle handle)` **Parameters**: - `handle` (`HookHandle`): The handle of the hook to remove. **Return Type**: void **Threading/Safety**: Can be called from any thread. ### `IsHooked()` **Description**: Checks if a specific method is currently hooked. **Signature**: `bool IsHooked(Symbol symbol)` **Parameters**: - `symbol` (`Symbol`): Represents the method to check. **Return Type**: `bool`: true if the method is hooked, false otherwise. **Threading/Safety**: Can be called from any thread. ### `Deoptimize()` **Description**: Disables ART inlining for specified methods, ensuring hooks are always invoked. **Signature**: `void Deoptimize(Symbol symbol)` **Parameters**: - `symbol` (`Symbol`): Represents the method to deoptimize. **Return Type**: void **Threading/Safety**: Can be called from any thread. ### `GetNativeFunction()` **Description**: Retrieves the native function pointer for a given method. **Signature**: `void* GetNativeFunction(Symbol symbol)` **Parameters**: - `symbol` (`Symbol`): Represents the method. **Return Type**: `void*`: Pointer to the native function. **Threading/Safety**: Can be called from any thread. ### `MakeClassInheritable()` **Description**: Removes the `final` modifier from a class, allowing it to be subclassed. **Signature**: `void MakeClassInheritable(JClass klass)` **Parameters**: - `klass` (`JClass`): The Java class object. **Return Type**: void **Threading/Safety**: Can be called from any thread. ### `MakeDexFileTrusted()` **Description**: Enables hidden API access for DexFiles, allowing access to restricted APIs. **Signature**: `void MakeDexFileTrusted(DexFile* dex_file)` **Parameters**: - `dex_file` (`DexFile*`): Pointer to the DexFile structure. **Return Type**: void **Threading/Safety**: Can be called from any thread. ``` -------------------------------- ### Implement art_symbol_prefix_resolver in C++ Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-initinfo.md Provides an optional function to resolve symbols by prefix matching. This is useful when exact symbol names are unknown or vary by Android version. The example shows a placeholder implementation returning nullptr. ```cpp #include #include lsplant::InitInfo init_info{ .art_symbol_prefix_resolver = [](std::string_view symbol_prefix) -> void * { // Iterate through libart.so's symbol table looking for a prefix match // This is complex in practice; libraries like LSPlant typically use custom ELF readers return nullptr; // Simplified placeholder }, // ... other fields }; ``` -------------------------------- ### ScopedLocalRef Reset Method Example Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Use the reset method to replace the currently held reference with a new one. The old reference will be deleted automatically. Pass nullptr to release the current reference without acquiring a new one. ```cpp lsplant::ScopedLocalRef ref(env, nullptr); ref.reset(env->FindClass("java/lang/String")); // Old reference (nullptr) is deleted; new one is held ``` -------------------------------- ### Find and Get Object Class Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Use these functions to find a Java class or get the class of an existing Java object. ```cpp auto JNI_FindClass(JNIEnv *env, std::string_view name); auto JNI_GetObjectClass(JNIEnv *env, const Object &obj); ``` -------------------------------- ### Integrate Hook Helpers with LSPlant Initialization Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-hook-helpers.md Demonstrates how to use hook helpers within InitInfo callbacks for custom hooking and symbol resolution. Ensure your hooking framework provides backup and unhooking mechanisms. ```cpp lsplant::InitInfo init_info{ .inline_hooker = [](void *target, void *hooker) -> void * { // Return backup from your hooking framework void *backup; my_hook_framework(target, hooker, &backup); return backup; }, .inline_unhooker = [](void *func) -> bool { return my_unhook_framework(func); }, .art_symbol_resolver = [](std::string_view symbol_name) -> void * { // dlsym or custom resolution return dlsym(art_lib, symbol_name.data()); }, }; HookHandler handler(init_info); // Now use handler to resolve and hook Function<"symbol"_sym, void()> func; Hooker<"symbol2"_sym, int(bool)> hook; handler(func, hook); ``` -------------------------------- ### Complete LSPlant Initialization Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/configuration.md This C++ code snippet shows the full initialization process for LSPlant within the JNI_OnLoad function. It configures inline hooking using Dobby, symbol resolution for libart.so, and custom naming strategies for generated code. Ensure Dobby is correctly integrated for hooking to function. ```cpp #include #include #include #include #define LOG_TAG "LSPlantExample" extern "C" jint JNI_OnLoad(JavaVM *vm, void *) { JNIEnv *env; vm->GetEnv((void **)&env, JNI_VERSION_1_6); void *art_lib = nullptr; lsplant::InitInfo init_info{ // Inline hooking via Dobby .inline_hooker = [](void *target, void *hooker) -> void * { void *backup = nullptr; if (DobbyHook(target, (void *)hooker, &backup) != DOBBY_NO_ERROR) { __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, "Hook failed"); return nullptr; } return backup; }, // Inline unhooking via Dobby .inline_unhooker = [](void *func) -> bool { if (DobbyDestroy(func) != DOBBY_NO_ERROR) { __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, "Unhook failed"); return false; } return true; }, // Symbol resolution .art_symbol_resolver = [&art_lib](std::string_view symbol_name) -> void * { if (!art_lib) { art_lib = dlopen("libart.so", RTLD_LAZY); if (!art_lib) { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "dlopen failed: %s", dlerror()); return nullptr; } } return dlsym(art_lib, symbol_name.data()); }, // Optional prefix resolver .art_symbol_prefix_resolver = nullptr, // Code generation names .generated_class_name = "LSPHooker_", .generated_source_name = "LSP", .generated_field_name = "hooker", .generated_method_name = "{target}", // Use default memory management .executable_memory_allocator = nullptr, .executable_memory_recycler = nullptr, }; if (!lsplant::Init(env, init_info)) { __android_log_write(ANDROID_LOG_ERROR, LOG_TAG, "LSPlant initialization failed"); return JNI_VERSION_1_4; } __android_log_write(ANDROID_LOG_INFO, LOG_TAG, "LSPlant initialized successfully"); return JNI_VERSION_1_6; } ``` -------------------------------- ### Class Operations Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Functions for finding and getting the class of an object. ```APIDOC ## Class Operations ### `JNI_FindClass` Finds a class given its fully qualified name. #### Signature ```cpp auto JNI_FindClass(JNIEnv *env, std::string_view name); ``` ### `JNI_GetObjectClass` Gets the class of a given object. #### Signature ```cpp auto JNI_GetObjectClass(JNIEnv *env, const Object &obj); ``` ``` -------------------------------- ### Field Operations Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Functions for getting field IDs and values from objects. ```APIDOC ## Field Operations ### `JNI_GetFieldID` Gets the field ID for a field within a class. #### Signature ```cpp auto JNI_GetFieldID(JNIEnv *env, Class &&clazz, std::string_view name, std::string_view sig); ``` ### `JNI_GetObjectField` Gets the object value of an instance field. #### Signature ```cpp auto JNI_GetObjectField(JNIEnv *env, Object &&obj, jfieldID fieldId); ``` ### `JNI_GetBooleanField` Gets the boolean value of an instance field. #### Signature ```cpp auto JNI_GetBooleanField(JNIEnv *env, Object &&obj, jfieldID fieldId); ``` ### `JNI_GetByteField` Gets the byte value of an instance field. #### Signature ```cpp auto JNI_GetByteField(JNIEnv *env, Object &&obj, jfieldID fieldId); ``` ### `JNI_GetIntField` Gets the integer value of an instance field. #### Signature ```cpp auto JNI_GetIntField(JNIEnv *env, Object &&obj, jfieldID fieldId); ``` ### `JNI_GetLongField` Gets the long value of an instance field. #### Signature ```cpp auto JNI_GetLongField(JNIEnv *env, Object &&obj, jfieldID fieldId); ``` *Note: Similar functions exist for float, double, char, and short types.* ``` -------------------------------- ### Init Source: https://github.com/lsposed/lsplant/blob/master/README.md Initializes LSPlant for subsequent operations. This function prefetches symbols and hooks essential ART functions. It requires a JNI environment and initialization information. ```APIDOC ## Init ### Description Initialize LSPlant for the proceeding hook. It mainly prefetch needed symbols and hook some functions. + `env` is the Java environment. + `info` is the information for initialized. Basically, the info provides the inline hooker and unhooker together with a symbol resolver of `libart.so` to hook and extract needed native functions of ART. ### Signature ```c++ bool Init(JNIEnv *env, const InitInfo &info); ``` ### Returns Returns whether initialization succeed. Behavior is undefined if calling other LSPlant interfaces before initialization or after a fail initialization. ``` -------------------------------- ### Init Function Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-core.md Initializes the LSPlant library. This function must be called before any other LSPlant functions to prefetch symbols and hook necessary ART runtime functions. ```APIDOC ## Init ### Description Initialize LSPlant before calling other functions. This function prefetches symbols and hooks necessary ART runtime functions. ### Signature ```cpp bool Init(JNIEnv *env, const InitInfo &info); ``` ### Parameters #### Path Parameters - **env** (`JNIEnv*`) - Required - The Java environment obtained during JNI_OnLoad. Must have unrestricted access to hidden APIs. - **info** (`const InitInfo&`) - Required - Configuration object containing inline hooker, unhooker, symbol resolver, and generator options. ### Return Type `bool` - True if initialization succeeds, false if it fails. Calling other LSPlant functions before successful initialization results in undefined behavior. ### Example ```cpp #include // In JNI_OnLoad: extern "C" jint JNI_OnLoad(JavaVM *vm, void *) { JNIEnv *env; vm->GetEnv((void **)&env, JNI_VERSION_1_6); // Define inline hooker (using your inline hook framework) auto inline_hooker = [](void *target, void *hooker) -> void * { // Your inline hooking implementation return original_function_backup; // Return non-null on success }; // Define inline unhooker auto inline_unhooker = [](void *func) -> bool { // Your unhooking implementation return true; // Return true on success }; // Define ART symbol resolver auto art_symbol_resolver = [](std::string_view symbol_name) -> void * { // Use dlopen/dlsym on libart.so to resolve the symbol return resolved_address; // Return nullptr if not found }; lsplant::InitInfo init_info{ .inline_hooker = inline_hooker, .inline_unhooker = inline_unhooker, .art_symbol_resolver = art_symbol_resolver, }; if (!lsplant::Init(env, init_info)) { __android_log_write(ANDROID_LOG_ERROR, "MyApp", "LSPlant init failed"); return JNI_FALSE; } return JNI_VERSION_1_6; } ``` ### Source Location `lsplant/src/main/jni/include/lsplant.hpp:96-97` ``` -------------------------------- ### Static Field Operations Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Functions for getting and setting static field IDs and values. ```APIDOC ## Static Field Operations ### `JNI_GetStaticFieldID` Gets the static field ID for a static field within a class. #### Signature ```cpp auto JNI_GetStaticFieldID(JNIEnv *env, Class &&clazz, std::string_view name, std::string_view sig); ``` ### `JNI_GetStaticObjectField` Gets the object value of a static field. #### Signature ```cpp auto JNI_GetStaticObjectField(JNIEnv *env, Class &&clazz, jfieldID fieldId); ``` ### `JNI_SetStaticIntField` Sets the integer value of a static field. #### Signature ```cpp auto JNI_SetStaticIntField(JNIEnv *env, Class &&clazz, jfieldID fieldId, jint value); ``` *Note: Similar functions exist for other static field types.* ``` -------------------------------- ### Static Method Operations Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Functions for getting static method IDs and calling static methods. ```APIDOC ## Static Method Operations ### `JNI_GetStaticMethodID` Gets the static method ID for a static method within a class. #### Signature ```cpp auto JNI_GetStaticMethodID(JNIEnv *env, Class &&clazz, std::string_view name, std::string_view sig); ``` ### `JNI_CallStaticVoidMethod` Calls a static method that returns void. #### Signature ```cpp auto JNI_CallStaticVoidMethod(JNIEnv *env, Class &&clazz, jmethodID method, Args &&...args); ``` ### `JNI_CallStaticObjectMethod` Calls a static method that returns an object. #### Signature ```cpp auto JNI_CallStaticObjectMethod(JNIEnv *env, Class &&clazz, jmethodID method, Args &&...args); ``` *Note: Similar functions exist for other static method return types.* ``` -------------------------------- ### LSPlant Directory Structure Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/project-structure.md This snippet outlines the standard directory layout for the LSPlant project, including source files, build configurations, and test directories. ```text lsplant/ ├── README.md # Project overview and quick start ├── build.gradle.kts # Gradle build configuration ├── lsplant/ │ ├── build.gradle.kts # Module-specific build config │ └── src/main/jni/ │ ├── CMakeLists.txt # CMake build configuration │ ├── lsplant.cc # Implementation (C++ module) │ ├── logging.hpp # Logging utilities │ └── include/ │ ├── lsplant.hpp # Main public API header │ └── utils/ │ ├── jni_helper.hpp # JNI RAII wrappers and convenience functions │ ├── hook_helper.hpp # Type-safe function/field wrappers │ └── type_traits.hpp # Architecture detection and type utilities ├── test/ │ ├── build.gradle.kts │ └── src/main/jni/ │ ├── CMakeLists.txt │ └── test.cpp # Test implementation └── docs/ └── jni.h # JNI header reference ``` -------------------------------- ### Reflection Utilities Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Utilities for obtaining reflected method and field objects, and for registering native methods. ```cpp auto JNI_ToReflectedMethod(JNIEnv *env, Class &&clazz, jmethodID method, jboolean isStatic = JNI_FALSE); auto JNI_ToReflectedField(JNIEnv *env, Class &&clazz, jfieldID field, jboolean isStatic = JNI_FALSE); auto JNI_RegisterNatives(JNIEnv *env, Class &&clazz, const JNINativeMethod *methods, jint size); ``` -------------------------------- ### Initialize LSPlant Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-core.md Call `lsplant::Init` during `JNI_OnLoad` to initialize the library. Provide JNIEnv and an `InitInfo` struct containing callbacks for inline hooking, unhooking, and ART symbol resolution. Initialization failure will log an error and return false. ```cpp #include // In JNI_OnLoad: extern "C" jint JNI_OnLoad(JavaVM *vm, void *) { JNIEnv *env; vm->GetEnv((void **)&env, JNI_VERSION_1_6); // Define inline hooker (using your inline hook framework) auto inline_hooker = [](void *target, void *hooker) -> void * { // Your inline hooking implementation return original_function_backup; // Return non-null on success }; // Define inline unhooker auto inline_unhooker = [](void *func) -> bool { // Your unhooking implementation return true; // Return true on success }; // Define ART symbol resolver auto art_symbol_resolver = [](std::string_view symbol_name) -> void * { // Use dlopen/dlsym on libart.so to resolve the symbol return resolved_address; // Return nullptr if not found }; lsplant::InitInfo init_info{ .inline_hooker = inline_hooker, .inline_unhooker = inline_unhooker, .art_symbol_resolver = art_symbol_resolver, }; if (!lsplant::Init(env, init_info)) { __android_log_write(ANDROID_LOG_ERROR, "MyApp", "LSPlant init failed"); return JNI_FALSE; } return JNI_VERSION_1_6; } ``` -------------------------------- ### Unhook a Hooker with HookHandler Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-hook-helpers.md Use the unhook method of HookHandler to remove a previously installed hook. This requires the Hooker object that was originally hooked. ```cpp handler.unhook(hook1); ``` -------------------------------- ### Define and Attach Compile-Time Hook Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-hook-helpers.md Shows how to define a replacement handler for a symbol and attach it using the `hook` member and the `->*` operator. The `BackupFunc` is provided for calling the original function. ```cpp // Define a replacement handler auto replacement = [](int value) { // Custom logic return BackupFunc(value); }; // Attach to symbol via operator->* auto hooked = "symbol"_sym.hook ->* replacement; ``` -------------------------------- ### Get Native Function Pointer - C++ Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-core.md Retrieve the native function pointer for a given JNI method. Use this to back up original function pointers before hooking. ```cpp // Original native function typedef jint (*Original_nativeMethod)(JNIEnv *env, jobject thiz, jint value); Original_nativeMethod original_native = nullptr; // Replacement native function jint hook_nativeMethod(JNIEnv *env, jobject thiz, jint value) { // Custom logic __android_log_print(ANDROID_LOG_INFO, "MyApp", "nativeMethod called with %d", value); // Call original if we have it if (original_native) { return original_native(env, thiz, value); } return 0; } extern "C" JNIEXPORT void Java_com_example_NativeHook_hookNativeMethod(JNIEnv *env, jobject thiz, jobject method_obj) { // Get the original native function pointer original_native = (Original_nativeMethod)lsplant::GetNativeFunction(env, method_obj); if (!original_native) { __android_log_write(ANDROID_LOG_ERROR, "MyApp", "Failed to get original native function"); return; } // Register our replacement JNINativeMethod native_method = { "nativeMethod", "(I)I", (void *)hook_nativeMethod }; jclass cls = env->GetObjectClass(method_obj); env->RegisterNatives(cls, &native_method, 1); } ``` -------------------------------- ### InitInfo Structure Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/types.md The `InitInfo` structure holds configuration details for initializing LSPlant, including various callback function types for inline hooking, symbol resolution, and memory allocation. It also defines options for generated code naming conventions. ```APIDOC ## InitInfo ### Description Configuration structure containing initialization callbacks and code generation options. ### Fields #### inline_hooker - **Type**: `InlineHookFunType` (std::function) - **Required**: Yes - **Description**: Callback for installing inline hooks. #### inline_unhooker - **Type**: `InlineUnhookFunType` (std::function) - **Required**: Yes - **Description**: Callback for removing inline hooks. #### art_symbol_resolver - **Type**: `ArtSymbolResolver` (std::function) - **Required**: Yes - **Description**: Callback for resolving ART symbols. #### art_symbol_prefix_resolver - **Type**: `ArtSymbolPrefixResolver` (std::function) - **Required**: No - **Default**: nullptr - **Description**: Callback for prefix-based symbol resolution. #### generated_class_name - **Type**: `std::string_view` - **Required**: No - **Default**: "LSPHooker_" - **Description**: Base name for generated stub classes. #### generated_source_name - **Type**: `std::string_view` - **Required**: No - **Default**: "LSP" - **Description**: Source name attribute for generated classes. #### generated_field_name - **Type**: `std::string_view` - **Required**: No - **Default**: "hooker" - **Description**: Field name in generated classes. #### generated_method_name - **Type**: `std::string_view` - **Required**: No - **Default**: "{target}" - **Description**: Method name template in generated classes. #### executable_memory_allocator - **Type**: `MemoryAllocator` (std::function data)>) - **Required**: No - **Default**: nullptr - **Description**: Custom allocator for executable trampolines. #### executable_memory_recycler - **Type**: `MemoryRecycler` (std::function) - **Required**: No - **Default**: nullptr - **Description**: Custom deallocator for executable trampolines. ### Usage This structure is used by the `Init()` function. ``` -------------------------------- ### Dereference Field to Reference Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-hook-helpers.md Shows how to use the operator*() to get a direct reference to the field's value. This allows for direct modification of the field's content. ```cpp auto &value_ref = *field; value_ref = 42; ``` -------------------------------- ### ScopedLocalRef Operator Bool Example Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md The operator bool allows checking if the ScopedLocalRef holds a valid (non-null) JNI reference, similar to checking a raw pointer. ```cpp lsplant::ScopedLocalRef ref(env, class_or_null); if (ref) { // Reference is valid } ``` -------------------------------- ### Implement Executable Memory Allocator Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/configuration.md Use this to allocate executable memory (RWX or RX) for JIT code caches or position-independent code. Ensure the allocator is page-aligned and does not have a capture list. ```cpp #include .executable_memory_allocator = +[](std::span data) -> void * { // Allocate RWX memory void *addr = mmap(nullptr, data.size(), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (addr == MAP_FAILED) return nullptr; // Copy trampoline code memcpy(addr, data.data(), data.size()); return addr; } ``` -------------------------------- ### Object Creation and Manipulation Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-jni-helpers.md Create new Java objects, check instance types, compare object references, create global references, and manage direct byte buffers. ```cpp auto JNI_NewObject(JNIEnv *env, Class &&clazz, jmethodID method, Args &&...args); auto JNI_IsInstanceOf(JNIEnv *env, Object &&obj, Class &&clazz); auto JNI_IsSameObject(JNIEnv *env, Object1 &&a, Object2 &&b); auto JNI_NewGlobalRef(JNIEnv *env, Object &&x); auto JNI_NewDirectByteBuffer(JNIEnv *env, void *address, jlong capacity); ``` -------------------------------- ### InitInfo Structure Definition Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/configuration.md Defines the complete configuration object for LSPlant initialization. It includes required and optional callbacks, code generation options, and custom memory management settings. ```cpp struct InitInfo { // Required callbacks std::function inline_hooker; std::function inline_unhooker; std::function art_symbol_resolver; // Optional callbacks std::function art_symbol_prefix_resolver = nullptr; // Code generation options std::string_view generated_class_name = "LSPHooker_"; std::string_view generated_source_name = "LSP"; std::string_view generated_field_name = "hooker"; std::string_view generated_method_name = "{target}"; // Custom memory management std::function data)> executable_memory_allocator = nullptr; std::function executable_memory_recycler = nullptr; }; ``` -------------------------------- ### inline_unhooker Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/api-reference-initinfo.md A required inline unhook function that removes previously installed hooks. It takes the address of the hooked function as input and returns a boolean indicating success or failure. ```APIDOC ## Field: inline_unhooker Required inline unhook function that removes previously installed hooks. ### Type ```cpp std::function ``` ### Parameters | Parameter | Type | Description | |-----------|------|-------------| | func | `void*` | The address of the hooked function to restore. | ### Return Value `bool` — True if unhooking succeeds, false otherwise. ### Requirements - **Must not be null**: Initialization fails if not provided. - Can use lambda with capture list. - Must restore the original function to its pre-hooked state. - Must be compatible with the `inline_hooker` implementation. ### Example Implementation ```cpp lsplant::InitInfo init_info{ .inline_unhooker = [](void *func) -> bool { return DobbyDestroy(func); // Returns true on success }, // ... other fields }; ``` ``` -------------------------------- ### LSPlant Initialization Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/project-structure.md Initializes the LSPlant library. This function must be called before using other LSPlant functionalities. ```APIDOC ## Init ### Description Initialize LSPlant. ### Method N/A (Function Call) ### Parameters None explicitly documented. ### Request Example N/A ### Response N/A ``` -------------------------------- ### Batch Hooking Utility Source: https://github.com/lsposed/lsplant/blob/master/_autodocs/types.md A utility for resolving and hooking multiple symbols efficiently. It supports batch resolution and hooking operations. ```cpp struct HookHandler { HookHandler(const InitInfo &info); template bool operator()(T &&arg) const; template bool operator()(T1 &&arg1, T2 &&arg2, U &&...args) const; template typename T> bool unhook(const T &hooker) const; }; ```