investigate

This commit is contained in:
5ec1cff
2024-07-17 20:03:39 +08:00
parent 49554a8bbd
commit ebdaf87061
7 changed files with 275 additions and 7 deletions

View File

@@ -0,0 +1,163 @@
/*
* Copyright (C) 2005 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <binder/Common.h>
#include <binder/IInterface.h>
#include <utils/Vector.h>
#include <utils/String16.h>
#include <optional>
namespace android {
// ----------------------------------------------------------------------
/**
* Service manager for C++ services.
*
* IInterface is only for legacy ABI compatibility
*/
class LIBBINDER_EXPORTED IServiceManager : public IInterface {
public:
// for ABI compatibility
virtual const String16 &getInterfaceDescriptor() const;
IServiceManager();
virtual ~IServiceManager();
/**
* Must match values in IServiceManager.aidl
*/
/* Allows services to dump sections according to priorities. */
static const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0;
static const int DUMP_FLAG_PRIORITY_HIGH = 1 << 1;
static const int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2;
/**
* Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the
* same priority as NORMAL priority but the services are not called with dump priority
* arguments.
*/
static const int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3;
static const int DUMP_FLAG_PRIORITY_ALL = DUMP_FLAG_PRIORITY_CRITICAL |
DUMP_FLAG_PRIORITY_HIGH |
DUMP_FLAG_PRIORITY_NORMAL |
DUMP_FLAG_PRIORITY_DEFAULT;
static const int DUMP_FLAG_PROTO = 1 << 4;
/**
* Retrieve an existing service, blocking for a few seconds if it doesn't yet exist. This
* does polling. A more efficient way to make sure you unblock as soon as the service is
* available is to use waitForService or to use service notifications.
*
* Warning: when using this API, typically, you should call it in a loop. It's dangerous to
* assume that nullptr could mean that the service is not available. The service could just
* be starting. Generally, whether a service exists, this information should be declared
* externally (for instance, an Android feature might imply the existence of a service,
* a system property, or in the case of services in the VINTF manifest, it can be checked
* with isDeclared).
*/
[[deprecated("this polls for 5s, prefer waitForService or checkService")]]
virtual sp<IBinder> getService(const String16 &name) const = 0;
/**
* Retrieve an existing service, non-blocking.
*/
virtual sp<IBinder> checkService(const String16 &name) const = 0;
/**
* Register a service.
*/
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t addService(const String16 &name, const sp<IBinder> &service,
bool allowIsolated = false,
int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) = 0;
/**
* Return list of all existing services.
*/
// NOLINTNEXTLINE(google-default-arguments)
virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
/**
* Efficiently wait for a service.
*
* Returns nullptr only for permission problem or fatal error.
*/
virtual sp<IBinder> waitForService(const String16 &name) = 0;
/**
* Check if a service is declared (e.g. VINTF manifest).
*
* If this returns true, waitForService should always be able to return the
* service.
*/
virtual bool isDeclared(const String16 &name) = 0;
/**
* Get all instances of a service as declared in the VINTF manifest
*/
virtual Vector<String16> getDeclaredInstances(const String16 &interface) = 0;
/**
* If this instance is updatable via an APEX, returns the APEX with which
* this can be updated.
*/
virtual std::optional<String16> updatableViaApex(const String16 &name) = 0;
/**
* Returns all instances which are updatable via the APEX. Instance names are fully qualified
* like `pack.age.IFoo/default`.
*/
virtual Vector<String16> getUpdatableNames(const String16 &apexName) = 0;
/**
* If this instance has declared remote connection information, returns
* the ConnectionInfo.
*/
struct ConnectionInfo {
std::string ipAddress;
unsigned int port;
};
virtual std::optional<ConnectionInfo> getConnectionInfo(const String16 &name) = 0;
struct LocalRegistrationCallback : public virtual RefBase {
virtual void
onServiceRegistration(const String16 &instance, const sp<IBinder> &binder) = 0;
virtual ~LocalRegistrationCallback() {}
};
virtual status_t registerForNotifications(const String16 &name,
const sp<LocalRegistrationCallback> &callback) = 0;
virtual status_t unregisterForNotifications(const String16 &name,
const sp<LocalRegistrationCallback> &callback) = 0;
struct ServiceDebugInfo {
std::string name;
int pid;
};
virtual std::vector<ServiceDebugInfo> getServiceDebugInfo() = 0;
};
LIBBINDER_EXPORTED sp<IServiceManager> defaultServiceManager();
LIBBINDER_EXPORTED void setDefaultServiceManager(const sp<IServiceManager> &sm);
} // namespace android

View File

