perf: improve processing of override related methods (#1072)
This commit is contained in:
@@ -3,6 +3,8 @@ package jadx.api;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.nodes.MethodOverrideAttr;
|
||||
import jadx.core.dex.info.AccessInfo;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
@@ -61,6 +63,15 @@ public final class JavaMethod implements JavaNode {
|
||||
return getDeclaringClass().getRootDecompiler().convertNodes(mth.getUseIn());
|
||||
}
|
||||
|
||||
public List<JavaNode> getOverrideRelatedMethods() {
|
||||
MethodOverrideAttr ovrdAttr = mth.get(AType.METHOD_OVERRIDE);
|
||||
if (ovrdAttr == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
JadxDecompiler decompiler = getDeclaringClass().getRootDecompiler();
|
||||
return decompiler.convertNodes(ovrdAttr.getRelatedMthNodes());
|
||||
}
|
||||
|
||||
public boolean isConstructor() {
|
||||
return mth.getMethodInfo().isConstructor();
|
||||
}
|
||||
|
||||
@@ -211,15 +211,22 @@ public class Deobfuscator {
|
||||
private void renameMethod(MethodNode mth) {
|
||||
String alias = getMethodAlias(mth);
|
||||
if (alias != null) {
|
||||
mth.getMethodInfo().setAlias(alias);
|
||||
resolveOverriding(mth, alias);
|
||||
applyMethodAlias(mth, alias);
|
||||
}
|
||||
}
|
||||
|
||||
public void forceRenameMethod(MethodNode mth) {
|
||||
String alias = makeMethodAlias(mth);
|
||||
mth.getMethodInfo().setAlias(alias);
|
||||
resolveOverriding(mth, alias);
|
||||
applyMethodAlias(mth, alias);
|
||||
}
|
||||
|
||||
private void applyMethodAlias(MethodNode mth, String alias) {
|
||||
MethodInfo methodInfo = mth.getMethodInfo();
|
||||
methodInfo.setAlias(alias);
|
||||
String prev = mthMap.put(methodInfo, alias);
|
||||
if (prev == null) {
|
||||
resolveOverriding(mth, alias);
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveOverriding(MethodNode mth, String alias) {
|
||||
@@ -512,12 +519,7 @@ public class Deobfuscator {
|
||||
if (alias != null) {
|
||||
return alias;
|
||||
}
|
||||
String presetAlias = deobfPresets.getForMth(methodInfo);
|
||||
if (presetAlias != null) {
|
||||
mthMap.put(methodInfo, presetAlias);
|
||||
return presetAlias;
|
||||
}
|
||||
return null;
|
||||
return deobfPresets.getForMth(methodInfo);
|
||||
}
|
||||
|
||||
public String makeFieldAlias(FieldNode field) {
|
||||
@@ -533,9 +535,7 @@ public class Deobfuscator {
|
||||
} else {
|
||||
prefix = "m";
|
||||
}
|
||||
String alias = String.format("%s%d%s", prefix, mthIndex++, prepareNamePart(mth.getName()));
|
||||
mthMap.put(mth.getMethodInfo(), alias);
|
||||
return alias;
|
||||
return String.format("%s%d%s", prefix, mthIndex++, prepareNamePart(mth.getName()));
|
||||
}
|
||||
|
||||
private void processPackageFull(PackageNode pkg, String fullName) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package jadx.core.dex.attributes.nodes;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.IAttribute;
|
||||
@@ -17,9 +18,9 @@ public class MethodOverrideAttr implements IAttribute {
|
||||
/**
|
||||
* All method nodes from override hierarchy. Current method included.
|
||||
*/
|
||||
private List<MethodNode> relatedMthNodes;
|
||||
private SortedSet<MethodNode> relatedMthNodes;
|
||||
|
||||
public MethodOverrideAttr(List<IMethodDetails> overrideList, List<MethodNode> relatedMthNodes) {
|
||||
public MethodOverrideAttr(List<IMethodDetails> overrideList, SortedSet<MethodNode> relatedMthNodes) {
|
||||
this.overrideList = overrideList;
|
||||
this.relatedMthNodes = relatedMthNodes;
|
||||
}
|
||||
@@ -36,11 +37,11 @@ public class MethodOverrideAttr implements IAttribute {
|
||||
this.overrideList = overrideList;
|
||||
}
|
||||
|
||||
public List<MethodNode> getRelatedMthNodes() {
|
||||
public SortedSet<MethodNode> getRelatedMthNodes() {
|
||||
return relatedMthNodes;
|
||||
}
|
||||
|
||||
public void setRelatedMthNodes(List<MethodNode> relatedMthNodes) {
|
||||
public void setRelatedMthNodes(SortedSet<MethodNode> relatedMthNodes) {
|
||||
this.relatedMthNodes = relatedMthNodes;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,16 +2,18 @@ package jadx.core.dex.visitors;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.core.clsp.ClspClass;
|
||||
import jadx.core.clsp.ClspMethod;
|
||||
@@ -39,9 +41,20 @@ import jadx.core.utils.exceptions.JadxException;
|
||||
}
|
||||
)
|
||||
public class OverrideMethodVisitor extends AbstractVisitor {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(OverrideMethodVisitor.class);
|
||||
|
||||
@Override
|
||||
public boolean visit(ClassNode cls) throws JadxException {
|
||||
public void init(RootNode root) throws JadxException {
|
||||
long startTime = System.currentTimeMillis();
|
||||
for (ClassNode cls : root.getClasses()) {
|
||||
processCls(cls);
|
||||
}
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("OverrideMethod pass time: {}ms", System.currentTimeMillis() - startTime);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean processCls(ClassNode cls) {
|
||||
List<ArgType> superTypes = collectSuperTypes(cls);
|
||||
if (!superTypes.isEmpty()) {
|
||||
for (MethodNode mth : cls.getMethods()) {
|
||||
@@ -111,7 +124,8 @@ public class OverrideMethodVisitor extends AbstractVisitor {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private MethodOverrideAttr buildOverrideAttr(MethodNode mth, List<IMethodDetails> overrideList, @Nullable MethodOverrideAttr attr) {
|
||||
private MethodOverrideAttr buildOverrideAttr(MethodNode mth, List<IMethodDetails> overrideList,
|
||||
@Nullable MethodOverrideAttr attr) {
|
||||
if (overrideList.isEmpty() && attr == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -129,21 +143,36 @@ public class OverrideMethodVisitor extends AbstractVisitor {
|
||||
private MethodOverrideAttr applyOverrideAttr(MethodNode mth, List<IMethodDetails> overrideList, boolean update) {
|
||||
// don't rename method if override list contains not resolved method
|
||||
boolean dontRename = overrideList.stream().anyMatch(m -> !(m instanceof MethodNode));
|
||||
SortedSet<MethodNode> relatedMethods = null;
|
||||
List<MethodNode> mthNodes = getMethodNodes(mth, overrideList);
|
||||
if (update) {
|
||||
// merge related methods from all override attributes
|
||||
Set<MethodNode> relatedMthSet = new HashSet<>(mthNodes);
|
||||
for (MethodNode mthNode : mthNodes) {
|
||||
MethodOverrideAttr ovrdAttr = mthNode.get(AType.METHOD_OVERRIDE);
|
||||
if (ovrdAttr != null) {
|
||||
relatedMthSet.addAll(ovrdAttr.getRelatedMthNodes());
|
||||
// use one of already allocated sets
|
||||
relatedMethods = ovrdAttr.getRelatedMthNodes();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (relatedMthSet.size() != mthNodes.size()) {
|
||||
mthNodes = new ArrayList<>(relatedMthSet);
|
||||
Collections.sort(mthNodes);
|
||||
if (relatedMethods != null) {
|
||||
relatedMethods.addAll(mthNodes);
|
||||
} else {
|
||||
relatedMethods = new TreeSet<>(mthNodes);
|
||||
}
|
||||
for (MethodNode mthNode : mthNodes) {
|
||||
MethodOverrideAttr ovrdAttr = mthNode.get(AType.METHOD_OVERRIDE);
|
||||
if (ovrdAttr != null) {
|
||||
SortedSet<MethodNode> set = ovrdAttr.getRelatedMthNodes();
|
||||
if (relatedMethods != set) {
|
||||
relatedMethods.addAll(set);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
relatedMethods = new TreeSet<>(mthNodes);
|
||||
}
|
||||
|
||||
int depth = 0;
|
||||
for (MethodNode mthNode : mthNodes) {
|
||||
if (dontRename) {
|
||||
@@ -157,26 +186,25 @@ public class OverrideMethodVisitor extends AbstractVisitor {
|
||||
if (update) {
|
||||
MethodOverrideAttr ovrdAttr = mthNode.get(AType.METHOD_OVERRIDE);
|
||||
if (ovrdAttr != null) {
|
||||
ovrdAttr.setRelatedMthNodes(mthNodes);
|
||||
ovrdAttr.setRelatedMthNodes(relatedMethods);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
mthNode.addAttr(new MethodOverrideAttr(Utils.listTail(overrideList, depth), mthNodes));
|
||||
mthNode.addAttr(new MethodOverrideAttr(Utils.listTail(overrideList, depth), relatedMethods));
|
||||
depth++;
|
||||
}
|
||||
return new MethodOverrideAttr(overrideList, mthNodes);
|
||||
return new MethodOverrideAttr(overrideList, relatedMethods);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<MethodNode> getMethodNodes(MethodNode mth, List<IMethodDetails> overrideList) {
|
||||
ArrayList<MethodNode> list = new ArrayList<>();
|
||||
List<MethodNode> list = new ArrayList<>(1 + overrideList.size());
|
||||
list.add(mth);
|
||||
for (IMethodDetails md : overrideList) {
|
||||
if (md instanceof MethodNode) {
|
||||
list.add((MethodNode) md);
|
||||
}
|
||||
}
|
||||
list.trimToSize();
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.JadxArgs;
|
||||
import jadx.core.Consts;
|
||||
@@ -24,6 +26,7 @@ import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
|
||||
public class RenameVisitor extends AbstractVisitor {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RenameVisitor.class);
|
||||
|
||||
@Override
|
||||
public void init(RootNode root) {
|
||||
@@ -31,6 +34,14 @@ public class RenameVisitor extends AbstractVisitor {
|
||||
if (inputFiles.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
long startTime = System.currentTimeMillis();
|
||||
process(root);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Rename pass time: {}ms", System.currentTimeMillis() - startTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void process(RootNode root) {
|
||||
Deobfuscator deobfuscator = new Deobfuscator(root);
|
||||
JadxArgs args = root.getArgs();
|
||||
if (args.isDeobfuscationOn()) {
|
||||
|
||||
@@ -6,8 +6,6 @@ import org.slf4j.LoggerFactory;
|
||||
import jadx.api.plugins.input.data.ICodeReader;
|
||||
import jadx.api.plugins.input.insns.InsnData;
|
||||
import jadx.api.plugins.input.insns.Opcode;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.nodes.MethodOverrideAttr;
|
||||
import jadx.core.dex.info.FieldInfo;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
@@ -67,12 +65,6 @@ public class UsageInfoVisitor extends AbstractVisitor {
|
||||
} catch (Exception e) {
|
||||
mth.addError("Dependency scan failed", e);
|
||||
}
|
||||
MethodOverrideAttr overrideAttr = mth.get(AType.METHOD_OVERRIDE);
|
||||
if (overrideAttr != null) {
|
||||
for (MethodNode relatedMthNode : overrideAttr.getRelatedMthNodes()) {
|
||||
usageInfo.methodUse(relatedMthNode, mth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void processInstructions(MethodNode mth, UsageInfo usageInfo) {
|
||||
|
||||
@@ -37,6 +37,10 @@ public class JMethod extends JNode {
|
||||
return mth;
|
||||
}
|
||||
|
||||
public JavaMethod getJavaMethod() {
|
||||
return mth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JClass getJParent() {
|
||||
return jParent;
|
||||
|
||||
@@ -188,6 +188,9 @@ public class RenameDialog extends JDialog {
|
||||
if (javaNode != null) {
|
||||
toUpdate.add(javaNode);
|
||||
toUpdate.addAll(javaNode.getUseIn());
|
||||
if (node instanceof JMethod) {
|
||||
toUpdate.addAll(((JMethod) node).getJavaMethod().getOverrideRelatedMethods());
|
||||
}
|
||||
} else if (node instanceof JPackage) {
|
||||
processPackage(toUpdate);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user