使用ASM在Android中进行字节码注入

news2024/12/24 0:31:12

目录

在这里插入图片描述

使用方法

1.编译使用插件

这里自定义了一个插件用来对字节码进行操作
在这里插入图片描述首先我们需要找到这个Gradle任务,双击进行编译打包
在这里插入图片描述打包成功后会生成如下目录
在这里插入图片描述然后我们需要在项目的gradle文件中进行引用
在这里插入图片描述
然后在application的model下的gradle中应用插件
在这里插入图片描述

2.使用ASM清空特定方法体

这里在Activity中加了一个点击事件,这次是将点击事件的方法体进行清除
在这里插入图片描述这里我们在插件的MethodEmptyBodyVisitor中修改
首先在visitMethod函数中找到OnClickListener的onClick方法(通过判断函数签名,函数名等找到特定函数)

 @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
        MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
        String mInterfaceStr = "";
        if(mInterface != null && mInterface.length > 0){
            for(int i = 0 ; i < mInterface.length ; i++){
                mInterfaceStr += mInterface[i];
            }
        }
        if (mv != null && name.contains("onClick") && mInterfaceStr.contains("android/view/View$OnClickListener") && descriptor.contains("(Landroid/view/View;)V")) {
            boolean isAbstractMethod = (access & ACC_ABSTRACT) != 0;
            boolean isNativeMethod = (access & ACC_NATIVE) != 0;
            if (!isAbstractMethod && !isNativeMethod) {
                generateNewBody(mv, owner, access, name, descriptor,signature,exceptions);
                return null;
            }
        }
        return mv;
    }

然后我们在generateNewBody中进行处理

protected void generateNewBody(MethodVisitor mv, String owner, int methodAccess, String methodName, String methodDesc,String signature, String[] exceptions) {
        // (1) method argument types and return type
        Type t = Type.getType(methodDesc);
        Type[] argumentTypes = t.getArgumentTypes();
        Type returnType = t.getReturnType();


        // (2) compute the size of local variable and operand stack
        boolean isStaticMethod = ((methodAccess & Opcodes.ACC_STATIC) != 0);
        int localSize = isStaticMethod ? 0 : 1;
        for (Type argType : argumentTypes) {
            localSize += argType.getSize();
        }
        int stackSize = returnType.getSize();

        // (3) method body
        mv.visitCode();
        if (returnType.getSort() == Type.VOID) {
            mv.visitInsn(RETURN);
        }
        else if (returnType.getSort() >= Type.BOOLEAN && returnType.getSort() <= Type.INT) {
            mv.visitInsn(ICONST_1);
            mv.visitInsn(IRETURN);
        }
        else if (returnType.getSort() == Type.LONG) {
            mv.visitInsn(LCONST_0);
            mv.visitInsn(LRETURN);
        }
        else if (returnType.getSort() == Type.FLOAT) {
            mv.visitInsn(FCONST_0);
            mv.visitInsn(FRETURN);
        }
        else if (returnType.getSort() == Type.DOUBLE) {
            mv.visitInsn(DCONST_0);
            mv.visitInsn(DRETURN);
        }
        else {
            mv.visitInsn(ACONST_NULL);
            mv.visitInsn(ARETURN);
        }
        mv.visitMaxs(stackSize, localSize);
        mv.visitEnd();
    }

可以看到编译后的class文件中方法体已经清除了
在这里插入图片描述

3.使用ASM替换特定方法体

我们修改generateNewBody方法为

protected void generateNewBody(MethodVisitor mv, String owner, int methodAccess, String methodName, String methodDesc,String signature, String[] exceptions) {
        // (1) method argument types and return type
        Type t = Type.getType(methodDesc);
        Type[] argumentTypes = t.getArgumentTypes();
        Type returnType = t.getReturnType();


        // (2) compute the size of local variable and operand stack
        boolean isStaticMethod = ((methodAccess & Opcodes.ACC_STATIC) != 0);
        int localSize = isStaticMethod ? 0 : 1;
        for (Type argType : argumentTypes) {
            localSize += argType.getSize();
        }
        int stackSize = returnType.getSize();

        // (3) method body
        mv.visitCode();
        String mInterfaceStr = owner;
        if(exceptions != null && exceptions.length > 0){
            for(int i = 0 ; i < exceptions.length ; i++){
                mInterfaceStr += exceptions[i];
            }
        }

        //插入替换代码
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, "com/yxhuang/asm/MainActivity$1", "this$0", "Lcom/yxhuang/asm/MainActivity;");
        mv.visitMethodInsn(INVOKESTATIC, "com/yxhuang/asm/TTT", "test", "(Landroid/content/Context;)V", false);

        if (returnType.getSort() == Type.VOID) {
            mv.visitInsn(RETURN);
        }
        else if (returnType.getSort() >= Type.BOOLEAN && returnType.getSort() <= Type.INT) {
            mv.visitInsn(ICONST_1);
            mv.visitInsn(IRETURN);
        }
        else if (returnType.getSort() == Type.LONG) {
            mv.visitInsn(LCONST_0);
            mv.visitInsn(LRETURN);
        }
        else if (returnType.getSort() == Type.FLOAT) {
            mv.visitInsn(FCONST_0);
            mv.visitInsn(FRETURN);
        }
        else if (returnType.getSort() == Type.DOUBLE) {
            mv.visitInsn(DCONST_0);
            mv.visitInsn(DRETURN);
        }
        else {
            mv.visitInsn(ACONST_NULL);
            mv.visitInsn(ARETURN);
        }
        mv.visitMaxs(stackSize, localSize);
        mv.visitEnd();
    }

