Co-authored-by: tobias <tobias.hotmail.com>
This commit is contained in:
@@ -30,10 +30,7 @@ import jadx.api.plugins.input.data.ILoadResult;
|
||||
import jadx.core.Jadx;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.nodes.LineAttrNode;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
import jadx.core.dex.nodes.*;
|
||||
import jadx.core.dex.visitors.SaveCode;
|
||||
import jadx.core.export.ExportGradleProject;
|
||||
import jadx.core.utils.Utils;
|
||||
@@ -449,6 +446,10 @@ public final class JadxDecompiler implements Closeable {
|
||||
if (obj instanceof FieldNode) {
|
||||
return getJavaFieldByNode((FieldNode) obj);
|
||||
}
|
||||
if (obj instanceof VariableNode) {
|
||||
VariableNode varNode = (VariableNode) obj;
|
||||
return new JavaVariable(getJavaClassByNode(varNode.getClassNode()), varNode);
|
||||
}
|
||||
throw new JadxRuntimeException("Unexpected node type: " + obj);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package jadx.api;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import jadx.core.dex.nodes.VariableNode;
|
||||
|
||||
public class JavaVariable implements JavaNode {
|
||||
JavaClass cls;
|
||||
VariableNode node;
|
||||
|
||||
public JavaVariable(JavaClass cls, VariableNode node) {
|
||||
this.cls = cls;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public VariableNode getVariableNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return node.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullName() {
|
||||
return node.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaClass getDeclaringClass() {
|
||||
return cls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaClass getTopParentClass() {
|
||||
return cls.getTopParentClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDecompiledLine() {
|
||||
return node.getDecompiledLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JavaNode> getUseIn() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return node.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return node.equals(obj);
|
||||
}
|
||||
}
|
||||
@@ -35,25 +35,16 @@ import jadx.core.dex.instructions.InvokeNode;
|
||||
import jadx.core.dex.instructions.InvokeType;
|
||||
import jadx.core.dex.instructions.NewArrayNode;
|
||||
import jadx.core.dex.instructions.SwitchInsn;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.CodeVar;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.InsnWrapArg;
|
||||
import jadx.core.dex.instructions.args.LiteralArg;
|
||||
import jadx.core.dex.instructions.args.Named;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.instructions.args.SSAVar;
|
||||
import jadx.core.dex.instructions.args.*;
|
||||
import jadx.core.dex.instructions.mods.ConstructorInsn;
|
||||
import jadx.core.dex.instructions.mods.TernaryInsn;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
import jadx.core.dex.nodes.*;
|
||||
import jadx.core.utils.CodeGenUtils;
|
||||
import jadx.core.utils.RegionUtils;
|
||||
import jadx.core.utils.exceptions.CodegenException;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
import static jadx.core.dex.nodes.VariableNode.*;
|
||||
import static jadx.core.utils.android.AndroidResourcesUtils.handleAppResField;
|
||||
|
||||
public class InsnGen {
|
||||
@@ -97,12 +88,26 @@ public class InsnGen {
|
||||
|
||||
public void addArg(CodeWriter code, InsnArg arg, boolean wrap) throws CodegenException {
|
||||
if (arg.isRegister()) {
|
||||
CodeVar codeVar = CodeGenUtils.getCodeVar((RegisterArg) arg);
|
||||
if (codeVar != null) {
|
||||
VariableNode node = mth.getVariable(codeVar.getIndex());
|
||||
if (node != null) {
|
||||
node.useVar(code, codeVar);
|
||||
code.attachAnnotation(node);
|
||||
}
|
||||
}
|
||||
code.add(mgen.getNameGen().useArg((RegisterArg) arg));
|
||||
} else if (arg.isLiteral()) {
|
||||
code.add(lit((LiteralArg) arg));
|
||||
} else if (arg.isInsnWrap()) {
|
||||
addWrappedArg(code, (InsnWrapArg) arg, wrap);
|
||||
} else if (arg.isNamed()) {
|
||||
if (arg instanceof NamedArg) {
|
||||
VariableNode node = mth.getVariable(((NamedArg) arg).getIndex());
|
||||
if (node != null) {
|
||||
code.attachAnnotation(node);
|
||||
}
|
||||
}
|
||||
code.add(((Named) arg).getName());
|
||||
} else {
|
||||
throw new CodegenException("Unknown arg type " + arg);
|
||||
@@ -140,7 +145,16 @@ public class InsnGen {
|
||||
}
|
||||
useType(code, codeVar.getType());
|
||||
code.add(' ');
|
||||
code.add(mgen.getNameGen().assignArg(codeVar));
|
||||
VariableNode node = mth.declareVar(codeVar, mgen.getNameGen(), VarKind.VAR);
|
||||
String name;
|
||||
if (node != null) {
|
||||
code.attachDefinition(node);
|
||||
name = node.getName();
|
||||
codeVar.setName(name);
|
||||
} else {
|
||||
name = mgen.getNameGen().assignArg(codeVar);
|
||||
}
|
||||
code.add(name);
|
||||
}
|
||||
|
||||
private String lit(LiteralArg arg) {
|
||||
@@ -639,6 +653,7 @@ public class InsnGen {
|
||||
if (insn.isSuper()) {
|
||||
code.add("super");
|
||||
} else if (insn.isThis()) {
|
||||
code.attachAnnotation(mth.getParentClass());
|
||||
code.add("this");
|
||||
} else {
|
||||
code.add("new ");
|
||||
|
||||
@@ -29,6 +29,7 @@ import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.instructions.args.SSAVar;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.nodes.VariableNode;
|
||||
import jadx.core.dex.trycatch.CatchAttr;
|
||||
import jadx.core.dex.visitors.DepthTraversal;
|
||||
import jadx.core.dex.visitors.IDexTreeVisitor;
|
||||
@@ -42,6 +43,7 @@ import jadx.core.utils.exceptions.JadxOverflowException;
|
||||
import static jadx.core.codegen.MethodGen.FallbackOption.BLOCK_DUMP;
|
||||
import static jadx.core.codegen.MethodGen.FallbackOption.COMMENTED_DUMP;
|
||||
import static jadx.core.codegen.MethodGen.FallbackOption.FALLBACK_MODE;
|
||||
import static jadx.core.dex.nodes.VariableNode.*;
|
||||
|
||||
public class MethodGen {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MethodGen.class);
|
||||
@@ -220,7 +222,19 @@ public class MethodGen {
|
||||
classGen.useType(code, argType);
|
||||
}
|
||||
code.add(' ');
|
||||
code.add(nameGen.assignArg(var));
|
||||
VariableNode node = mth.declareVar(var, nameGen, VarKind.ARG);
|
||||
String name;
|
||||
if (node != null) {
|
||||
code.attachDefinition(node);
|
||||
name = node.getName();
|
||||
var.setName(name);
|
||||
} else {
|
||||
name = nameGen.assignArg(var);
|
||||
}
|
||||
if (var.isThis()) {
|
||||
code.attachDefinition(mth.getParentClass());
|
||||
}
|
||||
code.add(name);
|
||||
|
||||
i++;
|
||||
if (it.hasNext()) {
|
||||
|
||||
@@ -21,12 +21,7 @@ import jadx.core.dex.instructions.args.CodeVar;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.NamedArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
import jadx.core.dex.nodes.IBlock;
|
||||
import jadx.core.dex.nodes.IContainer;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.*;
|
||||
import jadx.core.dex.regions.Region;
|
||||
import jadx.core.dex.regions.SwitchRegion;
|
||||
import jadx.core.dex.regions.SwitchRegion.CaseInfo;
|
||||
@@ -40,10 +35,13 @@ import jadx.core.dex.regions.loops.LoopRegion;
|
||||
import jadx.core.dex.regions.loops.LoopType;
|
||||
import jadx.core.dex.trycatch.ExceptionHandler;
|
||||
import jadx.core.utils.BlockUtils;
|
||||
import jadx.core.utils.CodeGenUtils;
|
||||
import jadx.core.utils.RegionUtils;
|
||||
import jadx.core.utils.exceptions.CodegenException;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
import static jadx.core.dex.nodes.VariableNode.*;
|
||||
|
||||
public class RegionGen extends InsnGen {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RegionGen.class);
|
||||
|
||||
@@ -351,10 +349,29 @@ public class RegionGen extends InsnGen {
|
||||
if (arg == null) {
|
||||
code.add("unknown"); // throwing exception is too late at this point
|
||||
} else if (arg instanceof RegisterArg) {
|
||||
RegisterArg reg = (RegisterArg) arg;
|
||||
code.add(mgen.getNameGen().assignArg(reg.getSVar().getCodeVar()));
|
||||
String name;
|
||||
CodeVar codeVar = CodeGenUtils.getCodeVar((RegisterArg) arg);
|
||||
if (codeVar != null) {
|
||||
VariableNode node = mth.declareVar(codeVar, mgen.getNameGen(), VarKind.CATCH_ARG);
|
||||
if (node != null) {
|
||||
code.attachDefinition(node);
|
||||
name = node.getName();
|
||||
codeVar.setName(name);
|
||||
} else {
|
||||
name = mgen.getNameGen().assignArg(codeVar);
|
||||
}
|
||||
} else {
|
||||
RegisterArg reg = (RegisterArg) arg;
|
||||
name = mgen.getNameGen().assignArg(reg.getSVar().getCodeVar());
|
||||
}
|
||||
code.add(name);
|
||||
} else if (arg instanceof NamedArg) {
|
||||
code.add(mgen.getNameGen().assignNamedArg((NamedArg) arg));
|
||||
VariableNode node = mth.declareVar((NamedArg) arg, mgen.getNameGen(), VarKind.CATCH_ARG);
|
||||
if (node != null) {
|
||||
code.add(node.getName());
|
||||
} else {
|
||||
code.add(mgen.getNameGen().assignNamedArg((NamedArg) arg));
|
||||
}
|
||||
} else {
|
||||
throw new JadxRuntimeException("Unexpected arg type in catch block: " + arg + ", class: " + arg.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@@ -6,11 +6,7 @@ import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
@@ -20,6 +16,7 @@ import jadx.core.dex.info.ClassInfo;
|
||||
import jadx.core.dex.info.FieldInfo;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
import jadx.core.dex.nodes.VariableNode;
|
||||
import jadx.core.utils.files.FileUtils;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
@@ -35,6 +32,7 @@ public class DeobfPresets {
|
||||
private final Map<String, String> clsPresetMap = new HashMap<>();
|
||||
private final Map<String, String> fldPresetMap = new HashMap<>();
|
||||
private final Map<String, String> mthPresetMap = new HashMap<>();
|
||||
private final Map<String, Set<String>> varPresetMap = new HashMap<>();
|
||||
|
||||
@Nullable
|
||||
public static DeobfPresets build(RootNode root) {
|
||||
@@ -94,6 +92,13 @@ public class DeobfPresets {
|
||||
case 'm':
|
||||
mthPresetMap.put(origName, alias);
|
||||
break;
|
||||
case 'v':
|
||||
String[] mthIDAndVarIndex = origName.split(VariableNode.VAR_SEPARATOR);
|
||||
if (mthIDAndVarIndex.length == 2) {
|
||||
Set<String> nameList = varPresetMap.computeIfAbsent(mthIDAndVarIndex[0], k -> new HashSet<>());
|
||||
nameList.add(makeVarSecIndex(mthIDAndVarIndex[1], alias));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -101,6 +106,10 @@ public class DeobfPresets {
|
||||
}
|
||||
}
|
||||
|
||||
public static String makeVarSecIndex(String indexes, String name) {
|
||||
return indexes + VariableNode.VAR_SEPARATOR + name;
|
||||
}
|
||||
|
||||
private static String[] splitAndTrim(String str) {
|
||||
String[] v = str.substring(2).split("=");
|
||||
for (int i = 0; i < v.length; i++) {
|
||||
@@ -123,6 +132,15 @@ public class DeobfPresets {
|
||||
for (Map.Entry<String, String> mthEntry : mthPresetMap.entrySet()) {
|
||||
list.add(String.format("m %s = %s", mthEntry.getKey(), mthEntry.getValue()));
|
||||
}
|
||||
for (Map.Entry<String, Set<String>> varEntry : varPresetMap.entrySet()) {
|
||||
for (String val : varEntry.getValue()) {
|
||||
String[] indexAndName = val.split(VariableNode.VAR_SEPARATOR);
|
||||
if (indexAndName.length == 2) {
|
||||
list.add(String.format("v %s%s%s = %s",
|
||||
varEntry.getKey(), VariableNode.VAR_SEPARATOR, indexAndName[0], indexAndName[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(list);
|
||||
Files.write(deobfMapFile, list, MAP_FILE_CHARSET,
|
||||
StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
@@ -147,6 +165,7 @@ public class DeobfPresets {
|
||||
clsPresetMap.clear();
|
||||
fldPresetMap.clear();
|
||||
mthPresetMap.clear();
|
||||
varPresetMap.clear();
|
||||
}
|
||||
|
||||
public Path getDeobfMapFile() {
|
||||
@@ -168,4 +187,18 @@ public class DeobfPresets {
|
||||
public Map<String, String> getMthPresetMap() {
|
||||
return mthPresetMap;
|
||||
}
|
||||
|
||||
public Map<String, Set<String>> getVarPresetMap() {
|
||||
return varPresetMap;
|
||||
}
|
||||
|
||||
public void updateVariableName(VariableNode node, String name) {
|
||||
String key = node.getRenameKey();
|
||||
key = key.substring(0, key.indexOf(VariableNode.VAR_SEPARATOR));
|
||||
String newIndex = makeVarSecIndex(node.makeVarIndex(), name);
|
||||
String oldIndex = makeVarSecIndex(node.makeVarIndex(), node.getName());
|
||||
Set<String> indexSet = varPresetMap.computeIfAbsent(key, k -> new HashSet<>());
|
||||
indexSet.remove(oldIndex);
|
||||
indexSet.add(newIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,7 @@ package jadx.core.deobf;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.*;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
@@ -209,6 +203,10 @@ public class Deobfuscator {
|
||||
}
|
||||
|
||||
private void renameMethod(MethodNode mth) {
|
||||
Set<String> names = deobfPresets.getVarPresetMap().get(mth.getMethodInfo().getRawFullId());
|
||||
if (names != null) {
|
||||
mth.getMethodInfo().setVarNameMap(names);
|
||||
}
|
||||
String alias = getMethodAlias(mth);
|
||||
if (alias != null) {
|
||||
applyMethodAlias(mth, alias);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package jadx.core.dex.info;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -10,6 +9,7 @@ import jadx.api.plugins.input.data.IMethodRef;
|
||||
import jadx.core.codegen.TypeGen;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
import jadx.core.dex.nodes.VariableNode;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
public final class MethodInfo implements Comparable<MethodInfo> {
|
||||
@@ -20,6 +20,7 @@ public final class MethodInfo implements Comparable<MethodInfo> {
|
||||
private final ClassInfo declClass;
|
||||
private final String shortId;
|
||||
private String alias;
|
||||
private Map<String, String> varNameMap;
|
||||
|
||||
private MethodInfo(ClassInfo declClass, String name, List<ArgType> args, ArgType retType) {
|
||||
this.name = name;
|
||||
@@ -148,6 +149,29 @@ public final class MethodInfo implements Comparable<MethodInfo> {
|
||||
return !name.equals(alias);
|
||||
}
|
||||
|
||||
public synchronized void setVarNameMap(Set<String> names) {
|
||||
if (varNameMap == null) {
|
||||
varNameMap = new HashMap<>();
|
||||
}
|
||||
for (String name : names) {
|
||||
String[] indexesAndName = name.split(VariableNode.VAR_SEPARATOR);
|
||||
if (indexesAndName.length == 2) {
|
||||
varNameMap.put(indexesAndName[0], indexesAndName[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getVariableName(String indexes) {
|
||||
if (varNameMap != null) {
|
||||
return varNameMap.get(indexes);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasVarNameMap() {
|
||||
return varNameMap != null && varNameMap.size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return shortId.hashCode() + 31 * declClass.hashCode();
|
||||
|
||||
@@ -4,7 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class CodeVar {
|
||||
public class CodeVar implements VisibleVar {
|
||||
private String name;
|
||||
private ArgType type; // before type inference can be null and set only for immutable types
|
||||
private List<SSAVar> ssaVars = Collections.emptyList();
|
||||
@@ -13,6 +13,18 @@ public class CodeVar {
|
||||
private boolean isThis;
|
||||
private boolean isDeclared;
|
||||
|
||||
private int index = -1;
|
||||
|
||||
@Override
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public static CodeVar fromMthArg(RegisterArg mthArg, boolean linkRegister) {
|
||||
CodeVar var = new CodeVar();
|
||||
var.setType(mthArg.getInitType());
|
||||
@@ -26,14 +38,17 @@ public class CodeVar {
|
||||
return var;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -2,16 +2,28 @@ package jadx.core.dex.instructions.args;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class NamedArg extends InsnArg implements Named {
|
||||
public final class NamedArg extends InsnArg implements Named, VisibleVar {
|
||||
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
private int index = -1;
|
||||
|
||||
public NamedArg(@NotNull String name, @NotNull ArgType type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return name;
|
||||
@@ -22,6 +34,7 @@ public final class NamedArg extends InsnArg implements Named {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(@NotNull String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package jadx.core.dex.instructions.args;
|
||||
|
||||
public interface VisibleVar {
|
||||
int getIndex();
|
||||
|
||||
void setIndex(int index);
|
||||
|
||||
String getName();
|
||||
|
||||
void setName(String name);
|
||||
|
||||
ArgType getType();
|
||||
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
package jadx.core.dex.nodes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -16,6 +13,7 @@ import jadx.api.plugins.input.data.IMethodData;
|
||||
import jadx.api.plugins.input.data.annotations.EncodedValue;
|
||||
import jadx.api.plugins.input.data.annotations.IAnnotation;
|
||||
import jadx.core.Consts;
|
||||
import jadx.core.codegen.NameGen;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.annotations.AnnotationsList;
|
||||
import jadx.core.dex.attributes.annotations.MethodParameters;
|
||||
@@ -26,10 +24,8 @@ import jadx.core.dex.info.AccessInfo.AFType;
|
||||
import jadx.core.dex.info.ClassInfo;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
import jadx.core.dex.instructions.InsnDecoder;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.instructions.args.SSAVar;
|
||||
import jadx.core.dex.instructions.args.*;
|
||||
import jadx.core.dex.nodes.VariableNode.VarKind;
|
||||
import jadx.core.dex.nodes.utils.TypeUtils;
|
||||
import jadx.core.dex.regions.Region;
|
||||
import jadx.core.dex.trycatch.ExceptionHandler;
|
||||
@@ -73,6 +69,7 @@ public class MethodNode extends NotificationAttrNode implements IMethodDetails,
|
||||
private Region region;
|
||||
|
||||
private List<MethodNode> useIn = Collections.emptyList();
|
||||
private List<VariableNode> variables = new ArrayList<>();
|
||||
|
||||
public static MethodNode build(ClassNode classNode, IMethodData methodData) {
|
||||
MethodNode methodNode = new MethodNode(classNode, methodData);
|
||||
@@ -102,6 +99,59 @@ public class MethodNode extends NotificationAttrNode implements IMethodDetails,
|
||||
unload();
|
||||
}
|
||||
|
||||
public List<VariableNode> getVars() {
|
||||
return new ArrayList<>(variables);
|
||||
}
|
||||
|
||||
public VariableNode getVariable(int index) {
|
||||
if (index >= 0 && index < variables.size()) {
|
||||
return variables.get(index);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public VariableNode getVariable(int index, VarKind varType) {
|
||||
for (VariableNode variable : variables) {
|
||||
if (variable.getVarKind() == varType && variable.getIndex() == index) {
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public VariableNode declareVar(VisibleVar var, NameGen nameGen, VarKind varKind) {
|
||||
if (var instanceof CodeVar) {
|
||||
if (((CodeVar) var).isThis()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
VariableNode varNode;
|
||||
int index = var.getIndex();
|
||||
if (index == -1) {
|
||||
index = variables.size();
|
||||
var.setIndex(index);
|
||||
varNode = null;
|
||||
} else {
|
||||
varNode = getVariable(var.getIndex());
|
||||
}
|
||||
if (varNode == null) {
|
||||
String name = mthInfo.getVariableName(VariableNode.makeVarIndex(index, varKind));
|
||||
if (name != null) {
|
||||
var.setName(name); // set name with user renamed previously.
|
||||
}
|
||||
if (var instanceof CodeVar) { // let NameGen record this name or gen an valid name.
|
||||
name = nameGen.assignArg((CodeVar) var);
|
||||
} else if (var instanceof NamedArg) {
|
||||
name = nameGen.assignNamedArg((NamedArg) var);
|
||||
} else {
|
||||
throw new JadxRuntimeException("Unexpected var type: " + var);
|
||||
}
|
||||
varNode = new VariableNode(this, name, var.getType(), varKind, index);
|
||||
this.variables.add(varNode);
|
||||
}
|
||||
return varNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
loaded = false;
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package jadx.core.dex.nodes;
|
||||
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.dex.attributes.nodes.LineAttrNode;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.CodeVar;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
public class VariableNode extends LineAttrNode {
|
||||
public enum VarKind {
|
||||
// note: better not change the order of these fields,
|
||||
// they are also used for variable renaming
|
||||
VAR, ARG, CATCH_ARG
|
||||
}
|
||||
|
||||
public static final String VAR_SEPARATOR = "--->>"; // do not contain '='
|
||||
private VarKind varKind = VarKind.VAR;
|
||||
private ArgType type;
|
||||
private String name;
|
||||
private int index;
|
||||
MethodNode mth;
|
||||
|
||||
public VariableNode(MethodNode mth, String name, ArgType type, VarKind varKind, int index) {
|
||||
this.mth = mth;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.index = index;
|
||||
this.varKind = varKind;
|
||||
}
|
||||
|
||||
public MethodNode getMethodNode() {
|
||||
return mth;
|
||||
}
|
||||
|
||||
public ClassNode getClassNode() {
|
||||
return mth.getParentClass();
|
||||
}
|
||||
|
||||
public VarKind getVarKind() {
|
||||
return this.varKind;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ArgType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public void addUsage(int line, int offset, int codeOffset) {
|
||||
}
|
||||
|
||||
public void useVar(CodeWriter code, CodeVar codeVar) {
|
||||
if (!codeVar.isThis()) { // TODO: add usage
|
||||
// IdentifierVisitor.VariableNode node = codeVar.getVariableNode();
|
||||
// node.addUsage(code.getLine(), code.getOffset(), code.bufLength());
|
||||
// code.attachAnnotation(node);
|
||||
}
|
||||
}
|
||||
|
||||
public String getRenameKey() {
|
||||
return mth.getMethodInfo().getRawFullId() + VAR_SEPARATOR + makeVarIndex(index, varKind);
|
||||
}
|
||||
|
||||
public String makeVarIndex() {
|
||||
return makeVarIndex(index, varKind);
|
||||
}
|
||||
|
||||
public static String makeVarIndex(int index, VarKind kind) {
|
||||
return kindToStr(kind) + "@" + kind.ordinal() + "_" + index;
|
||||
}
|
||||
|
||||
private static String kindToStr(VarKind varKind) {
|
||||
String kind;
|
||||
switch (varKind) {
|
||||
case VAR:
|
||||
kind = "var";
|
||||
break;
|
||||
case ARG:
|
||||
kind = "param";
|
||||
break;
|
||||
case CATCH_ARG:
|
||||
kind = "catch";
|
||||
break;
|
||||
default:
|
||||
throw new JadxRuntimeException("Unexpected variable type " + varKind);
|
||||
}
|
||||
return kind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mth.hashCode() + 31 * getDefPosition() + 31 * makeVarIndex().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return this == obj;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,9 @@ import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.AttrNode;
|
||||
import jadx.core.dex.attributes.nodes.RenameReasonAttr;
|
||||
import jadx.core.dex.attributes.nodes.SourceFileAttr;
|
||||
import jadx.core.dex.instructions.args.CodeVar;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.instructions.args.SSAVar;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
|
||||
public class CodeGenUtils {
|
||||
@@ -36,6 +39,14 @@ public class CodeGenUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static CodeVar getCodeVar(RegisterArg arg) {
|
||||
SSAVar svar = arg.getSVar();
|
||||
if (svar != null) {
|
||||
return svar.getCodeVar();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private CodeGenUtils() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package jadx.gui.treemodel;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import jadx.api.JavaNode;
|
||||
import jadx.api.JavaVariable;
|
||||
|
||||
public class JVariable extends JNode {
|
||||
JClass cls;
|
||||
JavaVariable var;
|
||||
|
||||
public JVariable(JavaVariable var, JClass cls) {
|
||||
this.cls = cls;
|
||||
this.var = var;
|
||||
}
|
||||
|
||||
public JavaVariable getJavaVarNode() {
|
||||
return (JavaVariable) getJavaNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JClass getRootClass() {
|
||||
return cls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaNode getJavaNode() {
|
||||
return var;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JClass getJParent() {
|
||||
return cls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String makeString() {
|
||||
return var.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRename() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,11 +4,7 @@ import java.awt.BorderLayout;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
@@ -27,26 +23,20 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.JavaClass;
|
||||
import jadx.api.JavaField;
|
||||
import jadx.api.JavaMethod;
|
||||
import jadx.api.JavaNode;
|
||||
import jadx.api.*;
|
||||
import jadx.core.codegen.CodeWriter;
|
||||
import jadx.core.deobf.DeobfPresets;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.nodes.MethodOverrideAttr;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
import jadx.core.dex.nodes.VariableNode;
|
||||
import jadx.core.dex.visitors.RenameVisitor;
|
||||
import jadx.core.utils.Utils;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
import jadx.gui.jobs.IndexJob;
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JField;
|
||||
import jadx.gui.treemodel.JMethod;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.treemodel.JPackage;
|
||||
import jadx.gui.treemodel.*;
|
||||
import jadx.gui.ui.codearea.ClassCodeContentPanel;
|
||||
import jadx.gui.ui.codearea.CodePanel;
|
||||
import jadx.gui.utils.*;
|
||||
@@ -126,6 +116,9 @@ public class RenameDialog extends JDialog {
|
||||
deobfPresets.getClsPresetMap().put(javaClass.getRawName(), renameText);
|
||||
} else if (node instanceof JPackage) {
|
||||
deobfPresets.getPkgPresetMap().put(((JPackage) node).getFullName(), renameText);
|
||||
} else if (node instanceof JVariable) {
|
||||
VariableNode varNode = ((JVariable) node).getJavaVarNode().getVariableNode();
|
||||
deobfPresets.updateVariableName(varNode, renameText);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,15 +3,9 @@ package jadx.gui.utils;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import jadx.api.JavaClass;
|
||||
import jadx.api.JavaField;
|
||||
import jadx.api.JavaMethod;
|
||||
import jadx.api.JavaNode;
|
||||
import jadx.api.*;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JField;
|
||||
import jadx.gui.treemodel.JMethod;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.treemodel.*;
|
||||
|
||||
public class JNodeCache {
|
||||
|
||||
@@ -45,6 +39,10 @@ public class JNodeCache {
|
||||
JavaField fld = (JavaField) node;
|
||||
return new JField(fld, (JClass) makeFrom(fld.getDeclaringClass()));
|
||||
}
|
||||
if (node instanceof JavaVariable) {
|
||||
JavaVariable var = (JavaVariable) node;
|
||||
return new JVariable(var, (JClass) makeFrom(var.getDeclaringClass()));
|
||||
}
|
||||
throw new JadxRuntimeException("Unknown type for JavaNode: " + node.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package jadx.gui.utils;
|
||||
|
||||
import jadx.api.JavaClass;
|
||||
import jadx.api.JavaField;
|
||||
import jadx.api.JavaMethod;
|
||||
import jadx.api.JavaNode;
|
||||
import jadx.api.*;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
import jadx.gui.treemodel.*;
|
||||
|
||||
@@ -55,6 +52,9 @@ public class JumpPosition {
|
||||
if (node instanceof JField) {
|
||||
return ((JField) node).getJavaField().getFieldNode().getDefPosition();
|
||||
}
|
||||
if (node instanceof JVariable) {
|
||||
return ((JVariable) node).getJavaVarNode().getVariableNode().getDefPosition();
|
||||
}
|
||||
throw new JadxRuntimeException("Unexpected node " + node);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,9 @@ public class JumpPosition {
|
||||
if (node instanceof JavaField) {
|
||||
return ((JavaField) node).getFieldNode().getDefPosition();
|
||||
}
|
||||
if (node instanceof JavaVariable) {
|
||||
return ((JavaVariable) node).getVariableNode().getDefPosition();
|
||||
}
|
||||
throw new JadxRuntimeException("Unexpected node " + node);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user