feat: Add IInputMethodManager proxy and refactor IActivityManagerProxy's GetContentProvider hook for improved content provider resolution.

This commit is contained in:
alex5402
2026-01-31 01:01:53 +05:30
parent 7f044c4f1d
commit d188e0891c
4 changed files with 140 additions and 13 deletions
@@ -91,6 +91,7 @@ import top.niunaijun.blackbox.utils.compat.BuildCompat;
import top.niunaijun.blackbox.fake.service.ISettingsProviderProxy;
import top.niunaijun.blackbox.fake.service.FeatureFlagUtilsProxy;
import top.niunaijun.blackbox.fake.service.WorkManagerProxy;
import top.niunaijun.blackbox.fake.service.IInputMethodManagerProxy;
/**
* updated by alex5402 on 3/30/21.
@@ -176,6 +177,7 @@ public class HookManager {
addInjector(new IMediaRouterServiceProxy());
addInjector(new IPowerManagerProxy());
addInjector(new IContextHubServiceProxy());
addInjector(new IInputMethodManagerProxy());
addInjector(new IVibratorServiceProxy());
addInjector(new IPersistentDataBlockServiceProxy());
addInjector(AppInstrumentation.get());
@@ -139,21 +139,87 @@ public class IActivityManagerProxy extends ClassInvocationStub {
public static class GetContentProvider extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
try {
// Try to use the original method first
Object result = method.invoke(who, args);
if (result != null) {
return result;
int authIndex = getAuthIndex();
Object auth = args[authIndex];
Object content = null;
if (auth instanceof String) {
if (ProxyManifest.isProxy((String) auth)) {
return method.invoke(who, args);
}
// If original method fails, return null to prevent crashes
Slog.w(TAG, "getContentProvider failed, returning null to prevent crash");
return null;
} catch (Exception e) {
Slog.w(TAG, "Error in getContentProvider, returning null: " + e.getMessage());
return null;
if (BuildCompat.isQ()) {
args[1] = BlackBoxCore.getHostPkg();
}
if (auth.equals("settings")
|| auth.equals("media")
|| auth.equals("telephony")
|| ((String) auth).contains("com.google.android.gms")
|| ((String) auth).contains("com.android.vending")
|| ((String) auth).contains("com.google.android.gsf")
|| auth.equals("com.google.android.gms.chimera")
|| auth.equals("com.huawei.android.launcher.settings")
|| auth.equals("com.hihonor.android.launcher.settings")) {
content = method.invoke(who, args);
ContentProviderDelegate.update(content, (String) auth);
return content;
} else {
// Log.d(TAG, "hook getContentProvider: " + auth);
ProviderInfo providerInfo = BlackBoxCore.getBPackageManager()
.resolveContentProvider(
(String) auth, GET_META_DATA, BActivityThread.getUserId());
if (providerInfo == null) {
// Fallback removed to avoid using original Google services
return null;
}
// Log.d(TAG, "hook app: " + auth);
IBinder providerBinder = null;
if (BActivityThread.getAppPid() != -1) {
AppConfig appConfig = BlackBoxCore.getBActivityManager()
.initProcess(
providerInfo.packageName,
providerInfo.processName,
BActivityThread.getUserId());
if (appConfig.bPID != BActivityThread.getAppPid()) {
providerBinder = BlackBoxCore.getBActivityManager()
.acquireContentProviderClient(providerInfo);
}
args[authIndex] = ProxyManifest.getProxyAuthorities(appConfig.bPID);
args[getUserIndex()] = BlackBoxCore.getHostUserId();
}
if (providerBinder == null)
return null;
content = method.invoke(who, args);
Reflector.with(content).field("info").set(providerInfo);
Reflector.with(content)
.field("provider")
.set(
new ContentProviderStub()
.wrapper(
BRContentProviderNative.get().asInterface(providerBinder),
providerInfo.packageName));
}
return content;
}
return method.invoke(who, args);
}
protected int getAuthIndex() {
// 10.0
if (BuildCompat.isQ()) {
return 2;
} else {
return 1;
}
}
protected int getUserIndex() {
return getAuthIndex() + 1;
}
}
@@ -0,0 +1,51 @@
package top.niunaijun.blackbox.fake.service;
import android.content.Context;
import android.os.IBinder;
import java.lang.reflect.Method;
import black.android.os.BRServiceManager;
import top.niunaijun.blackbox.fake.hook.BinderInvocationStub;
import top.niunaijun.blackbox.fake.hook.MethodHook;
import top.niunaijun.blackbox.fake.hook.ProxyMethod;
import top.niunaijun.blackbox.fake.hook.ScanClass;
/**
* Created by Milk on 2021/4/26.
* * ∧_∧
* (`・ω・∥
* 丶 つ0
* しーJ
*/
@ScanClass(IInputMethodManagerProxy.class)
public class IInputMethodManagerProxy extends BinderInvocationStub {
public static final String TAG = "IInputMethodManagerProxy";
public IInputMethodManagerProxy() {
super(BRServiceManager.get().getService(Context.INPUT_METHOD_SERVICE));
}
@Override
protected Object getWho() {
return BRServiceManager.get().getService(Context.INPUT_METHOD_SERVICE);
}
@Override
protected void inject(Object baseInvocation, Object proxyInvocation) {
replaceSystemService(Context.INPUT_METHOD_SERVICE);
}
@Override
public boolean isBadEnv() {
return false;
}
@ProxyMethod("startInputOrWindowGainedFocus")
public static class StartInputOrWindowGainedFocus extends MethodHook {
@Override
protected Object hook(Object who, Method method, Object[] args) throws Throwable {
return method.invoke(who, args);
}
}
}
@@ -28,6 +28,14 @@ public class WebViewProxy extends ClassInvocationStub {
super();
}
/**
* getWho() returns null and inject() is empty because this class hooks
* instance/static methods on WebView class itself, NOT a system service binder.
*
* Unlike binder proxies (e.g., IActivityManagerProxy) that replace services
* in ServiceManager.sCache, class proxies use @ProxyMethod inner classes
* to intercept specific methods via reflection/instrumentation.
*/
@Override
protected Object getWho() {
return null; // Not needed for class method hooks