[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
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,

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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) {

View File

@ -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");