From ed9b5cdfc648e86fd463bfa8d86b94c41671e14c Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 8 Feb 2015 21:29:25 -0500 Subject: switch all classes to new signature/type system --- src/cuchaz/enigma/bytecode/InnerClassWriter.java | 102 +++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/cuchaz/enigma/bytecode/InnerClassWriter.java (limited to 'src/cuchaz/enigma/bytecode/InnerClassWriter.java') diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java new file mode 100644 index 0000000..817500b --- /dev/null +++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.bytecode; + +import java.util.Collection; + +import javassist.CtClass; +import javassist.bytecode.AccessFlag; +import javassist.bytecode.ConstPool; +import javassist.bytecode.Descriptor; +import javassist.bytecode.EnclosingMethodAttribute; +import javassist.bytecode.InnerClassesAttribute; +import cuchaz.enigma.Constants; +import cuchaz.enigma.analysis.JarIndex; +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.ClassEntry; + +public class InnerClassWriter { + + private JarIndex m_jarIndex; + + public InnerClassWriter(JarIndex jarIndex) { + m_jarIndex = jarIndex; + } + + public void write(CtClass c) { + + // is this an inner or outer class? + String obfInnerClassName = new ClassEntry(Descriptor.toJvmName(c.getName())).getSimpleName(); + String obfOuterClassName = m_jarIndex.getOuterClass(obfInnerClassName); + if (obfOuterClassName == null) { + // this is an outer class + obfOuterClassName = Descriptor.toJvmName(c.getName()); + } else { + // this is an inner class, rename it to outer$inner + ClassEntry obfClassEntry = new ClassEntry(obfOuterClassName + "$" + obfInnerClassName); + c.setName(obfClassEntry.getName()); + + BehaviorEntry caller = m_jarIndex.getAnonymousClassCaller(obfInnerClassName); + if (caller != null) { + // write the enclosing method attribute + if (caller.getName().equals("")) { + c.getClassFile().addAttribute(new EnclosingMethodAttribute(c.getClassFile().getConstPool(), caller.getClassName())); + } else { + c.getClassFile().addAttribute(new EnclosingMethodAttribute(c.getClassFile().getConstPool(), caller.getClassName(), caller.getName(), caller.getSignature().toString())); + } + } + } + + // write the inner classes if needed + Collection obfInnerClassNames = m_jarIndex.getInnerClasses(obfOuterClassName); + if (obfInnerClassNames != null && !obfInnerClassNames.isEmpty()) { + writeInnerClasses(c, obfOuterClassName, obfInnerClassNames); + } + } + + private void writeInnerClasses(CtClass c, String obfOuterClassName, Collection obfInnerClassNames) { + InnerClassesAttribute attr = new InnerClassesAttribute(c.getClassFile().getConstPool()); + c.getClassFile().addAttribute(attr); + for (String obfInnerClassName : obfInnerClassNames) { + // get the new inner class name + ClassEntry obfClassEntry = new ClassEntry(obfOuterClassName + "$" + obfInnerClassName); + + // here's what the JVM spec says about the InnerClasses attribute + // append( inner, outer of inner if inner is member of outer 0 ow, name after $ if inner not anonymous 0 ow, flags ); + + // update the attribute with this inner class + ConstPool constPool = c.getClassFile().getConstPool(); + int innerClassIndex = constPool.addClassInfo(obfClassEntry.getName()); + int outerClassIndex = 0; + int innerClassSimpleNameIndex = 0; + if (!m_jarIndex.isAnonymousClass(obfInnerClassName)) { + outerClassIndex = constPool.addClassInfo(obfClassEntry.getOuterClassName()); + innerClassSimpleNameIndex = constPool.addUtf8Info(obfClassEntry.getInnerClassName()); + } + + attr.append(innerClassIndex, outerClassIndex, innerClassSimpleNameIndex, c.getClassFile().getAccessFlags() & ~AccessFlag.SUPER); + + /* DEBUG + System.out.println(String.format("\tOBF: %s -> ATTR: %s,%s,%s (replace %s with %s)", + obfClassEntry, + attr.outerClass(attr.tableLength() - 1), + attr.innerClass(attr.tableLength() - 1), + attr.innerName(attr.tableLength() - 1), + Constants.NonePackage + "/" + obfInnerClassName, + obfClassEntry.getName() + )); + */ + + // make sure the outer class references only the new inner class names + c.replaceClassName(Constants.NonePackage + "/" + obfInnerClassName, obfClassEntry.getName()); + } + } +} -- cgit v1.2.3