Android跨进程通信,binder传输数据过大导致客户端APP,Crash,异常捕获,监听异常的数值临界值,提前Hook拦截。

news2024/7/2 21:05:01

文章目录

  • Android跨进程通信,binder传输数据过大导致Crash,异常捕获,监听异常的数值临界值,提前Hook拦截。
    • 1.binder在做跨进程传输时,最大可以携带多少数据
      • 1.1有时候这个1m的崩溃系统捕获不到异常,
    • 2.监测异常,提前上报
    • Hook IActivityTaskManager
  • 扩展:Hook AMS绕过Manifest的Activity注册检测

Android跨进程通信,binder传输数据过大导致Crash,异常捕获,监听异常的数值临界值,提前Hook拦截。

Java Crash捕获

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Thread.UncaughtExceptionHandler uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
        Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
            Log.e("crash", "当前进程id:" + android.os.Process.myPid());
            Log.e("crash", Log.getStackTraceString(e));
            if (uncaughtExceptionHandler != null) {
                uncaughtExceptionHandler.uncaughtException(t, e);
            }
        });
    }
}

1.binder在做跨进程传输时,最大可以携带多少数据

测试代码,跨进程传输1m数据

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startBinding();
        mBtn = findViewById(R.id.btn);
        mBtn.setOnClickListener(v -> {
            Bundle bundle = new Bundle();
            bundle.putByteArray("binder_data", new byte[1 * 1024 * 1024]);
            Intent intent = new Intent();
            intent.putExtras(bundle);
            ComponentName componentName = new ComponentName("com.example.myapplication", "com.example.myapplication.MainActivity");
            intent.setComponent(componentName);
            startActivity(intent);
        });
    }

不出意外崩了

在这里插入图片描述

在这里插入图片描述

1.1有时候这个1m的崩溃系统捕获不到异常,

把数据传输从1M改成了800k测试

还是崩了,崩溃的数据量大概是500bk(不崩溃)-600kb(崩溃)之间。

在这里插入图片描述

核心log

在这里插入图片描述

IActivityTaskManager是个aidl文件;

IActivityTaskManager$Stub是binder服务端的类,运行在system进程的

在这里插入图片描述

Proxy对象是运行在我们app进程的,称之为binder代理

Proxy对象通过transact方法调用到Stub对象的onTransact方法。这个异常发生在App进程,所以代码捕获到了这个异常。

2.监测异常,提前上报

大概500k就是危险的极限大小,容易发生异常。

hook拦截startActivity的方法,到达一个危险的大小容易崩溃的时候,我们就上报。

android.os.BinderProxy.transact(BinderProxy.java:510)

这里面Parcel有个dataSize记录数据的大小

Hook IActivityTaskManager

看日志调用流程,在startActivity时候就可以拦截数据,Instrumentation.execStartActivity

Caused by: android.os.TransactionTooLargeException: data parcel size 1049052 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(BinderProxy.java:510)
at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:3823)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1705)
at android.app.Activity.startActivityForResult(Activity.java:5173) 

在这里插入图片描述

在这里插入图片描述

ActivityTaskManager对象

final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
return IActivityTaskManager.Stub.asInterface(b);

在这里插入图片描述

sCache,是个静态的ArrayMap对象:

@UnsupportedAppUsage
private static Map<String, IBinder> sCache = new ArrayMap<String, IBinder>();

反射换掉IActivityTaskManager对象的IBinder对象,IBinder有监控的transact方法。

invoke方法中,关注transact方法获得跨进程传输的参数的大小

IBinde的transact方法:Parcel data

public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
        throws RemoteException;
/**
 * Returns the total amount of data contained in the parcel.
 */
public final int dataSize() {
    return nativeDataSize(mNativePtr);
}

完整Demo