这是一段跳转其他Activity的代码,原代码如下

public class TTT {
    //跳转A页面
    public static void test(Context context){
        context.startActivity(new Intent(context,A.class));
    }
}

未被替换的代码如下

mTvHello.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this,"aaa",Toast.LENGTH_SHORT).show();
            }
        });

替换后的class如下
在这里插入图片描述

辅助工具

由于字节码的插桩具有一定难度,因此我们可以通过ASM Bytecode Viewer Support Kotlin这款插件来辅助
在这里插入图片描述生成的代码如下所示
在这里插入图片描述然后我们可以通过选择ASMified来查看ASM插桩的代码
在这里插入图片描述

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

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

相关文章

【裸机开发】中断系统(二)—— Reset 中断服务函数(汇编实现)

目录 一、Reset 中断服务函数的实现步骤 二、汇编实现 Reset 中断服务函数 1、禁止/打开全局中断 2、设置SP指针 3、清除 .bss 段 4、完整 Reset 中断服务函数 一、Reset 中断服务函数的实现步骤 实现 Reset 中断服务函数的基本步骤如下&#xff1a; 设置各个模式下的S…

发布Android Lib 到 MavenCentral

新建 Sonatype 项目 注册账号&#xff1a; https://issues.sonatype.org/secure/Signup!default.jspa 这里注册不需要什么验证码&#xff0c;很简单。 创建问题 点击新建&#xff1a; 概要&#xff1a;自定义&#xff0c;写项目名称即可。 GroupId&#xff1a;如果是git…

C语音:打印整数二进制的奇数位和偶数位

题目&#xff1a; 获取一个整数二进制序列中所有的偶数位和奇数位&#xff0c;分别打印出二进制序列 思路&#xff1a; 总体思路&#xff1a; &#xff08;一&#xff09;. 输入数据 &#xff08;二&#xff09;. 打印奇数位&#xff1a; 使用 for循环 循环产生 1~32 之间的偶…

2023年5月 青少年软件编程(图形化) 等级考试试卷(一级)

青少年软件编程&#xff08;图形化&#xff09; 等级考试试卷&#xff08;一级&#xff09;2023.6 一、 单选题(共 25 题&#xff0c; 共 50 分) 1.看图找规律&#xff0c; 请问下图红框中是&#xff1f; &#xff08; &#xff09; A. B. C. D. 标准答案&#xff1a; D 试题解…

centos系统把.net6 web api部署到docker

为了搞定docker是怎么部署的&#xff0c;做个笔记 前提条件准备一个core项目,使用vs自带的docker打包假如你选择docker支持的时候不小心安装了Docker Desktop&#xff1b;还可以简单的先部署到本地docker中发布到centosdocker常用命令 前提条件 一台centos 8.0 版本以上的linu…

软件测试的7年,我秃了,也变强了...

当前就业环境&#xff0c;裁员、失业消息满天飞&#xff0c;好像能有一份工作就不错了&#xff0c;更别说高薪。其实这只是一方面。另一方面&#xff0c;各大企业依然求贤若渴&#xff0c;高技术人才依然紧缺&#xff0c;只要技术过硬&#xff0c;拿个年包50w不是问题。 人生格…

i.MX RT1010跨界MCU(MCUXpresso IDE上手体验)

MCUXpresso IDE是专为NXP半导体的基于ARM Cortex-M内核的MCU芯片开发而设计的&#xff0c;其优势主要体现在以下几个方面&#xff1a; MCUXpresso IDE集成了MCUXpresso SDK&#xff0c;这是NXP提供的一个软件开发套件&#xff0c;包含了底层驱动、中间件以及大量的示例代码和应…

Charles Windows10使用 证书安装 过期重设 证书加入到受信任根目录 配置访问WhatsApp

普通教程文档 抓包神器 Charles 使用教程详解 - 知乎 界面选项详细讲解 Charles的功能介绍与使用教程&#xff0c;一学就会&#xff0c;不信就来试试&#xff1f; 疑难杂症 由于CA 根证书不在“受信任的根证书颁发机构”存储区中&#xff0c;所以它不受信任 1、winr 运行…

SandQuant停止运营,免费获取A股数据

