更改已编译 class 中的所有 class 引用

Change all class references in a compiled class

我正在尝试修改已编译的 class(源代码不可用),例如,我想将所有对 java.lang.Object 的引用更改为 some.packageName.SomeClass

参考资料是指:

基本上,通过这个例子,修改后的 class 应该不能直接访问 java.lang.Object class,只能通过 some.packageName.SomeClass 访问。请注意,示例 class 可以是任意的 class,无论是否来自 jre。提供的替代品将完全符合预期的原件。

这可以通过使用 BCEL 或 Javassist 实现吗?如果没有,是否有任何其他库提供实现此目标的功能?

没试过,不过javassist和ASM肯定可以改class中的常量池。这是 class 文件中此类引用的存储位置。

我使用 ASM,这非常简单。我有一个 org.objectweb.asm.commons.Remapper 的实现,它将 classes 的名称和描述符更改为新的。

例如,其中一种方法如下所示:

@Override
public String mapDesc(String desc) {
    return super.mapDesc(StringUtil.fixDesc(desc, renamed));
}

描述如下:Lcom/example/Class;。我输入 fixDesc 的字段 'renamed' 是我制作的包含旧值到新值的 class 映射的映射。因此,如果我想将 com/example/AAA 变成 com/example/BBB 我将前后值输入地图并调用像这样重新映射:

/**
 * Given a map of ClassNodes and mappings, returns a map of class names to
 * class bytes.
 */
public static Map<String, byte[]> process(Map<String, ClassNode> nodes, Map<String, MappedClass> mappings) {
    Map<String, byte[]> out = new HashMap<String, byte[]>();
    RemapperImpl mapper = new RemapperImpl(mappings);
    for (ClassNode cn : nodes.values()) {
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
        ClassVisitor remapper = new ClassRemapper(cw, mapper);
        cn.accept(remapper);
        out.put(mappings.get(cn.name).getNewName(), cw.toByteArray());
    }
    return out;
}