JVM类加载以及执行的实战(2)

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);
    }

// 下面所有的方法都与java.lang.System的名称一样
    // 实现都是字节转调System的对应方法
    // 因版面原因,省略了其他方法
}

那就有人问了,既然能代替System类,就直接用这个类不就完了呗,也没有System类的事了?问得好,这就是下面第4点。

4)我们在客户端编写待执行类时,不能依赖特定的类;如果依赖了特定的类,就只有在能够访问到特定类的地方才能编译通过,受限制太多。也就是说,我们在写执行类时,不能用到HackSystem类,但是执行的时候,却又必须是HackSystem类。所以思路应该是这样的:在执行类里面输出时,还是用System.out,编译完成后,再去修改编译成的class文件,将常量池中java.lang.System这个符号替换成HackSystem。这里的难点是在程序中修改class文件,需要你特别熟悉class文件的每个数据项。

/**
 * 修改Class文件,暂时只提供修改常量池常量的功能
 * @author zzm
 */
public class ClassModifier {

/**
    * Class文件中常量池的起始偏移
    */
    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 ClassModifier(byte[] classByte) {
        this.classByte = classByte;
    }

/**
    * 修改常量池中CONSTANT_Utf8_info常量的内容
    * @param oldStr 修改前的字符串
    * @param newStr 修改后的字符串
    * @return 修改结果
    */
    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;
    }

/**
    * 获取常量池中常量的数量
    * @return 常量池数量
    */
    public int getConstantPoolCount() {
        return ByteUtils.bytes2Int(classByte, CONSTANT_POOL_COUNT_INDEX, u2);
    }
}


/**
 * Bytes数组处理工具
 * @author
 */
public class ByteUtils {

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/8ff2bf33cd541bc70e3386cb68fc3482.html