Hook Transact方法监控IPC流量

背景

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<String, IBinder>
            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"))
        }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值