public static void hook() {
        Log.e(TAG, "hook: ");
        try {
            Class serviceManager = Class.forName("android.os.ServiceManager");
            Method getServiceMethod = serviceManager.getMethod("getService", String.class);

            Field sCacheField = serviceManager.getDeclaredField("sCache");
            sCacheField.setAccessible(true);
            Map<String, IBinder> sCache = (Map<String, IBinder>) sCacheField.get(null);
            Map<String, IBinder> sNewCache;
                sNewCache = new ArrayMap<>();
                sNewCache.putAll(sCache);
            IBinder activityTaskRemoteBinder = (IBinder) getServiceMethod.invoke(null, "activity_task");

            sNewCache.put("activity_task", (IBinder) Proxy.newProxyInstance(serviceManager.getClassLoader(),
                    new Class[]{IBinder.class},
                    new InvocationHandler() {
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            Log.e(TAG, "activity_task method = " + method.getName() + ", args = " + Arrays.toString(args));
                            if ("transact".equals(method.getName())) {
                                if (args != null && args.length > 1) {
                                    Object arg = args[1];
                                    if (arg instanceof Parcel) {
                                        Parcel parcelArg = (Parcel) arg;
                                        int dataSize = parcelArg.dataSize();
                                        if (dataSize > 300 * 1024) {
                                            // TODO 报警
                                            Log.e(TAG, Log.getStackTraceString(new RuntimeException("[error]TransactionTooLargeException:  300Kb:" + dataSize)));
                                            if (BuildConfig.DEBUG) {
                                                if (dataSize > 512 * 1024) {
                                                    throw new RuntimeException("[error]TransactionTooLargeException:300Kb:" + dataSize);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            return method.invoke(activityTaskRemoteBinder, args);
                        }
                    }));
            sCacheField.set(null, sNewCache);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

测试

在这里插入图片描述

从日志看出我们是hook系统服务成功了。

总结:

  1. binder数据量过大崩溃,Java异常捕获机制捕获不到,提前拦截。
  2. DEBUG,超过512k,崩溃可以看到日志;
  3. ServiceManager中的sCache获取到原来activity_task对应的IBinder实例对象; IBinder是接口,通过动态代理创造一个IBinder的代理对象IBinderProxy; 把IBinderProxy放到ServiceManager的sCache,Application attachBaseContext中调用Hook方法;

在这里插入图片描述

扩展:Hook AMS绕过Manifest的Activity注册检测

思路,先启动一个注册的代理的Activity,然后绕过manifest的检测后,把代理的Activity替换成未注册的

package com.example.myapplication;

import android.content.Intent;
import android.os.Handler;
import android.os.Message;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

public class HookUtil {

    private static final String TARGET_INTENT = "target_intent";

    // 使用代理的Activity替换需要启动的未注册的Activity
    public static void hookAMS() {
        try {
            Class<?> clazz = Class.forName("android.app.ActivityTaskManager");
            Field singletonField = clazz.getDeclaredField("IActivityTaskManagerSingleton");

            singletonField.setAccessible(true);
            Object singleton = singletonField.get(null);

            Class<?> singletonClass = Class.forName("android.util.Singleton");
            Field mInstanceField = singletonClass.getDeclaredField("mInstance");
            mInstanceField.setAccessible(true);
            Method getMethod = singletonClass.getMethod("get");
            Object mInstance = getMethod.invoke(singleton);

            Class IActivityTaskManagerClass = Class.forName("android.app.IActivityTaskManager");

            Object mInstanceProxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                    new Class[]{IActivityTaskManagerClass}, new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                            if ("startActivity".equals(method.getName())) {
                                int index = -1;

                                // 获取 Intent 参数在 args 数组中的index值
                                for (int i = 0; i < args.length; i++) {
                                    if (args[i] instanceof Intent) {
                                        index = i;
                                        break;
                                    }
                                }
                                // 生成代理proxyIntent
                                Intent proxyIntent = new Intent();
                                proxyIntent.setClassName("com.example.myapplication",
                                        ProxyActivity.class.getName());

                                // 保存原始的Intent对象
                                Intent intent = (Intent) args[index];
                                proxyIntent.putExtra(TARGET_INTENT, intent);

                                // 使用proxyIntent替换数组中的Intent
                                args[index] = proxyIntent;
                            }

                            // 被代理对象调用
                            return method.invoke(mInstance, args);
                        }
                    });

            // 用代理的对象替换系统的对象
            mInstanceField.set(singleton, mInstanceProxy);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 需要启动的未注册的Activity 替换回来  ProxyActivity
    public static void hookHandler() {
        try {
            Class<?> clazz = Class.forName("android.app.ActivityThread");

            Field activityThreadField = clazz.getDeclaredField("sCurrentActivityThread");
            activityThreadField.setAccessible(true);
            Object activityThread = activityThreadField.get(null);

            Field mHField = clazz.getDeclaredField("mH");
            mHField.setAccessible(true);
            final Handler mH = (Handler) mHField.get(activityThread);

            Field mCallbackField = Handler.class.getDeclaredField("mCallback");
            mCallbackField.setAccessible(true);

            mCallbackField.set(mH, new Handler.Callback() {

                @Override
                public boolean handleMessage(Message msg) {
                    switch (msg.what) {
                        case 159:
                            try {
                                Field mActivityCallbacksField = msg.obj.getClass()
                                        .getDeclaredField("mActivityCallbacks");
                                mActivityCallbacksField.setAccessible(true);
                                List mActivityCallbacks = (List) mActivityCallbacksField.get(msg.obj);

                                for (int i = 0; i < mActivityCallbacks.size(); i++) {
                                    if (mActivityCallbacks.get(i).getClass().getName()
                                            .equals("android.app.servertransaction.LaunchActivityItem")) {
                                        Object launchActivityItem = mActivityCallbacks.get(i);
                                        Field mIntentField = launchActivityItem.getClass()
                                                .getDeclaredField("mIntent");
                                        mIntentField.setAccessible(true);
                                        Intent proxyIntent = (Intent) mIntentField.get(launchActivityItem);

                                        Intent intent = proxyIntent.getParcelableExtra(TARGET_INTENT);
                                        if (intent != null) {
                                            mIntentField.set(launchActivityItem, intent);
                                        }
                                    }
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            break;
                    }
                    return false;
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1880287.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大模型系列课程学习-基于2080TI-22G魔改卡搭建双卡大模型训练平台(双系统)

1.选择合适的硬件配置 再配置电脑之前&#xff0c;需要确认自己需要的显存大小、主板、内存条、电源、散热等核心配件。经过前期调研&#xff0c;选择的硬件配置如下&#xff1a; &#xff08;1&#xff09;主板&#xff1a;华南X99_F8D(DDR4主板)&#xff0c;因为需要支持双卡…

springboot 3.x相比之前版本有什么区别

Spring Boot 3.x相比之前的版本&#xff08;尤其是Spring Boot 2.x&#xff09;&#xff0c;主要存在以下几个显著的区别和新特性&#xff1a; Java版本要求&#xff1a; Spring Boot 3.x要求至少使用Java 17作为最低版本&#xff0c;同时已经通过了Java 19的测试&#xff0c;…

【C语言】指针剖析(完结)

©作者:末央&#xff06; ©系列:C语言初阶(适合小白入门) ©说明:以凡人之笔墨&#xff0c;书写未来之大梦 目录 回调函数概念回调函数的使用 - qsort函数 sizeof/strlen深度理解概念手脑并用1.sizeof-数组/指针专题2.strlen-数组/指针专题 指针面试题专题 回调函…

C++ | Leetcode C++题解之第205题同构字符串

题目&#xff1a; 题解&#xff1a; class Solution { public:bool isIsomorphic(string s, string t) {unordered_map<char, char> s2t;unordered_map<char, char> t2s;int len s.length();for (int i 0; i < len; i) {char x s[i], y t[i];if ((s2t.coun…

HDFS详细介绍以及HDFS集群环境部署【hadoop组件HDFS笔记】(图片均为学习时截取的)

HDFS详细介绍 HDFS是什么 HDFS是Hadoop三大组件(HDFS、MapReduce、YARN)之一 全称是&#xff1a;Hadoop Distributed File System&#xff08;Hadoop分布式文件系统&#xff09;&#xff1b;是Hadoop技术栈内提供的分布式数据存储解决方案 可以在多台服务器上构建存储集群&…

C : 线性规划例题求解

Submit Page TestData Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 93 Solved: 49 Description 求解下述线性规划模型的最优值min &#xfffd;1&#xfffd;1&#xfffd;2&#xfffd;2&#xfffd;3&#xfffd;3&#xfffd;.&#xfffd;. &…

Java 并发编程常见问题

1、线程状态它们之间是如何扭转的&#xff1f; 1、谈谈对于多线程的理解&#xff1f; 1、对于多核CPU&#xff0c;多线程可以提升CPU的利用率&#xff1b; 2、对于多IO操作的程序&#xff0c;多线程可以提升系统的整体性能及吞吐量&#xff1b; 3、使用多线程在一些场景下可…

StringUTF_16错误认识字节长度

众所周知&#xff0c;在 UTF-8 编码中&#xff0c;中文字符通常占用 3 个字节: import java.nio.charset.StandardCharsets;/*** author shenyang* version 1.0* info untitled* since 2024/6/30 上午9:42*/ public class Test {public static void main(String[] args) {Stri…

【机器学习】机器学习的重要方法——强化学习:理论,方法与实践

目录 一、强化学习的核心概念 二、强化学习算法的分类与示例代码 三.强化学习的优势 四.强化学习的应用与挑战 五、总结与展望 强化学习&#xff1a;理论&#xff0c;方法和实践 在人工智能的广阔领域中&#xff0c;强化学习&#xff08;Reinforcement Learning, RL&…

第3章-数据类型和运算符

#本章目标 掌握Python中的保留字与标识符 理解Python中变量的定义及使用 掌握Python中基本数据类型 掌握数据类型之间的相互转换 掌握eval()函数的使用 了解不同的进制数 掌握Python中常用的运算符及优先级1&#xff0c;保留字与标识符 保留字 指在Python中被赋予特定意义的一…

【操作系统】内存管理——页面分配策略(个人笔记)

学习日期&#xff1a;2024.6.28 内容摘要&#xff1a;页面分配策略和内存映射文件&#xff0c;内存映射文件 页面分配置换策略 基本概念 驻留集&#xff0c;指请求分页存储管理中给进程分配的物理块的集合&#xff0c;在采用了虚拟存储技术的系统中&#xff0c;驻留集大小一…

docker harbor仓库搭建,主从库复制

背景&#xff1a;需要主机安装docker-ce和docer-compose #1.安装相关依赖. yum install -y yum-utils device-mapper-persistent-data lvm2 #2.下载官方的docker yum源文件 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo …

专题三:Spring容器ApplicationContext初始化

前面我们构建好了Spring源码&#xff0c;接下来肯定迫不及待来调试啦&#xff0c;来一起看看大名鼎鼎ApplicationContext 新建模块 1、基础步骤 2、重要文件 build.gradle plugins {id java }group org.springframework version 5.2.6.RELEASErepositories {mavenCentral(…

DDD学习笔记五

模型引力场&#xff1a;聚合 强作用力体现&#xff1a; 某个领域模型是另一些模型存在的前提&#xff0c;没有前者&#xff0c;后者就失去了生存的意义。 一组领域模型之间存在关联的领域逻辑&#xff0c;任何时候都不能违反。 一组领域模型必须以一个完整的、一致的状态呈现给…

专业指南:U盘数据恢复全攻略

一、引言&#xff1a;U盘数据恢复的重要性 在信息化日益发展的今天&#xff0c;U盘已成为我们日常生活中不可或缺的存储设备。然而&#xff0c;由于各种原因&#xff0c;U盘中的数据可能会面临丢失的风险。U盘数据恢复技术便应运而生&#xff0c;它旨在帮助用户找回因误删除、…

多平台自动养号【开心版】偷偷使用就行了!

大家好&#xff0c;今天我无意间发现了一款【多平台自动养号工具】&#xff0c;看了一下里面的功能还是挺全面的&#xff0c;包含了【抖音&#xff0c;快手&#xff0c;小红薯】还有一些截流功能 虽然这款工具功能强大&#xff0c;但美中不足的是需要付费的。但别担心&#xf…

线性结构之栈结构

栈是一种只能从一端存取数据并且遵循“后进先出”原则的线性存储结构。这句话中体现了栈结构的三个特征——只能从一端存取数据&#xff0c;遵循“后进先出”的原则和线性存储结构。因此如果我们要实现一个栈结构的数据结构&#xff0c;就必须要满足这三点要求。提到线性结构&a…

构建高效业财一体化管理体系

构建高效业财一体化管理体系 业财一体化战略意义 提升决策质量 强化数据支撑&#xff1a;通过整合业务与财务数据&#xff0c;为决策提供准确、实时的信息基础&#xff0c;确保分析的深度与广度。促进业务与财务协同&#xff1a;打破信息孤岛&#xff0c;实现业务流程与财务管…

最流行的文件同步软件

PanguFlow是一款免费的文件同步软件&#xff0c;他支持文件的全量同步、支持文件的增量同步、支持文件的实时备份&#xff0c;支持双向同步&#xff0c;支持三向同步甚至多向同步&#xff0c;支持无人值守运行。 PanguFlow数据同步软件下载地址https://pan.baidu.com/s/1GLjFR…

博客都在使用的打字机效果,居然这么简单?

效果展示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>body …