[core] Fix binder for system server
This commit is contained in:
parent
fbe39af620
commit
85e6b88bf5
|
|
@ -197,7 +197,9 @@ namespace lspd {
|
|||
void
|
||||
Context::OnNativeForkSystemServerPost(JNIEnv *env, jint res) {
|
||||
if (res != 0) return;
|
||||
auto binder = Service::instance()->RequestBinder(env);
|
||||
LoadDex(env);
|
||||
Service::instance()->HookBridge(*this, env);
|
||||
auto binder = Service::instance()->RequestBinderForSystemServer(env);
|
||||
if (binder) {
|
||||
if (void *buf = mmap(nullptr, 1, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1,
|
||||
|
|
@ -208,14 +210,15 @@ namespace lspd {
|
|||
} else {
|
||||
munmap(buf, 1);
|
||||
}
|
||||
} else {
|
||||
skip_ = true;
|
||||
LOGD("skip injecting into android because no module is hooking it");
|
||||
}
|
||||
LoadDex(env);
|
||||
if (!skip_ && binder) {
|
||||
if (!skip_) {
|
||||
InstallInlineHooks();
|
||||
Init(env);
|
||||
FindAndCall(env, "forkSystemServerPost", "(Landroid/os/IBinder;)V", binder);
|
||||
}
|
||||
Service::instance()->HookBridge(*this, env);
|
||||
}
|
||||
|
||||
void Context::OnNativeForkAndSpecializePre(JNIEnv *env,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@
|
|||
#include "JNIHelper.h"
|
||||
|
||||
namespace lspd {
|
||||
jboolean Service::exec_transact_replace(jboolean *res, JNIEnv *env, [[maybe_unused]] jobject obj, va_list args) {
|
||||
jboolean
|
||||
Service::exec_transact_replace(jboolean *res, JNIEnv *env, [[maybe_unused]] jobject obj,
|
||||
va_list args) {
|
||||
jint code;
|
||||
|
||||
va_list copy;
|
||||
|
|
@ -44,39 +46,40 @@ namespace lspd {
|
|||
initialized_ = true;
|
||||
|
||||
// ServiceManager
|
||||
serviceManagerClass_ = env->FindClass("android/os/ServiceManager");
|
||||
if (serviceManagerClass_) {
|
||||
serviceManagerClass_ = (jclass) env->NewGlobalRef(serviceManagerClass_);
|
||||
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;
|
||||
}
|
||||
getServiceMethod_ = env->GetStaticMethodID(serviceManagerClass_, "getService",
|
||||
"(Ljava/lang/String;)Landroid/os/IBinder;");
|
||||
if (!getServiceMethod_) {
|
||||
get_service_method_ = env->GetStaticMethodID(service_manager_class_, "getService",
|
||||
"(Ljava/lang/String;)Landroid/os/IBinder;");
|
||||
if (!get_service_method_) {
|
||||
env->ExceptionClear();
|
||||
return;
|
||||
}
|
||||
|
||||
// IBinder
|
||||
jclass iBinderClass = env->FindClass("android/os/IBinder");
|
||||
transactMethod_ = env->GetMethodID(iBinderClass, "transact",
|
||||
"(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z");
|
||||
jclass ibinder_class = env->FindClass("android/os/IBinder");
|
||||
transact_method_ = env->GetMethodID(ibinder_class, "transact",
|
||||
"(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z");
|
||||
|
||||
// Parcel
|
||||
parcelClass_ = env->FindClass("android/os/Parcel");
|
||||
if (parcelClass_) parcelClass_ = (jclass) env->NewGlobalRef(parcelClass_);
|
||||
obtainMethod_ = env->GetStaticMethodID(parcelClass_, "obtain", "()Landroid/os/Parcel;");
|
||||
recycleMethod_ = env->GetMethodID(parcelClass_, "recycle", "()V");
|
||||
writeInterfaceTokenMethod_ = env->GetMethodID(parcelClass_, "writeInterfaceToken",
|
||||
"(Ljava/lang/String;)V");
|
||||
writeIntMethod_ = env->GetMethodID(parcelClass_, "writeInt", "(I)V");
|
||||
writeStringMethod_ = env->GetMethodID(parcelClass_, "writeString", "(Ljava/lang/String;)V");
|
||||
readExceptionMethod_ = env->GetMethodID(parcelClass_, "readException", "()V");
|
||||
readStrongBinderMethod_ = env->GetMethodID(parcelClass_, "readStrongBinder",
|
||||
"()Landroid/os/IBinder;");
|
||||
createStringArray_ = env->GetMethodID(parcelClass_, "createStringArray",
|
||||
"()[Ljava/lang/String;");
|
||||
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");
|
||||
// writeStringMethod_ = env->GetMethodID(parcel_class_, "writeString",
|
||||
// "(Ljava/lang/String;)V");
|
||||
read_exception_method_ = env->GetMethodID(parcel_class_, "readException", "()V");
|
||||
read_strong_binder_method_ = env->GetMethodID(parcel_class_, "readStrongBinder",
|
||||
"()Landroid/os/IBinder;");
|
||||
// createStringArray_ = env->GetMethodID(parcel_class_, "createStringArray",
|
||||
// "()[Ljava/lang/String;");
|
||||
|
||||
deadObjectExceptionClass_ = env->FindClass("android/os/DeadObjectException");
|
||||
if (deadObjectExceptionClass_)
|
||||
|
|
@ -94,16 +97,16 @@ namespace lspd {
|
|||
return;
|
||||
}
|
||||
bridge_service_class_ = (jclass) env->NewGlobalRef(bridge_service_class_);
|
||||
exec_transact_replace_methodID_ = env->GetStaticMethodID(bridge_service_class_,
|
||||
"execTransact",
|
||||
"(IJJI)Z");
|
||||
exec_transact_replace_methodID_ = JNI_GetStaticMethodID(env, bridge_service_class_,
|
||||
"execTransact",
|
||||
"(IJJI)Z");
|
||||
if (!exec_transact_replace_methodID_) {
|
||||
LOGE("execTransact class not found");
|
||||
return;
|
||||
}
|
||||
|
||||
ScopedLocalRef<jclass> binderClass(env, env->FindClass("android/os/Binder"));
|
||||
exec_transact_backup_methodID_ = env->GetMethodID(binderClass.get(), "execTransact",
|
||||
exec_transact_backup_methodID_ = JNI_GetMethodID(env, binderClass.get(), "execTransact",
|
||||
"(IJJI)Z");
|
||||
auto set_table_override = reinterpret_cast<void (*)(
|
||||
JNINativeInterface *)>(DobbySymbolResolver(nullptr,
|
||||
|
|
@ -129,32 +132,31 @@ namespace lspd {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
auto bridgeServiceName = env->NewStringUTF(BRIDGE_SERVICE_NAME.data());
|
||||
auto bridgeService = JNI_CallStaticObjectMethod(env, serviceManagerClass_,
|
||||
getServiceMethod_, bridgeServiceName);
|
||||
auto bridgeService = JNI_CallStaticObjectMethod(env, service_manager_class_,
|
||||
get_service_method_, bridgeServiceName);
|
||||
if (!bridgeService) {
|
||||
LOGD("can't get %s", BRIDGE_SERVICE_NAME.data());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto data = JNI_CallStaticObjectMethod(env, parcelClass_, obtainMethod_);
|
||||
auto reply = JNI_CallStaticObjectMethod(env, parcelClass_, obtainMethod_);
|
||||
auto data = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_);
|
||||
auto reply = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_);
|
||||
|
||||
auto descriptor = env->NewStringUTF(BRIDGE_SERVICE_DESCRIPTOR.data());
|
||||
JNI_CallVoidMethod(env, data, writeInterfaceTokenMethod_, descriptor);
|
||||
JNI_CallVoidMethod(env, data, writeIntMethod_, BRIDGE_ACTION_GET_BINDER);
|
||||
JNI_CallVoidMethod(env, data, write_interface_token_method_, descriptor);
|
||||
JNI_CallVoidMethod(env, data, write_int_method_, BRIDGE_ACTION_GET_BINDER);
|
||||
|
||||
auto res = JNI_CallBooleanMethod(env, bridgeService, transactMethod_,
|
||||
auto res = JNI_CallBooleanMethod(env, bridgeService, transact_method_,
|
||||
BRIDGE_TRANSACTION_CODE,
|
||||
data,
|
||||
reply, 0);
|
||||
|
||||
jobject service = nullptr;
|
||||
if (res) {
|
||||
env->CallVoidMethod(reply, readExceptionMethod_);
|
||||
env->CallVoidMethod(reply, read_exception_method_);
|
||||
if (!ClearException(env)) {
|
||||
service = JNI_CallObjectMethod(env, reply, readStrongBinderMethod_);
|
||||
service = JNI_CallObjectMethod(env, reply, read_strong_binder_method_);
|
||||
}
|
||||
}
|
||||
JNI_CallVoidMethod(env, data, recycleMethod_);
|
||||
|
|
@ -162,4 +164,17 @@ namespace lspd {
|
|||
|
||||
return service;
|
||||
}
|
||||
|
||||
jobject Service::RequestBinderForSystemServer(JNIEnv *env) {
|
||||
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;
|
||||
}
|
||||
auto method = JNI_GetStaticMethodID(env, bridge_service_class_, "getApplicationServiceForSystemServer", "(Landroid/os/IBinder;)Landroid/os/IBinder;");
|
||||
auto app_binder = JNI_CallStaticObjectMethod(env, bridge_service_class_, method, binder);
|
||||
return app_binder;
|
||||
}
|
||||
}
|
||||
|
|
@ -13,8 +13,9 @@ using namespace std::literals::string_view_literals;
|
|||
namespace lspd {
|
||||
class Service {
|
||||
constexpr static jint BRIDGE_TRANSACTION_CODE = 1598837584;
|
||||
constexpr static auto BRIDGE_SERVICE_DESCRIPTOR = "android.app.IActivityManager"sv;
|
||||
constexpr static auto BRIDGE_SERVICE_DESCRIPTOR = "LSPosed"sv;
|
||||
constexpr static auto BRIDGE_SERVICE_NAME = "activity"sv;
|
||||
constexpr static auto SYSTEM_SERVER_BRIDGE_SERVICE_NAME = "serial"sv;
|
||||
constexpr static jint BRIDGE_ACTION_GET_BINDER = 2;
|
||||
|
||||
public:
|
||||
|
|
@ -32,6 +33,8 @@ namespace lspd {
|
|||
|
||||
jobject RequestBinder(JNIEnv *env);
|
||||
|
||||
jobject RequestBinderForSystemServer(JNIEnv *env);
|
||||
|
||||
private:
|
||||
inline static std::unique_ptr<Service> instance_ = std::make_unique<Service>();
|
||||
bool initialized_ = false;
|
||||
|
|
@ -52,20 +55,18 @@ namespace lspd {
|
|||
jclass bridge_service_class_ = nullptr;
|
||||
jmethodID exec_transact_replace_methodID_ = nullptr;
|
||||
|
||||
jclass serviceManagerClass_ = nullptr;
|
||||
jmethodID getServiceMethod_ = nullptr;
|
||||
jclass service_manager_class_ = nullptr;
|
||||
jmethodID get_service_method_ = nullptr;
|
||||
|
||||
jmethodID transactMethod_ = nullptr;
|
||||
jmethodID transact_method_ = nullptr;
|
||||
|
||||
jclass parcelClass_ = nullptr;
|
||||
jmethodID obtainMethod_ = nullptr;
|
||||
jclass parcel_class_ = nullptr;
|
||||
jmethodID obtain_method_ = nullptr;
|
||||
jmethodID recycleMethod_ = nullptr;
|
||||
jmethodID writeInterfaceTokenMethod_ = nullptr;
|
||||
jmethodID writeIntMethod_ = nullptr;
|
||||
jmethodID writeStringMethod_ = nullptr;
|
||||
jmethodID readExceptionMethod_ = nullptr;
|
||||
jmethodID readStrongBinderMethod_ = nullptr;
|
||||
jmethodID createStringArray_ = nullptr;
|
||||
jmethodID write_interface_token_method_ = nullptr;
|
||||
jmethodID write_int_method_ = nullptr;
|
||||
jmethodID read_exception_method_ = nullptr;
|
||||
jmethodID read_strong_binder_method_ = nullptr;
|
||||
|
||||
jclass deadObjectExceptionClass_ = nullptr;
|
||||
|
||||
|
|
|
|||
|
|
@ -104,28 +104,12 @@ public class Main implements KeepAll {
|
|||
return getEdxpImpl().getVariant();
|
||||
}
|
||||
|
||||
private static void waitSystemService(String name) {
|
||||
while (android.os.ServiceManager.getService(name) == null) {
|
||||
try {
|
||||
Log.i(TAG, "service " + name + " is not started, wait 1s.");
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Log.i(TAG, Log.getStackTraceString(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
for (String arg : args) {
|
||||
if (arg.equals("--debug")) {
|
||||
DdmHandleAppName.setAppName("lspd", 0);
|
||||
}
|
||||
}
|
||||
waitSystemService("package");
|
||||
waitSystemService("activity");
|
||||
waitSystemService(Context.USER_SERVICE);
|
||||
waitSystemService(Context.APP_OPS_SERVICE);
|
||||
|
||||
ServiceManager.start();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import android.os.Parcel;
|
|||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
import android.os.Process;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -22,7 +23,7 @@ import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
|||
|
||||
public class BridgeService {
|
||||
private static final int TRANSACTION_CODE = ('_' << 24) | ('L' << 16) | ('S' << 8) | 'P';
|
||||
private static final String DESCRIPTOR = "android.app.IActivityManager";
|
||||
private static final String DESCRIPTOR = "LSPosed";
|
||||
private static final String SERVICE_NAME = "activity";
|
||||
|
||||
enum ACTION {
|
||||
|
|
@ -194,6 +195,7 @@ public class BridgeService {
|
|||
data.enforceInterface(DESCRIPTOR);
|
||||
|
||||
ACTION action = ACTION.values()[data.readInt()];
|
||||
|
||||
Log.d(TAG, "onTransact: action=" + action + ", callingUid=" + Binder.getCallingUid() + ", callingPid=" + Binder.getCallingPid());
|
||||
|
||||
switch (action) {
|
||||
|
|
@ -264,4 +266,17 @@ public class BridgeService {
|
|||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Keep
|
||||
public static IBinder getApplicationServiceForSystemServer(IBinder binder) {
|
||||
if (binder == null) return null;
|
||||
try {
|
||||
ILSPosedService service = ILSPosedService.Stub.asInterface(binder);
|
||||
ILSPApplicationService applicationService = service.requestApplicationService(Process.myUid(), Process.myPid());
|
||||
if (applicationService != null) applicationService.asBinder();
|
||||
} catch (Throwable e) {
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import android.os.RemoteException;
|
|||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
|
@ -22,6 +21,7 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
|
|||
handles.add(handle);
|
||||
int uid = Binder.getCallingUid();
|
||||
int pid = Binder.getCallingPid();
|
||||
|
||||
cache.add(new Pair<>(uid, pid));
|
||||
handle.linkToDeath(new DeathRecipient() {
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -11,24 +11,6 @@ import android.util.Log;
|
|||
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
||||
|
||||
public class LSPosedService extends ILSPosedService.Stub {
|
||||
LSPosedService() {
|
||||
BridgeService.send(this, new BridgeService.Listener() {
|
||||
@Override
|
||||
public void onSystemServerRestarted() {
|
||||
Log.w(TAG, "system restarted...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponseFromBridgeService(boolean response) {
|
||||
if (response) {
|
||||
Log.i(TAG, "sent service to bridge");
|
||||
} else {
|
||||
Log.w(TAG, "no response from bridge");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ILSPApplicationService requestApplicationService(int uid, int pid) {
|
||||
if (Binder.getCallingUid() != 1000) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package io.github.lsposed.lspd.service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
|
|
@ -9,6 +10,18 @@ public class ServiceManager {
|
|||
private static LSPApplicationService applicationService = null;
|
||||
private static LSPManagerService managerService = null;
|
||||
public static final String TAG = "LSPosedService";
|
||||
|
||||
private static void waitSystemService(String name) {
|
||||
while (android.os.ServiceManager.getService(name) == null) {
|
||||
try {
|
||||
Log.i(TAG, "service " + name + " is not started, wait 1s.");
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Log.i(TAG, Log.getStackTraceString(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// call by ourselves
|
||||
public static void start() {
|
||||
Log.i(TAG, "starting server...");
|
||||
|
|
@ -18,6 +31,30 @@ public class ServiceManager {
|
|||
moduleService = new LSPModuleService();
|
||||
applicationService = new LSPApplicationService();
|
||||
managerService = new LSPManagerService();
|
||||
|
||||
android.os.ServiceManager.addService("serial", mainService);
|
||||
|
||||
waitSystemService("package");
|
||||
waitSystemService("activity");
|
||||
waitSystemService(Context.USER_SERVICE);
|
||||
waitSystemService(Context.APP_OPS_SERVICE);
|
||||
|
||||
BridgeService.send(mainService, new BridgeService.Listener() {
|
||||
@Override
|
||||
public void onSystemServerRestarted() {
|
||||
Log.w(TAG, "system restarted...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponseFromBridgeService(boolean response) {
|
||||
if (response) {
|
||||
Log.i(TAG, "sent service to bridge");
|
||||
} else {
|
||||
Log.w(TAG, "no response from bridge");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Looper.loop();
|
||||
|
||||
Log.i(TAG, "server exited");
|
||||
|
|
|
|||
Loading…
Reference in New Issue