Neste artigo, falarei um pouco sobre como vocĂȘ pode redirecionar chamadas de função para bibliotecas nativas usando a estrutura AndHook . VocĂȘ pode interceptar chamadas pĂșblicas (funçÔes exportadas) e nĂŁo pĂșblicas diretamente para o endereço delas. VocĂȘ pode ler mais sobre redirecionamento aqui e na pĂĄgina da estrutura.
Como exemplo, consideraremos o caso com a implementação de sua biblioteca. No entanto, essa estrutura tambĂ©m permite que vocĂȘ trabalhe sem reconstruir o aplicativo usando xposed.
Neste artigo, usarei o Visual Studio e o BatchApkTool para Windows. Em vez do Visual Studio, vocĂȘ pode usar o Android Studio ou atĂ© compilĂĄ-lo atravĂ©s do gcc ou clang (uma opção para avançado). Em vez do BatchApkTool, vocĂȘ pode usar o apktool. NĂŁo pararei em detalhes sobre o trabalho com o BatchApkTool, porque Lidar com o trabalho no programa nĂŁo Ă© difĂcil.
Primeiro, vocĂȘ precisa analisar o APK usando o BatchApkTool ou apktool.
Agora faça o download da biblioteca e do arquivo de cabeçalho na pågina do projeto. Para isso, siga este link e o link e faça o download da biblioteca para sua plataforma. (Eu não encontrei a diferença entre a versão do Compat e a usual, eu pessoalmente usei a versão normal. Talvez eles digam nos comentårios)
Configurando o Visual Studio para trabalhar com NDKVisual Studio Installer :

.
Criando um novo projeto no Visual Studio, , , .
" (Android)", .
:

. : , : < >, API 14 ARM X86, ARM64 X64 21 .
.
-> , :
, , , , .
. .
. .
, .cpp
#include "AndHook.h"
Vamos criar a função JNI_OnLoad, na qual registraremos nossos ganchos.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;
}
O RegisterHooks funciona em si:
#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);
}
Também para aplicar patches em vårias arquiteturas, é conveniente usar #define
Exemplo#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);
Depois de terminar de escrever o cĂłdigo, ele deve ser compilado.
Para fazer isso, vocĂȘ precisa:
Escolha a plataforma de destino Se vĂĄrias plataformas repetirem as etapas 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/