- 浏览: 136799 次
- 性别:
- 来自: 广州
文章分类
- 全部博客 (172)
- java (172)
- c# winform 关于窗体最大化时的是否全屏效果与是否遮盖任务栏 (1)
- c# winform 只运行一个程序实例 (1)
- Shiro权限框架 (1)
- Java字节码(.class文件)的代码解析 (1)
- Hibernate、Spring和Struts工作原理及使用理由 (1)
- 基本PKG处理命令 (1)
- 最近写的代码的小结 (1)
- Dual Palindromes (1)
- 编译TortoiseSVN1.7源代码笔记 (1)
- Android项目代码混淆 (1)
- 关于就业叨咕几句 (1)
- Java重定向System.out和System.err (1)
- IHS与WAS集成插件静默安装 (1)
- 专题地图概述 (1)
- 关于MapXtreme2004附带Sample不能运行的问题 (1)
- SQL注入漏洞 (1)
- 回顾过去 展望未来(写给自己) (1)
- DB2认证考试经验谈(700&&701) (1)
- 今天用到了RM格式文件的分割工具RealProducer (1)
- 搜索引擎还是很有发展前途的 (1)
- 泰利德破解,实现学校机房免费上网 (1)
- Arduino 引言:移动互联外设传感展望 (1)
- c/c++ static 用法总结(三版本合一) (1)
- JQuery与xml的组合谈 (1)
- Android开发之消息处理机制(一)——Handler (1)
- Android开发之PopupWindow (1)
- 解析BitmapData.getPixel32()返回值因何不准确 (1)
- 关于Ext引用js的顺序问题 (1)
- Js事件大全 (1)
- 使用JavaFX2.0编写国际象棋游戏 (1)
- Hibernate/JPA常见异常分析与解决 (1)
最新评论
-
amcucn:
这排版看得
Shiro权限框架 -
WAMING5:
这也太紧凑了,眼看花了
Shiro权限框架 -
longzhun:
大虾 ,看得出你很懒啊!发个贴 这样子怎么看!!!
Shiro权限框架 -
swanky_yao:
活干的不细!!
Spring+Hibernate框架下Mysql读写分离、主从数据库配 -
饶首建:
不错,不过用处比较少吧
批处理设ip和dns
Java字节码(.class文件)的代码解析
Java二进制指令代码以以下格式紧凑排列(opcode占一个字节):
opcode operand*
除了tableswitch和lookupswitch两条指令中间存在填充字节以外,其他指令都没有填充字节,即使在两条指令之间也没有。因而在读取指令的时候,要根据指令的定义读取。
通过对上面Java指令集的分析可以知道,Java指令集中很大一部分没有操作数,因而对这部分指令,只需要读取一个字节的操作码,将操作码映射成助记符即可。
而对其他带操作数的指令,则需要根据不同类型分析(由于apache中的bcel(Binary Code Engineering Library)对字节码的支持,操作码和助记符的映射可以用com.sun.org.apache.bcel.internal.Constats中提供的映射表数组来完成)。
1. 处理两条特殊的指令tableswitch和lookupswitch指令。
对这两条指令,首先都要去掉填充字符以使defaultbyte1索引号是字对齐的。
private static void make4ByteAlignment(ByteSequence codes) {
int usedBytes = codes.getIndex() % 4;
int paddingBytes = (usedBytes == 0) ? 0 : 4 - usedBytes;
for(int i = 0;i < paddingBytes;i++) {
codes.readByte();
}
}
对tableswitch指令,读取defaultoffset值,最小项的值,最大项的值以及在最小项和最大项之间每一项的offset值。并且将读取到的offset值和当前指令的基地址相加:
int defaultOffset1 = baseOffset + codes.readInt();
builder.append("\tdefault = #" + defaultOffset1);
int low = codes.readInt();
int high = codes.readInt();
int npair1 = high - low + 1;
builder.append(", npairs = " + npair1 + "\n");
for(int i = low;i <= high;i++) {
int match = i;
offset = baseOffset + codes.readInt();
builder.append(String.format("\tcase %d : #%d\n", match, offset));
}
对lookupswitch指令,读取defaultoffset值,键值对数值(npairs),以及npairs对的键值对,将得到的offset值和当前指令的基地址相加:
int defaultOffset2 = baseOffset + codes.readInt();
builder.append("\tdefault = #" + defaultOffset2);
int npairs2 = codes.readInt();
builder.append(", npairs = " + npairs2 + "\n");
for(int i = 0;i < npairs2;i++) {
int match = codes.readInt();
offset = baseOffset + codes.readInt();
builder.append(String.format("\tcase %d : #%d\n", match, offset));
}
2. 所有条件跳转指令都有两个字节的偏移量操作数(if<cond>, if_icmp<cond>, ifnull, ifnonnull, if_acmp<cond>)。无条件跳转指令goto和子例程跳转指令jsr也都是两个字节的偏移量作为操作数。
offset = baseOffset + codes.readShort();
builder.append(String.format("\t\t#%d\n", offset));
3. 对宽偏移量的跳转指令goto_w和子例程跳转指令jsr_w的操作数是四个字节的偏移量。
offset = baseOffset + codes.readInt();
builder.append(String.format("\t\t#%d\n", offset));
4. wide指令,则继续读取下一条指令,并将wide参数设置为true。
byteCodeToString(codes, pool, verbose, true);
5. 还有一些指令值以一个字节的局部变量索引号作为操作数的,如果有wide修饰,则用两个字节作为操作数,代表局部变量索引号。这样的指令有:aload, iload, fload, lload, dload, astore, istore, fstore, lstore, dstore, ret。
if(wide) {
index = codes.readUnsignedShort();
} else {
index = codes.readUnsignedByte();
}
builder.append(String.format("\t\t%%%d\n", index));
6. iinc指令,以一个字节的局部变量索引号和一个自己的常量作为参数;如果以wide修饰,则该指令的局部变量索引号和常量都占两个字节。
if(wide) {
index = codes.readUnsignedShort();
constValue = codes.readShort();
} else {
index = codes.readUnsignedByte();
constValue = codes.readByte();
}
builder.append(String.format("\t\t%d %d\n", index, constValue));
7. 对象操作指令,它们的操作数都是常量池中的索引,长度为两个字节。指向CONSTANT_Class_info类型的结构,这些指令有new, checkcast, instanceof, anewarray。
index = codes.readUnsignedShort();
builder.append("\t\t" + pool.getClassInfo(index).toInstructionString(verbose) + "\n");
8. 所有字段操作指令,它们的操作数都是常量池中的索引,长度为两个字节。指向CONSTANT_Fieldref_info类型结构,这些指令有getfield, putfield, getstatic, putstatic。
index = codes.readUnsignedShort();
builder.append("\t\t" + pool.getFieldRefInfo(index).toInstructionString(verbose) + "\n");
9. 非接口方法调用指令,也都是以两个字节的索引号作为操作数,指向常量池中的CONSTANT_Methodref_info类型结构,这些指令有invokespecial, invokevirtual, invokestatic。
index = codes.readUnsignedShort();
builder.append("\t\t" + pool.getMethodRefInfo(index).toInstructionString(verbose) + "\n");
10. 接口方法调用指令invokeinterface,它有四个字节的操作数,前两个字节为常量池的索引号,指向CONSTANT_InterfaceMethodref_info类型,第三个字节为count,表示参数的字节数,最后一个字节为0值。
index = codes.readUnsignedShort();
int nargs = codes.readUnsignedByte(); //Historical, redundant
builder.append("\t\t" + pool.getInterfaceMethodRefInfo(index).toInstructionString(verbose));
builder.append(" : " + nargs + "\n");
codes.readUnsignedByte(); //reserved should be zero
11. 基本类型的数组创建指令newarray,它的操作数为一个字节的类型标识。
String type = Constants.TYPE_NAMES[codes.readByte()];
builder.append(String.format("\t\t(%s)\n", type));
12. 多维数组的创建指令multianewarray,它有三个字节的操作数,前两个字节为索引号,指向CONSTANT_Class_info类型,表示数组的类型,最后一个字节指定数组的维度。
index = codes.readUnsignedShort();
int dimensions = codes.readUnsignedByte();
builder.append(String.format("\t\t%s (%d)\n", pool.getClassInfo(index).getName(), dimensions));
13. 常量入栈指令ldc,以一个字节的索引号作为参数,指向CONSTANT_Integer_info、CONSTANT_Float_info、CONSTANT_String_info、CONSTANT_Class_info类型,表示要入栈的常量值(int类型值、float类型值、String引用类型值或对象引用类型值)。
index = codes.readUnsignedByte();
builder.append("\t\t" + pool.getPoolItem(index).toInstructionString(verbose) + "\n");
14. 宽索引的常量入栈指令ldc_w,以两个字节的索引号作为参数,指向CONSTANT_Integer_info、CONSTANT_Float_info、CONSTANT_String_info、CONSTANT_Class_info类型,表示要入栈的常量值(int类型值、float类型值、String引用类型值或对象引用类型值)。
index = codes.readUnsignedShort();
builder.append("\t\t" + pool.getPoolItem(index).toInstructionString(verbose) + "\n");
15. 宽索引的常量入栈指令ldc2_w,以两个字节的索引号作为参数,指向CONSTANT_Long_info、CONSTANT_Double_info类型,表示要入栈的常量值(long类型值、double类型值)。
index = codes.readUnsignedShort();
builder.append("\t\t" + pool.getPoolItem(index).toInstructionString(verbose) + "\n");
16. bipush指令,以一个字节的常量作为操作数。
byte constByte = codes.readByte();
builder.append(“\t” + constByte);
17. sipush指令,以两个字节的常量作为操作数。
short constShort = codes.readShort();
builder.append(“\t” + constShort);
以上还有一些没有完成的代码,包括字段(方法)的签名和描述符没有解析,有一些解析的格式还需要调整等。不管怎么样,总体的结构就是这样了,其它的都是细节问题,这里不讨论了。
参见bcel项目的org.apache.bcel.classfile.Utility类.2010年10月6日
发表评论
-
Hibernate/JPA常见异常分析与解决
2012-02-07 17:24 14701. ClassNotFoundException: ... -
使用JavaFX2.0编写国际象棋游戏
2012-02-07 16:24 1062前面发布了不少Javafx2的教程,不觉手痒,想尝试一 ... -
Js事件大全
2012-02-04 15:34 747一般事件 事件 ... -
关于Ext引用js的顺序问题
2012-02-02 15:49 722今天自己搞了个ext的helloworld,所需的包都 ... -
解析BitmapData.getPixel32()返回值因何不准确
2012-02-02 12:29 957<div style="widt ... -
Android开发之PopupWindow
2012-01-31 13:48 1648<h1>Android开发之PopupWi ... -
Android开发之消息处理机制(一)——Handler
2012-01-11 15:19 1132<h1>Android开发之消息处理机制( ... -
JQuery与xml的组合谈
2011-12-21 17:18 771JQuery与xml的组合谈 今天谈的是XML,学ja ... -
c/c++ static 用法总结(三版本合一)
2011-12-21 10:34 786<span style="&qu ... -
Arduino 引言:移动互联外设传感展望
2011-12-20 14:08 1296作者:mznewfacer (Wolf Geek) ... -
泰利德破解,实现学校机房免费上网
2011-12-20 13:58 923泰利德破解,实现学校机房免费上网<br> ... -
搜索引擎还是很有发展前途的
2011-12-19 11:49 926相信大家已经听说,在头几天,搜狐推出了一个专业搜索门户 ... -
今天用到了RM格式文件的分割工具RealProducer
2011-12-19 09:19 673项目要加一些视频文件,这些视频都是几个老师对数据结构课 ... -
DB2认证考试经验谈(700&&701)
2011-12-16 17:17 1082很多人都通过了D ... -
回顾过去 展望未来(写给自己)
2011-12-15 16:19 1450本来想用“昨天今天明天”做标题来着,但是人家本山大叔说 ... -
SQL注入漏洞
2011-12-15 12:19 693CSDN上的ASP.NET电子杂志下载下来看,就看到了 ... -
关于MapXtreme2004附带Sample不能运行的问题
2011-12-15 10:54 648</span> -
专题地图概述
2011-12-14 12:49 807<p class="MsoNorma ... -
IHS与WAS集成插件静默安装
2011-12-14 12:04 942<span style="col ... -
Java重定向System.out和System.err
2011-12-13 14:49 1143<div>继承PrintStream类: ...
相关推荐
Java字节码分析工具,系统分析了java字节码文件,即java class类文件,对该文件中的各种成分以树的形式描述出来,只能针对未加密的class文件,一般由标准java编译器编译生成的class文件都未加密,该系统在vs2003下面...
如果您只想运行已编译的字节码,则只需一个Python解释器。 运行测试 该项目带有许多单元测试。 如果运行shell脚本test.sh ,它将在示例目录中编译Java文件并运行单元测试。 您将能够看到通过了多少测试以及失败了...
4. Java字节码程序是可以在Java虚拟机上执行的。( ) 答案:√ [考点范围] JAVA简介 5. Java程序对计算机硬件平台的依赖性很低。( ) 答案:√ [考点范围] JAVA简介 6. Java可以用来进行多媒体及网络编程。( ) ...
2.11 字节码指令集简介 ............................................... 40 2.11.1 数据类型与Java虚拟机 ..................................... 41 2.11.2 加载和存储指令 .......................................
应用程序通过读取配置文件来获取到指定名称的类的字节码文件并加载其中的内容进行调用,对一个类文件进行解剖,就可以取得任意一个已知名称的class的内部信息,包括其modifiers(诸如public,static等等)、...
一个解析java class文件的代码
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...
到目前为止,GraalVM提供了两种运行Java程序的方法:将Java HotSpot VM与GraalVM JIT(即时)编译器一起使用,以及第二种方法:使用GraalVM ...单遍.class文件解析器 简单对象模型 Java中的Java本机接口(JNI)实现
Java 基础部分..................................................................................................................... 7 1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
JBC是一个eclipse插件,使开发人员可以查看和编辑eclipse中包含Java字节代码(* .class)的文件。 这样做的方式是让专门的编辑器打开.class文件,并将二进制代码显示为文本DSL,而关键字则将字节序列插入。 更改...
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...