Obfuscate all classes (#1850)
* Obfuscate more classes WIP DO NOT USE THIS BRANCH * Fix resources hook NOT TESTED * done * remode debug code * use fmt * obfuscate core & nativebridge * BridgeService * update proguard rules Co-authored-by: 南宫雪珊 <vvb2060@gmail.com> Co-authored-by: LoveSy <shana@zju.edu.cn>
This commit is contained in:
parent
961676d772
commit
a1a9cb4d1b
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* This file is part of LSPosed.
|
||||||
|
*
|
||||||
|
* LSPosed is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LSPosed is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 LSPosed Contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Created by Kotori0 on 2022/4/14.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef LSPOSED_CONFIGBRIDGE_H
|
||||||
|
#define LSPOSED_CONFIGBRIDGE_H
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
using obfuscation_map_t = std::map<std::string, std::string>;
|
||||||
|
class ConfigBridge {
|
||||||
|
public:
|
||||||
|
inline static ConfigBridge *GetInstance() {
|
||||||
|
return instance_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static std::unique_ptr<ConfigBridge> ReleaseInstance() {
|
||||||
|
return std::move(instance_);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual obfuscation_map_t& obfuscation_map() = 0;
|
||||||
|
virtual void obfuscation_map(obfuscation_map_t) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
inline static std::unique_ptr<ConfigBridge> instance_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //LSPOSED_CONFIGBRIDGE_H
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2020 EdXposed Contributors
|
* Copyright (C) 2020 EdXposed Contributors
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
* Copyright (C) 2021 - 2022 LSPosed Contributors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include "ConfigBridge.h"
|
||||||
|
|
||||||
#define _uintval(p) reinterpret_cast<uintptr_t>(p)
|
#define _uintval(p) reinterpret_cast<uintptr_t>(p)
|
||||||
#define _ptr(p) reinterpret_cast<void *>(p)
|
#define _ptr(p) reinterpret_cast<void *>(p)
|
||||||
|
|
@ -47,13 +48,13 @@ namespace lspd {
|
||||||
|
|
||||||
[[gnu::always_inline]]
|
[[gnu::always_inline]]
|
||||||
inline bool RegisterNativeMethodsInternal(JNIEnv *env,
|
inline bool RegisterNativeMethodsInternal(JNIEnv *env,
|
||||||
const char *class_name,
|
std::string_view class_name,
|
||||||
const JNINativeMethod *methods,
|
const JNINativeMethod *methods,
|
||||||
jint method_count) {
|
jint method_count) {
|
||||||
|
|
||||||
auto clazz = Context::GetInstance()->FindClassFromCurrentLoader(env, class_name);
|
auto clazz = Context::GetInstance()->FindClassFromCurrentLoader(env, class_name.data());
|
||||||
if (clazz.get() == nullptr) {
|
if (clazz.get() == nullptr) {
|
||||||
LOGF("Couldn't find class: {}", class_name);
|
LOGF("Couldn't find class: {}", class_name.data());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return JNI_RegisterNatives(env, clazz, methods, method_count);
|
return JNI_RegisterNatives(env, clazz, methods, method_count);
|
||||||
|
|
@ -83,7 +84,7 @@ inline bool RegisterNativeMethodsInternal(JNIEnv *env,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define REGISTER_LSP_NATIVE_METHODS(class_name) \
|
#define REGISTER_LSP_NATIVE_METHODS(class_name) \
|
||||||
RegisterNativeMethodsInternal(env, "org.lsposed.lspd.nativebridge." #class_name, gMethods, arraysize(gMethods))
|
RegisterNativeMethodsInternal(env, GetNativeBridgeSignature() + #class_name, gMethods, arraysize(gMethods))
|
||||||
|
|
||||||
inline int HookFunction(void *original, void *replace, void **backup) {
|
inline int HookFunction(void *original, void *replace, void **backup) {
|
||||||
_make_rwx(original, _page_size);
|
_make_rwx(original, _page_size);
|
||||||
|
|
@ -108,6 +109,12 @@ inline int UnhookFunction(void *original) {
|
||||||
return DobbyDestroy(original);
|
return DobbyDestroy(original);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string GetNativeBridgeSignature() {
|
||||||
|
const auto &obfs_map = ConfigBridge::GetInstance()->obfuscation_map();
|
||||||
|
static auto signature = obfs_map.at("org.lsposed.lspd.nativebridge.");
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace lspd
|
} // namespace lspd
|
||||||
|
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,11 @@ namespace lspd {
|
||||||
}();
|
}();
|
||||||
return api_level;
|
return api_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::string JavaNameToSignature(std::string s) {
|
||||||
|
std::replace(s.begin(), s.end(), '.', '/');
|
||||||
|
return "L" + s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2020 EdXposed Contributors
|
* Copyright (C) 2020 EdXposed Contributors
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
* Copyright (C) 2021 - 2022 LSPosed Contributors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2020 EdXposed Contributors
|
* Copyright (C) 2020 EdXposed Contributors
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
* Copyright (C) 2021 - 2022 LSPosed Contributors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
|
@ -24,12 +24,11 @@
|
||||||
#include "elf_util.h"
|
#include "elf_util.h"
|
||||||
#include "native_util.h"
|
#include "native_util.h"
|
||||||
#include "resources_hook.h"
|
#include "resources_hook.h"
|
||||||
|
#include "ConfigBridge.h"
|
||||||
|
|
||||||
using namespace lsplant;
|
using namespace lsplant;
|
||||||
|
|
||||||
namespace lspd {
|
namespace lspd {
|
||||||
static constexpr const char *kXResourcesClassName = "android/content/res/XResources";
|
|
||||||
|
|
||||||
using TYPE_GET_ATTR_NAME_ID = int32_t (*)(void *, int);
|
using TYPE_GET_ATTR_NAME_ID = int32_t (*)(void *, int);
|
||||||
|
|
||||||
using TYPE_STRING_AT = char16_t *(*)(const void *, int32_t, size_t *);
|
using TYPE_STRING_AT = char16_t *(*)(const void *, int32_t, size_t *);
|
||||||
|
|
@ -46,6 +45,18 @@ namespace lspd {
|
||||||
static TYPE_RESTART ResXMLParser_restart = nullptr;
|
static TYPE_RESTART ResXMLParser_restart = nullptr;
|
||||||
static TYPE_GET_ATTR_NAME_ID ResXMLParser_getAttributeNameID = nullptr;
|
static TYPE_GET_ATTR_NAME_ID ResXMLParser_getAttributeNameID = nullptr;
|
||||||
|
|
||||||
|
static std::string GetXResourcesClassName() {
|
||||||
|
auto &obfs_map = ConfigBridge::GetInstance()->obfuscation_map();
|
||||||
|
if (obfs_map.empty()) {
|
||||||
|
LOGW("GetXResourcesClassName: obfuscation_map empty?????");
|
||||||
|
}
|
||||||
|
static auto name = lspd::JavaNameToSignature(
|
||||||
|
obfs_map.at("android.content.res.X")) // TODO: kill this hardcoded name
|
||||||
|
.substr(1) + "Resources";
|
||||||
|
LOGD("{}", name.c_str());
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
static bool PrepareSymbols() {
|
static bool PrepareSymbols() {
|
||||||
SandHook::ElfImg fw(kLibFwName);
|
SandHook::ElfImg fw(kLibFwName);
|
||||||
if (!fw.isValid()) {
|
if (!fw.isValid()) {
|
||||||
|
|
@ -72,22 +83,23 @@ namespace lspd {
|
||||||
}
|
}
|
||||||
|
|
||||||
LSP_DEF_NATIVE_METHOD(jboolean, ResourcesHook, initXResourcesNative) {
|
LSP_DEF_NATIVE_METHOD(jboolean, ResourcesHook, initXResourcesNative) {
|
||||||
|
const auto x_resources_class_name = GetXResourcesClassName();
|
||||||
if (auto classXResources_ = Context::GetInstance()->FindClassFromCurrentLoader(env,
|
if (auto classXResources_ = Context::GetInstance()->FindClassFromCurrentLoader(env,
|
||||||
kXResourcesClassName)) {
|
x_resources_class_name)) {
|
||||||
classXResources = JNI_NewGlobalRef(env, classXResources_);
|
classXResources = JNI_NewGlobalRef(env, classXResources_);
|
||||||
} else {
|
} else {
|
||||||
LOGE("Error while loading XResources class '{}':", kXResourcesClassName);
|
LOGE("Error while loading XResources class '{}':", x_resources_class_name);
|
||||||
return JNI_FALSE;
|
return JNI_FALSE;
|
||||||
}
|
}
|
||||||
methodXResourcesTranslateResId = JNI_GetStaticMethodID(
|
methodXResourcesTranslateResId = JNI_GetStaticMethodID(
|
||||||
env, classXResources, "translateResId",
|
env, classXResources, "translateResId",
|
||||||
"(ILandroid/content/res/XResources;Landroid/content/res/Resources;)I");
|
fmt::format("(IL{};Landroid/content/res/Resources;)I", x_resources_class_name));
|
||||||
if (!methodXResourcesTranslateResId) {
|
if (!methodXResourcesTranslateResId) {
|
||||||
return JNI_FALSE;
|
return JNI_FALSE;
|
||||||
}
|
}
|
||||||
methodXResourcesTranslateAttrId = JNI_GetStaticMethodID(
|
methodXResourcesTranslateAttrId = JNI_GetStaticMethodID(
|
||||||
env, classXResources, "translateAttrId",
|
env, classXResources, "translateAttrId",
|
||||||
"(Ljava/lang/String;Landroid/content/res/XResources;)I");
|
fmt::format("(Ljava/lang/String;L{};)I", x_resources_class_name));
|
||||||
if (!methodXResourcesTranslateAttrId) {
|
if (!methodXResourcesTranslateAttrId) {
|
||||||
return JNI_FALSE;
|
return JNI_FALSE;
|
||||||
}
|
}
|
||||||
|
|
@ -210,6 +222,9 @@ namespace lspd {
|
||||||
};
|
};
|
||||||
|
|
||||||
void RegisterResourcesHook(JNIEnv *env) {
|
void RegisterResourcesHook(JNIEnv *env) {
|
||||||
|
auto sign = fmt::format("(JL{};Landroid/content/res/Resources;)V", GetXResourcesClassName());
|
||||||
|
gMethods[3].signature = sign.c_str();
|
||||||
|
|
||||||
REGISTER_LSP_NATIVE_METHODS(ResourcesHook);
|
REGISTER_LSP_NATIVE_METHODS(ResourcesHook);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2020 EdXposed Contributors
|
* Copyright (C) 2020 EdXposed Contributors
|
||||||
* Copyright (C) 2021 LSPosed Contributors
|
* Copyright (C) 2021 - 2022 LSPosed Contributors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
@ -23,9 +23,6 @@
|
||||||
#include "jni.h"
|
#include "jni.h"
|
||||||
|
|
||||||
namespace lspd {
|
namespace lspd {
|
||||||
|
|
||||||
static constexpr uint32_t kAccFinal = 0x0010;
|
|
||||||
|
|
||||||
void RegisterResourcesHook(JNIEnv *);
|
void RegisterResourcesHook(JNIEnv *);
|
||||||
|
|
||||||
} // namespace lspd
|
} // namespace lspd
|
||||||
|
|
|
||||||
|
|
@ -375,12 +375,14 @@ public class ConfigFileManager {
|
||||||
if (moduleClassNames.isEmpty()) return null;
|
if (moduleClassNames.isEmpty()) return null;
|
||||||
|
|
||||||
if (obfuscate) {
|
if (obfuscate) {
|
||||||
|
var signatures = ObfuscationManager.getSignatures();
|
||||||
for (int i = 0; i < moduleClassNames.size(); i++) {
|
for (int i = 0; i < moduleClassNames.size(); i++) {
|
||||||
var s = moduleClassNames.get(i);
|
var s = moduleClassNames.get(i);
|
||||||
var original = ObfuscationManager.getOriginalSignature();
|
for (String key : signatures.keySet()) {
|
||||||
if (s.startsWith(original)) {
|
if (s.startsWith(key)) {
|
||||||
var obfuscated = ObfuscationManager.getObfuscatedSignature();
|
// value should not be null, but idk how to ignore this warning
|
||||||
moduleClassNames.add(i, s.replace(original, obfuscated));
|
moduleClassNames.add(i, s.replace(key, signatures.get(key)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class LSPApplicationService extends ILSPApplicationService.Stub {
|
public class LSPApplicationService extends ILSPApplicationService.Stub {
|
||||||
final static int DEX_TRANSACTION_CODE = 1310096052;
|
final static int DEX_TRANSACTION_CODE = 1310096052;
|
||||||
|
final static int OBFUSCATION_MAP_TRANSACTION_CODE = 724533732;
|
||||||
// key: <uid, pid>
|
// key: <uid, pid>
|
||||||
private final static Map<Pair<Integer, Integer>, ProcessInfo> processes = new ConcurrentHashMap<>();
|
private final static Map<Pair<Integer, Integer>, ProcessInfo> processes = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
@ -81,13 +82,24 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
|
||||||
@Override
|
@Override
|
||||||
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
|
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
|
||||||
Log.d(TAG, "LSPApplicationService.onTransact: code=" + code);
|
Log.d(TAG, "LSPApplicationService.onTransact: code=" + code);
|
||||||
if (code == DEX_TRANSACTION_CODE) {
|
switch (code) {
|
||||||
var shm = ConfigManager.getInstance().getPreloadDex();
|
case DEX_TRANSACTION_CODE: {
|
||||||
if (shm == null) return false;
|
var shm = ConfigManager.getInstance().getPreloadDex();
|
||||||
// assume that write only a fd
|
if (shm == null) return false;
|
||||||
shm.writeToParcel(reply, 0);
|
// assume that write only a fd
|
||||||
reply.writeLong(shm.getSize());
|
shm.writeToParcel(reply, 0);
|
||||||
return true;
|
reply.writeLong(shm.getSize());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case OBFUSCATION_MAP_TRANSACTION_CODE: {
|
||||||
|
var signatures = ObfuscationManager.getSignatures();
|
||||||
|
reply.writeInt(signatures.size() * 2);
|
||||||
|
for(Map.Entry<String,String> entry : signatures.entrySet()){
|
||||||
|
reply.writeString(entry.getKey());
|
||||||
|
reply.writeString(entry.getValue());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return super.onTransact(code, data, reply, flags);
|
return super.onTransact(code, data, reply, flags);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ public class LSPSystemServerService extends ILSPSystemServerService.Stub impleme
|
||||||
Log.d(TAG, "LSPSystemServerService.onTransact requestApplicationService rejected");
|
Log.d(TAG, "LSPSystemServerService.onTransact requestApplicationService rejected");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
case LSPApplicationService.OBFUSCATION_MAP_TRANSACTION_CODE:
|
||||||
case LSPApplicationService.DEX_TRANSACTION_CODE:
|
case LSPApplicationService.DEX_TRANSACTION_CODE:
|
||||||
// Proxy LSP dex transaction to Application Binder
|
// Proxy LSP dex transaction to Application Binder
|
||||||
return ServiceManager.getApplicationService().onTransact(code, data, reply, flags);
|
return ServiceManager.getApplicationService().onTransact(code, data, reply, flags);
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@ package org.lsposed.lspd.service;
|
||||||
|
|
||||||
import android.os.SharedMemory;
|
import android.os.SharedMemory;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class ObfuscationManager {
|
public class ObfuscationManager {
|
||||||
// For module dexes
|
// For module dexes
|
||||||
static native SharedMemory obfuscateDex(SharedMemory memory);
|
static native SharedMemory obfuscateDex(SharedMemory memory);
|
||||||
|
|
||||||
// generates signature
|
// generates signature
|
||||||
static native String getObfuscatedSignature();
|
static native HashMap<String, String> getSignatures();
|
||||||
|
|
||||||
static native String getOriginalSignature();
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,14 @@
|
||||||
using namespace lsplant;
|
using namespace lsplant;
|
||||||
namespace {
|
namespace {
|
||||||
std::mutex init_lock{};
|
std::mutex init_lock{};
|
||||||
std::string obfuscated_signature;
|
std::map<const std::string, std::string> signatures = {
|
||||||
const std::string original_signature = "Lde/robv/android/xposed/";
|
{"Lde/robv/android/xposed/", ""},
|
||||||
|
{ "Landroid/app/AndroidApp", ""},
|
||||||
|
{ "Landroid/content/res/X", ""},
|
||||||
|
{ "Lorg/lsposed/lspd/core/", ""},
|
||||||
|
{ "Lorg/lsposed/lspd/nativebridge/", ""},
|
||||||
|
{ "Lorg/lsposed/lspd/service/", ""},
|
||||||
|
};
|
||||||
|
|
||||||
jclass class_file_descriptor;
|
jclass class_file_descriptor;
|
||||||
jmethodID method_file_descriptor_ctor;
|
jmethodID method_file_descriptor_ctor;
|
||||||
|
|
@ -73,7 +79,7 @@ void maybeInit(JNIEnv *env) {
|
||||||
|
|
||||||
method_shared_memory_ctor = JNI_GetMethodID(env, class_shared_memory, "<init>", "(Ljava/io/FileDescriptor;)V");
|
method_shared_memory_ctor = JNI_GetMethodID(env, class_shared_memory, "<init>", "(Ljava/io/FileDescriptor;)V");
|
||||||
|
|
||||||
auto regen = []() {
|
auto regen = [](std::string_view original_signature) {
|
||||||
static auto& chrs = "abcdefghijklmnopqrstuvwxyz"
|
static auto& chrs = "abcdefghijklmnopqrstuvwxyz"
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
|
@ -101,40 +107,72 @@ void maybeInit(JNIEnv *env) {
|
||||||
return out;
|
return out;
|
||||||
};
|
};
|
||||||
|
|
||||||
obfuscated_signature = regen();
|
for (auto &i: signatures) {
|
||||||
|
i.second = regen(i.first);
|
||||||
|
LOGD("%s => %s", i.first.c_str(), i.second.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
LOGD("ObfuscationManager.getObfuscatedSignature: %s", obfuscated_signature.c_str());
|
|
||||||
LOGD("ObfuscationManager init successfully");
|
LOGD("ObfuscationManager init successfully");
|
||||||
inited = true;
|
inited = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
// https://stackoverflow.com/questions/4844022/jni-create-hashmap with modifications
|
||||||
JNIEXPORT jstring JNICALL
|
jobject stringMapToJavaHashMap(JNIEnv *env, const decltype(signatures)& map) {
|
||||||
Java_org_lsposed_lspd_service_ObfuscationManager_getObfuscatedSignature(JNIEnv *env, [[maybe_unused]] jclass obfuscation_manager) {
|
jclass mapClass = env->FindClass("java/util/HashMap");
|
||||||
maybeInit(env);
|
if(mapClass == nullptr)
|
||||||
static std::string obfuscated_signature_java = to_java(obfuscated_signature);
|
return nullptr;
|
||||||
return env->NewStringUTF(obfuscated_signature_java.c_str());
|
|
||||||
|
jmethodID init = env->GetMethodID(mapClass, "<init>", "()V");
|
||||||
|
jobject hashMap = env->NewObject(mapClass, init);
|
||||||
|
jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||||
|
|
||||||
|
auto citr = map.begin();
|
||||||
|
for( ; citr != map.end(); ++citr) {
|
||||||
|
jstring keyJava = env->NewStringUTF(citr->first.c_str());
|
||||||
|
jstring valueJava = env->NewStringUTF(citr->second.c_str());
|
||||||
|
|
||||||
|
env->CallObjectMethod(hashMap, put, keyJava, valueJava);
|
||||||
|
|
||||||
|
env->DeleteLocalRef(keyJava);
|
||||||
|
env->DeleteLocalRef(valueJava);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto hashMapGobal = static_cast<jobject>(env->NewGlobalRef(hashMap));
|
||||||
|
env->DeleteLocalRef(hashMap);
|
||||||
|
env->DeleteLocalRef(mapClass);
|
||||||
|
|
||||||
|
return hashMapGobal;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT jstring JNICALL
|
JNIEXPORT jobject JNICALL
|
||||||
Java_org_lsposed_lspd_service_ObfuscationManager_getOriginalSignature(JNIEnv *env, [[maybe_unused]] jclass obfuscation_manager) {
|
Java_org_lsposed_lspd_service_ObfuscationManager_getSignatures(JNIEnv *env, [[maybe_unused]] jclass obfuscation_manager) {
|
||||||
static std::string original_signature_java = to_java(original_signature);
|
maybeInit(env);
|
||||||
return env->NewStringUTF(original_signature_java.c_str());
|
static jobject signatures_jni = nullptr;
|
||||||
|
if (signatures_jni) return signatures_jni;
|
||||||
|
decltype(signatures) signatures_java;
|
||||||
|
for (const auto &i: signatures) {
|
||||||
|
signatures_java[to_java(i.first)] = to_java(i.second);
|
||||||
|
}
|
||||||
|
signatures_jni = stringMapToJavaHashMap(env, signatures_java);
|
||||||
|
return signatures_jni;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int obfuscateDex(const void *dex, size_t size) {
|
static int obfuscateDex(const void *dex, size_t size) {
|
||||||
const char* new_sig = obfuscated_signature.c_str();
|
// const char* new_sig = obfuscated_signature.c_str();
|
||||||
dex::Reader reader{reinterpret_cast<const dex::u1*>(dex), size};
|
dex::Reader reader{reinterpret_cast<const dex::u1*>(dex), size};
|
||||||
|
|
||||||
reader.CreateFullIr();
|
reader.CreateFullIr();
|
||||||
auto ir = reader.GetIr();
|
auto ir = reader.GetIr();
|
||||||
for (auto &i: ir->strings) {
|
for (auto &i: ir->strings) {
|
||||||
const char *s = i->c_str();
|
const char *s = i->c_str();
|
||||||
char* p = const_cast<char *>(strstr(s, original_signature.c_str()));
|
for (const auto &signature: signatures) {
|
||||||
if (p) {
|
char* p = const_cast<char *>(strstr(s, signature.first.c_str()));
|
||||||
// NOLINTNEXTLINE bugprone-not-null-terminated-result
|
if (p) {
|
||||||
memcpy(p, new_sig, strlen(new_sig));
|
auto new_sig = signature.second.c_str();
|
||||||
|
// NOLINTNEXTLINE bugprone-not-null-terminated-result
|
||||||
|
memcpy(p, new_sig, strlen(new_sig));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dex::Writer writer(ir);
|
dex::Writer writer(ir);
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
|
#include "ConfigImpl.h"
|
||||||
#include "magisk_loader.h"
|
#include "magisk_loader.h"
|
||||||
#include "symbol_cache.h"
|
#include "symbol_cache.h"
|
||||||
|
|
||||||
|
|
@ -42,6 +43,7 @@ namespace lspd {
|
||||||
LOGI("onModuleLoaded: version v{} ({})", versionName, versionCode);
|
LOGI("onModuleLoaded: version v{} ({})", versionName, versionCode);
|
||||||
InitSymbolCache(nullptr);
|
InitSymbolCache(nullptr);
|
||||||
MagiskLoader::Init();
|
MagiskLoader::Init();
|
||||||
|
ConfigImpl::Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void nativeForkAndSpecializePre(JNIEnv *env, jclass, jint *_uid, jint *,
|
void nativeForkAndSpecializePre(JNIEnv *env, jclass, jint *_uid, jint *,
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include "zygisk.h"
|
#include "zygisk.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
|
#include "ConfigImpl.h"
|
||||||
#include "magisk_loader.h"
|
#include "magisk_loader.h"
|
||||||
#include "symbol_cache.h"
|
#include "symbol_cache.h"
|
||||||
|
|
||||||
|
|
@ -282,6 +283,7 @@ namespace lspd {
|
||||||
env_ = env;
|
env_ = env;
|
||||||
api_ = api;
|
api_ = api;
|
||||||
MagiskLoader::Init();
|
MagiskLoader::Init();
|
||||||
|
ConfigImpl::Init();
|
||||||
|
|
||||||
auto companion = api->connectCompanion();
|
auto companion = api->connectCompanion();
|
||||||
if (companion == -1) {
|
if (companion == -1) {
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,6 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
namespace lspd {
|
namespace lspd {
|
||||||
inline static constexpr auto kEntryClassName = "org.lsposed.lspd.core.Main"_tstr;
|
|
||||||
inline static constexpr auto kBridgeServiceClassName = "org.lsposed.lspd.service.BridgeService"_tstr;
|
|
||||||
|
|
||||||
extern const int apiVersion;
|
extern const int apiVersion;
|
||||||
extern const char* const moduleName;
|
extern const char* const moduleName;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* This file is part of LSPosed.
|
||||||
|
*
|
||||||
|
* LSPosed is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LSPosed is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 LSPosed Contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Created by Kotori0 on 2022/4/14.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef LSPOSED_CONFIGIMPL_H
|
||||||
|
#define LSPOSED_CONFIGIMPL_H
|
||||||
|
#include "ConfigBridge.h"
|
||||||
|
#include "service.h"
|
||||||
|
|
||||||
|
class ConfigImpl: public ConfigBridge {
|
||||||
|
public:
|
||||||
|
inline static void Init() {
|
||||||
|
instance_ = std::make_unique<ConfigImpl>();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual obfuscation_map_t& obfuscation_map() override { return obfuscation_map_; }
|
||||||
|
virtual void obfuscation_map(obfuscation_map_t m) override { obfuscation_map_ = std::move(m); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline static std::map<std::string, std::string> obfuscation_map_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //LSPOSED_CONFIGIMPL_H
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include "ConfigImpl.h"
|
||||||
#include "elf_util.h"
|
#include "elf_util.h"
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
#include "magisk_loader.h"
|
#include "magisk_loader.h"
|
||||||
|
|
@ -73,9 +74,15 @@ namespace lspd {
|
||||||
env->DeleteLocalRef(dex_buffer);
|
env->DeleteLocalRef(dex_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetEntryClassName() {
|
||||||
|
const auto &obfs_map = ConfigBridge::GetInstance()->obfuscation_map();
|
||||||
|
static auto signature = obfs_map.at("org.lsposed.lspd.core.") + "Main";
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
void MagiskLoader::SetupEntryClass(JNIEnv *env) {
|
void MagiskLoader::SetupEntryClass(JNIEnv *env) {
|
||||||
if (auto entry_class = FindClassFromLoader(env, GetCurrentClassLoader(),
|
if (auto entry_class = FindClassFromLoader(env, GetCurrentClassLoader(),
|
||||||
kEntryClassName)) {
|
GetEntryClassName())) {
|
||||||
entry_class_ = JNI_NewGlobalRef(env, entry_class);
|
entry_class_ = JNI_NewGlobalRef(env, entry_class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +111,10 @@ namespace lspd {
|
||||||
|
|
||||||
// Call application_binder directly if application binder is available,
|
// Call application_binder directly if application binder is available,
|
||||||
// or we proxy the request from system server binder
|
// or we proxy the request from system server binder
|
||||||
auto [dex_fd, size]= instance->RequestLSPDex(env, application_binder ? application_binder : system_server_binder);
|
const auto next_binder = std::move(application_binder ? application_binder : system_server_binder);
|
||||||
|
const auto [dex_fd, size] = instance->RequestLSPDex(env, next_binder);
|
||||||
|
auto obfs_map = instance->RequestObfuscationMap(env, next_binder);
|
||||||
|
ConfigBridge::GetInstance()->obfuscation_map(std::move(obfs_map));
|
||||||
LoadDex(env, PreloadedDex(dex_fd, size));
|
LoadDex(env, PreloadedDex(dex_fd, size));
|
||||||
close(dex_fd);
|
close(dex_fd);
|
||||||
instance->HookBridge(*this, env);
|
instance->HookBridge(*this, env);
|
||||||
|
|
@ -196,6 +206,8 @@ namespace lspd {
|
||||||
};
|
};
|
||||||
InstallInlineHooks(env, initInfo);
|
InstallInlineHooks(env, initInfo);
|
||||||
auto [dex_fd, size] = instance->RequestLSPDex(env, binder);
|
auto [dex_fd, size] = instance->RequestLSPDex(env, binder);
|
||||||
|
auto obfs_map = instance->RequestObfuscationMap(env, binder);
|
||||||
|
ConfigBridge::GetInstance()->obfuscation_map(std::move(obfs_map));
|
||||||
LoadDex(env, PreloadedDex(dex_fd, size));
|
LoadDex(env, PreloadedDex(dex_fd, size));
|
||||||
close(dex_fd);
|
close(dex_fd);
|
||||||
InitHooks(env, initInfo);
|
InitHooks(env, initInfo);
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include "utils/jni_helper.hpp"
|
#include "utils/jni_helper.hpp"
|
||||||
#include "symbol_cache.h"
|
#include "symbol_cache.h"
|
||||||
|
#include "ConfigBridge.h"
|
||||||
|
|
||||||
using namespace lsplant;
|
using namespace lsplant;
|
||||||
|
|
||||||
|
|
@ -108,6 +109,7 @@ namespace lspd {
|
||||||
if (auto parcel_class = JNI_FindClass(env, "android/os/Parcel")) {
|
if (auto parcel_class = JNI_FindClass(env, "android/os/Parcel")) {
|
||||||
parcel_class_ = JNI_NewGlobalRef(env, parcel_class);
|
parcel_class_ = JNI_NewGlobalRef(env, parcel_class);
|
||||||
} else return;
|
} else return;
|
||||||
|
data_size_method_ = JNI_GetMethodID(env, parcel_class_, "dataSize","()I");
|
||||||
obtain_method_ = JNI_GetStaticMethodID(env, parcel_class_, "obtain",
|
obtain_method_ = JNI_GetStaticMethodID(env, parcel_class_, "obtain",
|
||||||
"()Landroid/os/Parcel;");
|
"()Landroid/os/Parcel;");
|
||||||
recycleMethod_ = JNI_GetMethodID(env, parcel_class_, "recycle", "()V");
|
recycleMethod_ = JNI_GetMethodID(env, parcel_class_, "recycle", "()V");
|
||||||
|
|
@ -119,6 +121,7 @@ namespace lspd {
|
||||||
write_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "writeStrongBinder",
|
write_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "writeStrongBinder",
|
||||||
"(Landroid/os/IBinder;)V");
|
"(Landroid/os/IBinder;)V");
|
||||||
read_exception_method_ = JNI_GetMethodID(env, parcel_class_, "readException", "()V");
|
read_exception_method_ = JNI_GetMethodID(env, parcel_class_, "readException", "()V");
|
||||||
|
read_int_method_ = JNI_GetMethodID(env, parcel_class_, "readInt", "()I");
|
||||||
read_long_method_ = JNI_GetMethodID(env, parcel_class_, "readLong", "()J");
|
read_long_method_ = JNI_GetMethodID(env, parcel_class_, "readLong", "()J");
|
||||||
read_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "readStrongBinder",
|
read_strong_binder_method_ = JNI_GetMethodID(env, parcel_class_, "readStrongBinder",
|
||||||
"()Landroid/os/IBinder;");
|
"()Landroid/os/IBinder;");
|
||||||
|
|
@ -144,6 +147,12 @@ namespace lspd {
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetBridgeServiceName() {
|
||||||
|
const auto &obfs_map = ConfigBridge::GetInstance()->obfuscation_map();
|
||||||
|
static auto signature = obfs_map.at("org.lsposed.lspd.service.") + "BridgeService";
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
void Service::HookBridge(const Context &context, JNIEnv *env) {
|
void Service::HookBridge(const Context &context, JNIEnv *env) {
|
||||||
static bool kHooked = false;
|
static bool kHooked = false;
|
||||||
// This should only be ran once, so unlikely
|
// This should only be ran once, so unlikely
|
||||||
|
|
@ -151,7 +160,7 @@ namespace lspd {
|
||||||
if (!initialized_) [[unlikely]] return;
|
if (!initialized_) [[unlikely]] return;
|
||||||
kHooked = true;
|
kHooked = true;
|
||||||
if (auto bridge_service_class = context.FindClassFromCurrentLoader(env,
|
if (auto bridge_service_class = context.FindClassFromCurrentLoader(env,
|
||||||
kBridgeServiceClassName))
|
GetBridgeServiceName()))
|
||||||
bridge_service_class_ = JNI_NewGlobalRef(env, bridge_service_class);
|
bridge_service_class_ = JNI_NewGlobalRef(env, bridge_service_class);
|
||||||
else {
|
else {
|
||||||
LOGE("server class not found");
|
LOGE("server class not found");
|
||||||
|
|
@ -284,26 +293,20 @@ namespace lspd {
|
||||||
|
|
||||||
ScopedLocalRef<jobject> Service::RequestApplicationBinderFromSystemServer(JNIEnv *env, const ScopedLocalRef<jobject> &system_server_binder) {
|
ScopedLocalRef<jobject> Service::RequestApplicationBinderFromSystemServer(JNIEnv *env, const ScopedLocalRef<jobject> &system_server_binder) {
|
||||||
auto heart_beat_binder = JNI_NewObject(env, binder_class_, binder_ctor_);
|
auto heart_beat_binder = JNI_NewObject(env, binder_class_, binder_ctor_);
|
||||||
auto data = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_);
|
Wrapper wrapper{env, this};
|
||||||
auto reply = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_);
|
|
||||||
|
|
||||||
JNI_CallVoidMethod(env, data, write_int_method_, getuid());
|
JNI_CallVoidMethod(env, wrapper.data, write_int_method_, getuid());
|
||||||
JNI_CallVoidMethod(env, data, write_int_method_, getpid());
|
JNI_CallVoidMethod(env, wrapper.data, write_int_method_, getpid());
|
||||||
JNI_CallVoidMethod(env, data, write_string_method_, JNI_NewStringUTF(env, "android"));
|
JNI_CallVoidMethod(env, wrapper.data, write_string_method_, JNI_NewStringUTF(env, "android"));
|
||||||
JNI_CallVoidMethod(env, data, write_strong_binder_method_, heart_beat_binder);
|
JNI_CallVoidMethod(env, wrapper.data, write_strong_binder_method_, heart_beat_binder);
|
||||||
|
|
||||||
auto res = JNI_CallBooleanMethod(env, system_server_binder, transact_method_,
|
auto res = wrapper.transact(system_server_binder, BRIDGE_TRANSACTION_CODE);
|
||||||
BRIDGE_TRANSACTION_CODE,
|
|
||||||
data,
|
|
||||||
reply, 0);
|
|
||||||
|
|
||||||
ScopedLocalRef<jobject> app_binder = {env, nullptr};
|
ScopedLocalRef<jobject> app_binder = {env, nullptr};
|
||||||
if (res) {
|
if (res) {
|
||||||
JNI_CallVoidMethod(env, reply, read_exception_method_);
|
JNI_CallVoidMethod(env, wrapper.reply, read_exception_method_);
|
||||||
app_binder = JNI_CallObjectMethod(env, reply, read_strong_binder_method_);
|
app_binder = JNI_CallObjectMethod(env, wrapper.reply, read_strong_binder_method_);
|
||||||
}
|
}
|
||||||
JNI_CallVoidMethod(env, data, recycleMethod_);
|
|
||||||
JNI_CallVoidMethod(env, reply, recycleMethod_);
|
|
||||||
if (app_binder) {
|
if (app_binder) {
|
||||||
JNI_NewGlobalRef(env, heart_beat_binder);
|
JNI_NewGlobalRef(env, heart_beat_binder);
|
||||||
}
|
}
|
||||||
|
|
@ -312,23 +315,49 @@ namespace lspd {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<int, size_t> Service::RequestLSPDex(JNIEnv *env, const ScopedLocalRef<jobject> &binder) {
|
std::tuple<int, size_t> Service::RequestLSPDex(JNIEnv *env, const ScopedLocalRef<jobject> &binder) {
|
||||||
auto data = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_);
|
Wrapper wrapper{env, this};
|
||||||
auto reply = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_);
|
bool res = wrapper.transact(binder, DEX_TRANSACTION_CODE);
|
||||||
auto res = JNI_CallBooleanMethod(env, binder, transact_method_,
|
|
||||||
DEX_TRANSACTION_CODE,
|
|
||||||
data,
|
|
||||||
reply, 0);
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
LOGE("Service::RequestLSPDex: transaction failed?");
|
LOGE("Service::RequestLSPDex: transaction failed?");
|
||||||
return {-1, 0};
|
return {-1, 0};
|
||||||
}
|
}
|
||||||
auto parcel_fd = JNI_CallObjectMethod(env, reply, read_file_descriptor_method_);
|
auto parcel_fd = JNI_CallObjectMethod(env, wrapper.reply, read_file_descriptor_method_);
|
||||||
int fd = JNI_CallIntMethod(env, parcel_fd, detach_fd_method_);
|
int fd = JNI_CallIntMethod(env, parcel_fd, detach_fd_method_);
|
||||||
auto size = static_cast<size_t>(JNI_CallLongMethod(env, reply, read_long_method_));
|
auto size = static_cast<size_t>(JNI_CallLongMethod(env, wrapper.reply, read_long_method_));
|
||||||
JNI_CallVoidMethod(env, data, recycleMethod_);
|
LOGD("fd={}, size={}", fd, size);
|
||||||
JNI_CallVoidMethod(env, reply, recycleMethod_);
|
|
||||||
|
|
||||||
LOGD("Service::RequestLSPDex fd={}, size={}", fd, size);
|
|
||||||
return {fd, size};
|
return {fd, size};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<std::string, std::string>
|
||||||
|
Service::RequestObfuscationMap(JNIEnv *env, const ScopedLocalRef<jobject> &binder) {
|
||||||
|
std::map<std::string, std::string> ret;
|
||||||
|
Wrapper wrapper{env, this};
|
||||||
|
bool res = wrapper.transact(binder, OBFUSCATION_MAP_TRANSACTION_CODE);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
LOGE("Service::RequestObfuscationMap: transaction failed?");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
auto size = JNI_CallIntMethod(env, wrapper.reply, read_int_method_);
|
||||||
|
if (!size || (size & 1) == 1) {
|
||||||
|
LOGW("Service::RequestObfuscationMap: invalid parcel size");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto get_string = [this, &wrapper, &env]() -> std::string {
|
||||||
|
auto s = JNI_Cast<jstring>(JNI_CallObjectMethod(env, wrapper.reply, read_string_method_));
|
||||||
|
return JUTFString(s);
|
||||||
|
};
|
||||||
|
for (auto i = 0; i < size / 2; i++) {
|
||||||
|
// DO NOT TOUCH, or value evaluates before key.
|
||||||
|
auto &&key = get_string();
|
||||||
|
ret[key] = get_string();
|
||||||
|
}
|
||||||
|
#ifndef NDEBUG
|
||||||
|
for (const auto &i: ret) {
|
||||||
|
LOGD("{} => {}", i.first, i.second);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
} // namespace lspd
|
} // namespace lspd
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#ifndef LSPOSED_SERVICE_H
|
#ifndef LSPOSED_SERVICE_H
|
||||||
#define LSPOSED_SERVICE_H
|
#define LSPOSED_SERVICE_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
|
|
||||||
|
|
@ -32,6 +33,7 @@ using namespace std::literals::string_view_literals;
|
||||||
namespace lspd {
|
namespace lspd {
|
||||||
class Service {
|
class Service {
|
||||||
constexpr static jint DEX_TRANSACTION_CODE = 1310096052;
|
constexpr static jint DEX_TRANSACTION_CODE = 1310096052;
|
||||||
|
constexpr static jint OBFUSCATION_MAP_TRANSACTION_CODE = 724533732;
|
||||||
constexpr static jint BRIDGE_TRANSACTION_CODE = 1598837584;
|
constexpr static jint BRIDGE_TRANSACTION_CODE = 1598837584;
|
||||||
constexpr static auto BRIDGE_SERVICE_DESCRIPTOR = "LSPosed"sv;
|
constexpr static auto BRIDGE_SERVICE_DESCRIPTOR = "LSPosed"sv;
|
||||||
constexpr static auto BRIDGE_SERVICE_NAME = "activity"sv;
|
constexpr static auto BRIDGE_SERVICE_NAME = "activity"sv;
|
||||||
|
|
@ -39,6 +41,31 @@ namespace lspd {
|
||||||
constexpr static jint BRIDGE_ACTION_GET_BINDER = 2;
|
constexpr static jint BRIDGE_ACTION_GET_BINDER = 2;
|
||||||
inline static jint SET_ACTIVITY_CONTROLLER_CODE = -1;
|
inline static jint SET_ACTIVITY_CONTROLLER_CODE = -1;
|
||||||
|
|
||||||
|
class Wrapper {
|
||||||
|
public:
|
||||||
|
Service* service_;
|
||||||
|
JNIEnv *env_;
|
||||||
|
lsplant::ScopedLocalRef<jobject> data;
|
||||||
|
lsplant::ScopedLocalRef<jobject> reply;
|
||||||
|
|
||||||
|
Wrapper(JNIEnv *env, Service* service) :
|
||||||
|
service_(service),
|
||||||
|
env_(env),
|
||||||
|
data(lsplant::JNI_CallStaticObjectMethod(env, service->parcel_class_, service->obtain_method_)),
|
||||||
|
reply(lsplant::JNI_CallStaticObjectMethod(env, service->parcel_class_, service->obtain_method_))
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline bool transact(const lsplant::ScopedLocalRef<jobject> &binder, jint transaction_code) {
|
||||||
|
return JNI_CallBooleanMethod(env_, binder, service_->transact_method_,transaction_code,
|
||||||
|
data, reply, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~Wrapper() {
|
||||||
|
JNI_CallVoidMethod(env_, data, service_->recycleMethod_);
|
||||||
|
JNI_CallVoidMethod(env_, reply, service_->recycleMethod_);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline static Service* instance() {
|
inline static Service* instance() {
|
||||||
return instance_.get();
|
return instance_.get();
|
||||||
|
|
@ -59,6 +86,8 @@ namespace lspd {
|
||||||
|
|
||||||
std::tuple<int, size_t> RequestLSPDex(JNIEnv *env, const lsplant::ScopedLocalRef<jobject> &binder);
|
std::tuple<int, size_t> RequestLSPDex(JNIEnv *env, const lsplant::ScopedLocalRef<jobject> &binder);
|
||||||
|
|
||||||
|
std::map<std::string, std::string> RequestObfuscationMap(JNIEnv *env, const lsplant::ScopedLocalRef<jobject> &binder);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline static std::unique_ptr<Service> instance_ = std::make_unique<Service>();
|
inline static std::unique_ptr<Service> instance_ = std::make_unique<Service>();
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
|
|
@ -90,6 +119,7 @@ namespace lspd {
|
||||||
jmethodID transact_method_ = nullptr;
|
jmethodID transact_method_ = nullptr;
|
||||||
|
|
||||||
jclass parcel_class_ = nullptr;
|
jclass parcel_class_ = nullptr;
|
||||||
|
jmethodID data_size_method_ = nullptr;
|
||||||
jmethodID obtain_method_ = nullptr;
|
jmethodID obtain_method_ = nullptr;
|
||||||
jmethodID recycleMethod_ = nullptr;
|
jmethodID recycleMethod_ = nullptr;
|
||||||
jmethodID write_interface_token_method_ = nullptr;
|
jmethodID write_interface_token_method_ = nullptr;
|
||||||
|
|
@ -99,6 +129,7 @@ namespace lspd {
|
||||||
jmethodID read_strong_binder_method_ = nullptr;
|
jmethodID read_strong_binder_method_ = nullptr;
|
||||||
jmethodID write_strong_binder_method_ = nullptr;
|
jmethodID write_strong_binder_method_ = nullptr;
|
||||||
jmethodID read_file_descriptor_method_ = nullptr;
|
jmethodID read_file_descriptor_method_ = nullptr;
|
||||||
|
jmethodID read_int_method_ = nullptr;
|
||||||
jmethodID read_long_method_ = nullptr;
|
jmethodID read_long_method_ = nullptr;
|
||||||
jmethodID read_string_method_ = nullptr;
|
jmethodID read_string_method_ = nullptr;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit e183a459a23d8825f495caff30b81d88e56fc65b
|
Subproject commit ac9744ab71bc899c7954239fadbad605521c4b0c
|
||||||
Loading…
Reference in New Issue