Feature redirection in Android native libraries

In this article, I’ll talk a little about how you can redirect function calls to native libraries using the AndHook framework . You can intercept calls both public (exported functions) and non-public, directly to their address. You can read more about redirection here and on the framework page.


As an example, we will consider the case with the implementation of its library. However, this framework also allows you to work without rebuilding the application using xposed.


In this article, I will use Visual Studio and BatchApkTool for Windows. Instead of Visual Studio, you can use Android Studio, or even compile it through gcc or clang (an option for advanced). Instead of BatchApkTool, you can use apktool. I will not stop in detail about working with BatchApkTool, because Dealing with work in the program is not difficult.


First you need to parse the APK using BatchApkTool or apktool.


Now download the library and the header file from the project page, for this you need to follow this link and this link and download the library for your platform. (I did not find the difference between the version of Compat and the usual one, I personally used the normal version. Perhaps they will tell in the comments)


Setting up Visual Studio to work with NDK

Visual Studio Installer :



.


Creating a new project in Visual Studio

, , , .


" (Android)", .



:

. : , : < >, API 14 ARM X86, ARM64 X64 21 .
.
-> , :




, , , , .


. .



. .



, .cpp


#include "AndHook.h"

Let's create the JNI_OnLoad function, in which we will register our hooks.
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1;
    LOGD("JNI_OnLoad start!");

    if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) {
        LOGE("JNI_OnLoad! GetEnv failed");
        return -1;
    }

    RegisterHooks();

    result = JNI_VERSION_1_4;
    LOGD("JNI_OnLoad! finished!");
    return result;
}

The RegisterHooks function itself:


//       #define
#ifdef __arm__
#define Test_Offset 0x1234
#elif __aarch64__
#define Test_Offset 0x1235
#elif __i386__
#define Test_Offset 0x1236
#elif __x86_64__
#define Test_Offset 0x1237
#endif
void (*Old_Test)();
void Test()
{
    LOGD("Test!");
    // Do something
    Old_Test();
}
void (*Old_Test2)();
void Test2()
{
    LOGD("Test2!");
    Old_Test2(); //      Test2
}
void RegisterHooks() {
    const void* libil2cpp = AKGetImageByName("libil2cpp.so"); //     .
    if (libil2cpp == NULL) {
        LOGW("AKGetImageByName return null!");
        return;
    }

    //      
    //  -     IDA/Ghidra
    //    il2cpp-     https://github.com/Perfare/Il2CppDumper
    AKHookFunction(AKFindAnonymity(libil2cpp, Test_Offset), reinterpret_cast<void*>(&Test), reinterpret_cast<void**>(&Old_Test));
    //       Test_Offset   libil2cpp       Test,  .       Old_Test.

    //   
    AKHookFunction(AKFindSymbol(libil2cpp, "Test2"), reinterpret_cast<void*>(&Test2), reinterpret_cast<void**>(&Old_Test2));

    //         :
    void (*Test3)();
    Test3 = reinterpret_cast<void (*)()>(AKFindAnonymity(libil2cpp, 0x12345));
    Test3();

    //      
    const uint8_t data[] = { 0x00, 0xF0, 0x20, 0xE3 }; //  NOP
    AKPatchMemory(reinterpret_cast<const void*>(AKFindAnonymity(libil2cpp, 0x123456)), reinterpret_cast<const void*>(&data), 4);
    //       0x123456

    AKCloseImage(libil2cpp);
}

Also for patching under several architectures it is convenient to use #define


Example
#ifdef __arm__
#define Patch_Offset 0x1234
#define Patch_Data { 0x00, 0xF0, 0x20, 0xE3 }
#elif __aarch64__
#define Patch_Offset 0x1234
#define Patch_Data { 0x1F, 0x20, 0x03, 0xD5 }
#endif

const uint8_t data[] = Patch_Data;
const size_t len = sizeof(data) / sizeof(uint8_t);
AKPatchMemory(reinterpret_cast<const void*>(AKFindAnonymity(libil2cpp, Patch_Offset)), reinterpret_cast<const void*>(&data), len);

After we have finished writing the code, it must be compiled.
To do this, you need:


Choose target platform


Assemble project


If several platforms repeat steps 1-2.


AndHook lib . ( ).


. MainActivity . onCreate MainActivity :


const-string v0, "SharedObject1"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V

SharedObject1 lib .so
il2cpp- MainActivity onCreate smali/com/unity3d/player/UnityPlayerActivity.smali.


.


:
https://github.com/asLody/AndHook/
http://armconverter.com/
http://armconverter.com/hextoarm/


All Articles