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

文章目录

  • 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();
        }

    }

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度学习与飞桨 PaddlePaddle Fluid

编辑推荐 飞桨PaddlePaddle是百度推出的深度学习框架&#xff0c;不仅支撑了百度公司的很多业务和应用&#xff0c;而且随着其开源过程的推进&#xff0c;在其他行业得到普及和应用。 本书基于2019年7月4日发布的飞桨PaddlePaddle Fluid 1.5版本&#xff08;后续版本会兼容旧版…

[工业网络] 模型建立

普渡大学ICS参考模型 普渡企业参考架构&#xff08;PERA&#xff09;是由西奥多J威廉姆斯&#xff08;Theodore J. Williams&#xff09;和普渡大学计算机集成制造工业大学联盟的成员在1990年代开发的企业架构参考模型。该模型被ISA-99&#xff08;现为ISA/IEC 62443&#xff…

warning: LF will be replaced by CRLF the next time Git touches it warning

问题&#xff1a; warning: in the working copy of , LF will be replaced by CRLF the next time Git touches it warning: 今天上传git时报错&#xff0c;使用Ai&#xff1b;得知&#xff1b; 解决&#xff1a; 将 Git 配置为不自动转换换行符&#xff0c;使用以下命令…

snap和apt的区别简单了解

Linux中没有tree命令的时候提示安装的时候出现了两个命令&#xff0c;简单看了看两者有何区别&#xff08;一般用apt就可以了&#xff09;&#xff1a; sudo snap install tree 和 sudo apt install tree 这两个命令都是用来安装 tree 命令行工具的&#xff0c;但它们使用的是不…

webSocket网页通信---使用js模拟多页面实时通信

webSocket是什么 WebSocket是一种先进的网络技术&#xff0c;它提供了一种在单个TCP连接上进行全双工通信的能力。传统的基于HTTP的通信是单向的&#xff0c;即客户端发起请求&#xff0c;服务器响应请求&#xff0c;然后连接关闭。但是&#xff0c;WebSocket允许服务器和客户端…

Spring Boot2.x教程:(四)Spring Boot2.6及之后版本整合Knife4j的问题

Spring Boot2.6及之后版本整合Knife4j的问题 1、概述2、问题出现原因及解决办法3、拓展3.1、为什么发生这种变化 4、总结 大家好&#xff0c;我是欧阳方超&#xff0c;可以扫描下方二维码关注我的公众号“欧阳方超”&#xff0c;后续内容将在公众号首发。 1、概述 今天在2.7…

Raylib 坐标系适应与GPU绘制参数

通过750 - 鼠标坐标&#xff0c;把原点在左上角的鼠标坐标变成左下角 实现输入数据后的坐标系同GPU原点在左下角坐标相同&#xff0c; 比数组0&#xff0c;0对应左上角好&#xff0c; 此时实际上数组0&#xff0c;0对应左下角 #include <raylib.h> // 感受&#xff1a…

如何用Python实现三维可视化?

Python拥有很多优秀的三维图像可视化工具&#xff0c;主要基于图形处理库WebGL、OpenGL或者VTK。 这些工具主要用于大规模空间标量数据、向量场数据、张量场数据等等的可视化&#xff0c;实际运用场景主要在海洋大气建模、飞机模型设计、桥梁设计、电磁场分析等等。 本文简单…

OpenELM:开启开放训练和推理框架的高效语言模型家族

随着大模型模型规模的增长&#xff0c;这些强大工具的透明度、可复现性和对数据偏见的敏感性也引起了人们的关注。这些问题不仅关系到研究的开放性和公平性&#xff0c;也关系到模型输出的可信度和安全性。为了应对这些挑战&#xff0c;Apple的研究团队发布了名为OpenELM的新一…

守护进程到底是什么?如何创建?(图文并茂,你不得不看的一篇文章)

目录 守护进程&#xff08;Daemon Process&#xff09;详解 守护进程的特点 创建守护进程的步骤 用守护进程实现输入Hello功能 守护进程的用途 如何查看我们的守护进程&#xff1f; 1. ps 命令 2. top 命令 总结 守护进程&#xff08;Daemon Process&#xff09;详解 …

