[core] RAII JNI interface (#444)

Co-authored-by: Wang Han <wanghan1995315@gmail.com>
This commit is contained in:
LoveSy 2021-04-03 19:35:39 +08:00 committed by GitHub
parent 6d056a40fd
commit 80bc9c0b35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 216 additions and 174 deletions

View File

@ -122,6 +122,7 @@ namespace yahfa {
SDKVersion = sdkVersion;
jclass classExecutable = env->FindClass("java/lang/reflect/Executable");
fieldArtMethod = env->GetFieldID(classExecutable, "artMethod", "J");
env->DeleteLocalRef(classExecutable);
LOGI("init to SDK %d", sdkVersion);
switch (sdkVersion) {
case __ANDROID_API_S__:

View File

@ -25,6 +25,7 @@
#include <sys/mman.h>
#include "config.h"
#include "native_hook.h"
#include <concepts>
#define _uintval(p) reinterpret_cast<uintptr_t>(p)
#define _ptr(p) reinterpret_cast<void *>(p)
@ -140,9 +141,8 @@ namespace lspd {
};
template<typename Class, typename Return, typename T, typename... Args>
requires (std::is_same_v<T, void> || std::is_same_v<Class, T>)
inline static auto memfun_cast(Return (*func)(T *, Args...)) {
static_assert(std::is_same_v<T, void> || std::is_same_v<Class, T>,
"Not viable cast");
union {
Return (Class::*f)(Args...);
@ -155,8 +155,7 @@ namespace lspd {
return u.f;
}
template<typename T, typename Return, typename... Args,
typename = std::enable_if_t<!std::is_same_v<T, void>>>
template<std::same_as<void> T, typename Return, typename... Args>
inline auto memfun_cast(Return (*func)(T *, Args...)) {
return memfun_cast<T>(func);
}
@ -203,7 +202,7 @@ namespace lspd {
struct Hooker<Ret(Args...), tstring<cs...>> {
inline static Ret (*backup)(Args...) = nullptr;
inline static constexpr const char sym[sizeof...(cs) + 1] = {cs..., '\0'};
inline static constexpr const char *sym = tstring<cs...>::c_str();
};
template<typename, typename>
@ -211,10 +210,16 @@ namespace lspd {
template<typename Ret, typename This, typename... Args, char... cs>
struct MemHooker<Ret(This, Args...), tstring<cs...>> {
inline static MemberFunction<Ret(Args...)> backup;
inline static constexpr const char sym[sizeof...(cs) + 1] = {cs..., '\0'};
inline static constexpr const char *sym = tstring<cs...>::c_str();
};
template<typename T>
concept HookerType = requires(T a) {
a.backup;
a.replace;
};
template<HookerType T>
inline static bool HookSymNoHandle(void *original, T &arg) {
if (original) {
if constexpr(is_instance<decltype(arg.backup), MemberFunction>::value) {
@ -231,13 +236,13 @@ namespace lspd {
}
}
template<typename T>
template<HookerType T>
inline static bool HookSym(void *handle, T &arg) {
auto original = Dlsym(handle, arg.sym);
return HookSymNoHandle(original, arg);
}
template<typename T, typename...Args>
template<HookerType T, HookerType...Args>
inline static bool HookSyms(void *handle, T &first, Args &...rest) {
if (!(HookSym(handle, first) || ... || HookSym(handle, rest))) {
LOGW("Hook Fails: %s", first.sym);

View File

@ -24,6 +24,7 @@
#include "macros.h"
#include <string>
#include "logging.h"
#include "base/object.h"
#define JNI_START JNIEnv *env, [[maybe_unused]] jclass clazz
@ -78,6 +79,9 @@ private:
};
template<typename T>
concept JObject = std::is_base_of_v<std::remove_pointer_t<jobject>, std::remove_pointer_t<T>>;
template<JObject T>
class ScopedLocalRef {
public:
ScopedLocalRef(JNIEnv *env, T localRef) : mEnv(env), mLocalRef(localRef) {
@ -86,6 +90,10 @@ public:
ScopedLocalRef(ScopedLocalRef &&s) noexcept: mEnv(s.mEnv), mLocalRef(s.release()) {
}
template<JObject U>
ScopedLocalRef(ScopedLocalRef<U> &&s) noexcept: mEnv(s.mEnv), mLocalRef((T) s.release()) {
}
explicit ScopedLocalRef(JNIEnv *env) : mEnv(env), mLocalRef(nullptr) {
}
@ -93,18 +101,18 @@ public:
reset();
}
void reset(T ptr = NULL) {
void reset(T ptr = nullptr) {
if (ptr != mLocalRef) {
if (mLocalRef != NULL) {
if (mLocalRef != nullptr) {
mEnv->DeleteLocalRef(mLocalRef);
}
mLocalRef = ptr;
}
}
T release() __attribute__((warn_unused_result)) {
[[nodiscard]] T release() {
T localRef = mLocalRef;
mLocalRef = NULL;
mLocalRef = nullptr;
return localRef;
}
@ -123,26 +131,28 @@ public:
return *this;
}
// Allows "if (scoped_ref == nullptr)"
bool operator==(std::nullptr_t) const {
return mLocalRef == nullptr;
}
// Allows "if (scoped_ref != nullptr)"
bool operator!=(std::nullptr_t) const {
return mLocalRef != nullptr;
}
operator bool() const {
return mLocalRef;
}
template<JObject U>
friend
class ScopedLocalRef;
private:
JNIEnv *mEnv;
T mLocalRef;
DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef);
};
template<typename T, typename U>
concept ScopeOrRaw = std::is_same_v<T, U> || std::is_same_v<ScopedLocalRef<T>, U>;
template<typename T>
concept ScopeOrClass = ScopeOrRaw<jclass, T>;
template<typename T>
concept ScopeOrObject = ScopeOrRaw<jobject, T>;
inline ScopedLocalRef<jstring> ClearException(JNIEnv *env) {
if (auto exception = env->ExceptionOccurred()) {
env->ExceptionClear();
@ -157,15 +167,24 @@ inline ScopedLocalRef<jstring> ClearException(JNIEnv *env) {
template<typename T>
[[maybe_unused]]
inline auto unwrap_sv(T &&x) {
inline auto unwrap_scope(T &&x) {
if constexpr (std::is_same_v<std::decay_t<T>, std::string_view>) return x.data();
else if constexpr (lspd::is_instance<std::decay_t<T>, ScopedLocalRef>::value) return x.get();
else return std::forward<T>(x);
}
template<typename Func, typename ...Args>
template<typename T>
[[maybe_unused]]
inline auto JNI_SafeInvoke(JNIEnv *env, Func f, Args &&... args) {
static_assert(std::is_member_function_pointer_v<Func>);
inline auto wrap_scope(JNIEnv *env, T &&x) {
if constexpr (std::is_convertible_v<T, jobject>) {
return ScopedLocalRef(env, std::forward<T>(x));
} else return x;
}
template<typename Func, typename ...Args>
requires(std::is_function_v<Func>)
[[maybe_unused]]
inline auto JNI_SafeInvoke(JNIEnv *env, Func JNIEnv::*f, Args &&... args) {
struct finally {
finally(JNIEnv *env) : env_(env) {}
@ -178,7 +197,10 @@ inline auto JNI_SafeInvoke(JNIEnv *env, Func f, Args &&... args) {
JNIEnv *env_;
} _(env);
return (env->*f)(unwrap_sv(std::forward<Args>(args))...);
if constexpr (!std::is_same_v<void, std::invoke_result_t<Func, decltype(unwrap_scope(
std::forward<Args>(args)))...>>)
return wrap_scope(env, (env->*f)(unwrap_scope(std::forward<Args>(args))...));
else (env->*f)(unwrap_scope(std::forward<Args>(args))...);
}
[[maybe_unused]]
@ -186,93 +208,118 @@ inline auto JNI_FindClass(JNIEnv *env, std::string_view name) {
return JNI_SafeInvoke(env, &JNIEnv::FindClass, name);
}
template<ScopeOrObject Object>
[[maybe_unused]]
inline auto JNI_GetObjectClass(JNIEnv *env, jobject obj) {
inline auto JNI_GetObjectClass(JNIEnv *env, const Object &obj) {
return JNI_SafeInvoke(env, &JNIEnv::GetObjectClass, obj);
}
template<ScopeOrClass Class>
[[maybe_unused]]
inline auto JNI_GetFieldID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) {
inline auto
JNI_GetFieldID(JNIEnv *env, const Class &clazz, std::string_view name, std::string_view sig) {
return JNI_SafeInvoke(env, &JNIEnv::GetFieldID, clazz, name, sig);
}
template<ScopeOrClass Class>
[[maybe_unused]]
inline auto JNI_GetObjectField(JNIEnv *env, jclass clazz, jfieldID fieldId) {
inline auto JNI_GetObjectField(JNIEnv *env, const Class &clazz, jfieldID fieldId) {
return JNI_SafeInvoke(env, &JNIEnv::GetObjectField, clazz, fieldId);
}
template<ScopeOrClass Class>
[[maybe_unused]]
inline auto
JNI_GetMethodID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) {
JNI_GetMethodID(JNIEnv *env, const Class &clazz, std::string_view name, std::string_view sig) {
return JNI_SafeInvoke(env, &JNIEnv::GetMethodID, clazz, name, sig);
}
template<typename ...Args>
template<ScopeOrObject Object, typename ...Args>
[[maybe_unused]]
inline auto JNI_CallObjectMethod(JNIEnv *env, jobject obj, Args &&... args) {
inline auto JNI_CallObjectMethod(JNIEnv *env, const Object &obj, Args &&... args) {
return JNI_SafeInvoke(env, &JNIEnv::CallObjectMethod, obj, std::forward<Args>(args)...);
}
template<typename ...Args>
template<ScopeOrObject Object, typename ...Args>
[[maybe_unused]]
inline auto JNI_CallVoidMethod(JNIEnv *env, jobject obj, Args &&...args) {
inline auto JNI_CallVoidMethod(JNIEnv *env, const Object &obj, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallVoidMethod, obj, std::forward<Args>(args)...);
}
template<typename ...Args>
template<ScopeOrObject Object, typename ...Args>
[[maybe_unused]]
inline auto JNI_CallBooleanMethod(JNIEnv *env, jobject obj, Args &&...args) {
inline auto JNI_CallBooleanMethod(JNIEnv *env, const Object &obj, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallBooleanMethod, obj, std::forward<Args>(args)...);
}
template<ScopeOrClass Class>
[[maybe_unused]]
inline auto
JNI_GetStaticFieldID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) {
JNI_GetStaticFieldID(JNIEnv *env, const Class &clazz, std::string_view name, std::string_view sig) {
return JNI_SafeInvoke(env, &JNIEnv::GetStaticFieldID, clazz, name, sig);
}
template<ScopeOrClass Class>
[[maybe_unused]]
inline auto JNI_GetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldId) {
inline auto JNI_GetStaticObjectField(JNIEnv *env, const Class &clazz, jfieldID fieldId) {
return JNI_SafeInvoke(env, &JNIEnv::GetStaticObjectField, clazz, fieldId);
}
template<ScopeOrClass Class>
[[maybe_unused]]
inline auto
JNI_GetStaticMethodID(JNIEnv *env, jclass clazz, std::string_view name, std::string_view sig) {
JNI_GetStaticMethodID(JNIEnv *env, const Class &clazz, std::string_view name,
std::string_view sig) {
return JNI_SafeInvoke(env, &JNIEnv::GetStaticMethodID, clazz, name, sig);
}
template<typename ...Args>
template<ScopeOrClass Class, typename ...Args>
[[maybe_unused]]
inline auto JNI_CallStaticVoidMethod(JNIEnv *env, jclass clazz, Args &&...args) {
inline auto JNI_CallStaticVoidMethod(JNIEnv *env, const Class &clazz, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallStaticVoidMethod, clazz, std::forward<Args>(args)...);
}
template<typename ...Args>
template<ScopeOrClass Class, typename ...Args>
[[maybe_unused]]
inline auto JNI_CallStaticObjectMethod(JNIEnv *env, jclass clazz, Args &&...args) {
inline auto JNI_CallStaticObjectMethod(JNIEnv *env, const Class &clazz, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallStaticObjectMethod, clazz, std::forward<Args>(args)...);
}
template<typename ...Args>
template<ScopeOrClass Class, typename ...Args>
[[maybe_unused]]
inline auto JNI_CallStaticIntMethod(JNIEnv *env, jclass clazz, Args &&...args) {
inline auto JNI_CallStaticIntMethod(JNIEnv *env, const Class &clazz, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::CallStaticIntMethod, clazz, std::forward<Args>(args)...);
}
template<ScopeOrRaw<jarray> Array>
[[maybe_unused]]
inline auto JNI_GetArrayLength(JNIEnv *env, jarray array) {
inline auto JNI_GetArrayLength(JNIEnv *env, const Array &array) {
return JNI_SafeInvoke(env, &JNIEnv::GetArrayLength, array);
}
template<typename ...Args>
template<ScopeOrClass Class, typename ...Args>
[[maybe_unused]]
inline auto JNI_NewObject(JNIEnv *env, jclass clazz, Args &&...args) {
inline auto JNI_NewObject(JNIEnv *env, const Class &clazz, Args &&...args) {
return JNI_SafeInvoke(env, &JNIEnv::NewObject, clazz, std::forward<Args>(args)...);
}
template<ScopeOrClass Class>
[[maybe_unused]]
inline auto
JNI_RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint size) {
JNI_RegisterNatives(JNIEnv *env, const Class &clazz, const JNINativeMethod *methods, jint size) {
return JNI_SafeInvoke(env, &JNIEnv::RegisterNatives, clazz, methods, size);
}
template<typename T>
[[maybe_unused]]
inline auto JNI_NewGlobalRef(JNIEnv *env, T &&x) requires(std::is_convertible_v<T, jobject>){
return (T) env->NewGlobalRef(std::forward<T>(x));
}
template<typename T>
[[maybe_unused]]
inline auto
JNI_NewGlobalRef(JNIEnv *env, const ScopedLocalRef<T> &x) requires(
std::is_convertible_v<T, jobject>){
return (T) env->NewGlobalRef(x.get());
}

View File

@ -35,13 +35,12 @@ namespace lspd {
const JNINativeMethod *methods,
jint method_count) {
ScopedLocalRef clazz(env,
Context::GetInstance()->FindClassFromCurrentLoader(env, class_name));
auto clazz = Context::GetInstance()->FindClassFromCurrentLoader(env, class_name);
if (clazz.get() == nullptr) {
LOGF("Couldn't find class: %s", class_name);
return false;
}
return JNI_RegisterNatives(env, clazz.get(), methods, method_count);
return JNI_RegisterNatives(env, clazz, methods, method_count);
}
#if defined(__cplusplus)

View File

@ -42,11 +42,11 @@ namespace lspd {
template<char... chars>
struct tstring : public std::integer_sequence<char, chars...> {
constexpr const char *c_str() const {
inline constexpr static const char *c_str() {
return str_;
}
constexpr operator std::string_view() const {
inline constexpr operator std::string_view() const {
return c_str();
}

View File

@ -52,7 +52,7 @@ namespace lspd {
vm_->GetEnv((void **) (&env), JNI_VERSION_1_4);
art::JNIEnvExt env_ext(env);
ScopedLocalRef clazz(env, env_ext.NewLocalRefer(class_ptr));
if (clazz != nullptr) {
if (clazz) {
JNI_CallStaticVoidMethod(env, class_linker_class_, post_fixup_static_mid_, clazz.get());
}
}
@ -74,48 +74,44 @@ namespace lspd {
}
void Context::LoadDex(JNIEnv *env) {
jclass classloader = JNI_FindClass(env, "java/lang/ClassLoader");
jmethodID getsyscl_mid = JNI_GetStaticMethodID(
auto classloader = JNI_FindClass(env, "java/lang/ClassLoader");
auto getsyscl_mid = JNI_GetStaticMethodID(
env, classloader, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
jobject sys_classloader = JNI_CallStaticObjectMethod(env, classloader, getsyscl_mid);
auto sys_classloader = JNI_CallStaticObjectMethod(env, classloader, getsyscl_mid);
if (UNLIKELY(!sys_classloader)) {
LOGE("getSystemClassLoader failed!!!");
return;
}
jclass in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader");
jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
jclass byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer");
auto in_memory_classloader = JNI_FindClass(env, "dalvik/system/InMemoryDexClassLoader");
auto initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
auto byte_buffer_class = JNI_FindClass(env, "java/nio/ByteBuffer");
auto dex_buffer = env->NewDirectByteBuffer(reinterpret_cast<void *>(dex.data()),
dex.size());
jobject my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
dex_buffer, sys_classloader);
env->DeleteLocalRef(classloader);
env->DeleteLocalRef(sys_classloader);
env->DeleteLocalRef(in_memory_classloader);
env->DeleteLocalRef(byte_buffer_class);
if (UNLIKELY(my_cl == nullptr)) {
if (auto my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
dex_buffer, sys_classloader)) {
inject_class_loader_ = JNI_NewGlobalRef(env, my_cl);
} else {
LOGE("InMemoryDexClassLoader creation failed!!!");
return;
}
inject_class_loader_ = env->NewGlobalRef(my_cl);
env->DeleteLocalRef(my_cl);
env->DeleteLocalRef(dex_buffer);
env->GetJavaVM(&vm_);
}
void Context::Init(JNIEnv *env) {
class_linker_class_ = (jclass) env->NewGlobalRef(
FindClassFromCurrentLoader(env, kClassLinkerClassName));
if (auto class_linker_class = FindClassFromCurrentLoader(env, kClassLinkerClassName)) {
class_linker_class_ = JNI_NewGlobalRef(env, class_linker_class);
}
post_fixup_static_mid_ = JNI_GetStaticMethodID(env, class_linker_class_,
"onPostFixupStaticTrampolines",
"(Ljava/lang/Class;)V");
entry_class_ = (jclass) (env->NewGlobalRef(
FindClassFromLoader(env, GetCurrentClassLoader(), kEntryClassName)));
if (auto entry_class = FindClassFromLoader(env, GetCurrentClassLoader(), kEntryClassName)) {
entry_class_ = JNI_NewGlobalRef(env, entry_class);
}
RegisterLogger(env);
RegisterResourcesHook(env);
@ -125,44 +121,41 @@ namespace lspd {
RegisterNativeAPI(env);
}
jclass
ScopedLocalRef<jclass>
Context::FindClassFromLoader(JNIEnv *env, jobject class_loader, std::string_view class_name) {
if (class_loader == nullptr) return nullptr;
static auto clz = (jclass) env->NewGlobalRef(
env->FindClass("dalvik/system/DexClassLoader"));
if (class_loader == nullptr) return {env, nullptr};
static auto clz = JNI_NewGlobalRef(env, JNI_FindClass(env, "dalvik/system/DexClassLoader"));
static jmethodID mid = JNI_GetMethodID(env, clz, "loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
jclass ret = nullptr;
if (!mid) {
mid = JNI_GetMethodID(env, clz, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
}
if (LIKELY(mid)) {
jobject target = JNI_CallObjectMethod(env, class_loader, mid,
env->NewStringUTF(class_name.data()));
auto target = JNI_CallObjectMethod(env, class_loader, mid,
env->NewStringUTF(class_name.data()));
if (target) {
return (jclass) target;
return target;
}
} else {
LOGE("No loadClass/findClass method found");
}
LOGE("Class %s not found", class_name.data());
return ret;
return {env, nullptr};
}
inline void Context::FindAndCall(JNIEnv *env, const char *method_name,
const char *method_sig, ...) const {
template<typename ...Args>
void
Context::FindAndCall(JNIEnv *env, std::string_view method_name, std::string_view method_sig,
Args &&... args) const {
if (UNLIKELY(!entry_class_)) {
LOGE("cannot call method %s, entry class is null", method_name);
LOGE("cannot call method %s, entry class is null", method_name.data());
return;
}
jmethodID mid = JNI_GetStaticMethodID(env, entry_class_, method_name, method_sig);
if (LIKELY(mid)) {
va_list args;
va_start(args, method_sig);
env->CallStaticVoidMethodV(entry_class_, mid, args);
va_end(args);
JNI_CallStaticVoidMethod(env, entry_class_, mid, std::forward<Args>(args)...);
} else {
LOGE("method %s id is null", method_name);
LOGE("method %s id is null", method_name.data());
}
}
@ -184,7 +177,7 @@ namespace lspd {
InstallInlineHooks();
Init(env);
FindAndCall(env, "forkSystemServerPost", "(Landroid/os/IBinder;)V", binder);
}
} else skip_ = true;
}
setAllowUnload(skip_);
}
@ -221,7 +214,8 @@ namespace lspd {
void
Context::OnNativeForkAndSpecializePost(JNIEnv *env) {
const JUTFString process_name(env, nice_name_);
auto binder = skip_ ? nullptr : Service::instance()->RequestBinder(env, nice_name_);
auto binder = skip_ ? ScopedLocalRef<jobject>{env, nullptr}
: Service::instance()->RequestBinder(env, nice_name_);
if (binder) {
LoadDex(env);
InstallInlineHooks();

View File

@ -27,6 +27,7 @@
#include <tuple>
#include <string_view>
#include "utils.h"
#include "jni_helper.h"
namespace lspd {
class Context {
@ -44,9 +45,7 @@ namespace lspd {
void CallOnPostFixupStaticTrampolines(void *class_ptr);
void FindAndCall(JNIEnv *env, const char *method_name, const char *method_sig, ...) const;
inline jclass FindClassFromCurrentLoader(JNIEnv *env, std::string_view className) const {
inline ScopedLocalRef<jclass> FindClassFromCurrentLoader(JNIEnv *env, std::string_view className) const {
return FindClassFromLoader(env, GetCurrentClassLoader(), className);
};
@ -78,10 +77,13 @@ namespace lspd {
void Init(JNIEnv *env);
static jclass FindClassFromLoader(JNIEnv *env, jobject class_loader,
static ScopedLocalRef<jclass> FindClassFromLoader(JNIEnv *env, jobject class_loader,
std::string_view class_name);
static void setAllowUnload(bool unload);
template<typename ...Args>
void FindAndCall(JNIEnv *env, std::string_view method_name, std::string_view method_sig, Args&&... args) const;
friend std::unique_ptr<Context> std::make_unique<Context>();
};

View File

@ -69,9 +69,10 @@ namespace lspd {
}
LSP_DEF_NATIVE_METHOD(jboolean, ResourcesHook, initXResourcesNative) {
classXResources = Context::GetInstance()->FindClassFromCurrentLoader(env,
kXResourcesClassName);
if (!classXResources) {
if (auto classXResources_ = Context::GetInstance()->FindClassFromCurrentLoader(env,
kXResourcesClassName)) {
classXResources = JNI_NewGlobalRef(env, classXResources_);
} else {
LOGE("Error while loading XResources class '%s':", kXResourcesClassName);
return JNI_FALSE;
}
@ -90,14 +91,13 @@ namespace lspd {
if (!PrepareSymbols()) {
return JNI_FALSE;
}
classXResources = reinterpret_cast<jclass>(env->NewGlobalRef(classXResources));
return JNI_TRUE;
}
// @ApiSensitive(Level.MIDDLE)
LSP_DEF_NATIVE_METHOD(jboolean, ResourcesHook, removeFinalFlagNative, jclass target_class) {
if (target_class) {
jclass class_clazz = JNI_FindClass(env, "java/lang/Class");
auto class_clazz = JNI_FindClass(env, "java/lang/Class");
jfieldID java_lang_Class_accessFlags = JNI_GetFieldID(
env, class_clazz, "accessFlags", "I");
jint access_flags = env->GetIntField(target_class, java_lang_Class_accessFlags);
@ -110,8 +110,8 @@ namespace lspd {
LSP_DEF_NATIVE_METHOD(jobject, ResourcesHook, buildDummyClassLoader, jobject parent,
jobject resource_super_class, jobject typed_array_super_class) {
using namespace startop::dex;
static auto in_memory_classloader = (jclass) env->NewGlobalRef(
env->FindClass("dalvik/system/InMemoryDexClassLoader"));
static auto in_memory_classloader = JNI_NewGlobalRef(env, JNI_FindClass(env,
"dalvik/system/InMemoryDexClassLoader"));
static jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
DexBuilder dex_file;
@ -132,7 +132,7 @@ namespace lspd {
auto dex_buffer = env->NewDirectByteBuffer(const_cast<void *>(image.ptr()), image.size());
return JNI_NewObject(env, in_memory_classloader, initMid,
dex_buffer, parent);
dex_buffer, parent).release();
}
LSP_DEF_NATIVE_METHOD(void, ResourcesHook, rewriteXmlReferencesNative,

View File

@ -38,7 +38,7 @@ namespace lspd {
LSP_DEF_NATIVE_METHOD(jobject, Yahfa, findMethodNative, jclass targetClass,
jstring methodName, jstring methodSig) {
return yahfa::findMethodNative(env, clazz, targetClass, methodName,
methodSig);
methodSig);
}
LSP_DEF_NATIVE_METHOD(jboolean, Yahfa, backupAndHookNative, jobject target,
@ -60,8 +60,8 @@ namespace lspd {
LSP_DEF_NATIVE_METHOD(jclass, Yahfa, buildHooker, jobject app_class_loader, jclass return_class,
jobjectArray classes, jstring method_name) {
static auto in_memory_classloader = (jclass) env->NewGlobalRef(
env->FindClass("dalvik/system/InMemoryDexClassLoader"));
static auto in_memory_classloader = JNI_NewGlobalRef(env, JNI_FindClass(env,
"dalvik/system/InMemoryDexClassLoader"));
static jmethodID initMid = JNI_GetMethodID(env, in_memory_classloader, "<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
DexBuilder dex_file;
@ -158,8 +158,9 @@ namespace lspd {
slicer::MemView image{dex_file.CreateImage()};
auto dex_buffer = env->NewDirectByteBuffer(const_cast<void *>(image.ptr()), image.size());
jobject my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
dex_buffer, app_class_loader);
auto my_cl = JNI_NewObject(env, in_memory_classloader, initMid,
dex_buffer, app_class_loader);
env->DeleteLocalRef(dex_buffer);
static jmethodID mid = JNI_GetMethodID(env, in_memory_classloader, "loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
@ -167,10 +168,10 @@ namespace lspd {
mid = JNI_GetMethodID(env, in_memory_classloader, "findClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
}
jobject target = env->CallObjectMethod(my_cl, mid, env->NewStringUTF("LspHooker_"));
auto target = JNI_CallObjectMethod(env, my_cl, mid, env->NewStringUTF("LspHooker_"));
// LOGD("Created %zd", image.size());
if (target) {
return (jclass) target;
return (jclass) target.release();
}
return nullptr;
}

View File

@ -62,66 +62,64 @@ namespace lspd {
void Service::InitService(JNIEnv *env) {
if (LIKELY(initialized_)) return;
initialized_ = true;
// ServiceManager
service_manager_class_ = env->FindClass("android/os/ServiceManager");
if (service_manager_class_) {
service_manager_class_ = (jclass) env->NewGlobalRef(service_manager_class_);
} else {
env->ExceptionClear();
return;
}
get_service_method_ = env->GetStaticMethodID(service_manager_class_, "getService",
"(Ljava/lang/String;)Landroid/os/IBinder;");
if (!get_service_method_) {
env->ExceptionClear();
return;
}
if (auto service_manager_class = JNI_FindClass(env, "android/os/ServiceManager"))
service_manager_class_ = JNI_NewGlobalRef(env, service_manager_class);
else return;
get_service_method_ = JNI_GetStaticMethodID(env, service_manager_class_, "getService",
"(Ljava/lang/String;)Landroid/os/IBinder;");
if (!get_service_method_) return;
// IBinder
jclass ibinder_class = env->FindClass("android/os/IBinder");
transact_method_ = env->GetMethodID(ibinder_class, "transact",
"(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z");
if (auto ibinder_class = JNI_FindClass(env, "android/os/IBinder"))
transact_method_ = JNI_GetMethodID(env, ibinder_class, "transact",
"(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z");
else return;
binder_class_ = env->FindClass("android/os/Binder");
if (binder_class_) binder_class_ = (jclass) env->NewGlobalRef(binder_class_);
binder_ctor_ = env->GetMethodID(binder_class_, "<init>", "()V");
if (auto binder_class = JNI_FindClass(env, "android/os/Binder"))
binder_class_ = JNI_NewGlobalRef(env, binder_class);
else return;
binder_ctor_ = JNI_GetMethodID(env, binder_class_, "<init>", "()V");
// Parcel
parcel_class_ = env->FindClass("android/os/Parcel");
if (parcel_class_) parcel_class_ = (jclass) env->NewGlobalRef(parcel_class_);
obtain_method_ = env->GetStaticMethodID(parcel_class_, "obtain", "()Landroid/os/Parcel;");
recycleMethod_ = env->GetMethodID(parcel_class_, "recycle", "()V");
write_interface_token_method_ = env->GetMethodID(parcel_class_, "writeInterfaceToken",
"(Ljava/lang/String;)V");
write_int_method_ = env->GetMethodID(parcel_class_, "writeInt", "(I)V");
write_string_method_ = env->GetMethodID(parcel_class_, "writeString",
"(Ljava/lang/String;)V");
write_strong_binder_method_ = env->GetMethodID(parcel_class_, "writeStrongBinder",
"(Landroid/os/IBinder;)V");
read_exception_method_ = env->GetMethodID(parcel_class_, "readException", "()V");
read_strong_binder_method_ = env->GetMethodID(parcel_class_, "readStrongBinder",
"()Landroid/os/IBinder;");
if (auto parcel_class = JNI_FindClass(env, "android/os/Parcel"))
parcel_class_ = JNI_NewGlobalRef(env, parcel_class);
else return;
obtain_method_ = JNI_GetStaticMethodID(env, parcel_class_, "obtain",
"()Landroid/os/Parcel;");
recycleMethod_ = JNI_GetMethodID(env, parcel_class_, "recycle", "()V");
write_interface_token_method_ = JNI_GetMethodID(env, parcel_class_, "writeInterfaceToken",
"(Ljava/lang/String;)V");
write_int_method_ = JNI_GetMethodID(env, parcel_class_, "writeInt", "(I)V");
write_string_method_ = JNI_GetMethodID(env, parcel_class_, "writeString",
"(Ljava/lang/String;)V");
write_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "writeStrongBinder",
"(Landroid/os/IBinder;)V");
read_exception_method_ = JNI_GetMethodID(env, parcel_class_, "readException", "()V");
read_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "readStrongBinder",
"()Landroid/os/IBinder;");
// createStringArray_ = env->GetMethodID(parcel_class_, "createStringArray",
// "()[Ljava/lang/String;");
deadObjectExceptionClass_ = env->FindClass("android/os/DeadObjectException");
if (deadObjectExceptionClass_)
deadObjectExceptionClass_ = (jclass) env->NewGlobalRef(deadObjectExceptionClass_);
if (auto deadObjectExceptionClass = JNI_FindClass(env, "android/os/DeadObjectException"))
deadObjectExceptionClass_ = JNI_NewGlobalRef(env, deadObjectExceptionClass);
initialized_ = true;
}
void Service::HookBridge(const Context &context, JNIEnv *env) {
static bool hooked = false;
// This should only be ran once, so unlikely
if (UNLIKELY(hooked)) return;
if (UNLIKELY(!initialized_)) return;
hooked = true;
bridge_service_class_ = context.FindClassFromCurrentLoader(env, kBridgeServiceClassName);
if (!bridge_service_class_) {
if (auto bridge_service_class = context.FindClassFromCurrentLoader(env,
kBridgeServiceClassName))
bridge_service_class_ = JNI_NewGlobalRef(env, bridge_service_class);
else {
LOGE("server class not found");
return;
}
bridge_service_class_ = (jclass) env->NewGlobalRef(bridge_service_class_);
exec_transact_replace_methodID_ = JNI_GetStaticMethodID(env, bridge_service_class_,
"execTransact",
"(IJJI)Z");
@ -130,8 +128,8 @@ namespace lspd {
return;
}
ScopedLocalRef binderClass(env, env->FindClass("android/os/Binder"));
exec_transact_backup_methodID_ = JNI_GetMethodID(env, binderClass.get(), "execTransact",
auto binderClass = JNI_FindClass(env, "android/os/Binder");
exec_transact_backup_methodID_ = JNI_GetMethodID(env, binderClass, "execTransact",
"(IJJI)Z");
auto set_table_override = reinterpret_cast<void (*)(
JNINativeInterface *)>(Dlsym(handle_libart,
@ -151,10 +149,10 @@ namespace lspd {
LOGD("Done InitService");
}
jobject Service::RequestBinder(JNIEnv *env, jstring nice_name) {
ScopedLocalRef<jobject> Service::RequestBinder(JNIEnv *env, jstring nice_name) {
if (UNLIKELY(!initialized_)) {
LOGE("Service not initialized");
return nullptr;
return {env, nullptr};
}
auto bridgeServiceName = env->NewStringUTF(BRIDGE_SERVICE_NAME.data());
@ -162,7 +160,7 @@ namespace lspd {
get_service_method_, bridgeServiceName);
if (!bridgeService) {
LOGD("can't get %s", BRIDGE_SERVICE_NAME.data());
return nullptr;
return {env, nullptr};
}
auto heart_beat_binder = JNI_NewObject(env, binder_class_, binder_ctor_);
@ -181,7 +179,7 @@ namespace lspd {
data,
reply, 0);
jobject service = nullptr;
ScopedLocalRef<jobject> service = {env, nullptr};
if (res) {
JNI_CallVoidMethod(env, reply, read_exception_method_);
service = JNI_CallObjectMethod(env, reply, read_strong_binder_method_);
@ -189,25 +187,23 @@ namespace lspd {
JNI_CallVoidMethod(env, data, recycleMethod_);
JNI_CallVoidMethod(env, reply, recycleMethod_);
if (service) {
env->NewGlobalRef(heart_beat_binder);
} else {
env->DeleteLocalRef(heart_beat_binder);
JNI_NewGlobalRef(env, heart_beat_binder);
}
return service;
}
jobject Service::RequestBinderForSystemServer(JNIEnv *env) {
ScopedLocalRef<jobject> Service::RequestBinderForSystemServer(JNIEnv *env) {
if (UNLIKELY(!initialized_ || !bridge_service_class_)) {
LOGE("Service not initialized");
return nullptr;
return {env, nullptr};
}
auto bridgeServiceName = env->NewStringUTF(SYSTEM_SERVER_BRIDGE_SERVICE_NAME.data());
auto binder = JNI_CallStaticObjectMethod(env, service_manager_class_,
get_service_method_, bridgeServiceName);
if (!binder) {
LOGD("Fail to get binder for system server");
return nullptr;
return {env, nullptr};
}
auto method = JNI_GetStaticMethodID(env, bridge_service_class_,
"getApplicationServiceForSystemServer",
@ -216,9 +212,7 @@ namespace lspd {
auto app_binder = JNI_CallStaticObjectMethod(env, bridge_service_class_, method, binder,
heart_beat_binder);
if (app_binder) {
env->NewGlobalRef(heart_beat_binder);
} else {
env->DeleteLocalRef(heart_beat_binder);
JNI_NewGlobalRef(env, heart_beat_binder);
}
return app_binder;
}

View File

@ -49,10 +49,9 @@ namespace lspd {
void InitService(JNIEnv *env);
void HookBridge(const Context& context, JNIEnv *env);
ScopedLocalRef<jobject> RequestBinder(JNIEnv *env, jstring nice_name);
jobject RequestBinder(JNIEnv *env, jstring nice_name);
jobject RequestBinderForSystemServer(JNIEnv *env);
ScopedLocalRef<jobject> RequestBinderForSystemServer(JNIEnv *env);
private:
inline static std::unique_ptr<Service> instance_ = std::make_unique<Service>();