Вам нужно посетить все классы дважды:
В первом посещении раунда получите только список имен методов и дескрипторов (гарантированно уникальных в каждой области).
Эта реализация даст одно и то же имя методам с одинаковым именем и описанием в разных классах. Это может быть неоптимальным с точки зрения запутывания, но позволяет избежать дифференциации переопределенных методов и методов, которые просто называются одинаковыми.
final List<String> methods = new ArrayList<>();
for (ClassNode classNode : classes.values()) {
for (MethodNode methodNode : classNode.methods) {
methods.add(methodNode.name + methodNode.desc);
}
}
visitor
не подключен к устройству записи, поскольку никаких изменений еще не было сделано.
Затем сопоставьте каждое имя с новым запутанным именем (может быть, случайными числами или просто нумерацией методов):
final Map<String, String> map = new HashMap<>();
for (int i = 0; i < methods.size(); i++) {
String obfName = String.format("func_%03d", i);
map.put(methods.get(i), obfName);
}
Наконец, посетите каждое тело метода, чтобы соответствующим образом отредактировать каждую инструкцию вызова метода и сохранить измененный результат.
for (ClassNode classNode : classes.values()) {
ClassWriter classWriter = new ClassWriter(0);
ClassVisitor visitor = new ClassVisitor(ASM4, classWriter) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
final MethodVisitor mv = super.methodVisitor(access, name, desc, signature, exceptions);
return new AdviceAdapter(ASM4, mv, access, name, desc) {
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
String newName = map.getOrDefault(name + desc, name);
return super.visitMethodInsn(opcode, owner, newName, desc, itf);
}
};
}
};
classNode.accept(classVisitor);
generatedOutput.put(classNode.name, classWriter.toByteArray());
}
Примечание : у вас будут проблемы с переопределенными методами из классов, которые вы не изменяете, например String toString()
из Object
или любых других из Java или внешних библиотек. Чтобы избежать этого, у вас может быть белый список методов, которые вы хотите скрыть, прочитать аннотации, чтобы обнаружить переопределенные методы и пропустить их, например.