记一次使用修改字节码的方法解决java.lang.NoSuchMethodError
接兔兔国际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[i] != null) {
// System.out.print(i);
// System.out.print(" = ");
// System.out.print(infos[i].getVerbose());
// System.out.print(" = ");
// System.out.println(infos[i].getTagVerbose());
// if (i == 160) {//刚刚找到的是21位置
// ConstantUtf8Info uInfo = (ConstantUtf8Info) infos[i]; //刚刚那里是CONSTANT_Utf-8_info所以这里要用这个
//// System.out.println("xxxxxxxxxxxxxxxxxxxx");
//// uInfo.setString("getActivity"); // 如果用这种方式直接修改string ,不行, Name and Type 后面的type 还是Landroid/content/Context
//// infos[i] = uInfo;
// }
// }
// }
//这种方式也可以,一样的
/* if(infos[count] != null) {
ConstantUtf8Info uInfo = (ConstantUtf8Info) infos[i]; //刚刚那里是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
记一次使用修改字节码的方法解决java.lang.NoSuchMethodError的更多相关文章
- android apk 防止反编译技术第二篇-运行时修改字节码
上一篇我们讲了apk防止反编译技术中的加壳技术,如果有不明白的可以查看我的上一篇博客http://my.oschina.net/u/2323218/blog/393372.接下来我们将介绍另一种防止a ...
- JVM 字节码指令手册 - 查看 Java 字节码
JVM 字节码指令手册 - 查看 Java 字节码 jdk 进行的编译生成的 .class 是 16 进制数据文件,不利于学习分析.通过下命令 javap -c Demo.class > Dem ...
- 记一次部署时报java.lang.NoSuchMethodError:javax.persistence.spi.PersistenceUnitInfo.getValidationMode()Ljavax / persistence / ValidationMode;的解决办法
楼主在部署war包的时候,本地启动不报错,服务器商报如下问题: Error creating bean with name 'entityManagerFactory' defined in clas ...
- 动态修改字节码以替换用反射调用get set方法的形式
1. 起因 在前两天,为了解决websphere和JDK8上部署的应用发起webservice调用(框架用的cxf)时报错的问题,跟了一些代码,最终发现可以通过加上参数-Dcom.sun.xml.bi ...
- Python 文件编译为字节码的方法
一般情况下 python 不需要手动编译字节码.但是如果不想直接 release 源代码给其他人,将文件编译成字节码,可以实现一定程度的信息隐藏. 1) 使用模块 py_compile 编译一个单文件 ...
- 从字节码层面,解析 Java 布尔型的实现原理
最近在系统回顾学习 Java 虚拟机方面的知识,其中想到一个很有意思的问题:布尔型在虚拟机中到底是什么类型? 要想解答这个问题,我们看 JDK 的源码是无法解决源码的,我们必须深入到 class 文件 ...
- 从字节码的角度看Java内部类与外部类的互相访问
Java中non-static内部类为何可以访问外部类的变量?Java中外部类又为何可以访问内部类的private变量?这两个问题困扰过我一段时间,查了一些网上的答案,大多从“闭包”概念入手,理解起来 ...
- 记一次netty版本冲突,报java.lang.NoSuchMethodError: io.netty.util.internal.ObjectUtil.checkPositive的问题
elasticsearch 5.6中使用TransportClient初始化抛异常 在引入elasticsearch5.6的transportclient包中,会引入netty进行通信. <!- ...
- 记一次线上环境的内存溢出(java.lang.OutOfMemoryError)
事故背景 今天客户说风控项目有个别用户查询不到数据不是报错就是一直卡在那里,我就去那个接口看了下. 一看项目日志今天的都几个g了,平常也就几百兆吧,很明显出了问题. 请求接口后使用命令tail -f ...
随机推荐
- js/jQuery中load()、onload()、ready()的区别
一.两大事件 load事件:指页面包含图片等文件在内的所有元素都加载完毕后执行的事件. ready事件:表示文档结构已加载完成(不包括图片等非文字媒体文件) 浏览器页面渲染的过程 - 寸寸君 - 博客 ...
- arcgisserver成功发布服务后,浏览服务,无地图显示
软件:ArcMap10.2,ArcgisCatalog10.2 方法:ArcMap10.2添加数据库连接,成功登陆数据库后,拖拽目标图层至Map窗口,对各个图层进行符号化设置 ArcCatalog中找 ...
- python安装插件包注意事项
注意!注意!注意!安装以来lib库时强烈建议使用pip安装:原因:nu1:用exe安装会出现各种意想不到让您惊讶的错误!!!nu2:这种错误很难解决且花费无用功!!! 使用pip安装: nu1:使用. ...
- Vue学习之路---No.6(分享心得,欢迎批评指正)
我们还是先回顾一下上一次的重点: 1.事件绑定,我们可以对分别用方法和js表达式对事件进行处理 2.当方法名带括号的时候,在方法中一定要传参:而不带括号的时候,vm会自动配置默认event 3.各类事 ...
- js模块化加载器实现
背景 自es6以前,JavaScript是天生模块化缺失的,即缺少类似后端语言的class, 作用域也只以函数作为区分.这与早期js的语言定位有关, 作为一个只需要在网页中嵌入几十上百行代码来实现一些 ...
- delphi处理消息的几种方式
第一种:自定义处理单条消息 unit Unit2; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, C ...
- [原创]HBase学习笔记(4)- 数据导入
需要分别从Oracle和文本文件往HBase中导入数据,这里介绍几种数据导入方案. 1.使用importTSV导入HBase importTSV支持增量导入.新数据插入,已存在数据则修改. 1.1.首 ...
- pyqt样式表语法笔记(下)--原创
pyqt样式表语法笔记(下) python 启动界面 QSS pyqt 一.启动界面的设置 简单点~说话的方式简单点用一张静态图片作为程序启动界面为例. 原来的语句 python 7行 ...
- bootstrap-dialog插件的使用
官网文档:http://nakupanda.github.io/bootstrap3-dialog BootstrapDialog.show({ message: 'Hi Apple!', messa ...
- 在亚马逊Red Hat 7.1 linux上安装mysql
安装前检查之前是否安装并卸载之前的和删除关联文件 rpm -qa|grep mysql yum remove mysql mysql-server mysql-libs mysql-com ...