更改已编译 class 中的所有 class 引用
Change all class references in a compiled class
我正在尝试修改已编译的 class(源代码不可用),例如,我想将所有对 java.lang.Object
的引用更改为 some.packageName.SomeClass
。
参考资料是指:
- 字段类型
- 方法return类型
- 方法参数类型
- 超类型
- 方法体中的变量类型
- 静态 class 引用(例如
java.lang.Object.class
)
- 通用类型参数
- 等等
基本上,通过这个例子,修改后的 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;
}
我正在尝试修改已编译的 class(源代码不可用),例如,我想将所有对 java.lang.Object
的引用更改为 some.packageName.SomeClass
。
参考资料是指:
- 字段类型
- 方法return类型
- 方法参数类型
- 超类型
- 方法体中的变量类型
- 静态 class 引用(例如
java.lang.Object.class
) - 通用类型参数
- 等等
基本上,通过这个例子,修改后的 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;
}