手动实现远程调试class的工具
程序员文章站
2024-02-23 09:47:52
...
需要用到的类:
为多次载入执行类的类加载器(HopWrapClassLoader.java)
package com.madg.hotswap;
public class HotSwapClassLoader extends ClassLoader {
public HotSwapClassLoader()
{
//指定HotSwapClassLoader类的加载器为父类加载器
super(HotSwapClassLoader.class.getClassLoader());
}
public Class loadByte(byte[] classByte)
{
return defineClass(null,classByte,0,classByte.length);
}
}
ClassModify用来修改class文件(暂时只提供修改常量池的功能,ClassModify.java)
package com.madg.hotswap;
public class ClassModifer {
/**
* Class 文件中常量池的起始偏移
* 因为前面会有u4长度的magic,u2类型的minor version 和u2类型的major version
*/
private static final int CONSTANT_POOL_COUNT_INDEX=8;
/**
* Constant_utf8_info 常量的tag标志
*/
private static final int CONSTANT_Utf8_info=1;
/**
* 常量池中11种常量所占的长度,CONSTANT_Utf8_info型常量除外,因为他不是定长的
*/
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 ClassModifer(byte[] classByte)
{
this.classByte=classByte;
}
public byte[] modifyUTF8Constant(String oldStr,String newStr){
int cpc=getConstantPoolCount();
//跳过常量池数量的u2长度
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.bytesReplaces(classByte,offset-u2,u2,strLen);
classByte =ByteUtils.bytesReplaces(classByte,offset,len,strBytes);
return classByte;
}else{
offset+=len;
}
}else {
offset+=CONSTANT_ITEM_LENGTH[tag];
}
}
return classByte;
}
/**
* 获取常量池中常量的数量
* @return 常量池数量
*/
private int getConstantPoolCount() {
return ByteUtils.bytes2Int(classByte,CONSTANT_POOL_COUNT_INDEX,u2);
}
}
Bytes数组处理工具(ByteUtils.java)
package com.madg.hotswap;
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++) {
//byte 转化成 int时会出现符号扩展,解决方法如下(采用与操作):
int n=((int)b[i]) & 0xff;
n<<=(--len)*8;//n=n<<(len-1)*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[] bytesReplaces(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;
}
}
劫持System,完成对out,err的特殊处理(HackSystem.java)
package com.madg.hotswap;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.PrintStream;
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 setSecurityManeger(final SecurityManager s)
{
System.setSecurityManager(s);
}
public static SecurityManager getSecurityMagener()
{
return System.getSecurityManager();
}
public static long currentTimeMillis()
{
return System.currentTimeMillis();
}
public static void arraycopy(Object src,int srcPos,Object dest,int despPos,int length)
{
System.arraycopy(src,srcPos,dest,despPos,length);
}
public static int identityHashCode(Object x)
{
return System.identityHashCode(x);
}
public static String getProperty(String key, String def) {
return System.getProperty(key,def);
}
public static String setProperty(String key, String value) {
return System.setProperty(key,value);
}
public static String clearProperty(String key) {
return System.clearProperty(key);
}
public static String getenv(String name) {
return System.getenv(name);
}
}
JavaClass 执行工具(JavaClassExcuter.java)
package com.madg.hotswap;
import java.lang.reflect.Method;
public class JavaClassExcuter {
public static String excute(byte[] classByte)
{
HackSystem.clearBuffer();
ClassModifer cm=new ClassModifer(classByte);
byte[] modifyByte=cm.modifyUTF8Constant("java/lang/System","com/madg/hotswap/HackSystem");
HotSwapClassLoader classLoader=new HotSwapClassLoader();
Class clazz=classLoader.loadByte(modifyByte);
try {
Method method =clazz.getMethod("main",new Class[]{String[].class});
method.invoke(null,new String[] {null});
} catch (Throwable e) {
e.printStackTrace(HackSystem.out);
}
return HackSystem.getBufferString();
}
}
测试类
public class TestClass{
public static void main(String[] args) {
System.out.println("hello,this is a TestClass");
}
}
模拟调用远程类的jsp页面
<%@page import="java.io.*" %>
<%@page import="com.madg.hotswap.*" %>
<%
InputStream is=new FileInputStream("C:/Users/len/Desktop/TestClass.class");
byte[] b=new byte[is.available()];
is.read(b);
is.close();
out.println("<textarea style='width:1000px;height:800px'>");
out.println(JavaClassExcuter.excute(b));
out.println("</textarea>");
%>
最终执行结果
推荐阅读