如何在主动动态安全中使用人工智能驱动的威胁分类提高防御精准度

面对当今世界不断演变的网络威胁&#xff0c;人工智能和网络安全将会发挥重要的防护作用。在数据泄露和网络攻击日益突出的时代&#xff0c;人工智能和网络安全之间的合作成为数字安全战场上的强大盟友。 本文将深入研究这两个领域的融合&#xff0c;揭示它们在彻底改变威胁检测…

Java---Mybatis详解二

雄鹰展翅凌空飞&#xff0c; 大江奔流不回头。 壮志未酬心未老&#xff0c; 豪情万丈任遨游。 巍巍高山攀顶峰&#xff0c; 滔滔黄河入海流。 风云变幻凭君舞&#xff0c; 踏遍天涯尽逍遥。 目录 一&#xff0c;环境准备 二&#xff0c;删除 三&#xff0c;删除(预编译SQL) 为什…

奇瑞被曝强制加班,“896”成常态且没有加班费

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 更多资源欢迎关注 7 月 2 日消息&#xff0c;一位认证为“奇瑞员工”的网友近期发帖引发热议&#xff0c;奇瑞汽车内部存在强制加班行为&#xff0c;每周加班时长需大于 20 小时并且没有加班费&#xff0c;仅补贴 10 元…

CJSON库

目录 一、介绍 1、JSON是什么 2、为什么使用CJSON 3、JSON格式 二、使用CJSON构造JSON 1、创建对象 2、添加字段 3、转换格式 4、释放对象 三、使用CJSON解析JSON 1、解析数据 2、 获取字段 3、释放对象 一、介绍 1、JSON是什么 JSON是什么呢&#xff1f;JSON全称…

Android studio 打包低版本的Android项目报错

一、报错内容 Execution failed for task :app:packageRelease. > A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade> com.android.ide.common.signing.KeytoolException: Failed to read key key0 from store "…

如何创建移动类型

第一步打开事务代码&#xff1a; OMJJ 下面这个工作区可以不填&#xff0c;或者填入你的范围&#xff08;例如我准备copy Z52成为Z54 那么就可以输入从Z52到Z54&#xff0c;SAP的这个操作就是这么怪&#xff0c;哈哈&#xff09;不然就会出现一个这样的报错“在工作区中指定关…

聚焦西安应博会|2024西安城市安全应急产业展9月精彩呈现

2024西安城市安全应急产业博览会 时间&#xff1a;2024年9月12日-14日 地点&#xff1a;西安国际会展中心 运营&#xff1a;西安西部文化产业博览会有限公司 【展会简介】 为推动安全应急装备向智能化、成套化、专业化方向发展&#xff0c;迎接新质生产力在应急产业新技术…

在C++中,工厂模式的思考(《C++20设计模式》及常规设计模式对比)

文章目录 一、前言二、讲解1、构造函数的弊端2、工厂方法&#xff08;解决上述弊端&#xff09;3、简单工厂3.1 **UML类图**3.2 **实现** 4、工厂模式4.1 **UML类图**4.2 **实现** 5、抽象工厂5.1 **UML类图**5.2 **实现** 三、总结 一、前言 在看《C20设计模式》一书中产生了…

【软件测试】快速定位bug,编写测试用例

作为一名测试人员如果连常见的系统问题都不知道如何分析&#xff0c;频繁将前端人员问题指派给后端人员&#xff0c;后端人员问题指派给前端人员&#xff0c;那么在团队里你在开发中的地位显而易见 &#xff0c;口碑、升值、加薪那应该是你遥不可及的梦 但是作为测试人员来说&…

【ARMv8/v9 GIC 系列 5 -- GIC GICD_CTRL 使用详细介绍】

文章目录 GICD_CTRLGICD_CTLR 寄存器结构RWP&#xff08;Register Write Pending&#xff09;E1NWF&#xff08;Enable 1 of N Wakeup Functionality&#xff09;DS&#xff08;Disable Security&#xff09; 亲和性路由&#xff08;Affinity Routing&#xff09;ARE_NSARE_S 中…