亲爱的各位朋友们&#xff1a; SandQuant即日起不再对外提供任何服务&#xff0c;为了感恩曾经支持过我们的客户朋友&#xff0c;现免费提供所有A股数据&#xff08;数据非常庞大&#xff0c;请酌情下载&#xff09;&#xff0c;请通过链接自取。 请关注我们获取链接&#xff…

产品不可或缺的文档——帮助文档

在互联网时代&#xff0c;产品的更新迭代速度越来越快&#xff0c;产品功能也越来越复杂&#xff0c;为了让用户能够更好地理解和使用产品&#xff0c;帮助文档逐渐成为了产品不可或缺的一部分。本文将从帮助文档的作用、设计原则、撰写技巧等方面探讨帮助文档的重要性及如何编…

【AI面试】损失函数(Loss),定义、考虑因素,和怎么来的

神经网络学习的方式,就是不断的试错。知道了错误,然后沿着错误的反方向(梯度方向)不断的优化,就能够不断的缩小与真实世界的差异。 此时,如何评价正确答案与错误答案,错误的有多么的离谱,就需要一个评价指标。这时候,损失和损失函数就运用而生。 开始之前,我们先做…

MySQL数据库——初步安装与数据表结构数据管理

MySQL数据库——初步安装与数据表结构数据管理 一、数据库的基本概念1.数据库基本常识2.数据库系统发展史 二、数据库的分类1.关系数据库&#xff08;SQL&#xff09;2.非关系数据库&#xff08;NO SQL&#xff09; 三、mysql的数据类型1.常用的数据库类型2.char与varchar的区别…

ijkplayer 支持srt协议 rtmp协议编译步骤

写在前面 ffafaf这个编译真的太垃圾了 一堆毛病 感受下webrtc 傻瓜式编译 环境首先必须ndk 是android-ndk-r15c 或者 android-ndk-r14b ubuntu 系统随便22或者20&#xff0c;18都行 有个非常重要的点python必须是2.7 不然你会看到一大堆报错 高版本的ubuntu默认都是python3…

回溯算法基本思想及其实现

文章目录 基本思想回溯算法的递归框架组合问题组合总和组合去重子集全排列 基本思想 回溯算法是一种递归算法&#xff0c;它试图通过尝试不同的选择&#xff0c;解决一个问题。它的基本思想是从可能的决策开始搜索&#xff0c;如果发现这条路往下走不能得到有效的解答&#xf…

12-事件模型(也就是一个先后触发顺序)

一、事件与事件流 HTML文档、浏览器中发生的一种交互。使得具备互动性&#xff0c;加载、鼠标、自定义事件。 由于DOM是一个树结构&#xff0c;意味着标签存在嵌套关系&#xff0c;当绑定事件的时候&#xff0c;当触发子节点的时候&#xff0c;一个顺序问题&#xff0c;概念-事…

人机交互学习-4 交互设计过程

交互设计过程 交互设计过程基本活动关键特征 设计过程中的问题如何选取用户&#xff1f;如何明确需求&#xff1f;如何提出候选方案&#xff1f;如何在候选方案中选择&#xff1f; 交互设计生命周期模型星型生命周期模型可用性工程生命周期模型 交互设计过程管理界面设计的4个支…

这三个方法可以视频音频转换你知道吗?

小明&#xff1a;你听说过音频转换吗&#xff1f;最近我在学习音乐制作&#xff0c;发现这个功能特别有用&#xff01; 小红&#xff1a;啊&#xff0c;好像没有听说过。它是用来干嘛的&#xff1f; 小明&#xff1a;简单来说&#xff0c;就是可以将不同格式的音频文件进行转…

嵌入式Linux应用开发笔记:串口

文章目录 目的基础说明开发准备设备树应用程序 应用程序与演示代码演示 总结设备树文件 目的 串口&#xff08;UART&#xff09;是嵌入式设备中比较常用的功能。这篇文章将记录下应用程序中串口操作相关内容。 这篇文章中内容均在下面的开发板上进行测试&#xff1a; 《新唐N…

阿里 P8 架构师总结的 Java 面试笔记,上线仅七天,Github 标星 55K

作为一名优秀的程序员&#xff0c;技术面试是不可避免的一个环节&#xff0c;一般技术面试官都会通过自己的方式去考察程序员的技术功底与基础理论知识。 如果你参加过一些大厂面试&#xff0c;肯定会遇到一些这样的问题&#xff1a; 1、看你项目都用的框架&#xff0c;熟悉 …

AI翻唱整合

感谢阅读 不完全原创声明环境部署下载工具包安装人声背景音分离工具分离消除脏数据&#xff08;比如杂音&#xff09;准备自己的声音预处理完工效果参考 不完全原创声明 本人使用了多个第三方软件&#xff0c;并修改了一部分代码使得其可以在PC上训练&#xff0c;如有侵权请联…