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 {@Overridepublic 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数据

@Overrideprotected 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替换需要启动的未注册的Activitypublic 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() {@Overridepublic 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;}}// 生成代理proxyIntentIntent proxyIntent = new Intent();proxyIntent.setClassName("com.example.myapplication",ProxyActivity.class.getName());// 保存原始的Intent对象Intent intent = (Intent) args[index];proxyIntent.putExtra(TARGET_INTENT, intent);// 使用proxyIntent替换数组中的Intentargs[index] = proxyIntent;}// 被代理对象调用return method.invoke(mInstance, args);}});// 用代理的对象替换系统的对象mInstanceField.set(singleton, mInstanceProxy);} catch (Exception e) {e.printStackTrace();}}// 需要启动的未注册的Activity 替换回来  ProxyActivitypublic 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() {@Overridepublic 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.rhkb.cn/news/367585.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频编解码从H.264到H.266:浅析GB28181安防视频汇聚EasyCVR视频压缩技术

随着信息技术的飞速发展&#xff0c;视频编解码技术也在不断革新&#xff0c;以适应高清、超高清甚至8K视频时代的到来。视频编解码技术作为数字多媒体领域的核心技术之一&#xff0c;也在不断地演进和革新。从早期的H.261到现在的H.265、H.266&#xff0c;每一次技术的升级都极…

二叉树的层序遍历/后序遍历(leetcode104二叉树的最大深度、111二叉树的最小深度)(华为OD悄悄话、数组二叉树)

104二叉树的最大深度 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 本题可以使用前序&#xff08;中左右&#xff09;&#xff0c;也可以使用后序遍历&#xff08;左右中&#xff09;&#xff0c;…

线下生鲜蔬果店做小程序有什么方法

生鲜蔬果是生活所需&#xff0c;大小商家众多&#xff0c;零售批发各种经营模式&#xff0c;小摊贩或是超市门店都有着目标客户或准属性群体。竞争和获客转化也促进着商家寻找客源和加快线上进程。 尤其是以微信社交为主的私域场景&#xff0c;普客/会员都需要精细化管理营收和…

什么是带有 API 网关的代理?

带有 API 网关的代理服务显著提升了用户体验和性能。特别是对于那些使用需要频繁创建和轮换代理的工具的用户来说&#xff0c;使用 API 可以节省大量时间并提高效率。 了解 API API&#xff0c;即应用程序编程接口&#xff0c;是服务提供商和用户之间的连接网关。通过 API 连接…

Log4j日志框架讲解(全面,详细)

目录 Log4j概述 log4j的架构&#xff08;组成&#xff09; Loggers Appenders Layouts 快速入门 依赖 java代码 日志的级别 log4j.properties 自定义Logger 总结&#xff1a; Log4j概述 Log4j是Apache下的一款开源的日志框架&#xff0c;通过在项目中使用 Log4J&…

2024 年人工智能和数据科学的五个主要趋势

引言 2023年&#xff0c;人工智能和数据科学登上了新闻头条。生成性人工智能的兴起无疑是这一显著提升曝光度的驱动力。那么&#xff0c;在2024年&#xff0c;该领域将如何继续占据头条&#xff0c;并且这些趋势又将如何影响企业的发展呢&#xff1f; 在过去几个月&#xff0c;…

Sql审核平台Archery的搭建和简单配置

Sql审核平台Archery的搭建和简单配置 Archery是一个开源的Web应用&#xff0c;基于Python开发&#xff0c;利用Flask作为后端框架&#xff0c;前端采用Vue.js&#xff0c;构建了一个现代化的数据操作界面。提供了SQL审核、数据查询、报表生成等功能&#xff0c;同时支持多种数据…

qtreewidget 美化,htmlcss和qss 不是一个概念!已解决

这种样式的美化&#xff0c; 能气死个人&#xff0c;css 一个单词搞定&#xff0c;非要 在qss中。多少个单词不知道了。 m_tree_widget->setStyleSheet("QTreeView{background:transparent; selection-background-color:transparent;}""QTreeView::branch{b…

软考满分范文“论模型驱动架构设计方法及其应用”,软考高级,系统架构设计师

