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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gooaaee/article/details/81029461

书中的案例自己实现一遍,过程如下文

具体是在eclipse中实现,整体截图如下:



1.ByteUtils的代码如下:

package org.jvm;
/**
 * Bytes数组处理工具
 */
public class ByteUtils {
	public static int bytes2Int(byte[] b, int start, int len) {
		int sum = 0;
		int end = start + len;
		for(int i = start; i < end; i++){
			int n = ((int) b[i]) & 0xff;
			n <<= (--len) * 8;
			sum = n + sum;
		}
		return sum;
	}
	
	public static byte[] int2Bytes(int value, int len) {
		byte[] b = new byte[len];
		for(int i = 0; i < len; i++){
			b[len - i - 1] = (byte) ((value >> 8 * i) & 0xff);
		}
		return b;
	}
	
	public static String bytes2String(byte[] b, int start, int len) {
		return new String(b, start, len);
	}

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

	public static byte[] bytesReplace(byte[] originalBytes, int offset, int len,
			byte[] replaceBytes) {
		byte[] newBytes = new byte[originalBytes.length + (replaceBytes.length - len)];
		System.arraycopy(originalBytes, 0, newBytes, 0, offset);
		System.arraycopy(replaceBytes, 0, newBytes, offset, replaceBytes.length);
		System.arraycopy(originalBytes, offset + len, newBytes, offset + replaceBytes.length, originalBytes.length - offset - len);
		return newBytes;
	}
}

2.ClassModifier代码如下:

package org.jvm;
/**
 * 修改Class文件,暂时只提供修改常量池常量的功能
 */
public class ClassModifier {
	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,-1,5,5,9,9,3,3,5,5,5,5};
	private static final int u1 = 1;
	private static final int u2 = 2;
	private byte[] classByte;
	
	public ClassModifier(byte[] classByte){
		this.classByte = classByte;
	}
	
	public byte[] modifyUTF8Constant(String oldStr, String newStr){
		int cpc = getConstantPoolCount();
		int offset = CONSTANT_POOL_COUNT_INDEX + u2;
		for(int i = 0; i < cpc; i++){
			int tag = ByteUtils.bytes2Int(classByte,offset, u1);
			if(tag == CONSTANT_Utf8_info){
				int len = ByteUtils.bytes2Int(classByte, offset + u1, u2);
				offset += (u1 + u2);
				String str = ByteUtils.bytes2String(classByte, offset, len);
				if(str.equalsIgnoreCase(oldStr)){
					byte[] strBytes = ByteUtils.string2Bytes(newStr);
					byte[] strLen = ByteUtils.int2Bytes(newStr.length(),u2);
					classByte = ByteUtils.bytesReplace(classByte, offset - u2, u2, strLen);
					classByte = ByteUtils.bytesReplace(classByte, offset, len, strBytes);
					return classByte;
				}else{
					offset += len;
				}
			}else{
				offset += CONSTANT_ITEM_LENGTH[tag];
			}
		}
		return classByte;
	}
	
	public int getConstantPoolCount(){
		return ByteUtils.bytes2Int(classByte, CONSTANT_POOL_COUNT_INDEX, u2);
	}
}

3.HackSystem代码如下

package org.jvm;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.PrintStream;

/**
 * 为JavaClass劫持java.lang.System提供支持
 * 除了out和err外,其余的都直接转发给System处理
 */
public class HackSystem {
	public final static InputStream in = System.in;
	private static ByteArrayOutputStream buffer = new ByteArrayOutputStream();
	public final static PrintStream out = new PrintStream(buffer);
	public final static PrintStream err = out;
	
	public static String getBufferString(){
		return buffer.toString();
	}
	
	public static void clearBuffer(){
		buffer.reset();
	}
	public static void setSecurityManager(final SecurityManager s){
		System.setSecurityManager(s);
	}
	public static SecurityManager getSecurityManager(){
		return System.getSecurityManager();
	}
	public static long currentTimeMills(){
		return System.currentTimeMillis();
	}
	public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length){
		System.arraycopy(src, srcPos, dest, destPos, length);
	}
	public static int identityHashCode(Object x){
		return System.identityHashCode(x);
	}
}

4.HotSwapClassLoader代码如下

package org.jvm;
/**
 * 为了多次载入执行类而加入的加载器
 * 把defineClass方法开放出来,只有外部显式调用的时候才会使用到loadByte方法
 * 由虚拟机调用时,仍然按照原有的双亲委派规则使用loadClass方法进行类加载
 */
public class HotSwapClassLoader extends ClassLoader{

	public HotSwapClassLoader() {
		super(HotSwapClassLoader.class.getClassLoader());
	}
	public Class<?> loadByte(byte[] classByte){
		return defineClass(null,classByte,0,classByte.length);
	}
}

5.JavaClassExecuter代码如下

package org.jvm;
/**
 * 为了多次载入执行类而加入的加载器
 * 把defineClass方法开放出来,只有外部显式调用的时候才会使用到loadByte方法
 * 由虚拟机调用时,仍然按照原有的双亲委派规则使用loadClass方法进行类加载
 */
public class HotSwapClassLoader extends ClassLoader{

	public HotSwapClassLoader() {
		super(HotSwapClassLoader.class.getClassLoader());
	}
	public Class<?> loadByte(byte[] classByte){
		return defineClass(null,classByte,0,classByte.length);
	}
}

6.test.jsp代码如下

<%@ page import="java.lang.*" %>
<%@ page import="java.io.*" %>
<%@ page import="org.jvm.*" %>

<%
	InputStream is = new FileInputStream("c:/TestClass.class");
	byte[] b = new byte[is.available()];
	is.read(b);
	is.close();
	
	out.println("<textarea style='width:1000;heigth=800'>");
	out.println(JavaClassExecuter.execute(b));
	out.println("</textarea>");
%>

7.测试类放到了c盘根目录下,如下


其中TestClass代码如下

/**
 * 测试类
 */
public class TestClass {
	public static void main(String[] args) {
		System.out.println("-----this is test class out println----");
		System.out.println("hahhahahaha");
	}
}

以管理员身份打开cmd窗口,如下:


javac编译TestClass文件,如下:



最后运行tomcat,如下:


访问结果如下:


当直接修改TestClass.java文件,不关闭tomcat,直接运行localhost:8080/classLoaderTest/test.jsp,结果随之而变。

展开阅读全文

没有更多推荐了,返回首页