android hook(Toast BadTokenException案例)

news2025/1/16 17:45:41

什么是Hook?

 hook 技术又叫做钩子函数,在系统没有调用该函数之前,钩子程序先捕捉该消息,钩子函数先得到控制权,这时钩子函数即可以加工处理(改变)该函数的执行行为,还可以强制结束消息的传递。简单来说,就是把系统的程序拉出来,变成我们自己执行的代码片段。

Hook的实现?

实现hook我们必须要知道java的反射和动态代理。

​​​​​​Java反射机制详解_贺兰猪的博客-CSDN博Java动态代理_贺兰猪的博客-CSDN博客Java反射机制详解_贺兰猪的博客-CSDN博客

案例:Toast WindowManager$BadTokenException

tips:这一小段源码层面我们主要针对于Android7.x。

相信Android朋友们平时开发的时候应该都遇到过token失效。

按照正常的流程,是不会出现这种异常。但是由于在某些情况下, Android 进程某个 UI 线程的某个消息阻塞。导致 TNshow 方法 post 出来 0 (显示) 消息位于该消息之后,迟迟没有执行。这时候,NotificationManager 的超时检测结束,删除了 WMS 服务中的 token 记录。也就是如图所示,删除 token 发生在 Android 进程 show 方法之前。这就导致了我们上面的异常。

整个toast显示原理及分析大家可以完整的看下QQ音乐技术团队的分析,(上图来源也是那)[Android] Toast问题深度剖析(一) - 腾讯云开发者社区-腾讯云

用sleep的方式并没有复现出来这个token is valid,但阅读Toast源代码后可以用另一种方式来复现这个BadTokenException:

val mw = getSystemService(WINDOW_SERVICE) as WindowManager
        val tv = TextView(this)
        tv.layoutParams = WindowManager.LayoutParams(1, 1)
        tv.text = "模拟toast悬浮窗"
        val params = WindowManager.LayoutParams()
        params.type = WindowManager.LayoutParams.TYPE_TOAST
        mw.addView(tv, params)
        Toast.makeText(this, "xxxx", Toast.LENGTH_SHORT).show()

因为type==TYPE_TOAST的类型的toast不能重复添加,所以这样也会报一个BadTokenException,接下来我们就要通过这个demo,用hook的解决方案来解决这个异常。

阅读源码我们发现,在Android 7.0 Toast.java  handleShow方法:

和在Android 8.0 Toast.java上:

对比发现在Android 8.0中,在WindowManager进行addView的时候8.0进行了一层try catch保护,而在7.0上并没有。那么我们就可以参考8.0的方法,直接catch住这个异常。

寻找hook点

尽量hook静态变量和单例对象

尽量hook public的对象和方法

查看调用链,mHandler中发了一个消息,在handlerMessage中处理这个toast显示的消息后调用handlerShow,mHandler是TN类中的变量,Toast 里面有一个变量mTN(TN类)。所以就很简单了,我们hook点就定位这个mTN,然后反射替换TN的内部成员变量mHandler,对handleMessage方法添加try-catch做到保护即可。

public class HookToastUtil {
    private static Field sField_N;
    private static Field sField_TN_Handler;
    private static Toast mToast;


    private HookToastUtil() {

    }

    public static void show(Context context, CharSequence message, int duration) {
        if (mToast == null) {
            mToast = Toast.makeText(context.getApplicationContext(), message, duration);
            hook(mToast);
        } else {
            mToast.setDuration(duration);
            mToast.setText(message);

            mToast.show();
        }
    }

    public static void show(Context context, @StringRes int resId, int duration) {
        if (mToast == null) {
            mToast = Toast.makeText(context.getApplicationContext(), resId, duration);
            hook(mToast);
        } else {
            mToast.setDuration(duration);
            mToast.setText(context.getString(resId));
        }
        mToast.show();
    }

