في هذه المقالة ، سأتحدث قليلاً عن كيف ، باستخدام إطار AndHook ، يمكنك إعادة توجيه استدعاءات الوظائف في المكتبات الأصلية. يمكنك اعتراض المكالمات العامة (الوظائف المصدرة) وغير العامة مباشرة إلى عنوانها. يمكنك قراءة المزيد حول إعادة التوجيه هنا وفي صفحة إطار العمل.
كمثال ، سننظر في الحالة مع تنفيذ مكتبتها. ومع ذلك ، يتيح لك هذا الإطار أيضًا العمل دون إعادة إنشاء التطبيق باستخدام xposed.
في هذه المقالة ، سأستخدم Visual Studio و BatchApkTool لنظام التشغيل Windows. بدلاً من Visual Studio ، يمكنك استخدام Android Studio ، أو حتى تجميعه من خلال gcc أو clang (خيار متقدم). بدلاً من BatchApkTool ، يمكنك استخدام apktool. لن أتوقف بالتفصيل عن العمل مع BatchApkTool ، لأن التعامل مع العمل في البرنامج ليس بالأمر الصعب.
تحتاج أولاً إلى تحليل APK باستخدام BatchApkTool أو apktool.
الآن قم بتنزيل المكتبة وملف الرأس من صفحة المشروع ، لذلك تحتاج إلى اتباع هذا الرابط وهذا الرابط وتنزيل المكتبة لنظامك الأساسي. (لم أجد الفرق بين إصدار Compat والإصدار المعتاد ، فقد استخدمت شخصيًا الإصدار العادي. ربما سيخبرون في التعليقات)
إعداد Visual Studio للعمل مع NDKVisual Studio Installer :

.
إنشاء مشروع جديد في Visual Studio, , , .
" (Android)", .
:

. : , : < >, API 14 ARM X86, ARM64 X64 21 .
.
-> , :
, , , , .
. .
. .
, .cpp
#include "AndHook.h"
دعنا ننشئ وظيفة JNI_OnLoad ، حيث سنقوم بتسجيل الخطافات الخاصة بنا.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;
}
تعمل RegisterHooks نفسها:
#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!");
Old_Test();
}
void (*Old_Test2)();
void Test2()
{
LOGD("Test2!");
Old_Test2();
}
void RegisterHooks() {
const void* libil2cpp = AKGetImageByName("libil2cpp.so");
if (libil2cpp == NULL) {
LOGW("AKGetImageByName return null!");
return;
}
AKHookFunction(AKFindAnonymity(libil2cpp, Test_Offset), reinterpret_cast<void*>(&Test), reinterpret_cast<void**>(&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 };
AKPatchMemory(reinterpret_cast<const void*>(AKFindAnonymity(libil2cpp, 0x123456)), reinterpret_cast<const void*>(&data), 4);
AKCloseImage(libil2cpp);
}
أيضًا من أجل التصحيح تحت العديد من البنيات ، من السهل استخدام #define
مثال#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);
بعد الانتهاء من كتابة التعليمات البرمجية ، يجب أن يتم تجميعها.
للقيام بذلك ، تحتاج إلى:
إذا كررت عدة منصات الخطوات 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/