Android Hook Java
由于项目需要,实现了一个脱离XPosed框架的Android Hook Java方法。其原理是注入某系统进程,使该进程加载某动态链接库,执行该库里的某函数,通过该函数执行某jar包里的java函数,然后执行hook该进程中的java函数操作。其中Hook Java部分提取了XPosed框架中的hook原理。
1、进程注入
target_pid = find_pid_of("system_server");
if(inject_remote_process(target_pid, "/system/lib/libtest.so", "java_hook_test", "I'm parameter!", strlen("I'm parameter!")) == 0)
LOGV("inject success");
2、在C层执行Java方法
JavaVM* jvm = AndroidRuntime::getJavaVM();
JNIEnv* env;
jvm->AttachCurrentThread(&env, NULL);
jstring apk_path = env->NewStringUTF(INJECT_JAR_PATH);
jstring dex_out_path = env->NewStringUTF("/data/dalvik-cache");
jclass dexloader_claxx = env->FindClass("dalvik/system/DexClassLoader");
snprintf(sig_buffer, 512, "(%s%s%s%s)V", JSTRING, JSTRING, JSTRING, JCLASS_LOADER);
jmethodID dexloader_init_method = env->GetMethodID(dexloader_claxx, "<init>", sig_buffer);
snprintf(sig_buffer, 512, "(%s)%s", JSTRING, JCLASS);
jmethodID loadClass_method = env->GetMethodID(dexloader_claxx, "loadClass", sig_buffer);
jclass class_loader_claxx = env->FindClass("java/lang/ClassLoader");
snprintf(sig_buffer, 512, "()%s", JCLASS_LOADER);
jmethodID getSystemClassLoader_method = env->GetStaticMethodID(class_loader_claxx, "getSystemClassLoader", sig_buffer);
jobject class_loader = env->CallStaticObjectMethod(class_loader_claxx, getSystemClassLoader_method);
check_value(class_loader);
jobject dex_loader_obj = env->NewObject(dexloader_claxx, dexloader_init_method, apk_path, dex_out_path, NULL, class_loader);
jstring class_name = env->NewStringUTF(CLASS_JAVA);
jclass class_jia = static_cast<jclass>(env->CallObjectMethod(dex_loader_obj, loadClass_method, class_name));
check_value(class_jia);
jmethodID invoke_method = env->GetStaticMethodID(class_jia, "hook", "(I)V");
check_value(invoke_method);
env->CallStaticObjectMethod(class_jia, invoke_method, 0);
LOGI("end hook java");
jvm->DetachCurrentThread();
3、添加你想执行hook操作的java函数,interceptKeyBeforeQueueing方法主要做一下对特殊按键的处理。
Bridge.hookAllMethods(Helpers.findClass("com.android.internal.policy.impl.PhoneWindowManager"), "interceptKeyBeforeQueueing");
4、类似于XPosed框架,添加你想替换的java函数cb_interceptKeyBeforeQueueing,可根据需求添加执行真正函数前与执行完后的操作。
static XC_MethodHook cb_interceptKeyBeforeQueueing = new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param)
throws Throwable {
Log.v("test", "[KeyPress]" + param.args[0] + " | " + param.args[1] + " | " + param.args[2]);
}
};
handleHookedMethod是真正替换的函数。
private static Object handleHookedMethod(Member method, int originalMethodId, Object additionalInfoObj,
Object thisObject, Object[] args) throws Throwable {
//Log.v("test", "enter handleHookedMethod");
AdditionalHookInfo additionalInfo = (AdditionalHookInfo) additionalInfoObj;
MethodHookParam param = new MethodHookParam();
param.method = method;
param.thisObject = thisObject;
param.args = args;
// call "before method" callbacks
try {
if (method.getName().equals("interceptKeyBeforeQueueing"))
Hook.cb_interceptKeyBeforeQueueing.beforeHookedMethod(param);
} catch (Throwable t) {
Log.v("test", t.getMessage());
// reset result (ignoring what the unexpectedly exiting callback did)
param.setResult(null);
param.returnEarly = false;
}
// call original method if not requested otherwise
if (!param.returnEarly) {
try {
param.setResult(invokeOriginalMethodNative(method, originalMethodId,
additionalInfo.parameterTypes, additionalInfo.returnType, param.thisObject, param.args));
} catch (InvocationTargetException e) {
param.setThrowable(e.getCause());
}
}
// call "after method" callbacks
Object lastResult = param.getResult();
Throwable lastThrowable = param.getThrowable();
try {
//<span style="white-space:pre"> </span>if (method.getName().equals("init"))
//<span style="white-space:pre"> </span>Hook.cb_init.afterHookedMethod(param);
} catch (Throwable t) {
Log.v("test", t.getMessage());
// reset to last result (ignoring what the unexpectedly exiting callback did)
if (lastThrowable == null)
param.setResult(lastResult);
else
param.setThrowable(lastThrowable);
}
// return
if (param.hasThrowable())
throw param.getThrowable();
else
return param.getResult();}
整个工程已上传至github: https://github.com/phoebe1990/javaHook
运行结果如下:
hook类PhoneWindowManager中interceptKeyBeforeQueueing函数成功,使每次手机按键时都打印一条log信息。