    private static void hook(Toast toast) {
        if (Build.VERSION.SDK_INT != Build.VERSION_CODES.N_MR1) {
            return;
        }

        try {
            Class<?> cls = Class.forName("android.widget.Toast");
            sField_N = cls.getDeclaredField("mTN");
            sField_N.setAccessible(true);
            sField_TN_Handler = sField_N.getType().getDeclaredField("mHandler");
            sField_TN_Handler.setAccessible(true);
            Object tn = sField_N.get(toast);
            Handler handler = (Handler) sField_TN_Handler.get(tn);

            sField_TN_Handler.set(tn, new ReplaceHandler(handler));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static class ReplaceHandler extends Handler {
        private Handler tnHandler;

        public ReplaceHandler(Handler handler) {
            this.tnHandler = handler;
        }

        @Override
        public void handleMessage(Message msg) {
            try{
                tnHandler.handleMessage(msg);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

 调用HookToastUtil.show(this,"111",1000)  替换之前的Toast.makeText就不会报错了

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

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

相关文章

(详细)HTTP协议(应用层重点协议)

目录 一、HTTP协议工作过程 二、 协议格式 1、抓包工具Fiddler 2、HTTP请求格式 3、HTTP响应格式 4、HTTP协议格式总结 三、HTTP请求&#xff08;Request&#xff09; 1、URL &#xff08;1&#xff09;URL基本格式 &#xff08;2&#xff09;URL实例 &#xff08;…

什么是伪原创?SEO伪原创该怎么做

伪原创是指在原有的文章或内容基础上进行修改或调整&#xff0c;以产生看起来是全新内容的文章&#xff0c;但实际上并没有创造新的价值。多数情况下&#xff0c;伪原创的目的是为了在文章相对原创的情况下&#xff0c;提高搜索引擎的排名。 一、高质量伪原创 做好伪原创&#…

SpringCloud消息总线——Bus

Bus 本专栏学习内容来自尚硅谷周阳老师的视频 有兴趣的小伙伴可以点击视频地址观看 在SpringCloud Config学习过程中&#xff0c;还遗留下来一个问题&#xff1a;当运维更新git上的配置信息时&#xff0c;要想更改所有的客户端服务&#xff0c;必须得手动给客户端服务发送post请…

ESP32学习笔记14-mqtt-连接官方mqtt,onenet,thingsboard物联网平台

12.MQTT 12.0工程里的WiFi密码和ssid设置 工程的WiFi配置 ssid password 打开配置 配置ssid和密码 工程配置文件sdkconfig IP和端口配置 乐鑫服务器mqtt 12.1数据结构和配置函

力扣sql中等篇练习(四)

力扣sql中等篇练习(四) 1 游戏玩法分析IV 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # 首次登录后第二天登录的玩家数量/玩家总数量(去重) # 注意首日注册指的是表中的最早的一个日期 SELECT ROUND((SELECT count(distinct t1.player_id)FRO…

给孩子买台灯什么牌子好?盘点学生专用台灯第一品牌

现在的孩子近视率很高&#xff0c;双减政策的执行&#xff0c;也有导致许多孩子长时间接触电子产品&#xff0c;没有正确的看书姿势&#xff0c;合理的用眼距离等&#xff0c;使用专业的护眼台灯&#xff0c;能让孩子眼睛拥有一个好的视力。 要注意养成预防近视好习惯&#xf…

dsp28335杂记3

文章目录 DAC实验&#xff0c;SPITLV5620DACADC0实验-------niceDMAADC实验&#xff08;外设到存储器&#xff09; 中断 了解皮毛&#xff0c;嘿嘿内置XINTF接口配置 外扩SRAM DMA支持 了解皮毛&#xff0c;嘿嘿eCAP脉冲捕获&#xff0c;重点啦eCAP输出PWM&#xff08;APWM模…

【学习笔记】从MySQL快速入门 PostgreSQL

PGSQL 菜鸟教程/在线api文档 数据类型语法 DML条件 高级 一、数据类型 数值类型&#xff1a;和mysql类似&#xff0c;叫法不同 特殊&#xff1a;serial 自增整数 名字存储长度描述范围smallint2 字节小范围整数-32768 到 32767integer4 字节常用的整数-2147483648 到 21474…

C++——入门讲解(3)

作者&#xff1a;几冬雪来 时间&#xff1a;2023年4月19日 内容&#xff1a;C入门内容讲解 目录 前言&#xff1a; 1. 引用&#xff08;续&#xff09;&#xff1a; 1.输出型参数&#xff1a; 2.传引用返回&#xff1a; 2.常引用&#xff1a; 3.auto&#xff1a; 结…

Android安全性:保护你的应用和用户数据

Android安全性&#xff1a;保护你的应用和用户数据 引言 在移动应用开发领域&#xff0c;Android系统占据着主导地位&#xff0c;随着智能手机的广泛普及和移动应用的快速发展&#xff0c;越来越多的开发者投入到Android应用的开发中。然而&#xff0c;随着Android应用的数量不…

React--》useReducer的讲解与使用

目录 useReducer的使用 刨析useReducer参数 useReducer的使用 useReducer的使用 在React函数式组件中&#xff0c;我们可以通过useState()来创建state&#xff0c;这种state创建方式会给我们返回两个东西state和setState()。state用来读取数据&#xff0c;而setState()用来…

走心Python实战应用:【requests+re 模块】快速下载原shen图片

人生苦短&#xff0c;我用python 这次给大家带来的是模块实战 以便大家理解学习 觉得写的好的话&#xff0c;可以给我多多点赞鸭~ 走心Python实战应用&#xff1a;【requestsre 模块】快速下载原shen图片 一、理解Python requests 模块二、requests 方法三、ruqusets 模块实…

第15章_File类与IO流

第15章_File类与IO流 讲师&#xff1a;尚硅谷-宋红康&#xff08;江湖人称&#xff1a;康师傅&#xff09; 官网&#xff1a;http://www.atguigu.com 本章专题与脉络 1. java.io.File类的使用 1.1 概述 File类及本章下的各种流&#xff0c;都定义在java.io包下。 一个File对…

渗透测试成功的8个关键,98%的人都理解错了

01 知道为什么要测试 执行渗透测试的目的是什么&#xff1f;是满足审计要求&#xff1f;是你需要知道某个新应用在现实世界中表现如何&#xff1f;你最近换了安全基础设施中某个重要组件而需要知道它是否有效&#xff1f;或者渗透测试根本就是作为你定期检查防御健康的一项例行…

最新版本 Stable Diffusion 开源 AI 绘画工具之中文自动提词篇

✨ 目录 &#x1f388; 标签生成器&#x1f388; 提示词自动补全 &#x1f388; 标签生成器 由于输入正向提示词 prompt 和反向提示词 negative prompt 都是使用英文&#xff0c;所以对学习母语的我们非常不友好使用网址&#xff1a;https://tinygeeker.github.io/p/ai-prompt…

第05讲:OpenTracing 简介,先有标准后有天

自从 Google Dapper 的论文发布之后&#xff0c;各大互联网公司和开源社区开发的分布式链路追踪产品百花齐放&#xff0c;同时也给使用者带来了一个问题&#xff0c;各个分布式链路追踪产品的 API 并不兼容&#xff0c;如果用户在各个产品之间进行切换&#xff0c;成本非常高。…

Sprinboot聚合项目归夷

1、前言 在创建springboot项目时&#xff0c;都会有一个Main方法。如果将Springboot项目设计成聚合项目时&#xff0c;我们是不是要把所有的子项目都按照Springboot的方式创建呢&#xff1f;如果是会出现什么问题&#xff0c;以及我们怎么解决呢&#xff1f; 如果我们使用maven…

在线画图网站Graph Editor的使用

网站链接 链接 网站介绍 CS Academy是一个在线的算法学习和竞赛的网站&#xff0c;打开网站左侧导航栏中的App目录下有一个可以在线画图的应用Graph Editor&#xff0c;用来画图&#xff08;有向、无向&#xff09;非常好用。 网站使用 网站的界面如下&#xff1a; 左侧为…

Golang每日一练(leetDay0037) 二叉树专题(6)

目录 109. 有序链表转换二叉搜索树 Convert-sorted-list-to-binary-search-tree &#x1f31f;&#x1f31f; 110. 平衡二叉树 Balanced Binary Tree &#x1f31f; 111. 二叉树的最小深度 Minimum Depth of Binary Tree &#x1f31f; &#x1f31f; 每日一练刷题专栏 …

代码随想录算法训练营第五十七天 | 647. 回文子串、516.最长回文子序列

打卡第57天。 今日任务 ● 647. 回文子串 ● 516.最长回文子序列 647. 回文子串 给你一个字符串 s &#xff0c;请你统计并返回这个字符串中 回文子串 的数目。 回文字符串 是正着读和倒过来读一样的字符串。 子字符串 是字符串中的由连续字符组成的一个序列。 具有不同开…