forked from rovo89/Xposed
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlibxposed_art.cpp
198 lines (167 loc) · 6.66 KB
/
libxposed_art.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/**
* This file includes functions specific to the ART runtime.
*/
#include "xposed_shared.h"
#include "libxposed_common.h"
#include "thread.h"
#include "common_throws.h"
#if PLATFORM_SDK_VERSION >= 23
#include "art_method-inl.h"
#else
#include "mirror/art_method-inl.h"
#endif
#include "mirror/object-inl.h"
#include "mirror/throwable.h"
#include "native/scoped_fast_native_object_access.h"
#include "reflection.h"
#include "scoped_thread_state_change.h"
#include "well_known_classes.h"
using namespace art;
#if PLATFORM_SDK_VERSION < 23
using art::mirror::ArtMethod;
#endif
namespace xposed {
////////////////////////////////////////////////////////////
// Forward declarations
////////////////////////////////////////////////////////////
void prepareSubclassReplacement(JNIEnv* env, jclass clazz);
////////////////////////////////////////////////////////////
// Library initialization
////////////////////////////////////////////////////////////
/** Called by Xposed's app_process replacement. */
bool xposedInitLib(XposedShared* shared) {
xposed = shared;
xposed->onVmCreated = &onVmCreated;
return true;
}
/** Called very early during VM startup. */
void onVmCreated(JNIEnv* env) {
// TODO: Handle CLASS_MIUI_RESOURCES?
jclass classXTypedArray = env->FindClass(CLASS_XTYPED_ARRAY);
if (classXTypedArray == nullptr) {
XLOG(ERROR) << "Error while loading XTypedArray class '" CLASS_XTYPED_ARRAY "'";
logExceptionStackTrace();
env->ExceptionClear();
return;
}
prepareSubclassReplacement(env, classXTypedArray);
classXposedBridge = env->FindClass(CLASS_XPOSED_BRIDGE);
if (classXposedBridge == nullptr) {
XLOG(ERROR) << "Error while loading Xposed class '" CLASS_XPOSED_BRIDGE "'";
logExceptionStackTrace();
env->ExceptionClear();
return;
}
classXposedBridge = reinterpret_cast<jclass>(env->NewGlobalRef(classXposedBridge));
ArtMethod::xposed_callback_class = classXposedBridge;
XLOG(INFO) << "Found Xposed class " CLASS_XPOSED_BRIDGE ", now initializing";
if (register_natives_XposedBridge(env, classXposedBridge) != JNI_OK) {
#if PLATFORM_SDK_VERSION >= 23
auto* exception = Thread::Current()->GetException();
#else
auto* exception = Thread::Current()->GetException(nullptr);
#endif
XLOG(ERROR) << "Could not register natives for '" CLASS_XPOSED_BRIDGE "':\n "
<< exception->GetDetailMessage()->ToModifiedUtf8();
env->ExceptionClear();
return;
}
xposedLoadedSuccessfully = true;
}
////////////////////////////////////////////////////////////
// Utility methods
////////////////////////////////////////////////////////////
void logExceptionStackTrace() {
Thread* self = Thread::Current();
#if PLATFORM_SDK_VERSION >= 23
XLOG(ERROR) << self->GetException()->Dump();
#else
XLOG(ERROR) << self->GetException(nullptr)->Dump();
#endif
}
/** Lay the foundations for XposedBridge.setObjectClassNative() */
void prepareSubclassReplacement(JNIEnv* env, jclass clazz) {
// clazz is supposed to replace its superclass, so make sure enough memory is allocated
ScopedObjectAccess soa(env);
mirror::Class* sub = soa.Decode<mirror::Class*>(clazz);
mirror::Class* super = sub->GetSuperClass();
super->SetObjectSize(sub->GetObjectSize());
}
////////////////////////////////////////////////////////////
// JNI methods
////////////////////////////////////////////////////////////
jboolean callback_XposedBridge_initNative(JNIEnv* env) {
ArtMethod::xposed_callback_method = env->GetStaticMethodID(classXposedBridge, "handleHookedMethod",
"(Ljava/lang/reflect/Member;ILjava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
if (ArtMethod::xposed_callback_method == nullptr) {
XLOG(ERROR) << "ERROR: Could not find method " CLASS_XPOSED_BRIDGE ".handleHookedMethod(Member, int, Object, Object, Object[])";
logExceptionStackTrace();
env->ExceptionClear();
return false;
}
return true;
}
void XposedBridge_hookMethodNative(JNIEnv* env, jclass, jobject javaReflectedMethod,
jobject, jint, jobject javaAdditionalInfo) {
// Detect usage errors.
if (javaReflectedMethod == nullptr) {
#if PLATFORM_SDK_VERSION >= 23
ThrowIllegalArgumentException("method must not be null");
#else
ThrowIllegalArgumentException(nullptr, "method must not be null");
#endif
return;
}
// Get the ArtMethod of the method to be hooked.
ScopedObjectAccess soa(env);
ArtMethod* artMethod = ArtMethod::FromReflectedMethod(soa, javaReflectedMethod);
// Hook the method
artMethod->EnableXposedHook(soa, javaAdditionalInfo);
}
jobject XposedBridge_invokeOriginalMethodNative(JNIEnv* env, jclass, jobject javaMethod,
jint isResolved, jobjectArray, jclass, jobject javaReceiver, jobjectArray javaArgs) {
ScopedFastNativeObjectAccess soa(env);
if (UNLIKELY(!isResolved)) {
ArtMethod* artMethod = ArtMethod::FromReflectedMethod(soa, javaMethod);
if (LIKELY(artMethod->IsXposedHookedMethod())) {
javaMethod = artMethod->GetXposedHookInfo()->reflectedMethod;
}
}
#if PLATFORM_SDK_VERSION >= 23
return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs);
#else
return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs, true);
#endif
}
void XposedBridge_setObjectClassNative(JNIEnv* env, jclass, jobject javaObj, jclass javaClazz) {
ScopedObjectAccess soa(env);
mirror::Class* clazz = soa.Decode<mirror::Class*>(javaClazz);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> c(hs.NewHandle(clazz));
#if PLATFORM_SDK_VERSION >= 23
if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(soa.Self(), c, true, true)) {
#else
if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
#endif
XLOG(ERROR) << "Could not initialize class " << PrettyClass(clazz);
return;
}
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
obj->SetClass(clazz);
}
void XposedBridge_dumpObjectNative(JNIEnv*, jclass, jobject) {
// TODO Can be useful for debugging
UNIMPLEMENTED(ERROR|LOG_XPOSED);
}
jobject XposedBridge_cloneToSubclassNative(JNIEnv* env, jclass, jobject javaObject, jclass javaClazz) {
ScopedObjectAccess soa(env);
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObject);
mirror::Class* clazz = soa.Decode<mirror::Class*>(javaClazz);
mirror::Object* dest = obj->Clone(soa.Self(), clazz->GetObjectSize());
dest->SetClass(clazz);
return soa.AddLocalReference<jobject>(dest);
}
jint XposedBridge_getRuntime(JNIEnv* env, jclass clazz) {
return 2; // RUNTIME_ART
}
} // namespace xposed