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.pswp.cn/web/37324.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/37324.shtml
英文地址,請注明出處:http://en.pswp.cn/web/37324.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

志愿填報指南:為什么我強烈建議你報考計算機專業

首先恭喜2024屆高考的同學們&#xff0c;你們已經通過了高考的考驗&#xff0c;即將進入人生的新階段——大學。 現在正是高考完填報志愿的時刻&#xff0c;Left聽到身邊朋友提到報考志愿的諸多問題&#xff1a; 志愿填報怎么填&#xff1f;我要報考什么專業&#xff1f;這個…

[Cloud Networking] OSPF

OSPF 開放式最短路徑優先&#xff08;Open Shortest Path First&#xff09;是一種動態路由協議&#xff0c;它屬于鏈路狀態路由協議&#xff0c;具有路由變化收斂速度快、無路由環路、支持變長子網掩碼和匯總、層次區域劃分等優點。 1 OSPF Area 為了適應大型網絡&#xff0…

可編程定時計數器8253/8254 - 8253入門

時鐘-給設備打拍子 概述 在計算機系統中&#xff0c;為了使所有設備之間的通信井然有序&#xff0c;各通信設備間必須有統一的節奏&#xff0c;不能各干各的&#xff0c;這個節奏就被稱為定時或時鐘 時鐘并不是計算機處理速度的衡量&#xff0c;而是一種使設備間相互配合而避…

【2024-06-21】網易互娛秋招實習筆試三道編程題解

恭喜發現寶藏!搜索公眾號【TechGuide】回復公司名,解鎖更多新鮮好文和互聯網大廠的筆經面經。 作者@TechGuide【全網同名】 訂閱專欄: 【專享版】2024最新大廠筆試真題解析,錯過必后悔的寶藏資源! 第一題:陰陽師斗技 題目描述 小蓋正在參加陰陽師的斗技。已知斗技的規…

Linux 磁盤掛載與分區

Linux 磁盤掛載與分區 vda1: 其中vd表示虛擬磁盤&#xff0c;a表示第一塊磁盤&#xff0c;b表示第二塊磁盤&#xff0c;1表示第一塊磁盤的第一分區&#xff08;顯然兩塊磁盤都只有一個分區&#xff09;圖中可以看到&#xff0c;vda1磁盤只有一個分區&#xff0c;且全部掛載到根…

vue3使用vant4的列表vant-list點擊進入詳情自動滾動到對應位置,踩坑日記(一天半的踩坑經歷)

1.路由添加keepAlive <!-- Vue3緩存組件&#xff0c;寫法和Vue2不一樣--><router-view v-slot"{ Component }"><keep-alive><component :is"Component" v-if"$route.meta.keepAlive"/></keep-alive><component…

如何在MySQL中按字符串中的數字排序

在管理數據庫時&#xff0c;我們經常遇到需要按嵌入在字符串中的數字進行排序的情況。這在實際應用中尤為常見&#xff0c;比如文件名、代碼版本號等字段中通常包含數字&#xff0c;而這些數字往往是排序的關鍵。本文將詳細介紹如何在MySQL中利用正則表達式提取字符串中的數字并…

LiteDB - 一個單數據文件 .NET NoSQL 文檔存儲

LiteDB 一個小巧、快速、輕量級的 NoSQL 嵌入式數據庫。 Serverless NoSQL 文檔存儲類似于 MongoDB 的簡單 API100% C# 代碼,支持 .NET 3.5 / .NET 4.0 / NETStandard 1.3 / NETStandard 2.0,單 DLL (小于 300 kb)支持線程和進程安全支持文檔/操作級別的 ACID支持寫失敗后的數…

Google 發布最新開放大語言模型 Gemma 2,現已登陸 Hugging Face Hub

Google 發布了最新的開放大語言模型 Gemma 2&#xff0c;我們非常高興與 Google 合作&#xff0c;確保其在 Hugging Face 生態系統中的最佳集成。你可以在 Hub 上找到 4 個開源模型 (2 個基礎模型和 2 個微調模型) 。發布的功能和集成包括&#xff1a; Hub 上的模型https://hf.…

Java家教系統小程序APP公眾號h5源碼

