Funktionsumleitung in nativen Android-Bibliotheken

In diesem Artikel werde ich ein wenig darüber sprechen, wie Sie Funktionsaufrufe mithilfe des AndHook- Frameworks an native Bibliotheken umleiten können . Sie können öffentliche (exportierte) und nicht öffentliche Aufrufe direkt an ihre Adresse abfangen. Weitere Informationen zur Umleitung finden Sie hier und auf der Framework-Seite.


Als Beispiel betrachten wir den Fall bei der Implementierung seiner Bibliothek. Mit diesem Framework können Sie jedoch auch arbeiten, ohne die Anwendung mit xposed neu zu erstellen.


In diesem Artikel werde ich Visual Studio und BatchApkTool für Windows verwenden. Anstelle von Visual Studio können Sie Android Studio verwenden oder es sogar über gcc oder clang kompilieren (eine Option für Fortgeschrittene). Anstelle von BatchApkTool können Sie auch apktool verwenden. Ich werde nicht im Detail über die Arbeit mit BatchApkTool aufhören, weil Der Umgang mit der Arbeit im Programm ist nicht schwierig.


Zuerst müssen Sie die APK mit BatchApkTool oder apktool analysieren.


Laden Sie nun die Bibliothek und die Header-Datei von der Projektseite herunter. Dazu müssen Sie diesem Link und diesem Link folgen und die Bibliothek für Ihre Plattform herunterladen. (Ich habe den Unterschied zwischen der Version von Compat und der üblichen Version nicht gefunden. Ich habe persönlich die normale Version verwendet. Vielleicht werden sie es in den Kommentaren verraten.)


Einrichten von Visual Studio für die Arbeit mit NDK

Visual Studio Installer :



.


Erstellen eines neuen Projekts in Visual Studio

, , , .


" (Android)", .



:

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




, , , , .


. .



. .



, .cpp


#include "AndHook.h"

Erstellen wir die Funktion JNI_OnLoad, in der wir unsere Hooks registrieren.
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;
}

Die RegisterHooks-Funktion selbst:


//       #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);
}

Auch zum Patchen unter mehreren Architekturen ist es bequem, #define zu verwenden


Beispiel
#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);

Nachdem wir den Code fertig geschrieben haben, muss er kompiliert werden.
Dazu benötigen Sie:


Wählen Sie die Zielplattform


Projekt zusammenbauen


Wenn mehrere Plattformen vorhanden sind, wiederholen Sie die Schritte 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