java 远程执行_java 手动实现远程执行功能(深入理解java虚拟机)

本文介绍了一个Java工具类,用于对字节数组进行操作,特别是如何在Class文件中替换特定的UTF8字符串。通过ClassModifier类,可以实现在运行时动态修改测试类的常量池,适用于测试或自动化场景。
摘要由CSDN通过智能技术生成

1、功能类

功能类共有五,分别是:

packageorg.jvm;import java.io.*;/*** 对字节数组操作的工具类*/

public classByteUtils {public static int byte2Int(byte[] b,int start,intlen){int sum=0;int end=start+len;for(int i=start;i

n<<=(--len)*8;

sum=n+sum;

}returnsum;

}public static byte[] int2Bytes(int value ,intlen){byte[] b=new byte[len];for (int i=0;i

b[len-i-1]=(byte)((value>>8*i)&0xff);

}returnb;

}public static String bytes2String(byte[] b,int start,intlen){return newString (b,start,len);

}public static byte[] string2Bytes(String str){returnstr.getBytes();

}public static byte[] bytesReplace(byte[] origialBytes,int offset,int len,byte[] replaceBytes){byte[] newBytes=new byte[origialBytes.length+(replaceBytes.length-len)];

System.arraycopy(origialBytes,0,newBytes,0,offset);

System.arraycopy(replaceBytes,0,newBytes,offset,replaceBytes.length);

System.arraycopy(origialBytes,offset+len,newBytes,offset+replaceBytes.length,origialBytes.length-offset-len);returnnewBytes;

}

}

packageorg.jvm;import java.io.*;/*** 对测试类class文件的字节数组执行替换,将oldStr替换成newStr*/

public classClassModifier {private static final int CONSTANT_POOL_COUNT_INDEX=8;private static final int CONSTANT_UTF8_info=1;private static final int[] CONSTANT_ITEM_LENGTH={-1,-1,5,-1,5,9,9,3,3,5,5,5,5};private final int u1=1;private final int u2=2;private byte[] classByte;public ClassModifier(byte[] classByte){this.classByte=classByte;

}public byte[] modiftyUTF8Constant(String oldStr,String newStr){int cpc=getConstantPoolCount();int offset=CONSTANT_POOL_COUNT_INDEX+u2;for(int i =0;i

int tag=ByteUtils.byte2Int(classByte, offset, u1);//判断是否为CONSTANT_UTF8_info数据类型

if(tag==CONSTANT_UTF8_info){//取出CONSTANT_UTF8_info中字符串的长度

int len=ByteUtils.byte2Int(classByte,offset+u1,u2);

offset+=(u1+u2);//取出CONSTANT_UTF8_info中的字符串部分

String str=ByteUtils.bytes2String(classByte,offset,len);//通过字符串部分比较是否为需要修改的CONSTANT_UTF8_info

if(str.equalsIgnoreCase(oldStr)){//将新字符串的值打散成字节数组

byte[] strBytes=ByteUtils.string2Bytes(newStr);//将表示字符串长度值的两个字节分别以16进制的形式装在字节数组中

byte[] strLen=ByteUtils.int2Bytes(newStr.length(),u2);//将CONSTANT_UTF8_info中表示length部分进行替换

classByte=ByteUtils.bytesReplace(classByte,offset-u2,u2,strLen);//将CONSTANT_UTF8_info中字符串部分进行替换

classByte=ByteUtils.bytesReplace(classByte,offset,len,strBytes);returnclassByte;//如不是需要修改的CONSTANT_UTF8_info,则跳过这个类型,接着循环

}else{

offset+=len;

}//如果不是CONSTANT_UTF8_info数据类型,根据tag跳转CONSTANT_ITEM_LENGTH中定义的字节数

}else{

offset+=CONSTANT_ITEM_LENGTH[tag];

}

}returnclassByte;

}public int getConstantPoolCount(){

packageorg.jvm;importjava.io.ByteArrayInputStream;importjava.io.ByteArrayOutputStream;importjava.io.InputStream;importjava.io.PrintStream;/*** 用于替换System的输出,将测试类中每次System.out的内容输出到字节数组流中,最后一次性输出到页面*/

public classHackSystem {public final static InputStream in=System.in;private static ByteArrayOutputStream buffer=newByteArrayOutputStream();public static final PrintStream out=newPrintStream(buffer);public static final PrintStream err=out;public staticString getBuffer(){returnbuffer.toString();

}public static voidclearBuffer(){

buffer.reset();

}

}

packageorg.jvm;/*** 测试类的类加载器,通过字节数组的方式进行加载*/

public class HotSwapClassloader extendsClassLoader{publicHotSwapClassloader(){super(HotSwapClassloader.class.getClassLoader());

}public Class loadByte(byte[] classByte){return defineClass(null,classByte,0,classByte.length);

}

}

packageorg.jvm;importjava.lang.reflect.Method;/*** 执行类,通过反射调用测试类中的main方法,最后取出HackSystem中字节数组流中的数据进行返回*/

public classJavaClassExecuter {public static String executer(byte[] classByte) throwsNoSuchMethodException {

HackSystem.clearBuffer();

ClassModifier classModifier=newClassModifier(classByte);byte[] modiByte=classModifier.modiftyUTF8Constant("java/lang/System","org/jvm/HackSystem");

HotSwapClassloader loader=newHotSwapClassloader();

Class cs=loader.loadByte(modiByte);try{

Method method=cs.getMethod("main", new Class[]{String[].class});

method.invoke(null,new String []{null});

}catch(Throwable throwable){

throwable.printStackTrace(HackSystem.out);

}returnHackSystem.getBuffer();

}

}

2、测试类

packageorg.jvm;/*** 测试类,在此类中打印想要在页面看到的内容,System.out输出的内容会存在HackSystem的字节数组输出流中*/

public classTestClass {public static voidmain(String[] args) {

System.out.println("-----this is test class out println----");

}

}

3、jsp页面

test.jsp

inputStream.read(b);

inputStream.close();

out.println(JavaClassExecuter.executer(b));%>

使用方法:

1、将 ByteUtils ClassModifier HackSystem HotSwapClassloader JavaClassExecuter TestClass 这六个.java文件上传到服务器通过javac进行编译成.class 文件

2、将编译好的TestClass放在/opt目录中

3、在tomcat的项目位置的WEB-INF/classes/中新建org/jvm文件夹,再将编译好的 ByteUtils ClassModifier HackSystem HotSwapClassloader JavaClassExecuter 放在WEB-INF/classes/org/jvm中

4、将test.jsp放在项目中能访问到的位置,如项目的根路径中

5、在浏览器中访问jsp页面即可,如http://192.168.3.235:8080/test.jsp即可看到页面中会输出

-----this is test class out println----

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值