Class文件解析
1 准备工作
获取class文件byte[]
public static byte[] getFileBytes(File file) {
try (FileInputStream fileInputStream = new FileInputStream(file)) {
int available = fileInputStream.available();
byte[] data=new byte[available];
fileInputStream.read(data,0,available-1);
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
这里使用jdk的ByteBuffer包装bytes
ByteBuffer data = ByteBuffer.wrap(getFileBytes(file));
因为ByteBuffer没有无符号的读取方法,所以自己实现一下,也可以直接用netty的Bytebuf,里面方法齐全
// 图方便直接返回int
private int readUnsignedByte(ByteBuffer data) {
return data.get() & 0xff;
}
// 图方便直接返回int
private int readUnsignedShort(ByteBuffer data) {
return data.getShort() & 0xffff;
}
private long readUnsignedInt(ByteBuffer data) {
return data.getInt() & 0xffffffffL;
}
定义class文件结构
参考: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html
private static class ClassFileStructure {
long magic;
int minorVersion;
int majorVersion;
int constantPoolCount;
ConstantPool[] constantPool;
int accessFlags;
int thisClass;
int superClass;
int interfacesCount;
int[] interfaces;
int fieldsCount;
FieldInfo[] fields;
int methodsCount;
MethodInfo[] methods;
int attributesCount;
AttributeInfo[] attributes;
}
2 开始解析
2.1 magic
private void magic(ClassFileStructure structure, ByteBuffer data) {
structure.magic = readUnsignedInt(data);
}
2.2 minorVersion
private void minorVersion(ClassFileStructure structure, ByteBuffer data) {
structure.minorVersion = readUnsignedShort(data);
}
2.3 majorVersion
private void majorVersion(ClassFileStructure structure, ByteBuffer data) {
structure.majorVersion = readUnsignedShort(data);
}
2.4 constantPoolCount
private void constantPoolCount(ClassFileStructure structure, ByteBuffer data) {
structure.constantPoolCount = readUnsignedShort(data);
}
2.5 ConstantPool[]
ConstantPool不同tag解析方式不同,定义抽象类ConstantPool,子类按规则解析
private abstract static class ConstantPool {
int tag;
public ConstantPool(int tag) {
this.tag = tag;
}
abstract void parse(ByteBuffer data);
}
子类实现ConstantPool
ConstantUtf8:
private class ConstantUtf8 extends ConstantPool {
int length;
byte[] bytes;
public ConstantUtf8(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.length = readUnsignedShort(data);
bytes = new byte[this.length];
for (int i = 0; i < this.length; i++) {
bytes[i] = (byte) readUnsignedByte(data);
}
}
}
ConstantMethodHandle:
private class ConstantMethodHandle extends ConstantPool {
short referenceKind;
int referenceIndex;
public ConstantMethodHandle(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.referenceKind = (short) readUnsignedByte(data);
this.referenceIndex = readUnsignedShort(data);
}
}
ConstantMethodType:
private class ConstantMethodType extends ConstantPool {
int descriptorIndex;
public ConstantMethodType(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.descriptorIndex = readUnsignedShort(data);
}
}
ConstantClass:
private class ConstantClass extends ConstantPool {
int nameIndex;
public ConstantClass(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.nameIndex = readUnsignedShort(data);
}
}
ConstantClass:
private class ConstantClass extends ConstantPool {
int nameIndex;
public ConstantClass(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.nameIndex = readUnsignedShort(data);
}
}
ConstantFieldref:
private class ConstantFieldref extends ConstantPool {
int classIndex;
int nameAndTypeIndex;
public ConstantFieldref(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.classIndex = readUnsignedShort(data);
this.nameAndTypeIndex = readUnsignedShort(data);
}
}
ConstantMethodref:
private class ConstantMethodref extends ConstantPool {
int classIndex;
int nameAndTypeIndex;
public ConstantMethodref(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.classIndex = readUnsignedShort(data);
this.nameAndTypeIndex = readUnsignedShort(data);
}
}
ConstantInterfaceMethodref:
private class ConstantInterfaceMethodref extends ConstantPool {
int classIndex;
int nameAndTypeIndex;
public ConstantInterfaceMethodref(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.classIndex = readUnsignedShort(data);
this.nameAndTypeIndex = readUnsignedShort(data);
}
}
ConstantString:
private class ConstantString extends ConstantPool {
int stringIndex;
public ConstantString(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.stringIndex = readUnsignedShort(data);
}
}
ConstantInteger:
private class ConstantInteger extends ConstantPool {
long bytes;
public ConstantInteger(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.bytes = readUnsignedInt(data);
}
}
ConstantFloat:
private class ConstantFloat extends ConstantPool {
long bytes;
public ConstantFloat(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.bytes = readUnsignedInt(data);
}
}
ConstantLong:
private class ConstantLong extends ConstantPool {
long highBytes;
long lowBytes;
public ConstantLong(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.highBytes = readUnsignedInt(data);
this.lowBytes = readUnsignedInt(data);
}
}
ConstantDouble:
private class ConstantDouble extends ConstantPool {
long highBytes;
long lowBytes;
public ConstantDouble(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.highBytes = readUnsignedInt(data);
this.lowBytes = readUnsignedInt(data);
}
}
ConstantNameAndType:
private class ConstantNameAndType extends ConstantPool {
int nameIndex;
int descriptorIndex;
public ConstantNameAndType(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.nameIndex = readUnsignedShort(data);
this.descriptorIndex = readUnsignedShort(data);
}
}
ConstantInvokeDynamic:
private class ConstantInvokeDynamic extends ConstantPool {
int bootstrapMethodAttrIndex;
int nameAndTypeIndex;
public ConstantInvokeDynamic(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.bootstrapMethodAttrIndex = readUnsignedShort(data);
this.nameAndTypeIndex = readUnsignedShort(data);
}
}
以上是所有 constantPool 子类型,现在开始解析
坑:“所有 8 字节常量都占用文件constant_pool表中的两个条目class。 如果
CONSTANT_Long_infoorCONSTANT_Double_info结构是constant_pool表中索引n处的项目,则池中的下一个可用项目位于索引n +2 处。
constant_pool 索引n +1 必须有效但被视为不可用 。 回想起来,让 8 字节常量占用两个常量池条目是一个糟糕的选择。”
private void constantPool(ClassFileStructure structure, ByteBuffer data) {
structure.constantPool = new ConstantPool[structure.constantPoolCount - 1];
for (int i = 0; i < structure.constantPool.length; i++) {
int type = readUnsignedByte(data);
int index = i;
switch (type) {
case 1: //
structure.constantPool[i] = new ConstantUtf8(type);
break;
case 3: //
structure.constantPool[i] = new ConstantInteger(type);
break;
case 4:
structure.constantPool[i] = new ConstantFloat(type);
break;
case 5:
structure.constantPool[i] = new ConstantLong(type);
i++;// 占2位
break;
case 6:
structure.constantPool[i] = new ConstantDouble(type);
i++;// 占2位
break;
case 7: //
structure.constantPool[i] = new ConstantClass(type);
break;
case 8: //
structure.constantPool[i] = new ConstantString(type);
break;
case 9: //
structure.constantPool[i] = new ConstantFieldref(type);
break;
case 10: //
structure.constantPool[i] = new ConstantMethodref(type);
break;
case 11: //
structure.constantPool[i] = new ConstantInterfaceMethodref(type);
break;
case 12: //
structure.constantPool[i] = new ConstantNameAndType(type);
break;
case 15: //
structure.constantPool[i] = new ConstantMethodHandle(type);
break;
case 16: //
structure.constantPool[i] = new ConstantMethodType(type);
break;
case 18: //
structure.constantPool[i] = new ConstantInvokeDynamic(type);
break;
default:
throw new ParserException("class file parser exception");
}
structure.constantPool[index].parse(data);
}
}
2.6 accessFlags
private void accessFlags(ClassFileStructure structure, ByteBuffer data) {
structure.accessFlags = readUnsignedShort(data);
}
2.7 thisClass
private void thisClass(ClassFileStructure structure, ByteBuffer data) {
structure.thisClass = readUnsignedShort(data);
}
2.8 superClass
private void superClass(ClassFileStructure structure, ByteBuffer data) {
structure.superClass = readUnsignedShort(data);
}
2.9 interfacesCount
private void interfacesCount(ClassFileStructure structure, ByteBuffer data) {
structure.interfacesCount = readUnsignedShort(data);
}
2.10 int[] interfaces
private void interfaces(ClassFileStructure structure, ByteBuffer data) {
structure.interfaces = new int[structure.interfacesCount];
for (int i = 0; i < structure.interfacesCount; i++) {
structure.interfaces[i] = readUnsignedShort(data);
}
}
2.11 fieldsCount
private ClassFile fieldsCount(ClassFileStructure structure, ByteBuffer data) {
structure.fieldsCount = readUnsignedShort(data);
return this;
}
2.12 FieldInfo[] fields
FieldInfo:
private class FieldInfo {
int accessFlags;
int nameIndex;
int descriptorIndex;
int attributesCount;
AttributeInfo[] attributes;
public FieldInfo parse(ByteBuffer data) {
this.accessFlags = readUnsignedShort(data);
this.nameIndex = readUnsignedShort(data);
this.descriptorIndex = readUnsignedShort(data);
this.attributesCount = readUnsignedShort(data);
this.attributes = new AttributeInfo[attributesCount];
for (int i = 0; i < this.attributesCount; i++) {
this.attributes[i] = new AttributeInfo().parse(data);
}
return this;
}
}
AttributeInfo:
private class AttributeInfo {
int attributeNameIndex;
long attributeLength;
short[] info;
public AttributeInfo parse(ByteBuffer data) {
this.attributeNameIndex = readUnsignedShort(data);
this.attributeLength = readUnsignedInt(data);
this.info = new short[(int) attributeLength];
for (int i = 0; i < this.attributeLength; i++) {
this.info[i] = (short) readUnsignedByte(data);
}
return this;
}
}
private void fields(ClassFileStructure structure, ByteBuffer data) {
structure.fields = new FieldInfo[structure.fieldsCount];
for (int i = 0; i < structure.fieldsCount; i++) {
structure.fields[i] = new FieldInfo().parse(data);
}
}
2.13 methodsCount
private ClassFile methodsCount(ClassFileStructure structure, ByteBuffer data) {
structure.methodsCount = readUnsignedShort(data);
return this;
}
2.14 MethodInfo[]
MethodInfo:
private class MethodInfo {
int accessFlags;
int nameIndex;
int descriptorIndex;
int attributesCount;
AttributeInfo[] attributes;
public MethodInfo parse(ByteBuffer data) {
this.accessFlags = readUnsignedShort(data);
this.nameIndex = readUnsignedShort(data);
this.descriptorIndex = readUnsignedShort(data);
this.attributesCount = readUnsignedShort(data);
this.attributes = new AttributeInfo[attributesCount];
for (int i = 0; i < this.attributesCount; i++) {
this.attributes[i] = new AttributeInfo().parse(data);
}
return this;
}
}
private void methods(ClassFileStructure structure, ByteBuffer data) {
structure.methods = new MethodInfo[structure.methodsCount];
for (int i = 0; i < structure.methodsCount; i++) {
structure.methods[i] = new MethodInfo().parse(data);
}
}
2.15 attributesCount
private void attributesCount(ClassFileStructure structure, ByteBuffer data) {
structure.attributesCount = readUnsignedShort(data);
}
2.16 AttributeInfo[]
private void attributes(ClassFileStructure structure, ByteBuffer data) {
structure.attributes = new AttributeInfo[structure.attributesCount];
for (int i = 0; i < structure.attributesCount; i++) {
structure.attributes[i] = new AttributeInfo().parse(data);
}
}
Class文件解析的更多相关文章
- CocosStudio文件解析工具CsdAnalysis
起因 因为工作需要,所以需要使用CocosStudio来制作界面动画什么的.做完了发现需要找里边对象的时候会有很长一串代码,感觉不是很爽.之前写OC代码的时候可以吧程序中的对象指针跟编辑器中的对象相对 ...
- 通过正则表达式实现简单xml文件解析
这是我通过正则表达式实现的xml文件解析工具,有些XHTML文件中包含特殊符号,暂时还无法正常使用. 设计思路:常见的xml文件都是单根树结构,工具的目的是通过递归的方式将整个文档树装载进一个Node ...
- 八、Android学习第七天——XML文件解析方法(转)
(转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 八.Android学习第七天——XML文件解析方法 XML文件:exten ...
- phpcms V9 首页模板文件解析
在了解了<phpcms V9 URL访问解析>之后,我们已经知道首页最终执行的是content模块下index控制器的init方法. 下面, 我们逐步分析过程如下: 第一.首页默认执行的是 ...
- (转)AVI文件格式解析+AVI文件解析工具
AVI文件解析工具下载地址:http://download.csdn.net/detail/zjq634359531/7556659 AVI(Audio Video Interleaved的缩写)是一 ...
- itextSharp 附pdf文件解析
一.PdfObject: pdf对象 ,有9种,对象是按照对象内涵来分的,如果按照对象的使用规则来说,对象又分为间接对象和直接对象.间接对象是PDF中最常用的对象,如前面对象集合里面的,所有对象都是间 ...
- 《热血传奇2》wix、wil文件解析Java实现
在百度上搜索java+wil只有iteye上一篇有丁点儿内容,不过他说的是错的!或者说是不完整的,我个人认为我对于热血传奇客户端解析还是有一定研究的,请移步: <JMir——Java版热血传奇2 ...
- paper 37 : WINCE的BIB文件解析
WINCE的BIB文件解析 BIB的全称为Binary Image Builder,在Wince编译过程中的最后MakeImage阶段会用到BIB文件,BIB文件的作用是指示构建系统如何构建二进制映像 ...
- 如何让你的Apache支持include文件解析和支持shtml的相关配置
源地址:http://www.itokit.com/2011/0430/65992.html Apache支持include文件解析shtml首先要应该修改Apache配置文件httpd.conf . ...
- android基础知识13:AndroidManifest.xml文件解析
注:本文转载于:http://blog.csdn.net/xianming01/article/details/7526987 AndroidManifest.xml文件解析. 1.重要性 Andro ...
随机推荐
- 请求库之requests库
目录 一.介绍 二.基于get请求 1 基本请求 2 带参数的get请求 3 请求携带cookie 三.基于post请求 1 基本用法 2 发送post请求,模拟浏览器的登录行为 四.响应Respon ...
- ERP 系统的核心是什么?有什么作用?
ERP系统的核心就是系统的内部业务逻辑,这也是ERP复杂.专业性的体现!ERP系统需要适配企业的管理思想和业务流程,在技术上面也也要做到快速部署和个性化定制(客户化定制),而这些企业的规模不同.行业不 ...
- Tubian-Win上线!Tubian官方的Windows软件适配项目
Sourceforge.net下载:https://sourceforge.net/projects/tubian/ 123网盘下载: https://www.123pan.com/s/XjkKVv- ...
- HDU4734 F(x) (数位DP)
(如此简短的题目给人一种莫名的压迫感......) 题目中定义一个数的权值求解函数:F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1. 观察 ...
- 代码随想录第二天| 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II
2022/09/22 第二天 第一题 这题我就直接平方后排序了,很无脑但很快乐啊(官方题解是双指针 第二题 滑动窗口的问题,本来我也是直接暴力求解发现在leetCode上超时,看了官方题解,也是第一次 ...
- 驱动开发:内核中实现Dump进程转储
多数ARK反内核工具中都存在驱动级别的内存转存功能,该功能可以将应用层中运行进程的内存镜像转存到特定目录下,内存转存功能在应对加壳程序的分析尤为重要,当进程在内存中解码后,我们可以很容易的将内存镜像导 ...
- uoj131【NOI2015】品酒大会
题目链接 很容易想到p和q"r相似"就等价于在后缀数组中q与p之间的height值\(\ge r\),也就是说\(<r\)的那些height值会把排好序后的后缀分割成若干段, ...
- Java实现7种常见密码算法
原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介 前面在密码学入门一文中讲解了各种常见的密码学概念.算法与运用场景,但没有介绍过代码,因此,为作补充,这一篇将会介绍 ...
- 京东云开发者|京东云RDS数据迁移常见场景攻略
云时代已经来临,云上很多场景下都需要数据的迁移.备份和流转,各大云厂商也大都提供了自己的迁移工具.本文主要介绍京东云数据库为解决用户数据迁移的常见场景所提供的解决方案. 场景一:数据迁移上云 数据迁移 ...
- 基于 Docker 构建轻量级 CI 系统:Gitea 与 Woodpecker CI 集成
WoodpeckerCI 是一个由社区维护的 DroneCI 分支,使用 Apache License 2.0 许可证发布.社区版进一步扩展了 pipeline 的功能特性.支持对文件路径设置 pip ...