Hook Transact方法监控IPC流量

Nabila ·
更新时间:2024-11-13
· 849 次阅读

背景

Binder数据传输是有大小限制的。
oneway方式。手写MMAP初始化Binder服务(4M/2),ProcessState初始化BInder服务(1M-8K)/2。
非oneway方式。手写MMAP初始化Binder服务(4M),ProcessState初始化BInder服务(1M-8K)。
而且BInder的线程池默认是15个,15个线程共享这1MB-8KB的内存空间,所以实际传输大小会更加小。当数据传输达到限制的时候,就会抛出TransactionTooLargeException异常。
为了更加好的预防排查定位问题,我们可以hook transact方法监控整个APP的IPC流量。

方案

这里hook的是系统的Service,我们自己生成的Service也可以用这种思想实现。不过注意的是。API28开始asInterface方法,被定义为黑名单接口,所以这个方案只能在TargetSdk28以下使用,omg。

private fun hookService(context: Context, serviceName: String, interfaceName: String): Any { val serviceManager = Class.forName("android.os.ServiceManager") val getServiceMethod = serviceManager.getDeclaredMethod("getService", String::class.java) getServiceMethod.isAccessible = true val serviceBinder = getServiceMethod.invoke(null, serviceName) val interfaceStubClass = Class.forName("$interfaceName\$Stub") val asInterfaceMethod = interfaceStubClass.getDeclaredMethod("asInterface", IBinder::class.java) val serviceBinderImplProxy = Proxy.newProxyInstance(context.classLoader, arrayOf(IBinder::class.java)) { _, method, args -> Log.e("demoKillerTag", "method=$method") Log.e("demoKillerTag", Thread.currentThread().stackTrace.contentDeepToString()) if (method.name == "transact") { Log.e("demoKillerTag", "transact data.size=" + (args[1] as Parcel).dataSize()) } method.invoke(serviceBinder, *(args ?: emptyArray())) } val sCache = serviceManager.getDeclaredField("sCache") sCache.isAccessible = true val cacheMap = sCache.get(null) as MutableMap cacheMap[serviceName] = serviceBinderImplProxy as IBinder return asInterfaceMethod.invoke(null, serviceBinderImplProxy) }

由于Android做了Binder缓存,需要替换。然后APP内调用PackageManager的方法都会得到监控。

fun hookPackageManager(context: Context) { val packageManager = context.packageManager val field = packageManager::class.java.getDeclaredField("mPM") field.isAccessible = true field.set(packageManager, hookService(context, "package", "android.content.pm.IPackageManager")) }
作者:demokiller



ipc

需要 登录 后方可回复, 如果你还没有账号请 注册新账号
相关文章