这几天在写解析*.class文件的程序,实现class的反编译功能:目前所能实现的反编译是只含有方法的interface(不能反编译带有属性的interface)。不知道如何将源码打包上传,这里只帖出解析*.class文件的部分代码:
package com.hexin.study.interpreter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Administrator
*
* 更改所生成类型注释的模板为
* 窗口 > 首选项 > Java > 代码生成 > 代码和注释
*/
public class ClassParseFactory extends AbstractParseFactory {
private int CLASS_ATTRIBUTES = 16;
private short CONSTANT_POOL_COUNT = 0;
private short INTERFACES_COUNT = 0;
private short FIELDS_COUNT = 0;
private short METHODS_COUNT = 0;
private short ATTRIBUTES_COUNT = 0;
/* (非 Javadoc)
* @see com.hexin.study.interpreter.AbstractParseFactory#parse()
*/
public Context parse(File f) {
ClassContext cc = new ClassContext();
try {
DataInputStream dis = new DataInputStream(new FileInputStream(f));
int i = 0;
for(int m=0;m<CLASS_ATTRIBUTES;m++){
parseClass(dis,cc,i);
i++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return cc;
}
private void parseClass(DataInputStream dis,ClassContext cc,int i) throws IOException{
byte[] b = null;
switch(i){
case Constant.MAGIC:
b = new byte[4];
dis.read(b);
cc.setMAGIC(getHex(b));
break;
case Constant.MINOR_VERSION:
cc.setMINOR_VERSION(dis.readShort());
break;
case Constant.MAJOR_VERSION:
cc.setMAJOR_VERSION(dis.readShort());
break;
case Constant.CONSTANT_POOL_COUNT:
CONSTANT_POOL_COUNT = dis.readShort();
cc.setCONSTANT_POOL_COUNT(CONSTANT_POOL_COUNT);
break;
case Constant.CONSTANT_POOL:
List list = new ArrayList();
for(int l=1;l<CONSTANT_POOL_COUNT;l++)
parseCP(dis,list);
cc.setCONSTANT_POOL(list);
break;
case Constant.ACCESS_FLAGS:
cc.setACCESS_FLAGS(dis.readShort());
break;
case Constant.THIS_CLASS:
cc.setTHIS_CLASS(dis.readShort());
break;
case Constant.SUPER_CLASS:
cc.setSUPER_CLASS(dis.readShort());
break;
case Constant.INTERFACES_COUNT:
INTERFACES_COUNT = dis.readShort();
cc.setINTERFACES_COUNT(INTERFACES_COUNT);
break;
case Constant.INTERFACES:
List l = new ArrayList();
parseInfo(dis,l,INTERFACES_COUNT);
cc.setINTERFACES(l);
break;
case Constant.FIELDS_COUNT:
FIELDS_COUNT = dis.readShort();
cc.setFIELDS_COUNT(FIELDS_COUNT);
break;
case Constant.FIELDS:
List l_f = new ArrayList();
parseFieldInfo(dis,l_f,FIELDS_COUNT);
cc.setFIELDS(l_f);
break;
case Constant.METHODS_COUNT:
METHODS_COUNT = dis.readShort();
cc.setMETHODS_COUNT(METHODS_COUNT);
break;
case Constant.METHODS:
List l_m = new ArrayList();
parseMethodInfo(dis,l_m,METHODS_COUNT);
cc.setMETHODS(l_m);
break;
case Constant.ATTRIBUTES_COUNT:
ATTRIBUTES_COUNT = dis.readShort();
cc.setATTRIBUTES_COUNT(ATTRIBUTES_COUNT);
break;
case Constant.ATTRIBUTES:
Map m = new HashMap();
parseAttributeInfo(dis,m,ATTRIBUTES_COUNT);
cc.setATTRIBUTES(m);
break;
}
}
private void parseFieldInfo(DataInputStream dis,List l,int length) throws IOException{
for(int i=0;i<length;i++){
FieldNode fn = new FieldNode();
fn.setAccessFlags(dis.readShort());
fn.setNameIndex(dis.readShort());
fn.setDescriptorIndex(dis.readShort());
short count = dis.readShort();
fn.setAttributesCount(count);
parseAttributeInfo(dis,fn.getM(),count);
}
}
private void parseMethodInfo(DataInputStream dis,List l,int length) throws IOException{
for(int i=0;i<length;i++){
MethodNode mn = new MethodNode();
mn.setAccessFlags(dis.readShort());
mn.setNameIndex(dis.readShort());
mn.setDescriptorIndex(dis.readShort());
short count = dis.readShort();
mn.setAttributesCount(count);
parseAttributeInfo(dis,mn.getM(),count);
l.add(mn);
}
}
private void parseAttributeInfo(DataInputStream dis,Map m,int length) throws IOException{
for(int i=0;i<length;i++){
m.put(i+"_attibute_name_index",String.valueOf(dis.readShort()));
int count = dis.readInt();
m.put(i+"_attibute_length",String.valueOf(count));
List l = new ArrayList();
for(int n=0;n<count;n++){
l.add(String.valueOf(dis.readByte()));
}
m.put(i+"_attibute_info",l);
}
}
private void parseInfo(DataInputStream dis,List list,int length) throws IOException{
for(int i=0;i<length;i++){
list.add(String.valueOf(dis.readShort()));
}
}
private void parseCP(DataInputStream dis,List list) throws IOException{
byte f = dis.readByte();//判断是什么类别(utf-8,float。。。)
switch(f){
case 1://utf-8 string
short i = dis.readShort();//得到utf-8得长度
byte[] b = new byte[i];
dis.readFully(b);
list.add(new String(b));
break;
case 3://integer
list.add(String.valueOf(dis.readInt()));
break;
case 4://float
list.add(String.valueOf(dis.readFloat()));
break;
case 5://long
list.add(String.valueOf(dis.readLong()));
break;
case 6://double
list.add(String.valueOf(dis.readDouble()));
break;
case 7://class or interface reference
list.add(String.valueOf(dis.readShort()));
break;
case 8://string name_index
list.add(String.valueOf(dis.readShort()));
break;
case 9://field reference
list.add(String.valueOf(dis.readShort()));
list.add(String.valueOf(dis.readShort()));
break;
case 10://method reference
list.add(String.valueOf(dis.readShort()));
list.add(String.valueOf(dis.readShort()));
break;
case 11://interface method reference
list.add(String.valueOf(dis.readShort()));
list.add(String.valueOf(dis.readShort()));
break;
case 12://name and type reference
list.add(String.valueOf(dis.readShort()));
list.add(String.valueOf(dis.readShort()));
break;
default:
}
}
private String getHex(byte[] b){
StringBuffer sb = new StringBuffer();
for(int i=0;i<b.length;i++){
for(int m=0;m<2;m++){
int tmp = 0;
if(m==0) tmp = (b[i] & 240)>>4;
else tmp = b[i] &15;
if(tmp == 10) sb.append("A");
if(tmp == 11) sb.append("B");
if(tmp == 12) sb.append("C");
if(tmp == 13) sb.append("D");
if(tmp == 14) sb.append("E");
if(tmp == 15) sb.append("F");
if(tmp < 10) sb.append(tmp);
}
}
return sb.toString();
}
}
class的解析功能在这个类里面,存放结果的是下面的类:
package com.hexin.study.interpreter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Administrator
*
* 更改所生成类型注释的模板为
* 窗口 > 首选项 > Java > 代码生成 > 代码和注释
*/
public class ClassContext implements Context {
private String MAGIC = null;
private short MINOR_VERSION = -1;
private short MAJOR_VERSION = -1;
private short CONSTANT_POOL_COUNT = -1;
private List CONSTANT_POOL = new ArrayList();
private short ACCESS_FLAGS = -1;
private short THIS_CLASS = -1;
private short SUPER_CLASS = -1;
private short INTERFACES_COUNT = -1;
private List INTERFACES = new ArrayList();
private short FIELDS_COUNT = -1;
private List FIELDS = new ArrayList();//存储FieldNode对象
private short METHODS_COUNT = -1;
private List METHODS = new ArrayList();//存储MethodNode对象
private short ATTRIBUTES_COUNT = -1;
private Map ATTRIBUTES = new HashMap();
/**
* @return
*/
public short getACCESS_FLAGS() {
return ACCESS_FLAGS;
}
/**
* @return
*/
public short getATTRIBUTES_COUNT() {
return ATTRIBUTES_COUNT;
}
/**
* @return
*/
public short getCONSTANT_POOL_COUNT() {
return CONSTANT_POOL_COUNT;
}
/**
* @return
*/
public short getFIELDS_COUNT() {
return FIELDS_COUNT;
}
/**
* @return
*/
public List getINTERFACES() {
return INTERFACES;
}
/**
* @return
*/
public short getINTERFACES_COUNT() {
return INTERFACES_COUNT;
}
/**
* @return
*/
public String getMAGIC() {
return MAGIC;
}
/**
* @return
*/
public short getMAJOR_VERSION() {
return MAJOR_VERSION;
}
/**
* @return
*/
public short getMETHODS_COUNT() {
return METHODS_COUNT;
}
/**
* @return
*/
public short getMINOR_VERSION() {
return MINOR_VERSION;
}
/**
* @return
*/
public short getSUPER_CLASS() {
return SUPER_CLASS;
}
/**
* @return
*/
public short getTHIS_CLASS() {
return THIS_CLASS;
}
/**
* @param s
*/
public void setACCESS_FLAGS(short s) {
ACCESS_FLAGS = s;
}
/**
* @param s
*/
public void setATTRIBUTES_COUNT(short s) {
ATTRIBUTES_COUNT = s;
}
/**
* @param s
*/
public void setCONSTANT_POOL_COUNT(short s) {
CONSTANT_POOL_COUNT = s;
}
/**
* @param s
*/
public void setFIELDS_COUNT(short s) {
FIELDS_COUNT = s;
}
/**
* @param list
*/
public void setINTERFACES(List list) {
INTERFACES = list;
}
/**
* @param s
*/
public void setINTERFACES_COUNT(short s) {
INTERFACES_COUNT = s;
}
/**
* @param string
*/
public void setMAGIC(String string) {
MAGIC = string;
}
/**
* @param s
*/
public void setMAJOR_VERSION(short s) {
MAJOR_VERSION = s;
}
/**
* @param s
*/
public void setMETHODS_COUNT(short s) {
METHODS_COUNT = s;
}
/**
* @param s
*/
public void setMINOR_VERSION(short s) {
MINOR_VERSION = s;
}
/**
* @param s
*/
public void setSUPER_CLASS(short s) {
SUPER_CLASS = s;
}
/**
* @param s
*/
public void setTHIS_CLASS(short s) {
THIS_CLASS = s;
}
/**
* @return
*/
public List getCONSTANT_POOL() {
return CONSTANT_POOL;
}
/**
* @param list
*/
public void setCONSTANT_POOL(List list) {
CONSTANT_POOL = list;
}
/**
* @return
*/
public Map getATTRIBUTES() {
return ATTRIBUTES;
}
/**
* @param map
*/
public void setATTRIBUTES(Map map) {
ATTRIBUTES = map;
}
/**
* @return
*/
public List getFIELDS() {
return FIELDS;
}
/**
* @return
*/
public List getMETHODS() {
return METHODS;
}
/**
* @param list
*/
public void setFIELDS(List list) {
FIELDS = list;
}
/**
* @param list
*/
public void setMETHODS(List list) {
METHODS = list;
}
/* (非 Javadoc)
* @see com.hexin.study.interpreter.Context#getContent()
*/
public String getContent() {
StringBuffer sb = new StringBuffer();
sb.append("MAGIC: "+MAGIC);
sb.append("/nVERSION: "+MAJOR_VERSION+"."+MINOR_VERSION);
sb.append("/nCONSTANT_POOL_COUNT: "+CONSTANT_POOL_COUNT);
sb.append("/nCONSTANT_POOL: ");
int tmp = CONSTANT_POOL.size();
for(int i=0;i<tmp;i++)
sb.append("/n "+CONSTANT_POOL.get(i));
sb.append("/nACCESS_FLAGS: "+ACCESS_FLAGS);
sb.append("/nTHIS_CLASS: "+THIS_CLASS);
sb.append("/nSUPER_CLASS: "+SUPER_CLASS);
sb.append("/nINTERFACES_COUNT: "+INTERFACES_COUNT);
sb.append("/nINTERFACES: ");
sb.append("/nFIELDS_COUNT: "+FIELDS_COUNT);
sb.append("/nFIELDS: ");
sb.append("/nMETHODS_COUNT: "+METHODS_COUNT);
sb.append("/nMETHODS: ");
for(int i=0;i<METHODS.size();i++){
MethodNode mn = (MethodNode)METHODS.get(i);
sb.append(mn.toString());
}
sb.append("/n/nATTRIBUTES_COUNT: "+ATTRIBUTES_COUNT);
sb.append("/nATTRIBUTES: ");
return sb.toString();
}
}
整个编写过程不甚理想,咳,设计模式没掌握,写的时候心态比较急,只考虑功能的实现。对class中的attribute没有理解清楚,不过目前的功能实现上已经能反编译一些非常简单的咚咚,也算是一个进步吧。故此,把部分主要的源码帖出来,欢迎大家批评指正。
参考文献:《深入java虚拟机》中文版第二版