[core] Use Field.set instead of Method.invoke (#891)
This commit is contained in:
parent
59931f4f6e
commit
95c0f8aafc
|
|
@ -60,9 +60,9 @@ namespace lspd {
|
||||||
|
|
||||||
LSP_DEF_NATIVE_METHOD(jclass, Yahfa, buildHooker, jobject app_class_loader, jchar return_class,
|
LSP_DEF_NATIVE_METHOD(jclass, Yahfa, buildHooker, jobject app_class_loader, jchar return_class,
|
||||||
jcharArray classes, jstring method_name) {
|
jcharArray classes, jstring method_name) {
|
||||||
static auto in_memory_classloader = JNI_NewGlobalRef(env, JNI_FindClass(env,
|
static auto *kInMemoryClassloader = JNI_NewGlobalRef(env, JNI_FindClass(env,
|
||||||
"dalvik/system/InMemoryDexClassLoader"));
|
"dalvik/system/InMemoryDexClassLoader"));
|
||||||
static jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
|
static jmethodID kInitMid = JNI_GetMethodID(env, kInMemoryClassloader, "<init>",
|
||||||
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
|
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
|
||||||
DexBuilder dex_file;
|
DexBuilder dex_file;
|
||||||
|
|
||||||
|
|
@ -73,7 +73,7 @@ namespace lspd {
|
||||||
auto return_type =
|
auto return_type =
|
||||||
return_class == 'L' ? TypeDescriptor::Object : TypeDescriptor::FromDescriptor(
|
return_class == 'L' ? TypeDescriptor::Object : TypeDescriptor::FromDescriptor(
|
||||||
(char) return_class);
|
(char) return_class);
|
||||||
auto params = env->GetCharArrayElements(classes, nullptr);
|
auto *params = env->GetCharArrayElements(classes, nullptr);
|
||||||
for (int i = 0; i < parameter_length; ++i) {
|
for (int i = 0; i < parameter_length; ++i) {
|
||||||
parameter_types.push_back(
|
parameter_types.push_back(
|
||||||
params[i] == 'L' ? TypeDescriptor::Object : TypeDescriptor::FromDescriptor(
|
params[i] == 'L' ? TypeDescriptor::Object : TypeDescriptor::FromDescriptor(
|
||||||
|
|
@ -90,52 +90,44 @@ namespace lspd {
|
||||||
.access_flags(dex::kAccStatic)
|
.access_flags(dex::kAccStatic)
|
||||||
.Encode();
|
.Encode();
|
||||||
|
|
||||||
auto setupBuilder{cbuilder.CreateMethod(
|
auto hook_builder{cbuilder.CreateMethod(
|
||||||
"setup", Prototype{TypeDescriptor::Void, hooker_type})};
|
|
||||||
setupBuilder
|
|
||||||
.AddInstruction(Instruction::SetStaticObjectField(
|
|
||||||
hooker_field->decl->orig_index, Value::Parameter(0)))
|
|
||||||
.BuildReturn()
|
|
||||||
.Encode();
|
|
||||||
|
|
||||||
auto hookBuilder{cbuilder.CreateMethod(
|
|
||||||
JUTFString(env, method_name), Prototype{return_type, parameter_types})};
|
JUTFString(env, method_name), Prototype{return_type, parameter_types})};
|
||||||
// allocate tmp frist because of wide
|
// allocate tmp frist because of wide
|
||||||
auto tmp{hookBuilder.AllocRegister()};
|
auto tmp{hook_builder.AllocRegister()};
|
||||||
hookBuilder.BuildConst(tmp, parameter_types.size());
|
hook_builder.BuildConst(tmp, parameter_types.size());
|
||||||
auto hook_params_array{hookBuilder.AllocRegister()};
|
auto hook_params_array{hook_builder.AllocRegister()};
|
||||||
hookBuilder.BuildNewArray(hook_params_array, TypeDescriptor::Object, tmp);
|
hook_builder.BuildNewArray(hook_params_array, TypeDescriptor::Object, tmp);
|
||||||
for (size_t i = 0u, j = 0u; i < parameter_types.size(); ++i, ++j) {
|
for (size_t i = 0U, j = 0U; i < parameter_types.size(); ++i, ++j) {
|
||||||
hookBuilder.BuildBoxIfPrimitive(Value::Parameter(j), parameter_types[i],
|
hook_builder.BuildBoxIfPrimitive(Value::Parameter(j), parameter_types[i],
|
||||||
Value::Parameter(j));
|
Value::Parameter(j));
|
||||||
hookBuilder.BuildConst(tmp, i);
|
hook_builder.BuildConst(tmp, i);
|
||||||
hookBuilder.BuildAput(Instruction::Op::kAputObject, hook_params_array,
|
hook_builder.BuildAput(Instruction::Op::kAputObject, hook_params_array,
|
||||||
Value::Parameter(j), tmp);
|
Value::Parameter(j), tmp);
|
||||||
if (parameter_types[i].is_wide()) ++j;
|
if (parameter_types[i].is_wide()) ++j;
|
||||||
}
|
}
|
||||||
auto handle_hook_method{dex_file.GetOrDeclareMethod(
|
auto handle_hook_method{dex_file.GetOrDeclareMethod(
|
||||||
hooker_type, "handleHookedMethod",
|
hooker_type, "handleHookedMethod",
|
||||||
Prototype{TypeDescriptor::Object, TypeDescriptor::Object.ToArray()})};
|
Prototype{TypeDescriptor::Object, TypeDescriptor::Object.ToArray()})};
|
||||||
hookBuilder.AddInstruction(
|
hook_builder.AddInstruction(
|
||||||
Instruction::GetStaticObjectField(hooker_field->decl->orig_index, tmp));
|
Instruction::GetStaticObjectField(hooker_field->decl->orig_index, tmp));
|
||||||
hookBuilder.AddInstruction(Instruction::InvokeVirtualObject(
|
hook_builder.AddInstruction(Instruction::InvokeVirtualObject(
|
||||||
handle_hook_method.id, tmp, tmp, hook_params_array));
|
handle_hook_method.id, tmp, tmp, hook_params_array));
|
||||||
if (return_type == TypeDescriptor::Void) {
|
if (return_type == TypeDescriptor::Void) {
|
||||||
hookBuilder.BuildReturn();
|
hook_builder.BuildReturn();
|
||||||
} else if (return_type.is_primitive()) {
|
} else if (return_type.is_primitive()) {
|
||||||
auto box_type{return_type.ToBoxType()};
|
auto box_type{return_type.ToBoxType()};
|
||||||
const ir::Type *type_def = dex_file.GetOrAddType(box_type);
|
const ir::Type *type_def = dex_file.GetOrAddType(box_type);
|
||||||
hookBuilder.AddInstruction(
|
hook_builder.AddInstruction(
|
||||||
Instruction::Cast(tmp, Value::Type(type_def->orig_index)));
|
Instruction::Cast(tmp, Value::Type(type_def->orig_index)));
|
||||||
hookBuilder.BuildUnBoxIfPrimitive(tmp, box_type, tmp);
|
hook_builder.BuildUnBoxIfPrimitive(tmp, box_type, tmp);
|
||||||
hookBuilder.BuildReturn(tmp, false, return_type.is_wide());
|
hook_builder.BuildReturn(tmp, false, return_type.is_wide());
|
||||||
} else {
|
} else {
|
||||||
const ir::Type *type_def = dex_file.GetOrAddType(return_type);
|
const ir::Type *type_def = dex_file.GetOrAddType(return_type);
|
||||||
hookBuilder.AddInstruction(
|
hook_builder.AddInstruction(
|
||||||
Instruction::Cast(tmp, Value::Type(type_def->orig_index)));
|
Instruction::Cast(tmp, Value::Type(type_def->orig_index)));
|
||||||
hookBuilder.BuildReturn(tmp, true);
|
hook_builder.BuildReturn(tmp, true);
|
||||||
}
|
}
|
||||||
[[maybe_unused]] auto *hook_method = hookBuilder.Encode();
|
[[maybe_unused]] auto *hook_method = hook_builder.Encode();
|
||||||
|
|
||||||
auto backup_builder{
|
auto backup_builder{
|
||||||
cbuilder.CreateMethod("backup", Prototype{return_type, parameter_types})};
|
cbuilder.CreateMethod("backup", Prototype{return_type, parameter_types})};
|
||||||
|
|
@ -156,18 +148,18 @@ namespace lspd {
|
||||||
|
|
||||||
slicer::MemView image{dex_file.CreateImage()};
|
slicer::MemView image{dex_file.CreateImage()};
|
||||||
|
|
||||||
auto dex_buffer = env->NewDirectByteBuffer(const_cast<void *>(image.ptr()), image.size());
|
auto *dex_buffer = env->NewDirectByteBuffer(const_cast<void *>(image.ptr()), image.size());
|
||||||
auto my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
|
auto my_cl = JNI_NewObject(env, kInMemoryClassloader, kInitMid,
|
||||||
dex_buffer, app_class_loader);
|
dex_buffer, app_class_loader);
|
||||||
env->DeleteLocalRef(dex_buffer);
|
env->DeleteLocalRef(dex_buffer);
|
||||||
|
|
||||||
static jmethodID mid = JNI_GetMethodID(env, in_memory_classloader, "loadClass",
|
static jmethodID kMid = JNI_GetMethodID(env, kInMemoryClassloader, "loadClass",
|
||||||
"(Ljava/lang/String;)Ljava/lang/Class;");
|
"(Ljava/lang/String;)Ljava/lang/Class;");
|
||||||
if (!mid) {
|
if (!kMid) {
|
||||||
mid = JNI_GetMethodID(env, in_memory_classloader, "findClass",
|
kMid = JNI_GetMethodID(env, kInMemoryClassloader, "findClass",
|
||||||
"(Ljava/lang/String;)Ljava/lang/Class;");
|
"(Ljava/lang/String;)Ljava/lang/Class;");
|
||||||
}
|
}
|
||||||
auto target = JNI_CallObjectMethod(env, my_cl, mid, env->NewStringUTF("LspHooker_"));
|
auto target = JNI_CallObjectMethod(env, my_cl, kMid, env->NewStringUTF("LspHooker_"));
|
||||||
// LOGD("Created %zd", image.size());
|
// LOGD("Created %zd", image.size());
|
||||||
if (target) {
|
if (target) {
|
||||||
return (jclass) target.release();
|
return (jclass) target.release();
|
||||||
|
|
@ -191,4 +183,4 @@ namespace lspd {
|
||||||
REGISTER_LSP_NATIVE_METHODS(Yahfa);
|
REGISTER_LSP_NATIVE_METHODS(Yahfa);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace lspd
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ import de.robv.android.xposed.XposedBridge;
|
||||||
public class HookerDexMaker {
|
public class HookerDexMaker {
|
||||||
|
|
||||||
public static final String METHOD_NAME_BACKUP = "backup";
|
public static final String METHOD_NAME_BACKUP = "backup";
|
||||||
public static final String METHOD_NAME_SETUP = "setup";
|
public static final String FIELD_NAME_HOOKER = "hooker";
|
||||||
private static final HashMap<Class<?>, Character> descriptors = new HashMap<>() {{
|
private static final HashMap<Class<?>, Character> descriptors = new HashMap<>() {{
|
||||||
put(int.class, 'I');
|
put(int.class, 'I');
|
||||||
put(boolean.class, 'Z');
|
put(boolean.class, 'Z');
|
||||||
|
|
@ -109,7 +109,9 @@ public class HookerDexMaker {
|
||||||
// Execute our newly-generated code in-process.
|
// Execute our newly-generated code in-process.
|
||||||
Method backupMethod = hookClass.getMethod(METHOD_NAME_BACKUP, mActualParameterTypes);
|
Method backupMethod = hookClass.getMethod(METHOD_NAME_BACKUP, mActualParameterTypes);
|
||||||
mHooker = new LspHooker(mHookInfo, mMember, backupMethod);
|
mHooker = new LspHooker(mHookInfo, mMember, backupMethod);
|
||||||
hookClass.getMethod(METHOD_NAME_SETUP, LspHooker.class).invoke(null, mHooker);
|
var hooker = hookClass.getDeclaredField(FIELD_NAME_HOOKER);
|
||||||
|
hooker.setAccessible(true);
|
||||||
|
hooker.set(null, mHooker);
|
||||||
Method hookMethod = hookClass.getMethod(methodName, mActualParameterTypes);
|
Method hookMethod = hookClass.getMethod(methodName, mActualParameterTypes);
|
||||||
HookMain.backupAndHook(mMember, hookMethod, backupMethod);
|
HookMain.backupAndHook(mMember, hookMethod, backupMethod);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue