Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 358|回复: 0

记一次使用修改字节码的方法解决java.lang.NoSuchMethodError

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-5-30 23:19:14 | 显示全部楼层 |阅读模式

    接兔兔国际sdk ane

    充值界面选择兔币充值就会闪退,

    观察logcat ,NoSuchMethodError: com.tutu.common.a.b.getContext 原来是因为没有方法找不到

    04-19 10:10:54.224: E/AndroidRuntime(20315): FATAL EXCEPTION: main
    04-19 10:10:54.224: E/AndroidRuntime(20315): Process: com.tutusdk.global.demo, PID: 20315
    04-19 10:10:54.224: E/AndroidRuntime(20315): java.lang.NoSuchMethodError: com.tutu.common.a.b.getContext
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at com.tutu.common.a.b.a(TutuAlertDialog.java:78)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at com.tutu.common.a.b.onCreateView(TutuAlertDialog.java:66)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.support.v4.app.Fragment.performCreateView(Fragment.java:1786)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1126)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:739)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1489)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:454)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.os.Handler.handleCallback(Handler.java:733)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.os.Handler.dispatchMessage(Handler.java:95)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.os.Looper.loop(Looper.java:136)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at android.app.ActivityThread.main(ActivityThread.java:5113)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at java.lang.reflect.Method.invokeNative(Native Method)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at java.lang.reflect.Method.invoke(Method.java:515)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:609)
    04-19 10:10:54.224: E/AndroidRuntime(20315):     at dalvik.system.NativeStart.main(Native Method)

    可以用附件中的jar包练习,下载的是zip 解压之后就有jar包。用 jd-gui 反编译找到b class, 介绍一个更好用的反编译工具:apktoolbox,下载:http://www.52pojie.cn/thread-429318-1-1.html

    package com.tutu.common.a;
    
    import android.graphics.drawable.ColorDrawable;
    import android.os.Bundle;
    import android.support.v4.app.DialogFragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.ViewGroup;
    import android.widget.Button;
    import android.widget.TextView;
    import com.feng.android.i.e;
    import com.feng.android.i.f;
    
    /* compiled from: TutuAlertDialog */
    public class b extends DialogFragment {
        private TextView a;
        private Button b;
        private Button c;
        private String d;
        private String e;
        private String f;
        private String g;
        private a h;
    
        /* compiled from: TutuAlertDialog */
        public interface a {
            void c(String str);
    
            void c_(String str);
        }
    
        public void onCreate(Bundle bundle) {
            super.onCreate(bundle);
        }
    
        public static b a(String str, String str2, String str3, String str4, a aVar) {
            b bVar = new b();
            Bundle bundle = new Bundle();
            bundle.putString("left_text", str);
            bundle.putString("right_text", str2);
            bundle.putString("dialog_tips", str3);
            bundle.putString("dialog_tag", str4);
            bVar.setArguments(bundle);
            bVar.a(aVar);
            return bVar;
        }
    
        public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle bundle) {
            getDialog().requestWindowFeature(1);
            getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(0));
            View inflate = layoutInflater.inflate(e.c(getActivity(), "tutu_alert_dialog_layout"), viewGroup, false);
            getDialog().getWindow().setGravity(17);
            if (getArguments() != null) {
                this.d = getArguments().getString("left_text");
                this.e = getArguments().getString("right_text");
                this.f = getArguments().getString("dialog_tips");
                this.g = getArguments().getString("dialog_tag");
            }
            a(inflate);
            setCancelable(false);
            return inflate;
        }
    
        public void a(a aVar) {
            this.h = aVar;
        }
    
        private void a(View view) {
            this.b = (Button) view.findViewById(e.a(getActivity(), "tutu_alert_dialog_ignore_btn"));
            this.c = (Button) view.findViewById(e.a(getActivity(), "tutu_alert_dialog_recharge_btn"));
            this.a = (TextView) view.findViewById(e.a(getContext(), "tutu_alert_dialog_tips"));
            if (!f.c(this.d)) {
                this.b.setText(this.d);
            }
            if (!f.c(this.e)) {
                this.c.setText(this.e);
            }
            if (!f.c(this.f)) {
                this.a.setText(this.f);
            }
            this.b.setOnClickListener(new OnClickListener(this) {
                final /* synthetic */ b a;
    
                {
                    this.a = r1;
                }
    
                public void onClick(View view) {
                    if (this.a.h != null) {
                        this.a.h.c_(this.a.g);
                    }
                    this.a.dismiss();
                }
            });
            this.c.setOnClickListener(new OnClickListener(this) {
                final /* synthetic */ b a;
    
                {
                    this.a = r1;
                }
    
                public void onClick(View view) {
                    if (this.a.h != null) {
                        this.a.h.c(this.a.g);
                    }
                    this.a.dismiss();
                }
            });
        }
    }

     

    问题就出在标红的位置,通过这个 

    http://stackoverflow.com/questions/36116606/nosuchmethoderrorcom-android-app-fragment-getcontext-in-android

    知道, 新版的sdk才支持getContext方法,但是adobe air sdk 要跟进比较慢,没有该方法,要改成 getActivity

    因为这是第三方sdk , 没有源代码, 只能修改 class文件。 

    google 一番 如何修改字节码, 找到几篇文章。 放在最后。

     

    下载 jclasslib ,安装。打开jclasslib bytecode viewer 用于查看 b.class 文件的字节码

    解压jar包, 将 com/tutu/common/a文件夹内的b.class 文件 拖拽进bytecode viewer 

     

    根据上面反编译出来的源码,我们要修改的地方在   private void a(View view)  这个方法中,展开左边的Methods, 一个个看图中名称为a的方法, 观察右边的Access flags, 如果不是private的迅速跳过,是的话观察右边Descriptor ,这里面是参数列表。 觉得像的就展开它, 选中 [0]Code, 观察右边的byte code

     

     

     

    图中 22行 就是要找的 getContext。 鼠标点击前面的 #56 , 跳的下面这张图

     

     

    看到使用的 划红线的部分是 #80  再回到 bytecode中 , 看13行 getActivity的地方时 #54, 鼠标点击它, 跳到下面这张图

     

    看到 划红线的部分是 #78 , 滑动左边的列表, 发现这个东西是在Constant Pool 分类下。 好下面编代码修改字节码, 将指向#80 改成指向 #78

    在eclipse中新建一个java project。

    进入jclasslib 安装目录, 进入 modules/data/src/main/java ,拷贝 org 及其内容到 java project src 目录下

     

    新建一个 App 类,放main方法

    import java.io.DataInput;
    import java.io.DataInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    import org.gjt.jclasslib.io.ClassFileWriter;
    import org.gjt.jclasslib.structures.CPInfo;
    import org.gjt.jclasslib.structures.ClassFile;
    import org.gjt.jclasslib.structures.InvalidByteCodeException;
    import org.gjt.jclasslib.structures.MethodInfo;
    import org.gjt.jclasslib.structures.constants.ConstantMethodrefInfo;
    import org.gjt.jclasslib.structures.constants.ConstantNameAndTypeInfo;
    
    
    public class App {
        public static void main(String[] args) throws InvalidByteCodeException, IOException {
             String filePath = "C:/Users/fp/Documents/goalPlatformClientV1/ANE/tutu/package/Android-ARM/b.class";  
                FileInputStream fis = new FileInputStream(filePath);  
                DataInput di = new DataInputStream(fis);  
                ClassFile cf = new ClassFile();  
                cf.read(di);  
                
                CPInfo[] infos = cf.getConstantPool();  
                
                
                MethodInfo[] ms = cf.getMethods();
                MethodInfo m = ms[5];
                
    //            System.out.println(m.getAccessFlags());
    //            System.out.println(m.getAccessFlagsVerbose());
    //            System.out.println(m.getName());
    //            System.out.println(m.getNameIndex());
    //            System.out.println(m.getDescriptor());
    //            System.out.println(m.getDescriptorIndex());
    //            AttributeInfo[] getAttributes = m.getAttributes();
    //            System.out.println(m.getAttributes());
                
                
                ConstantMethodrefInfo uInfo = (ConstantMethodrefInfo) infos[56]; //刚刚那里是CONSTANT_Methodref_info所以这里要用这个  
                ConstantNameAndTypeInfo nt = uInfo.getNameAndTypeInfo();
                String s = String.format("%s\n%s\n%s\n%s", nt.getName(), nt.getTag(), nt.getTagVerbose() ,  nt.getVerbose());
                System.out.println(s);
                uInfo.setNameAndTypeIndex(78);
                  infos[56] = uInfo;  
          
    //            int count = infos.length;  
    //            for (int i = 0; i < count; i++) {  
    //                if (infos != null) {  
    //                    System.out.print(i);  
    //                    System.out.print(" = ");  
    //                    System.out.print(infos.getVerbose());  
    //                    System.out.print(" = ");  
    //                    System.out.println(infos.getTagVerbose());  
    //                    if (i == 160) {//刚刚找到的是21位置  
    //                        ConstantUtf8Info uInfo = (ConstantUtf8Info) infos; //刚刚那里是CONSTANT_Utf-8_info所以这里要用这个  
    ////                        System.out.println("xxxxxxxxxxxxxxxxxxxx");
    ////                        uInfo.setString("getActivity");  // 如果用这种方式直接修改string ,不行, Name and Type 后面的type 还是Landroid/content/Context
    ////                        infos = uInfo;  
    //                    }  
    //                }  
    //            }  
                //这种方式也可以,一样的  
        /*      if(infos[count] != null) { 
                    ConstantUtf8Info uInfo = (ConstantUtf8Info) infos; //刚刚那里是CONSTANT_Utf-8_info所以这里要用这个 
                    uInfo.setBytes("baidu".getBytes()); 
                    infos[count] = uInfo; 
                }*/  
                  
                cf.setConstantPool(infos);  
                fis.close();  
                File f = new File(filePath);  
                ClassFileWriter.writeToFile(f, cf);  
        }
    }

     

    用于练手的附件:

    http://files.cnblogs.com/files/lonkiss/java.library.tutu.zip 

    解压之后有个jar包。 博客园不让直接上传jar包

    参考资料:

    直接修改别人jar包里面的class文件 工具:jclasslib - hexin373的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/hexin373/article/details/6669813

    如何利用JClassLib修改.class文件 - “羊习习”的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/betterandroid/article/details/14520667

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-2 15:50 , Processed in 0.063171 second(s), 28 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表