讓學習更高效&#xff0c;更便捷 &#x1f31f; 引言&#xff1a;家教新選擇&#xff0c;小程序來助力 在快節奏的現代生活中&#xff0c;家長們越來越注重孩子的教育問題。然而&#xff0c;如何為孩子找到一位合適的家教老師&#xff0c;成為了許多家長頭疼的問題。現在&…

交叉編譯中的 --build、 --host和 --target

在交叉編譯中比較常見的一些參數就是build、host和target了,正確的理解這三者的含義對于交叉編譯是非常重要的,下面就此進行解釋   --build=編譯該軟件所使用的平臺   --host=該軟件將運行在哪個平臺   --target=該軟件所處理的目標平臺 我們經常會看到如下代碼:   …

谷歌個人號,20人連續封測14天所需設備該怎么解決?

現在&#xff0c;在Google Play上架應用&#xff0c;對于大部分開發者來說&#xff0c;真的是不小的挑戰&#xff0c;因為目前谷歌上架政策越來越嚴格了。特別是從2023年11月13日起&#xff0c;新政策要求個人開發者賬號的應用必須經過20個獨立用戶連續14天的封閉測試&#xff…

【C語言】--分支和循環(1)

&#x1f37f;個人主頁: 起名字真南 &#x1f9c7;個人專欄:【數據結構初階】 【C語言】 目錄 前言1 if 語句1.1 if1.2 else1.3 嵌套if1.4 懸空else 前言 C語言是結構化的程序設計語言&#xff0c;這里的結構指的是順序結構、選擇結構、循環結構。 我們可以用if、switch實現分支…

vue2實例實現一個初步的vuex

vue2實例實現一個初步的vuex 實現源碼&#xff1a;vue2-review 1.App.vue 2.store目錄下的index.js 3.效果 微信公眾號&#xff1a;刺頭拾年

MATLAB的.m文件與Python的.py文件:比較與互參

simulink MATLAB的.m文件與Python的.py文件&#xff1a;比較與互參相似之處**1. 基本結構****2. 執行邏輯****3. 可讀性和維護性** 差異性**1. 語法特性****2. 性能和應用****3. 開發環境** 互相學習的可能性結論 MATLAB的.m文件與Python的.py文件&#xff1a;比較與互參 在編…

擴展閱讀:什么是中斷

如果用一句話概括操作系統的原理,那就是:整個操作系統就是一個中斷驅動的死循環,用最簡單的代碼解釋如下: while(true){doNothing(); } 其他所有事情都是由操作系統提前注冊的中斷機制和其對應的中斷處理函數完成的。我們點擊一下鼠標,敲擊一下鍵盤,執行一個程序,…

重生之我要學后端100--計算機網絡部分概念(持續更新)

TCP/IP、DNS、負載均衡器等等 前言一、TCP/IP&#xff08;傳輸控制協議/互聯網協議&#xff09;二、DNS&#xff08;域名系統&#xff09;三、負載均衡器其他網絡概念 前言 了解網絡基礎知識對于后端開發者至關重要&#xff0c;因為這些知識有助于理解應用程序是如何在更廣闊的…

中英雙語介紹美國的州:麻省,馬塞諸塞州(Massachusetts)

中文版 馬薩諸塞州&#xff08;Massachusetts&#xff09;位于美國東北部的新英格蘭地區&#xff0c;是美國歷史最悠久、文化最豐富的州之一。以下是對馬薩諸塞州各方面的詳細介紹&#xff1a; 人口 截至2020年&#xff0c;美國人口普查數據顯示&#xff0c;馬薩諸塞州的人口…

C++ 之運算符

作用&#xff1a;用于執行代碼的運算 主要的運算符類型&#xff1a; 運算符類型作用算術運算符用于處理四則運算賦值運算符用于將表達式的值賦給變量比較運算符用于表達式的比較&#xff0c;并返回一個真值或假植邏輯運算符用于根據表達式的值返回真值或假植 1 算術運算符 …

Spring MVC中的DispatcherServlet、HandlerMapping和ViewResolver的作用

在Spring MVC框架中&#xff0c;DispatcherServlet、HandlerMapping和ViewResolver是核心組件&#xff0c;它們各自承擔著不同的角色和任務&#xff1a; 1.DispatcherServlet&#xff1a;它是Spring MVC生命周期中的前端控制器&#xff0c;負責接收HTTP請求并將它們分發給相應的…