Commit 39093130 authored by Skylot's avatar Skylot

core: fix processing overriden methods in deobfuscator (#207)

parent 9e9270a8
...@@ -3,7 +3,7 @@ package jadx.core.deobf; ...@@ -3,7 +3,7 @@ package jadx.core.deobf;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
...@@ -142,87 +142,72 @@ public class Deobfuscator { ...@@ -142,87 +142,72 @@ public class Deobfuscator {
ovrdMap.clear(); ovrdMap.clear();
} }
@Nullable private void resolveOverriding(MethodNode mth) {
private static ClassNode resolveOverridingInternal(DexNode dex, ClassNode cls, String signature, Set<ClassNode> clsParents = new LinkedHashSet<>();
Set<MethodInfo> overrideSet, ClassNode rootClass) { collectClassHierarchy(mth.getParentClass(), clsParents);
ClassNode result = null;
for (MethodNode m : cls.getMethods()) { String mthSignature = mth.getMethodInfo().makeSignature(false);
if (m.getMethodInfo().getShortId().startsWith(signature)) { Set<MethodInfo> overrideSet = new LinkedHashSet<>();
result = cls; for (ClassNode classNode : clsParents) {
overrideSet.add(m.getMethodInfo()); MethodInfo methodInfo = getMthOverride(classNode.getMethods(), mthSignature);
break; if (methodInfo != null) {
overrideSet.add(methodInfo);
} }
} }
if (overrideSet.isEmpty()) {
ArgType superClass = cls.getSuperClass(); return;
if (superClass != null) {
ClassNode superNode = dex.resolveClass(superClass);
if (superNode != null) {
ClassNode clsWithMth = resolveOverridingInternal(dex, superNode, signature, overrideSet, rootClass);
if (clsWithMth != null) {
if ((result != null) && (result != cls)) {
if (clsWithMth != result) {
LOG.warn(String.format("Multiple overriding '%s' from '%s' and '%s' in '%s'",
signature,
result.getFullName(), clsWithMth.getFullName(),
rootClass.getFullName()));
} }
} else { OverridedMethodsNode overrideNode = getOverrideMethodsNode(overrideSet);
result = clsWithMth; if (overrideNode == null) {
overrideNode = new OverridedMethodsNode(overrideSet);
ovrd.add(overrideNode);
} }
for (MethodInfo overrideMth : overrideSet) {
if (!ovrdMap.containsKey(overrideMth)) {
ovrdMap.put(overrideMth, overrideNode);
overrideNode.add(overrideMth);
} }
} }
} }
for (ArgType iFaceType : cls.getInterfaces()) { private OverridedMethodsNode getOverrideMethodsNode(Set<MethodInfo> overrideSet) {
ClassNode iFaceNode = dex.resolveClass(iFaceType); for (MethodInfo overrideMth : overrideSet) {
if (iFaceNode != null) { OverridedMethodsNode node = ovrdMap.get(overrideMth);
ClassNode clsWithMth = resolveOverridingInternal(dex, iFaceNode, signature, overrideSet, rootClass); if (node != null) {
if (clsWithMth != null) { return node;
if ((result != null) && (result != cls)) {
if (clsWithMth != result) {
LOG.warn(String.format("Multiple overriding '%s' from '%s' and '%s' in '%s'",
signature,
result.getFullName(), clsWithMth.getFullName(),
rootClass.getFullName()));
} }
} else {
result = clsWithMth;
} }
return null;
} }
private MethodInfo getMthOverride(List<MethodNode> methods, String mthSignature) {
for (MethodNode m : methods) {
MethodInfo mthInfo = m.getMethodInfo();
if (mthInfo.getShortId().startsWith(mthSignature)) {
return mthInfo;
} }
} }
return result; return null;
} }
private void resolveOverriding(MethodNode mth) { private void collectClassHierarchy(ClassNode cls, Set<ClassNode> collected) {
Set<MethodInfo> overrideSet = new HashSet<>(); boolean added = collected.add(cls);
String mthSignature = mth.getMethodInfo().makeSignature(false); if (added) {
ClassNode cls = mth.getParentClass(); ArgType superClass = cls.getSuperClass();
resolveOverridingInternal(mth.dex(), cls, mthSignature, overrideSet, cls); if (superClass != null) {
if (overrideSet.size() > 1) { ClassNode superNode = cls.dex().resolveClass(superClass);
OverridedMethodsNode overrideNode = null; if (superNode != null) {
for (MethodInfo _mth : overrideSet) { collectClassHierarchy(superNode, collected);
if (ovrdMap.containsKey(_mth)) {
overrideNode = ovrdMap.get(_mth);
break;
}
}
if (overrideNode == null) {
overrideNode = new OverridedMethodsNode(overrideSet);
ovrd.add(overrideNode);
} }
for (MethodInfo _mth : overrideSet) {
if (!ovrdMap.containsKey(_mth)) {
ovrdMap.put(_mth, overrideNode);
if (!overrideNode.contains(_mth)) {
overrideNode.add(_mth);
} }
for (ArgType argType : cls.getInterfaces()) {
ClassNode interfaceNode = cls.dex().resolveClass(argType);
if (interfaceNode != null) {
collectClassHierarchy(interfaceNode, collected);
} }
} }
} }
overrideSet.clear();
} }
private void processClass(ClassNode cls) { private void processClass(ClassNode cls) {
......
...@@ -4,7 +4,7 @@ import java.util.Set; ...@@ -4,7 +4,7 @@ import java.util.Set;
import jadx.core.dex.info.MethodInfo; import jadx.core.dex.info.MethodInfo;
/* package */ class OverridedMethodsNode { class OverridedMethodsNode {
private Set<MethodInfo> methods; private Set<MethodInfo> methods;
......
...@@ -30,10 +30,10 @@ public class TestMthRename extends IntegrationTest { ...@@ -30,10 +30,10 @@ public class TestMthRename extends IntegrationTest {
ClassNode cls = getClassNode(TestCls.class); ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString(); String code = cls.getCode().toString();
assertThat(code, containsString("public abstract void m0a();")); assertThat(code, containsString("public abstract void mo1a();"));
assertThat(code, not(containsString("public abstract void a();"))); assertThat(code, not(containsString("public abstract void a();")));
assertThat(code, containsString(".m0a();")); assertThat(code, containsString(".mo1a();"));
assertThat(code, not(containsString(".a();"))); assertThat(code, not(containsString(".a();")));
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment