Files
ProGuard-Unmapper/me/Unmapper/ClassNodeRemapper.java
SuspiciousActivity 964e264bdb Update
Updated ASM & some more fixes and options
2021-06-09 12:14:02 +02:00

356 lines
9.9 KiB
Java

package me.Unmapper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.FrameNode;
import org.objectweb.asm.tree.InnerClassNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.MultiANewArrayInsnNode;
import org.objectweb.asm.tree.TryCatchBlockNode;
import org.objectweb.asm.tree.TypeInsnNode;
public class ClassNodeRemapper {
private static final Pattern CLASS_NAME_PATTERN = Pattern.compile("(L[^;<]+[;<])");
private final HashMap<String, String> classMappings;
private final HashMap<MemberData, String> memberMappings;
public ClassNodeRemapper(HashMap<String, String> classMappings, HashMap<MemberData, String> memberMappings) {
this.classMappings = classMappings;
this.memberMappings = memberMappings;
}
public void remap(ClassNode cn) {
remapMethods(cn);
remapFields(cn);
cn.name = getOldClassName(cn.name);
cn.superName = getOldClassName(cn.superName);
cn.signature = getOldSignature(cn.signature);
if (Main.fakeJava8)
cn.version = 52;
if (!cn.interfaces.isEmpty()) {
List<String> newInterfaces = new ArrayList<String>();
for (String s : cn.interfaces) {
newInterfaces.add(getOldClassName(s));
}
cn.interfaces = newInterfaces;
}
if (cn.innerClasses != null && !cn.innerClasses.isEmpty()) {
for (InnerClassNode icn : cn.innerClasses) {
String full = getOldClassName(icn.name);
if (icn.outerName != null) {
String[] split = full.split("\\$");
icn.outerName = split[0];
if (icn.innerName != null) {
icn.innerName = split[1];
}
}
icn.name = full;
}
}
}
private void remapMethods(ClassNode cn) {
if (cn.methods == null)
return;
String clazz = cn.name;
for (MethodNode mn : cn.methods) {
MemberData data = new MemberData(cn.name, mn.desc, mn.name);
mn.name = getOldMemberName(data);
mn.desc = getOldMemberMethodDesc(mn.desc);
mn.signature = getOldSignature(mn.signature);
if (!mn.exceptions.isEmpty()) {
List<String> newExceptions = new ArrayList<String>();
for (String s : mn.exceptions) {
newExceptions.add(getOldClassName(s));
}
mn.exceptions = newExceptions;
}
if (mn.localVariables != null && !mn.localVariables.isEmpty()) {
if (Main.removeLocals) {
mn.localVariables.clear();
} else {
Iterator<LocalVariableNode> lvns = mn.localVariables.iterator();
while (lvns.hasNext()) {
LocalVariableNode lvn = lvns.next();
lvn.desc = getOldMemberFieldDesc(lvn.desc);
lvn.signature = getOldSignature(lvn.signature);
}
}
}
if (mn.tryCatchBlocks != null && !mn.tryCatchBlocks.isEmpty()) {
for (TryCatchBlockNode tcbn : mn.tryCatchBlocks) {
tcbn.type = getOldClassName(tcbn.type);
}
}
int len = mn.instructions.size();
for (int i = 0; i < len; i++) {
remapInstruction(clazz, mn.instructions.get(i));
}
}
}
private void remapFields(ClassNode cn) {
if (cn.fields == null)
return;
for (FieldNode fn : cn.fields) {
MemberData data = new MemberData(cn.name, fn.desc, fn.name);
fn.name = getOldMemberName(data);
fn.desc = getOldMemberFieldDesc(fn.desc);
fn.signature = getOldSignature(fn.signature);
}
}
private String getOldClassName(String name) {
if (name == null)
return null;
String old = classMappings.get(name);
if (old != null)
return old;
return name;
}
private String getOldMemberName(MemberData data) {
if (data == null)
return null;
String old = memberMappings.get(data);
if (old != null)
return old;
return data.getName();
}
private String getOldMemberMethodDesc(String desc) {
if (desc == null)
return null;
int argsEndIdx = desc.indexOf(')');
String retType = getOldMemberFieldDesc(desc.substring(argsEndIdx + 1));
String args = desc.substring(1, argsEndIdx);
int idx = 0;
char[] arr = args.toCharArray();
StringBuilder outerSb = new StringBuilder("(");
while (idx < arr.length) {
int arrayCount = 0;
for (; idx < arr.length && arr[idx] == '['; idx++)
arrayCount++;
if (idx >= arr.length) // weird input?
return desc;
StringBuilder sb = new StringBuilder();
switch (arr[idx]) {
case 'B':
case 'Z':
case 'I':
case 'J':
case 'C':
case 'D':
case 'F':
case 'S':
case 'V':
sb.append(arr[idx]);
idx++;
break;
case 'L': {
idx++;
int startIdx = idx;
for (; idx < arr.length && arr[idx] != ';'; idx++)
;
sb.append('L');
sb.append(getOldClassName(args.substring(startIdx, idx)));
sb.append(';');
idx++;
break;
}
default:
break;
}
for (int i = 0; i < arrayCount; i++)
sb.insert(0, '[');
outerSb.append(sb);
}
outerSb.append(')');
outerSb.append(retType);
return outerSb.toString();
}
private String getOldMemberFieldDesc(String desc) {
if (desc == null)
return null;
int idx = 0;
char[] arr = desc.toCharArray();
int arrayCount = 0;
for (; idx < arr.length && arr[idx] == '['; idx++)
arrayCount++;
if (idx >= arr.length) // weird input?
return desc;
StringBuilder sb = new StringBuilder();
switch (arr[idx]) {
case 'B':
case 'Z':
case 'I':
case 'J':
case 'C':
case 'D':
case 'F':
case 'S':
case 'V':
sb.append(arr[idx]);
break;
case 'L': {
idx++;
int startIdx = idx;
for (; idx < arr.length && arr[idx] != ';'; idx++)
;
sb.append('L');
sb.append(getOldClassName(desc.substring(startIdx, idx)));
sb.append(';');
break;
}
default:
break;
}
for (int i = 0; i < arrayCount; i++)
sb.insert(0, '[');
return sb.toString();
}
private String getOldSignature(String s) {
if (s == null || s.isEmpty())
return s;
if (s.startsWith("(")) { // Methods
int startIdx = s.indexOf('(');
int endIdx = s.indexOf(')');
if (endIdx < 0) // Weird?
return s;
String typeType = s.substring(0, startIdx);
String args = s.substring(startIdx + 1, endIdx);
String retType = s.substring(endIdx + 1);
return getOldSignature(typeType) + "(" + getOldSignature(args) + ")" + getOldSignature(retType);
} else {
StringBuffer sb = new StringBuffer();
Matcher m = CLASS_NAME_PATTERN.matcher(s);
while (m.find()) {
m.appendReplacement(sb, Matcher.quoteReplacement(getOldSignatureFromMatcher(m.group())));
}
m.appendTail(sb);
return sb.toString();
}
}
private String getOldSignatureFromMatcher(String s) {
boolean endsWithBracket = s.endsWith("<");
s = s.substring(1, s.length() - 1);
return "L" + getOldClassName(s) + (endsWithBracket ? "<" : ";");
}
private void remapInstruction(String clazz, AbstractInsnNode n) {
if (FieldInsnNode.class.isInstance(n)) {
FieldInsnNode node = (FieldInsnNode) n;
node.name = getOldMemberName(new MemberData(node.owner, node.desc, node.name));
node.desc = getOldMemberFieldDesc(node.desc);
node.owner = getOldClassName(node.owner);
} else if (FrameNode.class.isInstance(n)) {
FrameNode node = (FrameNode) n;
if (node.local != null) {
int len = node.local.size();
for (int i = 0; i < len; i++) {
Object o = node.local.get(i);
if (o == null)
continue;
if (o instanceof String) {
String s = (String) o;
if (s.startsWith("["))
s = getOldMemberFieldDesc(s);
else
s = getOldClassName(s);
node.local.set(i, s);
}
}
}
if (node.stack != null) {
int len = node.stack.size();
for (int i = 0; i < len; i++) {
Object o = node.stack.get(i);
if (o == null)
continue;
if (o instanceof String) {
String s = (String) o;
if (s.startsWith("["))
s = getOldMemberFieldDesc(s);
else
s = getOldClassName(s);
node.stack.set(i, s);
}
}
}
} else if (InvokeDynamicInsnNode.class.isInstance(n)) {
InvokeDynamicInsnNode node = (InvokeDynamicInsnNode) n;
node.name = getOldMemberName(new MemberData(clazz, node.desc, node.name));
node.desc = getOldMemberMethodDesc(node.desc);
node.bsm = new Handle(node.bsm.getTag(), getOldClassName(node.bsm.getOwner()),
getOldMemberName(new MemberData(node.bsm.getOwner(), node.bsm.getDesc(), node.bsm.getName())),
getOldMemberMethodDesc(node.bsm.getDesc()), node.bsm.isInterface());
int len = node.bsmArgs.length;
for (int i = 0; i < len; i++) {
Object o = node.bsmArgs[i];
if (o instanceof Type) {
Type type = (Type) o;
node.bsmArgs[i] = Type.getType(getOldSignature(type.getDescriptor()));
} else if (o instanceof Handle) {
Handle h = (Handle) o;
node.bsmArgs[i] = new Handle(h.getTag(), getOldClassName(h.getOwner()),
getOldMemberName(new MemberData(h.getOwner(), h.getDesc(), h.getName())),
getOldMemberMethodDesc(h.getDesc()), h.isInterface());
}
}
} else if (MethodInsnNode.class.isInstance(n)) {
MethodInsnNode node = (MethodInsnNode) n;
node.name = getOldMemberName(new MemberData(node.owner, node.desc, node.name));
node.desc = getOldMemberMethodDesc(node.desc);
node.owner = getOldClassName(node.owner);
} else if (TypeInsnNode.class.isInstance(n)) {
TypeInsnNode node = (TypeInsnNode) n;
node.desc = getOldClassName(node.desc);
} else if (MultiANewArrayInsnNode.class.isInstance(n)) {
MultiANewArrayInsnNode node = (MultiANewArrayInsnNode) n;
node.desc = getOldClassName(node.desc);
} else if (LdcInsnNode.class.isInstance(n)) {
LdcInsnNode node = (LdcInsnNode) n;
if (node.cst instanceof Type) {
Type type = (Type) node.cst;
node.cst = Type.getType(getOldSignature(type.getDescriptor()));
}
}
}
}