mirror of
https://github.com/LSPosed/LSPlant.git
synced 2025-05-04 20:42:02 +08:00
Android 5.x support (#7)
This commit is contained in:
parent
c97c87b815
commit
6d40254a3f
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@ -53,6 +53,18 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
- api-level: 21
|
||||||
|
target: default
|
||||||
|
arch: x86_64
|
||||||
|
- api-level: 21
|
||||||
|
target: default
|
||||||
|
arch: x86
|
||||||
|
- api-level: 22
|
||||||
|
target: default
|
||||||
|
arch: x86_64
|
||||||
|
- api-level: 22
|
||||||
|
target: default
|
||||||
|
arch: x86
|
||||||
- api-level: 23
|
- api-level: 23
|
||||||
target: default
|
target: default
|
||||||
arch: x86_64
|
arch: x86_64
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# LSPlant
|
# LSPlant
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
@ -12,7 +12,7 @@ This project is part of LSPosed framework under GNU Lesser General Public Licens
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
+ Support Android 6.0 - 13 (API level 23 - 33)
|
+ Support Android 5.0 - 13 (API level 21 - 33)
|
||||||
+ Support armeabi-v7a, arm64-v8a, x86, x86-64
|
+ Support armeabi-v7a, arm64-v8a, x86, x86-64
|
||||||
+ Support customized inline hook framework and ART symbol resolver
|
+ Support customized inline hook framework and ART symbol resolver
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
val androidTargetSdkVersion by extra(32)
|
val androidTargetSdkVersion by extra(32)
|
||||||
val androidMinSdkVersion by extra(23)
|
val androidMinSdkVersion by extra(21)
|
||||||
val androidBuildToolsVersion by extra("32.0.0")
|
val androidBuildToolsVersion by extra("32.0.0")
|
||||||
val androidCompileSdkVersion by extra(32)
|
val androidCompileSdkVersion by extra(32)
|
||||||
val androidNdkVersion by extra("23.1.7779620")
|
val androidNdkVersion by extra("23.1.7779620")
|
||||||
|
@ -13,6 +13,7 @@ Cpp11BracedListStyle: true
|
|||||||
Standard: Latest
|
Standard: Latest
|
||||||
# IndentAccessModifiers: false
|
# IndentAccessModifiers: false
|
||||||
IndentCaseLabels: false
|
IndentCaseLabels: false
|
||||||
|
BreakStringLiterals: false
|
||||||
IndentExternBlock: false
|
IndentExternBlock: false
|
||||||
AccessModifierOffset: -4
|
AccessModifierOffset: -4
|
||||||
# EmptyLineBeforeAccessModifier: true
|
# EmptyLineBeforeAccessModifier: true
|
||||||
|
@ -35,10 +35,25 @@ class Instrumentation {
|
|||||||
backup(thiz, MaybeUseBackupMethod(art_method, quick_code), quick_code);
|
backup(thiz, MaybeUseBackupMethod(art_method, quick_code), quick_code);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
CREATE_MEM_HOOK_STUB_ENTRY(
|
||||||
|
"_ZN3art15instrumentation15Instrumentation17UpdateMethodsCodeEPNS_6mirror9ArtMethodEPKvS6_b",
|
||||||
|
void, UpdateMethodsCodeWithProtableCode,
|
||||||
|
(Instrumentation * thiz, ArtMethod *art_method, const void *quick_code,
|
||||||
|
const void *portable_code, bool have_portable_code),
|
||||||
|
{
|
||||||
|
backup(thiz, MaybeUseBackupMethod(art_method, quick_code), quick_code, portable_code,
|
||||||
|
have_portable_code);
|
||||||
|
});
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static bool Init(const HookHandler &handler) {
|
static bool Init(const HookHandler &handler) {
|
||||||
int sdk_int = GetAndroidApiLevel();
|
int sdk_int = GetAndroidApiLevel();
|
||||||
|
if (sdk_int < __ANDROID_API_M__) [[unlikely]] {
|
||||||
|
if (!HookSyms(handler, UpdateMethodsCodeWithProtableCode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (!HookSyms(handler, UpdateMethodsCode)) {
|
if (!HookSyms(handler, UpdateMethodsCode)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -127,27 +127,35 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static art::ArtMethod *FromReflectedMethod(JNIEnv *env, jobject method) {
|
static art::ArtMethod *FromReflectedMethod(JNIEnv *env, jobject method) {
|
||||||
return reinterpret_cast<art::ArtMethod *>(JNI_GetLongField(env, method, art_method_field));
|
if (art_method_field) [[likely]] {
|
||||||
|
return reinterpret_cast<art::ArtMethod *>(
|
||||||
|
JNI_GetLongField(env, method, art_method_field));
|
||||||
|
} else {
|
||||||
|
return reinterpret_cast<art::ArtMethod *>(env->FromReflectedMethod(method));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Init(JNIEnv *env, const HookHandler handler) {
|
static bool Init(JNIEnv *env, const HookHandler handler) {
|
||||||
auto sdk_int = GetAndroidApiLevel();
|
auto sdk_int = GetAndroidApiLevel();
|
||||||
jclass executable = nullptr;
|
ScopedLocalRef<jclass> executable{env, nullptr};
|
||||||
if (sdk_int >= __ANDROID_API_O__) {
|
if (sdk_int >= __ANDROID_API_O__) {
|
||||||
executable = JNI_NewGlobalRef(env, JNI_FindClass(env, "java/lang/reflect/Executable"));
|
executable = JNI_FindClass(env, "java/lang/reflect/Executable");
|
||||||
|
} else if (sdk_int >= __ANDROID_API_M__) {
|
||||||
|
executable = JNI_FindClass(env, "java/lang/reflect/AbstractMethod");
|
||||||
} else {
|
} else {
|
||||||
executable =
|
executable = JNI_FindClass(env, "java/lang/reflect/ArtMethod");
|
||||||
JNI_NewGlobalRef(env, JNI_FindClass(env, "java/lang/reflect/AbstractMethod"));
|
|
||||||
}
|
}
|
||||||
if (!executable) {
|
if (!executable) {
|
||||||
LOGE("Failed to found Executable/AbstractMethod");
|
LOGE("Failed to found Executable/AbstractMethod/ArtMethod");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (art_method_field = JNI_GetFieldID(env, executable, "artMethod", "J");
|
if (sdk_int >= __ANDROID_API_M__) [[likely]] {
|
||||||
!art_method_field) {
|
if (art_method_field = JNI_GetFieldID(env, executable, "artMethod", "J");
|
||||||
LOGE("Failed to find artMethod field");
|
!art_method_field) {
|
||||||
return false;
|
LOGE("Failed to find artMethod field");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto throwable = JNI_FindClass(env, "java/lang/Throwable");
|
auto throwable = JNI_FindClass(env, "java/lang/Throwable");
|
||||||
@ -172,32 +180,59 @@ public:
|
|||||||
art_method_size = reinterpret_cast<uintptr_t>(second) - reinterpret_cast<uintptr_t>(first);
|
art_method_size = reinterpret_cast<uintptr_t>(second) - reinterpret_cast<uintptr_t>(first);
|
||||||
LOGD("ArtMethod size: %zu", art_method_size);
|
LOGD("ArtMethod size: %zu", art_method_size);
|
||||||
|
|
||||||
if (RoundUpTo(4 * 9, kPointerSize) + kPointerSize * 3 < art_method_size) {
|
if (RoundUpTo(4 * 9, kPointerSize) + kPointerSize * 3 < art_method_size) [[unlikely]] {
|
||||||
LOGW("ArtMethod size exceeds maximum assume. There may be something wrong.");
|
if (sdk_int >= __ANDROID_API_M__) {
|
||||||
|
LOGW("ArtMethod size exceeds maximum assume. There may be something wrong.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entry_point_offset = art_method_size - kPointerSize;
|
entry_point_offset = art_method_size - kPointerSize;
|
||||||
LOGD("ArtMethod::entrypoint offset: %zu", entry_point_offset);
|
|
||||||
|
|
||||||
data_offset = entry_point_offset - kPointerSize;
|
data_offset = entry_point_offset - kPointerSize;
|
||||||
LOGD("ArtMethod::data offset: %zu", data_offset);
|
|
||||||
|
|
||||||
if (auto access_flags_field = JNI_GetFieldID(env, executable, "accessFlags", "I");
|
if (sdk_int >= __ANDROID_API_M__) [[likely]] {
|
||||||
access_flags_field) {
|
if (auto access_flags_field = JNI_GetFieldID(env, executable, "accessFlags", "I");
|
||||||
uint32_t real_flags = JNI_GetIntField(env, first_ctor, access_flags_field);
|
access_flags_field) {
|
||||||
for (size_t i = 0; i < art_method_size; i += sizeof(uint32_t)) {
|
uint32_t real_flags = JNI_GetIntField(env, first_ctor, access_flags_field);
|
||||||
if (*reinterpret_cast<uint32_t *>(reinterpret_cast<uintptr_t>(first) + i) ==
|
for (size_t i = 0; i < art_method_size; i += sizeof(uint32_t)) {
|
||||||
real_flags) {
|
if (*reinterpret_cast<uint32_t *>(reinterpret_cast<uintptr_t>(first) + i) ==
|
||||||
access_flags_offset = i;
|
real_flags) {
|
||||||
LOGD("ArtMethod::access_flags offset: %zu", access_flags_offset);
|
access_flags_offset = i;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (access_flags_offset == 0) {
|
||||||
|
LOGW("Failed to find accessFlags field. Fallback to 4.");
|
||||||
|
access_flags_offset = 4U;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto art_field = JNI_FindClass(env, "java/lang/reflect/ArtField");
|
||||||
|
auto field = JNI_FindClass(env, "java/lang/reflect/Field");
|
||||||
|
auto art_field_field =
|
||||||
|
JNI_GetFieldID(env, field, "artField", "Ljava/lang/reflect/ArtField;");
|
||||||
|
auto field_offset = JNI_GetFieldID(env, art_field, "offset", "I");
|
||||||
|
auto get_offset_from_art_method = [&](const char *name, const char *sig) {
|
||||||
|
return JNI_GetIntField(
|
||||||
|
env,
|
||||||
|
JNI_GetObjectField(
|
||||||
|
env,
|
||||||
|
env->ToReflectedField(executable,
|
||||||
|
JNI_GetFieldID(env, executable, name, sig), false),
|
||||||
|
art_field_field),
|
||||||
|
field_offset);
|
||||||
|
};
|
||||||
|
access_flags_offset = get_offset_from_art_method("accessFlags", "I");
|
||||||
|
if (sdk_int == __ANDROID_API_L__) {
|
||||||
|
entry_point_offset =
|
||||||
|
get_offset_from_art_method("entryPointFromQuickCompiledCode", "J");
|
||||||
|
interpreter_entry_point_offset =
|
||||||
|
get_offset_from_art_method("entryPointFromInterpreter", "J");
|
||||||
|
data_offset = get_offset_from_art_method("entryPointFromJni", "J");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (access_flags_offset == 0) {
|
LOGD("ArtMethod::entrypoint offset: %zu", entry_point_offset);
|
||||||
LOGW("Failed to find accessFlags field. Fallback to 4.");
|
LOGD("ArtMethod::data offset: %zu", data_offset);
|
||||||
access_flags_offset = 4U;
|
LOGD("ArtMethod::access_flags offset: %zu", access_flags_offset);
|
||||||
}
|
|
||||||
|
|
||||||
if (sdk_int < __ANDROID_API_R__) {
|
if (sdk_int < __ANDROID_API_R__) {
|
||||||
kAccPreCompiled = 0;
|
kAccPreCompiled = 0;
|
||||||
@ -207,14 +242,16 @@ public:
|
|||||||
if (sdk_int < __ANDROID_API_Q__) kAccFastInterpreterToInterpreterInvoke = 0;
|
if (sdk_int < __ANDROID_API_Q__) kAccFastInterpreterToInterpreterInvoke = 0;
|
||||||
|
|
||||||
if (!RETRIEVE_FUNC_SYMBOL(GetMethodShorty,
|
if (!RETRIEVE_FUNC_SYMBOL(GetMethodShorty,
|
||||||
"_ZN3artL15GetMethodShortyEP7_JNIEnvP10_jmethodID")) {
|
"_ZN3artL15GetMethodShortyEP7_JNIEnvP10_jmethodID") &&
|
||||||
|
!RETRIEVE_FUNC_SYMBOL(GetMethodShorty,
|
||||||
|
"_ZN3art15GetMethodShortyEP7_JNIEnvP10_jmethodID")) {
|
||||||
LOGE("Failed to find GetMethodShorty");
|
LOGE("Failed to find GetMethodShorty");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!RETRIEVE_FUNC_SYMBOL(PrettyMethod, "_ZN3art9ArtMethod12PrettyMethodEPS0_b")) {
|
!RETRIEVE_FUNC_SYMBOL(PrettyMethod, "_ZN3art9ArtMethod12PrettyMethodEPS0_b") &&
|
||||||
RETRIEVE_FUNC_SYMBOL(PrettyMethod, "_ZN3art12PrettyMethodEPNS_9ArtMethodEb");
|
!RETRIEVE_FUNC_SYMBOL(PrettyMethod, "_ZN3art12PrettyMethodEPNS_9ArtMethodEb") &&
|
||||||
}
|
!RETRIEVE_FUNC_SYMBOL(PrettyMethod, "_ZN3art12PrettyMethodEPNS_6mirror9ArtMethodEb");
|
||||||
|
|
||||||
if (sdk_int <= __ANDROID_API_O__) [[unlikely]] {
|
if (sdk_int <= __ANDROID_API_O__) [[unlikely]] {
|
||||||
auto abstract_method_error = JNI_FindClass(env, "java/lang/AbstractMethodError");
|
auto abstract_method_error = JNI_FindClass(env, "java/lang/AbstractMethodError");
|
||||||
@ -246,12 +283,14 @@ public:
|
|||||||
if (sdk_int <= __ANDROID_API_N__) {
|
if (sdk_int <= __ANDROID_API_N__) {
|
||||||
kAccCompileDontBother = 0;
|
kAccCompileDontBother = 0;
|
||||||
}
|
}
|
||||||
if (sdk_int == __ANDROID_API_M__) [[unlikely]] {
|
if (sdk_int <= __ANDROID_API_M__) [[unlikely]] {
|
||||||
if (!RETRIEVE_FUNC_SYMBOL(art_interpreter_to_compiled_code_bridge,
|
if (!RETRIEVE_FUNC_SYMBOL(art_interpreter_to_compiled_code_bridge,
|
||||||
"artInterpreterToCompiledCodeBridge")) {
|
"artInterpreterToCompiledCodeBridge")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
interpreter_entry_point_offset = entry_point_offset - 2 * kPointerSize;
|
if (sdk_int >= __ANDROID_API_L_MR1__) {
|
||||||
|
interpreter_entry_point_offset = entry_point_offset - 2 * kPointerSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
|
|
||||||
@ -18,26 +19,74 @@ class DexFile {
|
|||||||
return OpenMemorySym(dex_file, size, location, location_checksum, mem_map, oat_dex_file,
|
return OpenMemorySym(dex_file, size, location, location_checksum, mem_map, oat_dex_file,
|
||||||
error_msg);
|
error_msg);
|
||||||
}
|
}
|
||||||
|
if (error_msg) *error_msg = "null sym";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
CREATE_FUNC_SYMBOL_ENTRY(const DexFile*, OpenMemoryRaw, const uint8_t* dex_file, size_t size,
|
||||||
static std::unique_ptr<DexFile> OpenMemory(const void* dex_file, size_t size,
|
const std::string& location, uint32_t location_checksum, void* mem_map,
|
||||||
std::string location, std::string* error_msg) {
|
const void* oat_dex_file, std::string* error_msg) {
|
||||||
return OpenMemory(reinterpret_cast<const uint8_t*>(dex_file), size, location,
|
if (OpenMemoryRawSym) [[likely]] {
|
||||||
reinterpret_cast<const Header*>(dex_file)->checksum_, nullptr, nullptr,
|
return OpenMemoryRawSym(dex_file, size, location, location_checksum, mem_map,
|
||||||
error_msg);
|
oat_dex_file, error_msg);
|
||||||
|
}
|
||||||
|
if (error_msg) *error_msg = "null sym";
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject ToJavaDexFile(JNIEnv* env) {
|
CREATE_FUNC_SYMBOL_ENTRY(const DexFile*, OpenMemoryWithoutOdex, const uint8_t* dex_file,
|
||||||
|
size_t size, const std::string& location, uint32_t location_checksum,
|
||||||
|
void* mem_map, std::string* error_msg) {
|
||||||
|
if (OpenMemoryWithoutOdexSym) [[likely]] {
|
||||||
|
return OpenMemoryWithoutOdexSym(dex_file, size, location, location_checksum, mem_map,
|
||||||
|
error_msg);
|
||||||
|
}
|
||||||
|
if (error_msg) *error_msg = "null sym";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CREATE_MEM_FUNC_SYMBOL_ENTRY(void, push_back, std::vector<const DexFile*>* thiz,
|
||||||
|
const DexFile** dex_file) {
|
||||||
|
push_backSym(thiz, dex_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const DexFile* OpenMemory(const void* dex_file, size_t size, std::string location,
|
||||||
|
std::string* error_msg) {
|
||||||
|
if (OpenMemorySym) [[likely]] {
|
||||||
|
return OpenMemory(reinterpret_cast<const uint8_t*>(dex_file), size, location,
|
||||||
|
reinterpret_cast<const Header*>(dex_file)->checksum_, nullptr,
|
||||||
|
nullptr, error_msg)
|
||||||
|
.release();
|
||||||
|
} else if (OpenMemoryRawSym) {
|
||||||
|
return OpenMemoryRaw(reinterpret_cast<const uint8_t*>(dex_file), size, location,
|
||||||
|
reinterpret_cast<const Header*>(dex_file)->checksum_, nullptr,
|
||||||
|
nullptr, error_msg);
|
||||||
|
} else if (OpenMemoryWithoutOdexSym) {
|
||||||
|
return OpenMemoryWithoutOdex(reinterpret_cast<const uint8_t*>(dex_file), size, location,
|
||||||
|
reinterpret_cast<const Header*>(dex_file)->checksum_,
|
||||||
|
nullptr, error_msg);
|
||||||
|
} else {
|
||||||
|
if (error_msg) *error_msg = "no sym";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jobject ToJavaDexFile(JNIEnv* env) const {
|
||||||
auto java_dex_file = env->AllocObject(dex_file_class);
|
auto java_dex_file = env->AllocObject(dex_file_class);
|
||||||
auto cookie = JNI_NewLongArray(env, dex_file_start_index + 1);
|
auto cookie = JNI_NewLongArray(env, dex_file_start_index + 1);
|
||||||
cookie[oat_file_index] = 0;
|
if (dex_file_start_index != size_t(-1)) [[likely]] {
|
||||||
cookie[dex_file_start_index] = reinterpret_cast<jlong>(this);
|
cookie[oat_file_index] = 0;
|
||||||
cookie.commit();
|
cookie[dex_file_start_index] = reinterpret_cast<jlong>(this);
|
||||||
JNI_SetObjectField(env, java_dex_file, cookie_field, cookie);
|
cookie.commit();
|
||||||
if (internal_cookie_field) {
|
JNI_SetObjectField(env, java_dex_file, cookie_field, cookie);
|
||||||
JNI_SetObjectField(env, java_dex_file, internal_cookie_field, cookie);
|
if (internal_cookie_field) {
|
||||||
|
JNI_SetObjectField(env, java_dex_file, internal_cookie_field, cookie);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
JNI_SetLongField(
|
||||||
|
env, java_dex_file, cookie_field,
|
||||||
|
static_cast<jlong>(reinterpret_cast<uintptr_t>(new std::vector{this})));
|
||||||
}
|
}
|
||||||
JNI_SetObjectField(env, java_dex_file, file_name_field, JNI_NewStringUTF(env, ""));
|
JNI_SetObjectField(env, java_dex_file, file_name_field, JNI_NewStringUTF(env, ""));
|
||||||
return java_dex_file;
|
return java_dex_file;
|
||||||
@ -53,15 +102,32 @@ public:
|
|||||||
LP_SELECT("_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_"
|
LP_SELECT("_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_"
|
||||||
"traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_",
|
"traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_",
|
||||||
"_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_"
|
"_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_"
|
||||||
"traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_")))
|
"traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_")) &&
|
||||||
[[unlikely]] {
|
!RETRIEVE_FUNC_SYMBOL(
|
||||||
|
OpenMemoryRaw,
|
||||||
|
LP_SELECT("_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_"
|
||||||
|
"traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_7OatFileEPS9_",
|
||||||
|
"_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_"
|
||||||
|
"traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_7OatFileEPS9_")) &&
|
||||||
|
!RETRIEVE_FUNC_SYMBOL(
|
||||||
|
OpenMemoryWithoutOdex,
|
||||||
|
LP_SELECT("_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_"
|
||||||
|
"traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPS9_",
|
||||||
|
"_ZN3art7DexFile10OpenMemoryEPKhmRKNSt3__112basic_stringIcNS3_11char_"
|
||||||
|
"traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPS9_"))) [[unlikely]] {
|
||||||
|
LOGE("Failed to find OpenMemory");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
dex_file_class = JNI_NewGlobalRef(env, JNI_FindClass(env, "dalvik/system/DexFile"));
|
dex_file_class = JNI_NewGlobalRef(env, JNI_FindClass(env, "dalvik/system/DexFile"));
|
||||||
if (!dex_file_class) {
|
if (!dex_file_class) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
cookie_field = JNI_GetFieldID(env, dex_file_class, "mCookie", "Ljava/lang/Object;");
|
if (sdk_int >= __ANDROID_API_M__) {
|
||||||
|
cookie_field = JNI_GetFieldID(env, dex_file_class, "mCookie", "Ljava/lang/Object;");
|
||||||
|
} else {
|
||||||
|
cookie_field = JNI_GetFieldID(env, dex_file_class, "mCookie", "J");
|
||||||
|
dex_file_start_index = -1;
|
||||||
|
}
|
||||||
if (!cookie_field) {
|
if (!cookie_field) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -228,23 +228,23 @@ bool InitNative(JNIEnv *env, const HookHandler &handler) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!Class::Init(env, handler)) {
|
if (!Class::Init(env, handler)) {
|
||||||
LOGE("failed to init mirror class");
|
LOGE("Failed to init mirror class");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!Instrumentation::Init(handler)) {
|
if (!Instrumentation::Init(handler)) {
|
||||||
LOGE("failed to init instrumentation");
|
LOGE("Failed to init instrumentation");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ScopedSuspendAll::Init(handler)) {
|
if (!ScopedSuspendAll::Init(handler)) {
|
||||||
LOGE("failed to init scoped suspend all");
|
LOGE("Failed to init scoped suspend all");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ScopedGCCriticalSection::Init(handler)) {
|
if (!ScopedGCCriticalSection::Init(handler)) {
|
||||||
LOGE("failed to init scoped gc critical section");
|
LOGE("Failed to init scoped gc critical section");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!JitCodeCache::Init(handler)) {
|
if (!JitCodeCache::Init(handler)) {
|
||||||
LOGE("failed to init jit code cache");
|
LOGE("Failed to init jit code cache");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!DexFile::Init(env, handler)) {
|
if (!DexFile::Init(env, handler)) {
|
||||||
@ -365,12 +365,14 @@ std::tuple<jclass, jfieldID, jmethodID, jmethodID> BuildDex(JNIEnv *env, jobject
|
|||||||
memcpy(target, image.ptr(), image.size());
|
memcpy(target, image.ptr(), image.size());
|
||||||
mprotect(target, image.size(), PROT_READ);
|
mprotect(target, image.size(), PROT_READ);
|
||||||
std::string err_msg;
|
std::string err_msg;
|
||||||
auto *dex = DexFile::OpenMemory(
|
const auto *dex = DexFile::OpenMemory(
|
||||||
target, image.size(),
|
target, image.size(), generated_source_name.empty() ? "lsplant" : generated_source_name,
|
||||||
generated_source_name.empty() ? "lsplant" : generated_source_name, &err_msg)
|
&err_msg);
|
||||||
.release();
|
if (!dex) {
|
||||||
auto java_dex_file = WrapScope(env, dex->ToJavaDexFile(env));
|
LOGE("Failed to open memory dex: %s", err_msg.data());
|
||||||
if (java_dex_file) {
|
}
|
||||||
|
auto java_dex_file = WrapScope(env, dex ? dex->ToJavaDexFile(env) : jobject{nullptr});
|
||||||
|
if (dex && java_dex_file) {
|
||||||
auto p = JNI_NewObject(env, path_class_loader, path_class_loader_init,
|
auto p = JNI_NewObject(env, path_class_loader, path_class_loader_init,
|
||||||
JNI_NewStringUTF(env, ""), class_loader);
|
JNI_NewStringUTF(env, ""), class_loader);
|
||||||
target_class = JNI_Cast<jclass>(JNI_CallObjectMethod(
|
target_class = JNI_Cast<jclass>(JNI_CallObjectMethod(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user