手动实现远程调试class的工具

需要用到的类:

为多次载入执行类的类加载器(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>");
%>

最终执行结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值