论文真题 模型驱动架构设计是一种用于应用系统开发的软件设计方法,以模型构造、模型转换和精化为核心,提供了一套软件设计的指导规范。在模型驱动架构环境下,通过创建出机器可读和高度抽象的模型实现对不同问题域的描述,这些模型独立于实现技术,以标准化的方式储存,利用…

Django QuerySet对象,all()方法

all()方法 在Django中&#xff0c;all()方法是QuerySet对象的一个方法&#xff0c;用于获取模型的所有实例。 当你调用ModelName.objects.all()时&#xff0c;Django会生成一个SQL查询&#xff0c;从数据库中获取该模型的所有记录&#xff0c;并返回一个QuerySet对象&#xf…

AzureDataFactory Dataverse connector自动处理了分页问题(单次查询上限5000条的限制)

众所周知&#xff0c;在用fetch执行D365的查询时&#xff0c;单次的查询是5000条&#xff0c;如果超过5000条则需要自己处理分页&#xff0c;添加额外的处理逻辑&#xff0c;但在ADF中&#xff0c;Dataverse connector已经自动处理了分页&#xff0c;我们可以很简单的做个POC. …

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(二十)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 30 节&#xff09; P30《29.数据持久化-用户首选项》 实现数据持久化在harmonyOS中有很多种方式&#xff0c;比较常见的是以下两…

在Redis中使用Lua脚本实现多条命令的原子性操作

Redis作为一个高性能的键值对数据库&#xff0c;被广泛应用于各种场景。然而&#xff0c;在某些情况下&#xff0c;我们需要执行一系列Redis命令&#xff0c;并确保这些命令的原子性。这时&#xff0c;Lua脚本就成为了一个非常实用的解决方案。 问题的提出 假设我们有一个计数…

抠图怎么保存抠出来的部分?这些方法非常简单

图像处理已成为我们日常生活和工作中不可或缺的一部分。无论是设计海报、编辑照片&#xff0c;还是制作视频特效&#xff0c;抠图技术都发挥着至关重要的作用。然而&#xff0c;很多人在完成抠图后&#xff0c;却不知道如何保存抠出来的部分&#xff0c;这无疑给他们的创作带来…

Day63 代码随想录打卡|回溯算法篇---电话号码的字母组合

题目&#xff08;leecode T17&#xff09;&#xff1a; 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 方法&#xff1a;…

串级PID控制算原理及法详解

文章目录 1. PID 2. 串级PID 3. 串级PID的物理量 4. C语言实现单极PID 5. C语言实现串极PID 6. 模拟仿真 1. PID PID是应用最广泛的闭环控制方法之一&#xff0c;是一种常用的反馈控制方法&#xff0c;对于每个PID控制器由三个部分组成&#xff1a;比例控制&#xff08;…

2024中国西安科博会暨硬科技产业博览会11月召开

2024第18届中国西安国际科学技术产业博览会暨硬科技产业博览会 时间&#xff1a;2024年11月3日-5日 地点&#xff1a;西安国际会展中心 主办单位&#xff1a;中国国际科学技术合作协会 陕西省科技资源统筹中心 协办单位&#xff1a;西安市科学技术协会 西安市中小企业协会、…

Hadoop3:Yarn容量调度器配置多队列案例

一、情景描述 需求1&#xff1a; default队列占总内存的40%&#xff0c;最大资源容量占总资源60%&#xff0c;hive队列占总内存的60%&#xff0c;最大资源容量占总资源80%。 二、多队列优点 &#xff08;1&#xff09;因为担心员工不小心&#xff0c;写递归死循环代码&#…

科研与英文学术论文写作指南——于静老师课程

看到了一个特别棒的科研与英文学术论文写作指南&#xff0c;理论框架实例。主讲人是中科院信息工程研究所的于静老师。推荐理由&#xff1a;写论文和读论文或者讲论文是完全不一样的&#xff0c;即使现在还没有发过论文&#xff0c;但是通过于老师的课程&#xff0c;会给后续再…

Unity之创建与导出PDF

内容将会持续更新&#xff0c;有错误的地方欢迎指正&#xff0c;谢谢! Unity之创建与导出PDF TechX 坚持将创新的科技带给世界&#xff01; 拥有更好的学习体验 —— 不断努力&#xff0c;不断进步&#xff0c;不断探索 TechX —— 心探索、心进取&#xff01; 助力快速…