diff --git a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java index d1cccf062..1b242b6ba 100644 --- a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java +++ b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java @@ -42,7 +42,7 @@ import jadx.core.xmlgen.ResourcesSaver; * jadx.load(); * jadx.save(); * - *
+ * * Instead of 'save()' you can iterate over decompiled classes: *
* for(JavaClass cls : jadx.getClasses()) {
diff --git a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
index d81906d09..f68d4679f 100644
--- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
+++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
@@ -137,13 +137,7 @@ public class InsnGen {
private void instanceField(CodeWriter code, FieldInfo field, InsnArg arg) throws CodegenException {
ClassNode pCls = mth.getParentClass();
- FieldNode fieldNode = pCls.searchField(field);
- while (fieldNode == null
- && pCls.getParentClass() != pCls
- && pCls.getParentClass() != null) {
- pCls = pCls.getParentClass();
- fieldNode = pCls.searchField(field);
- }
+ FieldNode fieldNode = pCls.dex().root().deepResolveField(field);
if (fieldNode != null) {
FieldReplaceAttr replace = fieldNode.get(AType.FIELD_REPLACE);
if (replace != null) {
@@ -163,7 +157,11 @@ public class InsnGen {
if (fieldNode != null) {
code.attachAnnotation(fieldNode);
}
- code.add(field.getAlias());
+ if (fieldNode == null) {
+ code.add(field.getAlias());
+ } else {
+ code.add(fieldNode.getAlias());
+ }
}
public static void makeStaticFieldAccess(CodeWriter code, FieldInfo field, ClassGen clsGen) {
@@ -176,11 +174,15 @@ public class InsnGen {
}
code.add('.');
}
- FieldNode fieldNode = clsGen.getClassNode().dex().resolveField(field);
+ FieldNode fieldNode = clsGen.getClassNode().dex().root().deepResolveField(field);
if (fieldNode != null) {
code.attachAnnotation(fieldNode);
}
- code.add(field.getAlias());
+ if (fieldNode == null) {
+ code.add(field.getAlias());
+ } else {
+ code.add(fieldNode.getAlias());
+ }
}
protected void staticField(CodeWriter code, FieldInfo field) {
diff --git a/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java b/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java
index 9480ee147..6dcfaecb5 100644
--- a/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java
+++ b/jadx-core/src/main/java/jadx/core/deobf/Deobfuscator.java
@@ -201,17 +201,13 @@ public class Deobfuscator {
private void collectClassHierarchy(ClassNode cls, Set collected) {
boolean added = collected.add(cls);
if (added) {
- ArgType superClass = cls.getSuperClass();
+ ClassNode superClass = cls.getSuperClassNode();
if (superClass != null) {
- ClassNode superNode = cls.dex().resolveClass(superClass);
- if (superNode != null) {
- collectClassHierarchy(superNode, collected);
- }
+ collectClassHierarchy(superClass, collected);
}
- for (ArgType argType : cls.getInterfaces()) {
- ClassNode interfaceNode = cls.dex().resolveClass(argType);
- if (interfaceNode != null) {
+ for (ClassNode interfaceNode : cls.getInterfaceNodes()) {
+ if(interfaceNode != null) {
collectClassHierarchy(interfaceNode, collected);
}
}
diff --git a/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java b/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java
index 6d4844f70..acb8feeef 100644
--- a/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java
+++ b/jadx-core/src/main/java/jadx/core/dex/info/FieldInfo.java
@@ -2,9 +2,13 @@ package jadx.core.dex.info;
import com.android.dex.FieldId;
+import com.android.dx.io.instructions.DecodedInstruction;
import jadx.core.codegen.TypeGen;
import jadx.core.dex.instructions.args.ArgType;
+import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.DexNode;
+import jadx.core.dex.nodes.FieldNode;
+import jadx.core.dex.nodes.MethodNode;
public final class FieldInfo {
diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java b/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java
index 920802d99..0baed6ea1 100644
--- a/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java
+++ b/jadx-core/src/main/java/jadx/core/dex/instructions/InsnDecoder.java
@@ -2,7 +2,9 @@ package jadx.core.dex.instructions;
import java.io.EOFException;
+import com.android.dex.ClassData;
import com.android.dex.Code;
+import com.android.dex.FieldId;
import com.android.dx.io.OpcodeInfo;
import com.android.dx.io.Opcodes;
import com.android.dx.io.instructions.DecodedInstruction;
@@ -10,6 +12,9 @@ import com.android.dx.io.instructions.FillArrayDataPayloadDecodedInstruction;
import com.android.dx.io.instructions.PackedSwitchPayloadDecodedInstruction;
import com.android.dx.io.instructions.ShortArrayCodeInput;
import com.android.dx.io.instructions.SparseSwitchPayloadDecodedInstruction;
+import jadx.core.dex.info.ClassInfo;
+import jadx.core.dex.nodes.ClassNode;
+import jadx.core.dex.nodes.FieldNode;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
index 327a738d6..02d167257 100644
--- a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
+++ b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
@@ -48,7 +48,9 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
private final ClassInfo clsInfo;
private final AccessInfo accessFlags;
private ArgType superClass;
+ private ClassNode superClassNode;
private List interfaces;
+ private List interfaceNodes; //some element is null whose declaration is out of the dex files
private Map> genericMap;
private final List methods;
@@ -72,12 +74,17 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
try {
if (cls.getSupertypeIndex() == DexNode.NO_INDEX) {
this.superClass = null;
+ this.superClassNode = null;
} else {
this.superClass = dex.getType(cls.getSupertypeIndex());
+ this.superClassNode = dex.resolveClass(ClassInfo.fromType(dex.root(), superClass));
}
this.interfaces = new ArrayList<>(cls.getInterfaces().length);
+ this.interfaceNodes = new ArrayList<>(cls.getInterfaces().length);
for (short interfaceIdx : cls.getInterfaces()) {
- this.interfaces.add(dex.getType(interfaceIdx));
+ ArgType intf = dex.getType(interfaceIdx);
+ this.interfaces.add(intf);
+ this.interfaceNodes.add(dex.resolveClass(intf));
}
if (cls.getClassDataOffset() != 0) {
ClassData clsData = dex.readClassData(cls);
@@ -138,6 +145,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
this.dex = dex;
this.clsInfo = clsInfo;
this.interfaces = Collections.emptyList();
+ this.interfaceNodes = Collections.emptyList();
this.methods = Collections.emptyList();
this.fields = Collections.emptyList();
this.accessFlags = new AccessInfo(AccessFlags.ACC_PUBLIC | AccessFlags.ACC_SYNTHETIC, AFType.CLASS);
@@ -280,10 +288,19 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
return superClass;
}
+ @Nullable
+ public ClassNode getSuperClassNode() {
+ return superClassNode;
+ }
+
public List getInterfaces() {
return interfaces;
}
+ public List getInterfaceNodes() {
+ return interfaceNodes;
+ }
+
public Map> getGenericMap() {
return genericMap;
}
@@ -323,7 +340,6 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
return null;
}
- @TestOnly
public FieldNode searchFieldByName(String name) {
for (FieldNode f : fields) {
if (f.getName().equals(name)) {
diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java
index bc653d8ef..b6f4008cc 100644
--- a/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java
+++ b/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java
@@ -95,6 +95,7 @@ public class DexNode implements IDexNode {
return resolveClass(ClassInfo.fromType(root, type));
}
+ @Deprecated
@Nullable
public MethodNode resolveMethod(@NotNull MethodInfo mth) {
ClassNode cls = resolveClass(mth.getDeclClass());
@@ -105,27 +106,23 @@ public class DexNode implements IDexNode {
}
@Nullable
- MethodNode deepResolveMethod(@NotNull ClassNode cls, String signature) {
- for (MethodNode m : cls.getMethods()) {
- if (m.getMethodInfo().getShortId().startsWith(signature)) {
- return m;
- }
+ MethodNode deepResolveMethod(@NotNull ClassNode cls, MethodInfo methodInfo) {
+ MethodNode field = cls.searchMethodByName(methodInfo.getShortId());
+ if (field != null) {
+ return field;
}
+
MethodNode found;
- ArgType superClass = cls.getSuperClass();
- if (superClass != null) {
- ClassNode superNode = resolveClass(superClass);
- if (superNode != null) {
- found = deepResolveMethod(superNode, signature);
- if (found != null) {
- return found;
- }
+ ClassNode superNode = cls.getSuperClassNode();
+ if (superNode != null) {
+ found = deepResolveMethod(superNode, methodInfo);
+ if (found != null) {
+ return found;
}
}
- for (ArgType iFaceType : cls.getInterfaces()) {
- ClassNode iFaceNode = resolveClass(iFaceType);
- if (iFaceNode != null) {
- found = deepResolveMethod(iFaceNode, signature);
+ for (ClassNode interfaceNode : cls.getInterfaceNodes()) {
+ if(interfaceNode != null) {
+ found = deepResolveMethod(interfaceNode, methodInfo);
if (found != null) {
return found;
}
@@ -134,6 +131,7 @@ public class DexNode implements IDexNode {
return null;
}
+ @Deprecated
@Nullable
public FieldNode resolveField(FieldInfo field) {
ClassNode cls = resolveClass(field.getDeclClass());
@@ -143,6 +141,32 @@ public class DexNode implements IDexNode {
return null;
}
+ @Nullable
+ FieldNode deepResolveField(@NotNull ClassNode cls, FieldInfo fieldInfo) {
+ FieldNode field = cls.searchFieldByName(fieldInfo.getName());
+ if (field != null) {
+ return field;
+ }
+
+ FieldNode found;
+ ClassNode superNode = cls.getSuperClassNode();
+ if (superNode != null) {
+ found = deepResolveField(superNode, fieldInfo);
+ if (found != null) {
+ return found;
+ }
+ }
+ for (ClassNode interfaceNode : cls.getInterfaceNodes()) {
+ if(interfaceNode != null) {
+ found = deepResolveField(interfaceNode, fieldInfo);
+ if (found != null) {
+ return found;
+ }
+ }
+ }
+ return null;
+ }
+
public DexFile getDexFile() {
return file;
}
diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
index e4fc3115a..6207e00e5 100644
--- a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
+++ b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
@@ -5,6 +5,8 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
+import com.android.dex.Dex;
+import jadx.core.dex.info.FieldInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
@@ -181,7 +183,50 @@ public class RootNode {
if (cls == null) {
return null;
}
- return cls.dex().deepResolveMethod(cls, mth.makeSignature(false));
+ MethodNode resolved;
+
+ //most of the time, the method node could be found in current dex.
+ DexNode declDex = cls.dex();
+ resolved = declDex.deepResolveMethod(cls, mth);
+ if (resolved != null){
+ return resolved;
+ }
+ for (DexNode dexNode : dexNodes) {
+ if(dexNodes == declDex) {
+ continue;
+ }
+ resolved = dexNode.deepResolveMethod(cls, mth);
+ if (resolved != null){
+ return resolved;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ public FieldNode deepResolveField(@NotNull FieldInfo field) {
+ ClassNode cls = resolveClass(field.getDeclClass());
+ if (cls == null) {
+ return null;
+ }
+ FieldNode resolved;
+
+ //most of the time, the field node could be found in current dex.
+ DexNode declDex = cls.dex();
+ resolved = declDex.deepResolveField(cls, field);
+ if (resolved != null){
+ return resolved;
+ }
+ for (DexNode dexNode : dexNodes) {
+ if(dexNodes == declDex) {
+ continue;
+ }
+ resolved = dexNode.deepResolveField(cls, field);
+ if (resolved != null){
+ return resolved;
+ }
+ }
+ return null;
}
public List getDexNodes() {
diff --git a/jadx-core/src/main/java/jadx/core/utils/InsnUtils.java b/jadx-core/src/main/java/jadx/core/utils/InsnUtils.java
index 4d9494964..51d2c1199 100644
--- a/jadx-core/src/main/java/jadx/core/utils/InsnUtils.java
+++ b/jadx-core/src/main/java/jadx/core/utils/InsnUtils.java
@@ -78,7 +78,7 @@ public class InsnUtils {
return ((ConstClassNode) insn).getClsType();
case SGET:
FieldInfo f = (FieldInfo) ((IndexInsnNode) insn).getIndex();
- FieldNode fieldNode = dex.resolveField(f);
+ FieldNode fieldNode = dex.root().deepResolveField(f);
if (fieldNode == null) {
LOG.warn("Field {} not found in dex {}", f, dex);
return null;