1 Star 0 Fork 10

战鹏/xposed

forked from Gitee 极速下载/xposed 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
libxposed_dalvik.cpp 12.32 KB
一键复制 编辑 原始数据 按行查看 历史
/**
* This file includes functions specific to the Dalvik runtime.
*/
#define LOG_TAG "Xposed"
#include "libxposed_dalvik.h"
#include "xposed_offsets.h"
#include <dlfcn.h>
namespace xposed {
////////////////////////////////////////////////////////////
// Forward declarations
////////////////////////////////////////////////////////////
bool initMemberOffsets(JNIEnv* env);
void hookedMethodCallback(const u4* args, JValue* pResult, const Method* method, ::Thread* self);
void XposedBridge_invokeOriginalMethodNative(const u4* args, JValue* pResult, const Method* method, ::Thread* self);
////////////////////////////////////////////////////////////
// Variables
////////////////////////////////////////////////////////////
static ClassObject* objectArrayClass = NULL;
static size_t arrayContentsOffset = 0;
static void* PTR_gDvmJit = NULL;
////////////////////////////////////////////////////////////
// Library initialization
////////////////////////////////////////////////////////////
/** Called by Xposed's app_process replacement. */
bool xposedInitLib(xposed::XposedShared* shared) {
xposed = shared;
xposed->onVmCreated = &onVmCreatedCommon;
return true;
}
/** Called very early during VM startup. */
bool onVmCreated(JNIEnv* env) {
if (!initMemberOffsets(env))
return false;
jclass classMiuiResources = env->FindClass(CLASS_MIUI_RESOURCES);
if (classMiuiResources != NULL) {
ClassObject* clazz = (ClassObject*)dvmDecodeIndirectRef(dvmThreadSelf(), classMiuiResources);
if (dvmIsFinalClass(clazz)) {
ALOGD("Removing final flag for class '%s'", CLASS_MIUI_RESOURCES);
clazz->accessFlags &= ~ACC_FINAL;
}
}
env->ExceptionClear();
Method* xposedInvokeOriginalMethodNative = (Method*) env->GetStaticMethodID(classXposedBridge, "invokeOriginalMethodNative",
"(Ljava/lang/reflect/Member;I[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
if (xposedInvokeOriginalMethodNative == NULL) {
ALOGE("ERROR: could not find method %s.invokeOriginalMethodNative(Member, int, Class[], Class, Object, Object[])", CLASS_XPOSED_BRIDGE);
dvmLogExceptionStackTrace();
env->ExceptionClear();
return false;
}
dvmSetNativeFunc(xposedInvokeOriginalMethodNative, XposedBridge_invokeOriginalMethodNative, NULL);
objectArrayClass = dvmFindArrayClass("[Ljava/lang/Object;", NULL);
if (objectArrayClass == NULL) {
ALOGE("Error while loading Object[] class");
dvmLogExceptionStackTrace();
env->ExceptionClear();
return false;
}
return true;
}
bool initMemberOffsets(JNIEnv* env) {
PTR_gDvmJit = dlsym(RTLD_DEFAULT, "gDvmJit");
if (PTR_gDvmJit == NULL) {
offsetMode = MEMBER_OFFSET_MODE_NO_JIT;
} else {
offsetMode = MEMBER_OFFSET_MODE_WITH_JIT;
}
ALOGD("Using structure member offsets for mode %s", xposedOffsetModesDesc[offsetMode]);
MEMBER_OFFSET_COPY(DvmJitGlobals, codeCacheFull);
int overrideCodeCacheFull = readIntConfig(XPOSED_OVERRIDE_JIT_RESET_OFFSET, -1);
if (overrideCodeCacheFull > 0 && overrideCodeCacheFull < 0x400) {
ALOGI("Offset for DvmJitGlobals.codeCacheFull is overridden, new value is 0x%x", overrideCodeCacheFull);
MEMBER_OFFSET_VAR(DvmJitGlobals, codeCacheFull) = overrideCodeCacheFull;
}
// detect offset of ArrayObject->contents
jintArray dummyArray = env->NewIntArray(1);
if (dummyArray == NULL) {
ALOGE("Could allocate int array for testing");
dvmLogExceptionStackTrace();
env->ExceptionClear();
return false;
}
jint* dummyArrayElements = env->GetIntArrayElements(dummyArray, NULL);
arrayContentsOffset = (size_t)dummyArrayElements - (size_t)dvmDecodeIndirectRef(dvmThreadSelf(), dummyArray);
env->ReleaseIntArrayElements(dummyArray,dummyArrayElements, 0);
env->DeleteLocalRef(dummyArray);
if (arrayContentsOffset < 12 || arrayContentsOffset > 128) {
ALOGE("Detected strange offset %d of ArrayObject->contents", arrayContentsOffset);
return false;
}
return true;
}
////////////////////////////////////////////////////////////
// Utility methods
////////////////////////////////////////////////////////////
/** Portable clone of dvmSetObjectArrayElement() */
inline void setObjectArrayElement(const ArrayObject* obj, int index, Object* val) {
uintptr_t arrayContents = (uintptr_t)obj + arrayContentsOffset;
((Object **)arrayContents)[index] = val;
dvmWriteBarrierArray(obj, index, index + 1);
}
/** Wrapper used by the common part of the library. */
void logExceptionStackTrace() {
dvmLogExceptionStackTrace();
}
/** Check whether a method is already hooked. */
inline bool isMethodHooked(const Method* method) {
return (method->nativeFunc == &hookedMethodCallback);
}
////////////////////////////////////////////////////////////
// JNI methods
////////////////////////////////////////////////////////////
/** This is called when a hooked method is executed. */
void hookedMethodCallback(const u4* args, JValue* pResult, const Method* method, ::Thread* self) {
if (!isMethodHooked(method)) {
dvmThrowNoSuchMethodError("Could not find Xposed original method - how did you even get here?");
return;
}
XposedHookInfo* hookInfo = (XposedHookInfo*) method->insns;
Method* original = (Method*) hookInfo;
Object* originalReflected = hookInfo->reflectedMethod;
Object* additionalInfo = hookInfo->additionalInfo;
// convert/box arguments
const char* desc = &method->shorty[1]; // [0] is the return type.
Object* thisObject = NULL;
size_t srcIndex = 0;
size_t dstIndex = 0;
// for non-static methods determine the "this" pointer
if (!dvmIsStaticMethod(original)) {
thisObject = (Object*) args[0];
srcIndex++;
}
ArrayObject* argsArray = dvmAllocArrayByClass(objectArrayClass, strlen(method->shorty) - 1, ALLOC_DEFAULT);
if (argsArray == NULL) {
return;
}
while (*desc != '\0') {
char descChar = *(desc++);
JValue value;
Object* obj;
switch (descChar) {
case 'Z':
case 'C':
case 'F':
case 'B':
case 'S':
case 'I':
value.i = args[srcIndex++];
obj = (Object*) dvmBoxPrimitive(value, dvmFindPrimitiveClass(descChar));
dvmReleaseTrackedAlloc(obj, self);
break;
case 'D':
case 'J':
value.j = dvmGetArgLong(args, srcIndex);
srcIndex += 2;
obj = (Object*) dvmBoxPrimitive(value, dvmFindPrimitiveClass(descChar));
dvmReleaseTrackedAlloc(obj, self);
break;
case '[':
case 'L':
obj = (Object*) args[srcIndex++];
break;
default:
ALOGE("Unknown method signature description character: %c", descChar);
obj = NULL;
srcIndex++;
}
setObjectArrayElement(argsArray, dstIndex++, obj);
}
// call the Java handler function
JValue result;
dvmCallMethod(self, (Method*) methodXposedBridgeHandleHookedMethod, NULL, &result,
originalReflected, (int) original, additionalInfo, thisObject, argsArray);
dvmReleaseTrackedAlloc(argsArray, self);
// exceptions are thrown to the caller
if (dvmCheckException(self)) {
return;
}
// return result with proper type
ClassObject* returnType = dvmGetBoxedReturnType(method);
if (returnType->primitiveType == PRIM_VOID) {
// ignored
} else if (result.l == NULL) {
if (dvmIsPrimitiveClass(returnType)) {
dvmThrowNullPointerException("null result when primitive expected");
}
pResult->l = NULL;
} else {
if (!dvmUnboxPrimitive(result.l, returnType, pResult)) {
dvmThrowClassCastException(result.l->clazz, returnType);
}
}
}
void XposedBridge_hookMethodNative(JNIEnv* env, jclass clazz, jobject reflectedMethodIndirect,
jobject declaredClassIndirect, jint slot, jobject additionalInfoIndirect) {
// Usage errors?
if (declaredClassIndirect == NULL || reflectedMethodIndirect == NULL) {
dvmThrowIllegalArgumentException("method and declaredClass must not be null");
return;
}
// Find the internal representation of the method
ClassObject* declaredClass = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), declaredClassIndirect);
Method* method = dvmSlotToMethod(declaredClass, slot);
if (method == NULL) {
dvmThrowNoSuchMethodError("Could not get internal representation for method");
return;
}
if (isMethodHooked(method)) {
// already hooked
return;
}
// Save a copy of the original method and other hook info
XposedHookInfo* hookInfo = (XposedHookInfo*) calloc(1, sizeof(XposedHookInfo));
memcpy(hookInfo, method, sizeof(hookInfo->originalMethodStruct));
hookInfo->reflectedMethod = dvmDecodeIndirectRef(dvmThreadSelf(), env->NewGlobalRef(reflectedMethodIndirect));
hookInfo->additionalInfo = dvmDecodeIndirectRef(dvmThreadSelf(), env->NewGlobalRef(additionalInfoIndirect));
// Replace method with our own code
SET_METHOD_FLAG(method, ACC_NATIVE);
method->nativeFunc = &hookedMethodCallback;
method->insns = (const u2*) hookInfo;
method->registersSize = method->insSize;
method->outsSize = 0;
if (PTR_gDvmJit != NULL) {
// reset JIT cache
char currentValue = *((char*)PTR_gDvmJit + MEMBER_OFFSET_VAR(DvmJitGlobals,codeCacheFull));
if (currentValue == 0 || currentValue == 1) {
MEMBER_VAL(PTR_gDvmJit, DvmJitGlobals, codeCacheFull) = true;
} else {
ALOGE("Unexpected current value for codeCacheFull: %d", currentValue);
}
}
}
/**
* Simplified copy of Method.invokeNative(), but calls the original (non-hooked) method
* and has no access checks. Used to call the real implementation of hooked methods.
*/
void XposedBridge_invokeOriginalMethodNative(const u4* args, JValue* pResult,
const Method* method, ::Thread* self) {
Method* meth = (Method*) args[1];
if (meth == NULL) {
meth = dvmGetMethodFromReflectObj((Object*) args[0]);
if (isMethodHooked(meth)) {
meth = (Method*) meth->insns;
}
}
ArrayObject* params = (ArrayObject*) args[2];
ClassObject* returnType = (ClassObject*) args[3];
Object* thisObject = (Object*) args[4]; // null for static methods
ArrayObject* argList = (ArrayObject*) args[5];
// invoke the method
pResult->l = dvmInvokeMethod(thisObject, meth, argList, params, returnType, true);
return;
}
void XposedBridge_setObjectClassNative(JNIEnv* env, jclass clazz, jobject objIndirect, jclass clzIndirect) {
Object* obj = (Object*) dvmDecodeIndirectRef(dvmThreadSelf(), objIndirect);
ClassObject* clz = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), clzIndirect);
if (clz->status < CLASS_INITIALIZED && !dvmInitClass(clz)) {
ALOGE("Could not initialize class %s", clz->descriptor);
return;
}
obj->clazz = clz;
}
void XposedBridge_dumpObjectNative(JNIEnv* env, jclass clazz, jobject objIndirect) {
Object* obj = (Object*) dvmDecodeIndirectRef(dvmThreadSelf(), objIndirect);
dvmDumpObject(obj);
}
jobject XposedBridge_cloneToSubclassNative(JNIEnv* env, jclass clazz, jobject objIndirect, jclass clzIndirect) {
Object* obj = (Object*) dvmDecodeIndirectRef(dvmThreadSelf(), objIndirect);
ClassObject* clz = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), clzIndirect);
jobject copyIndirect = env->AllocObject(clzIndirect);
if (copyIndirect == NULL)
return NULL;
Object* copy = (Object*) dvmDecodeIndirectRef(dvmThreadSelf(), copyIndirect);
size_t size = obj->clazz->objectSize;
size_t offset = sizeof(Object);
memcpy((char*)copy + offset, (char*)obj + offset, size - offset);
if (IS_CLASS_FLAG_SET(clz, CLASS_ISFINALIZABLE))
dvmSetFinalizable(copy);
return copyIndirect;
}
void XposedBridge_removeFinalFlagNative(JNIEnv* env, jclass, jclass javaClazz) {
ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(dvmThreadSelf(), javaClazz);
if (dvmIsFinalClass(clazz)) {
clazz->accessFlags &= ~ACC_FINAL;
}
}
jint XposedBridge_getRuntime(JNIEnv* env, jclass clazz) {
return 1; // RUNTIME_DALVIK
}
} // namespace android
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C/C++
1
https://gitee.com/war_peng/xposed.git
git@gitee.com:war_peng/xposed.git
war_peng
xposed
xposed
master

搜索帮助

0d507c66 1850385 C8b1a773 1850385