From 883429fa47969b7af92fab33529ee242ed0f447d Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 7 Feb 2015 21:18:53 +0300 Subject: [PATCH] core: fix enum class processing for obfuscated code --- .../jadx/core/dex/visitors/EnumVisitor.java | 28 ++++++++----- .../enums/TestEnumsWithConsts.java | 41 +++++++++++++++++++ 2 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/enums/TestEnumsWithConsts.java diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java index 92f9d1993..395a62515 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java @@ -28,6 +28,7 @@ import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +// TODO: run after code shrinker at final stage public class EnumVisitor extends AbstractVisitor { private static final Logger LOG = LoggerFactory.getLogger(EnumVisitor.class); @@ -91,6 +92,7 @@ public class EnumVisitor extends AbstractVisitor { // move enum specific instruction from static method to separate list BlockNode staticBlock = staticMethod.getBasicBlocks().get(0); + ClassInfo classInfo = cls.getClassInfo(); List insns = new ArrayList(); List list = staticBlock.getInstructions(); int size = list.size(); @@ -100,13 +102,19 @@ public class EnumVisitor extends AbstractVisitor { if (insn.getType() == InsnType.SPUT) { IndexInsnNode fp = (IndexInsnNode) insn; FieldInfo f = (FieldInfo) fp.getIndex(); - if (f.getName().equals("$VALUES")) { - if (i == size - 1) { - cls.getMethods().remove(staticMethod); - } else { - list.subList(0, i + 1).clear(); + if (f.getDeclClass().equals(classInfo)) { + FieldNode fieldNode = cls.searchField(f); + if (fieldNode != null + && fieldNode.getAccessFlags().isSynthetic() + && fieldNode.getType().isArray() + && fieldNode.getType().getArrayRootElement().equals(classInfo.getType())) { + if (i == size - 1) { + cls.getMethods().remove(staticMethod); + } else { + list.subList(0, i + 1).clear(); + } + break; } - break; } } } @@ -122,7 +130,7 @@ public class EnumVisitor extends AbstractVisitor { if (constrCls == null) { continue; } - if (!clsInfo.equals(cls.getClassInfo()) && !constrCls.getAccessFlags().isEnum()) { + if (!clsInfo.equals(classInfo) && !constrCls.getAccessFlags().isEnum()) { continue; } RegisterArg nameArg = (RegisterArg) insn.getArg(0); @@ -135,11 +143,11 @@ public class EnumVisitor extends AbstractVisitor { EnumField field = new EnumField(name, insn.getArgsCount() - 2); attr.getFields().add(field); for (int i = 2; i < insn.getArgsCount(); i++) { - InsnArg constrArg; InsnArg iArg = insn.getArg(i); + InsnArg constrArg = iArg; if (iArg.isLiteral()) { constrArg = iArg; - } else { + } else if (iArg.isRegister()) { constrArg = CodeShrinker.inlineArgument(staticMethod, (RegisterArg) iArg); if (constrArg == null) { throw new JadxException("Can't inline constructor arg in enum: " + cls); @@ -148,7 +156,7 @@ public class EnumVisitor extends AbstractVisitor { field.getArgs().add(constrArg); } - if (co.getClassType() != cls.getClassInfo()) { + if (!co.getClassType().equals(classInfo)) { // enum contains additional methods for (ClassNode innerCls : cls.getInnerClasses()) { if (innerCls.getClassInfo().equals(co.getClassType())) { diff --git a/jadx-core/src/test/java/jadx/tests/integration/enums/TestEnumsWithConsts.java b/jadx-core/src/test/java/jadx/tests/integration/enums/TestEnumsWithConsts.java new file mode 100644 index 000000000..970928c79 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/enums/TestEnumsWithConsts.java @@ -0,0 +1,41 @@ +package jadx.tests.integration.enums; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.IntegrationTest; + +import org.junit.Test; + +import static jadx.tests.api.utils.JadxMatchers.containsLines; +import static org.junit.Assert.assertThat; + +public class TestEnumsWithConsts extends IntegrationTest { + + public static class TestCls { + + public static final int C1 = 1; + public static final int C2 = 2; + public static final int C4 = 4; + + public static final String S = "NORTH"; + + public enum Direction { + NORTH, + SOUTH, + EAST, + WEST + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, containsLines(1, "public enum Direction {", + indent(1) + "NORTH,", + indent(1) + "SOUTH,", + indent(1) + "EAST,", + indent(1) + "WEST", + "}")); + } +}