@@ -1,6 +1,40 @@
#pragma once
/*
* Copyright (C) 2005 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_STRING16_H
#define ANDROID_STRING16_H
// TODO
namespace android {
class String16 {};
}
class String16 {
public:
String16();
String16(const String16 &o);
String16(String16 &&o) noexcept;
explicit String16(const char *o);
~String16();
private:
const char16_t *mString;
};
} // namespace android
#endif // ANDROID_STRING16_H

View File

@@ -4,6 +4,7 @@
#include "binder/IPCThreadState.h"
#include "binder/Parcel.h"
#include "binder/IInterface.h"
#include "binder/IServiceManager.h"
namespace android {
// IBinder.h
@@ -148,4 +149,17 @@ namespace android {
int32_t Parcel::readExceptionCode() const { return 0; }
int Parcel::readFileDescriptor() const { return 0; }
// IServiceManager.h
const String16 &IServiceManager::getInterfaceDescriptor() const {
return {};
}
IServiceManager::IServiceManager() {}
IServiceManager::~IServiceManager() {}
sp<IServiceManager> defaultServiceManager() { return nullptr; }
void setDefaultServiceManager(const sp<IServiceManager> &sm) {}
}

View File

@@ -1,5 +1,6 @@
#include "utils/StrongPointer.h"
#include "utils/RefBase.h"
#include "utils/String16.h"
namespace android {
void RefBase::incStrong(const void *id) const {
@@ -49,4 +50,14 @@ namespace android {
bool RefBase::weakref_type::attemptIncWeak(const void* id) { return false; }
void sp_report_race() {}
String16::String16() {}
String16::String16(const String16 &o) {}
String16::String16(String16 &&o) noexcept {}
String16::String16(const char *o) {}
String16::~String16() {}
}

View File

@@ -5,6 +5,7 @@
#include <binder/Binder.h>
#include <utils/StrongPointer.h>
#include <binder/Common.h>
#include <binder/IServiceManager.h>
#include <utility>
#include <map>
@@ -63,7 +64,7 @@ CREATE_MEM_HOOK_STUB_ENTRY(
LOGD("transact: binder=%p code=%d", thiz, code);
if (IPCThreadState::self()->getCallingUid() == 0 && reply != nullptr &&
thiz != gBinderInterceptor) [[unlikely]] {
if (code == 0xdeadbeef) {
if (code == 0xadbeef) {
LOGD("request binder interceptor");
reply->writeStrongBinder(gBinderInterceptor);
return OK;
@@ -268,6 +269,38 @@ bool hookBinder() {
}
LOGI("hook success!");
gBinderInterceptor = sp<BinderInterceptor>::make();
auto transactSym = handler.get_symbol("_ZN7android7BBinder8transactEjRKNS_6ParcelEPS1_j");
auto &img = handler.img;
auto [vtSym, vtSize] = img.getSymInfo("_ZTVN7android7BBinderE");
auto sm = defaultServiceManager();
if (sm == nullptr) {
LOGE("service manager is null!");
return false;
} else {
int transactPos = -1;
auto svc = sm->checkService(String16("android.system.keystore2.IKeystoreService/default"));
if (svc != nullptr) {
for (int i = 0; i < vtSize / sizeof(uintptr_t); i++) {
auto val = *((uintptr_t *) vtSym + i);
auto name = img.findSymbolNameForAddr(val);
LOGI("vtable %i: %p %s", i, val, name.c_str());
if (val == (uintptr_t) transactSym) {
transactPos = i - 3;
LOGI("transact pos %d", transactPos);
}
}
if (transactPos >= 0) {
auto svcTransactAddr = *(*reinterpret_cast<void ***>(svc.get()) + transactPos);
LOGI("transact of svc %p: %p", svc.get(), svcTransactAddr);
} else {
LOGE("transactPos not found!");
return false;
}
} else {
LOGE("IKeystoreService not found!");
return false;
}
}
return true;
}

View File

@@ -88,12 +88,18 @@ object KeystoreInterceptor : BinderInterceptor() {
return Skip
}
private var tried = false
fun tryRunKeystoreInterceptor(): Boolean {
Logger.i("trying to register keystore interceptor ...")
val b = ServiceManager.getService("android.system.keystore2.IKeystoreService/default") ?: return false
val bd = getBinderBackdoor(b)
if (bd == null) {
// no binder hook, try inject
if (tried) {
Logger.e("inject tried but still has no backdoor, exit")
exitProcess(1)
}
Logger.i("trying to inject keystore ...")
val p = Runtime.getRuntime().exec(
arrayOf(
@@ -108,6 +114,7 @@ object KeystoreInterceptor : BinderInterceptor() {
Logger.e("failed to inject! daemon exit")
exitProcess(1)
}
tried = true
return false
}
val ks = IKeystoreService.Stub.asInterface(b)

View File

@@ -3,6 +3,7 @@ package io.github.a13e300.tricky_store.binder
import android.os.Binder
import android.os.IBinder
import android.os.Parcel
import io.github.a13e300.tricky_store.Logger
open class BinderInterceptor : Binder() {
sealed class Result
@@ -16,9 +17,14 @@ open class BinderInterceptor : Binder() {
val data = Parcel.obtain()
val reply = Parcel.obtain()
try {
b.transact(0xdeadbeef.toInt(), data, reply, 0)
if (!b.transact(0xadbeef, data, reply, 0)) {
Logger.e("remote return false!")
return null
}
Logger.d("remote return true!")
return reply.readStrongBinder()
} catch (ignored: Throwable) {
} catch (t: Throwable) {
Logger.e("failed to read binder", t)
return null
} finally {
data.recycle()