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

news/2025/1/12 13:20:18/

目录

在这里插入图片描述

使用方法

1.编译使用插件

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

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

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

 @Overridepublic 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 typeType t = Type.getType(methodDesc);Type[] argumentTypes = t.getArgumentTypes();Type returnType = t.getReturnType();// (2) compute the size of local variable and operand stackboolean isStaticMethod = ((methodAccess & Opcodes.ACC_STATIC) != 0);int localSize = isStaticMethod ? 0 : 1;for (Type argType : argumentTypes) {localSize += argType.getSize();}int stackSize = returnType.getSize();// (3) method bodymv.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 typeType t = Type.getType(methodDesc);Type[] argumentTypes = t.getArgumentTypes();Type returnType = t.getReturnType();// (2) compute the size of local variable and operand stackboolean isStaticMethod = ((methodAccess & Opcodes.ACC_STATIC) != 0);int localSize = isStaticMethod ? 0 : 1;for (Type argType : argumentTypes) {localSize += argType.getSize();}int stackSize = returnType.getSize();// (3) method bodymv.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() {@Overridepublic void onClick(View v) {Toast.makeText(MainActivity.this,"aaa",Toast.LENGTH_SHORT).show();}});

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

辅助工具

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


http://www.ppmy.cn/news/401214.html

相关文章

接口自动化测试框架?你真的会封装吗?自动化框架几大功能专项...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 当准备使用一个接…

大数据项目常识

大数据项目 随着社会的进步&#xff0c;大数据的高需求&#xff0c;高薪资&#xff0c;高待遇&#xff0c;促使很多人都来学习和转行到大数据这个行业。学习大数据是为了什么&#xff1f;成为一名大数据高级工程师。而大数据工程师能得到高薪、高待遇的能力在哪&#xff1f;自…

Stream流的使用案例

Stream流的使用案例 1. 演员类Actor public class Actor {private String name;private Integer age;public Actor(String name, Integer age) {this.name name;this.age age;}public String getName() {return name;}public void setName(String name) {this.name name;}…

国产Excel处理控件spire.xls,新版抢先看~

Spire.XLS for .NET 是一款专业的 .NET Excel 组件&#xff0c; 可以用在各种 .NET 框架中&#xff0c;无需依赖于 Microsoft Office Excel&#xff0c;使开发人员可以快速地在 .NET 平台上完成对 Excel 的各种编程操作&#xff0c;如根据模板创建新的 Excel 文档&#xff0c;…

魔兽争霸V星际争霸V红警

魔兽争霸V星际争霸V红警 魔兽娱乐性强 比较搞笑 你常常越玩越轻松星际竞技性强 比较严肃 你常常越玩越紧张红警政治性强 比较偏激 你常常越玩越气愤玩魔兽 就像唱卡拉ok 普通人练一首歌半个月 已经能赢得同伴的掌声玩星际 就像唱京戏 曲不离口的练上一年 可能还唱不上调子玩红警…

星际争霸II发布了!!!

\r\n 今天,我怀着万分崇敬的心情, 看到了跳票无数次, 传说中的星际争霸 II -- StarCraft II 的最终发布! 有图为证!请看: <img style\"width: 612px; height: 458px;\" src\"http://blog.chinaunix.net/photo/31687_070520121001.jpg\"> 可惜现在主…

探秘AlphaStar:星际争霸人工智能

&#xff08;声明&#xff1a;此文已发表于《爱上机器人》2019年2月刊&#xff0c;转载请联系作者&#xff09; 前言 近十年来&#xff0c;人工智能的研究人员们一直在尝试将游戏用作测试和评估人工智能系统的方法。得益于算法的发展和计算能力的增长&#xff0c; 研究人…

摘录星际争霸1触发

1.防止玩家用show me the money 只要你的地图使用的钱数量不可能超过10000就可以&#xff0c;或是只用一种资源作钱也行.只要玩家的矿和汽同时上万&#xff0c;可判定他用了秘籍; 2.防止玩家用black sheep wall 在玩家无法到达的地方给玩家放置一个虫族防御塔&#…