[core] Fix binder for system server

This commit is contained in:
LoveSy 2021-02-17 23:32:10 +08:00 committed by tehcneko
parent fbe39af620
commit 85e6b88bf5
8 changed files with 126 additions and 89 deletions

View File

@ -197,7 +197,9 @@ namespace lspd {
void void
Context::OnNativeForkSystemServerPost(JNIEnv *env, jint res) { Context::OnNativeForkSystemServerPost(JNIEnv *env, jint res) {
if (res != 0) return; 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 (binder) {
if (void *buf = mmap(nullptr, 1, PROT_READ | PROT_WRITE | PROT_EXEC, if (void *buf = mmap(nullptr, 1, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANONYMOUS | MAP_PRIVATE, -1, MAP_ANONYMOUS | MAP_PRIVATE, -1,
@ -208,14 +210,15 @@ namespace lspd {
} else { } else {
munmap(buf, 1); munmap(buf, 1);
} }
} else {
skip_ = true;
LOGD("skip injecting into android because no module is hooking it");
} }
LoadDex(env); if (!skip_) {
if (!skip_ && binder) {
InstallInlineHooks(); InstallInlineHooks();
Init(env); Init(env);
FindAndCall(env, "forkSystemServerPost", "(Landroid/os/IBinder;)V", binder); FindAndCall(env, "forkSystemServerPost", "(Landroid/os/IBinder;)V", binder);
} }
Service::instance()->HookBridge(*this, env);
} }
void Context::OnNativeForkAndSpecializePre(JNIEnv *env, void Context::OnNativeForkAndSpecializePre(JNIEnv *env,

View File

@ -10,7 +10,9 @@
#include "JNIHelper.h" #include "JNIHelper.h"
namespace lspd { 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; jint code;
va_list copy; va_list copy;
@ -44,39 +46,40 @@ namespace lspd {
initialized_ = true; initialized_ = true;
// ServiceManager // ServiceManager
serviceManagerClass_ = env->FindClass("android/os/ServiceManager"); service_manager_class_ = env->FindClass("android/os/ServiceManager");
if (serviceManagerClass_) { if (service_manager_class_) {
serviceManagerClass_ = (jclass) env->NewGlobalRef(serviceManagerClass_); service_manager_class_ = (jclass) env->NewGlobalRef(service_manager_class_);
} else { } else {
env->ExceptionClear(); env->ExceptionClear();
return; return;
} }
getServiceMethod_ = env->GetStaticMethodID(serviceManagerClass_, "getService", get_service_method_ = env->GetStaticMethodID(service_manager_class_, "getService",
"(Ljava/lang/String;)Landroid/os/IBinder;"); "(Ljava/lang/String;)Landroid/os/IBinder;");
if (!getServiceMethod_) { if (!get_service_method_) {
env->ExceptionClear(); env->ExceptionClear();
return; return;
} }
// IBinder // IBinder
jclass iBinderClass = env->FindClass("android/os/IBinder"); jclass ibinder_class = env->FindClass("android/os/IBinder");
transactMethod_ = env->GetMethodID(iBinderClass, "transact", transact_method_ = env->GetMethodID(ibinder_class, "transact",
"(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z"); "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z");
// Parcel // Parcel
parcelClass_ = env->FindClass("android/os/Parcel"); parcel_class_ = env->FindClass("android/os/Parcel");
if (parcelClass_) parcelClass_ = (jclass) env->NewGlobalRef(parcelClass_); if (parcel_class_) parcel_class_ = (jclass) env->NewGlobalRef(parcel_class_);
obtainMethod_ = env->GetStaticMethodID(parcelClass_, "obtain", "()Landroid/os/Parcel;"); obtain_method_ = env->GetStaticMethodID(parcel_class_, "obtain", "()Landroid/os/Parcel;");
recycleMethod_ = env->GetMethodID(parcelClass_, "recycle", "()V"); recycleMethod_ = env->GetMethodID(parcel_class_, "recycle", "()V");
writeInterfaceTokenMethod_ = env->GetMethodID(parcelClass_, "writeInterfaceToken", write_interface_token_method_ = env->GetMethodID(parcel_class_, "writeInterfaceToken",
"(Ljava/lang/String;)V"); "(Ljava/lang/String;)V");
writeIntMethod_ = env->GetMethodID(parcelClass_, "writeInt", "(I)V"); write_int_method_ = env->GetMethodID(parcel_class_, "writeInt", "(I)V");
writeStringMethod_ = env->GetMethodID(parcelClass_, "writeString", "(Ljava/lang/String;)V"); // writeStringMethod_ = env->GetMethodID(parcel_class_, "writeString",
readExceptionMethod_ = env->GetMethodID(parcelClass_, "readException", "()V"); // "(Ljava/lang/String;)V");
readStrongBinderMethod_ = env->GetMethodID(parcelClass_, "readStrongBinder", read_exception_method_ = env->GetMethodID(parcel_class_, "readException", "()V");
read_strong_binder_method_ = env->GetMethodID(parcel_class_, "readStrongBinder",
"()Landroid/os/IBinder;"); "()Landroid/os/IBinder;");
createStringArray_ = env->GetMethodID(parcelClass_, "createStringArray", // createStringArray_ = env->GetMethodID(parcel_class_, "createStringArray",
"()[Ljava/lang/String;"); // "()[Ljava/lang/String;");
deadObjectExceptionClass_ = env->FindClass("android/os/DeadObjectException"); deadObjectExceptionClass_ = env->FindClass("android/os/DeadObjectException");
if (deadObjectExceptionClass_) if (deadObjectExceptionClass_)
@ -94,7 +97,7 @@ namespace lspd {
return; return;
} }
bridge_service_class_ = (jclass) env->NewGlobalRef(bridge_service_class_); bridge_service_class_ = (jclass) env->NewGlobalRef(bridge_service_class_);
exec_transact_replace_methodID_ = env->GetStaticMethodID(bridge_service_class_, exec_transact_replace_methodID_ = JNI_GetStaticMethodID(env, bridge_service_class_,
"execTransact", "execTransact",
"(IJJI)Z"); "(IJJI)Z");
if (!exec_transact_replace_methodID_) { if (!exec_transact_replace_methodID_) {
@ -103,7 +106,7 @@ namespace lspd {
} }
ScopedLocalRef<jclass> binderClass(env, env->FindClass("android/os/Binder")); 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"); "(IJJI)Z");
auto set_table_override = reinterpret_cast<void (*)( auto set_table_override = reinterpret_cast<void (*)(
JNINativeInterface *)>(DobbySymbolResolver(nullptr, JNINativeInterface *)>(DobbySymbolResolver(nullptr,
@ -129,32 +132,31 @@ namespace lspd {
return nullptr; return nullptr;
} }
auto bridgeServiceName = env->NewStringUTF(BRIDGE_SERVICE_NAME.data()); auto bridgeServiceName = env->NewStringUTF(BRIDGE_SERVICE_NAME.data());
auto bridgeService = JNI_CallStaticObjectMethod(env, serviceManagerClass_, auto bridgeService = JNI_CallStaticObjectMethod(env, service_manager_class_,
getServiceMethod_, bridgeServiceName); get_service_method_, bridgeServiceName);
if (!bridgeService) { if (!bridgeService) {
LOGD("can't get %s", BRIDGE_SERVICE_NAME.data()); LOGD("can't get %s", BRIDGE_SERVICE_NAME.data());
return nullptr; return nullptr;
} }
auto data = JNI_CallStaticObjectMethod(env, parcelClass_, obtainMethod_); auto data = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_);
auto reply = JNI_CallStaticObjectMethod(env, parcelClass_, obtainMethod_); auto reply = JNI_CallStaticObjectMethod(env, parcel_class_, obtain_method_);
auto descriptor = env->NewStringUTF(BRIDGE_SERVICE_DESCRIPTOR.data()); auto descriptor = env->NewStringUTF(BRIDGE_SERVICE_DESCRIPTOR.data());
JNI_CallVoidMethod(env, data, writeInterfaceTokenMethod_, descriptor); JNI_CallVoidMethod(env, data, write_interface_token_method_, descriptor);
JNI_CallVoidMethod(env, data, writeIntMethod_, BRIDGE_ACTION_GET_BINDER); 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, BRIDGE_TRANSACTION_CODE,
data, data,
reply, 0); reply, 0);
jobject service = nullptr; jobject service = nullptr;
if (res) { if (res) {
env->CallVoidMethod(reply, readExceptionMethod_); env->CallVoidMethod(reply, read_exception_method_);
if (!ClearException(env)) { if (!ClearException(env)) {
service = JNI_CallObjectMethod(env, reply, readStrongBinderMethod_); service = JNI_CallObjectMethod(env, reply, read_strong_binder_method_);
} }
} }
JNI_CallVoidMethod(env, data, recycleMethod_); JNI_CallVoidMethod(env, data, recycleMethod_);
@ -162,4 +164,17 @@ namespace lspd {
return service; 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;
}
} }

View File

@ -13,8 +13,9 @@ using namespace std::literals::string_view_literals;
namespace lspd { namespace lspd {
class Service { class Service {
constexpr static jint BRIDGE_TRANSACTION_CODE = 1598837584; 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 BRIDGE_SERVICE_NAME = "activity"sv;
constexpr static auto SYSTEM_SERVER_BRIDGE_SERVICE_NAME = "serial"sv;
constexpr static jint BRIDGE_ACTION_GET_BINDER = 2; constexpr static jint BRIDGE_ACTION_GET_BINDER = 2;
public: public:
@ -32,6 +33,8 @@ namespace lspd {
jobject RequestBinder(JNIEnv *env); jobject RequestBinder(JNIEnv *env);
jobject RequestBinderForSystemServer(JNIEnv *env);
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;
@ -52,20 +55,18 @@ namespace lspd {
jclass bridge_service_class_ = nullptr; jclass bridge_service_class_ = nullptr;
jmethodID exec_transact_replace_methodID_ = nullptr; jmethodID exec_transact_replace_methodID_ = nullptr;
jclass serviceManagerClass_ = nullptr; jclass service_manager_class_ = nullptr;
jmethodID getServiceMethod_ = nullptr; jmethodID get_service_method_ = nullptr;
jmethodID transactMethod_ = nullptr; jmethodID transact_method_ = nullptr;
jclass parcelClass_ = nullptr; jclass parcel_class_ = nullptr;
jmethodID obtainMethod_ = nullptr; jmethodID obtain_method_ = nullptr;
jmethodID recycleMethod_ = nullptr; jmethodID recycleMethod_ = nullptr;
jmethodID writeInterfaceTokenMethod_ = nullptr; jmethodID write_interface_token_method_ = nullptr;
jmethodID writeIntMethod_ = nullptr; jmethodID write_int_method_ = nullptr;
jmethodID writeStringMethod_ = nullptr; jmethodID read_exception_method_ = nullptr;
jmethodID readExceptionMethod_ = nullptr; jmethodID read_strong_binder_method_ = nullptr;
jmethodID readStrongBinderMethod_ = nullptr;
jmethodID createStringArray_ = nullptr;
jclass deadObjectExceptionClass_ = nullptr; jclass deadObjectExceptionClass_ = nullptr;

View File

@ -104,28 +104,12 @@ public class Main implements KeepAll {
return getEdxpImpl().getVariant(); 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) { public static void main(String[] args) {
for (String arg : args) { for (String arg : args) {
if (arg.equals("--debug")) { if (arg.equals("--debug")) {
DdmHandleAppName.setAppName("lspd", 0); DdmHandleAppName.setAppName("lspd", 0);
} }
} }
waitSystemService("package");
waitSystemService("activity");
waitSystemService(Context.USER_SERVICE);
waitSystemService(Context.APP_OPS_SERVICE);
ServiceManager.start(); ServiceManager.start();
} }
} }

View File

@ -9,6 +9,7 @@ import android.os.Parcel;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.util.Log; import android.util.Log;
import android.os.Process;
import androidx.annotation.Keep; import androidx.annotation.Keep;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -22,7 +23,7 @@ import static io.github.lsposed.lspd.service.ServiceManager.TAG;
public class BridgeService { public class BridgeService {
private static final int TRANSACTION_CODE = ('_' << 24) | ('L' << 16) | ('S' << 8) | 'P'; 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"; private static final String SERVICE_NAME = "activity";
enum ACTION { enum ACTION {
@ -194,6 +195,7 @@ public class BridgeService {
data.enforceInterface(DESCRIPTOR); data.enforceInterface(DESCRIPTOR);
ACTION action = ACTION.values()[data.readInt()]; ACTION action = ACTION.values()[data.readInt()];
Log.d(TAG, "onTransact: action=" + action + ", callingUid=" + Binder.getCallingUid() + ", callingPid=" + Binder.getCallingPid()); Log.d(TAG, "onTransact: action=" + action + ", callingUid=" + Binder.getCallingUid() + ", callingPid=" + Binder.getCallingPid());
switch (action) { switch (action) {
@ -264,4 +266,17 @@ public class BridgeService {
return res; 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;
}
} }

View File

@ -6,7 +6,6 @@ import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -22,6 +21,7 @@ public class LSPApplicationService extends ILSPApplicationService.Stub {
handles.add(handle); handles.add(handle);
int uid = Binder.getCallingUid(); int uid = Binder.getCallingUid();
int pid = Binder.getCallingPid(); int pid = Binder.getCallingPid();
cache.add(new Pair<>(uid, pid)); cache.add(new Pair<>(uid, pid));
handle.linkToDeath(new DeathRecipient() { handle.linkToDeath(new DeathRecipient() {
@Override @Override

View File

@ -11,24 +11,6 @@ import android.util.Log;
import static io.github.lsposed.lspd.service.ServiceManager.TAG; import static io.github.lsposed.lspd.service.ServiceManager.TAG;
public class LSPosedService extends ILSPosedService.Stub { 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 @Override
public ILSPApplicationService requestApplicationService(int uid, int pid) { public ILSPApplicationService requestApplicationService(int uid, int pid) {
if (Binder.getCallingUid() != 1000) { if (Binder.getCallingUid() != 1000) {

View File

@ -1,5 +1,6 @@
package io.github.lsposed.lspd.service; package io.github.lsposed.lspd.service;
import android.content.Context;
import android.os.Looper; import android.os.Looper;
import android.util.Log; import android.util.Log;
@ -9,6 +10,18 @@ public class ServiceManager {
private static LSPApplicationService applicationService = null; private static LSPApplicationService applicationService = null;
private static LSPManagerService managerService = null; private static LSPManagerService managerService = null;
public static final String TAG = "LSPosedService"; 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 // call by ourselves
public static void start() { public static void start() {
Log.i(TAG, "starting server..."); Log.i(TAG, "starting server...");
@ -18,6 +31,30 @@ public class ServiceManager {
moduleService = new LSPModuleService(); moduleService = new LSPModuleService();
applicationService = new LSPApplicationService(); applicationService = new LSPApplicationService();
managerService = new LSPManagerService(); 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(); Looper.loop();
Log.i(TAG, "server exited"); Log.i(TAG, "server exited");