Commit a3b961e7 authored by Skylot's avatar Skylot

core: fix method deobfuscation (#241)

parent 0e4c8df4
...@@ -29,3 +29,4 @@ jadx-output/ ...@@ -29,3 +29,4 @@ jadx-output/
*.log *.log
*.cfg *.cfg
jadx-core/src/test/java/jadx/tests/external/
...@@ -435,7 +435,7 @@ public class ClassGen { ...@@ -435,7 +435,7 @@ public class ClassGen {
} }
public void useClass(CodeWriter code, ArgType type) { public void useClass(CodeWriter code, ArgType type) {
useClass(code, ClassInfo.extCls(cls.dex(), type)); useClass(code, ClassInfo.extCls(cls.root(), type));
ArgType[] generics = type.getGenericTypes(); ArgType[] generics = type.getGenericTypes();
if (generics != null) { if (generics != null) {
code.add('<'); code.add('<');
......
...@@ -612,7 +612,7 @@ public class InsnGen { ...@@ -612,7 +612,7 @@ public class InsnGen {
MethodInfo callMth = insn.getCallMth(); MethodInfo callMth = insn.getCallMth();
// inline method // inline method
MethodNode callMthNode = mth.dex().deepResolveMethod(callMth); MethodNode callMthNode = mth.root().deepResolveMethod(callMth);
if (callMthNode != null) { if (callMthNode != null) {
if (inlineMethod(callMthNode, insn, code)) { if (inlineMethod(callMthNode, insn, code)) {
return; return;
......
...@@ -159,7 +159,7 @@ public class NameGen { ...@@ -159,7 +159,7 @@ public class NameGen {
if (alias != null) { if (alias != null) {
return alias; return alias;
} }
ClassInfo extClsInfo = ClassInfo.extCls(mth.dex(), type); ClassInfo extClsInfo = ClassInfo.extCls(mth.root(), type);
String shortName = extClsInfo.getShortName(); String shortName = extClsInfo.getShortName();
String vName = fromName(shortName); String vName = fromName(shortName);
if (vName != null) { if (vName != null) {
......
package jadx.core.deobf; package jadx.core.deobf;
import jadx.api.JadxArgs;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.SourceFileAttr;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.FieldInfo;
import jadx.core.dex.info.MethodInfo;
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;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
...@@ -26,6 +14,18 @@ import org.jetbrains.annotations.Nullable; ...@@ -26,6 +14,18 @@ import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jadx.api.JadxArgs;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.SourceFileAttr;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.FieldInfo;
import jadx.core.dex.info.MethodInfo;
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 class Deobfuscator { public class Deobfuscator {
private static final Logger LOG = LoggerFactory.getLogger(Deobfuscator.class); private static final Logger LOG = LoggerFactory.getLogger(Deobfuscator.class);
...@@ -89,7 +89,7 @@ public class Deobfuscator { ...@@ -89,7 +89,7 @@ public class Deobfuscator {
private void preProcess() { private void preProcess() {
for (DexNode dexNode : dexNodes) { for (DexNode dexNode : dexNodes) {
for (ClassNode cls : dexNode.getClasses()) { for (ClassNode cls : dexNode.getClasses()) {
doClass(cls); preProcessClass(cls);
} }
} }
} }
...@@ -101,7 +101,7 @@ public class Deobfuscator { ...@@ -101,7 +101,7 @@ public class Deobfuscator {
} }
for (DexNode dexNode : dexNodes) { for (DexNode dexNode : dexNodes) {
for (ClassNode cls : dexNode.getClasses()) { for (ClassNode cls : dexNode.getClasses()) {
processClass(dexNode, cls); processClass(cls);
} }
} }
postProcess(); postProcess();
...@@ -128,7 +128,6 @@ public class Deobfuscator { ...@@ -128,7 +128,6 @@ public class Deobfuscator {
mth.setAlias(aliasToUse); mth.setAlias(aliasToUse);
mth.setAliasFromPreset(aliasFromPreset); mth.setAliasFromPreset(aliasFromPreset);
} }
id++; id++;
} }
} }
...@@ -151,9 +150,7 @@ public class Deobfuscator { ...@@ -151,9 +150,7 @@ public class Deobfuscator {
for (MethodNode m : cls.getMethods()) { for (MethodNode m : cls.getMethods()) {
if (m.getMethodInfo().getShortId().startsWith(signature)) { if (m.getMethodInfo().getShortId().startsWith(signature)) {
result = cls; result = cls;
if (!overrideSet.contains(m.getMethodInfo())) {
overrideSet.add(m.getMethodInfo()); overrideSet.add(m.getMethodInfo());
}
break; break;
} }
} }
...@@ -196,13 +193,14 @@ public class Deobfuscator { ...@@ -196,13 +193,14 @@ public class Deobfuscator {
} }
} }
} }
return result; return result;
} }
private void resolveOverriding(DexNode dex, ClassNode cls, MethodNode mth) { private void resolveOverriding(MethodNode mth) {
Set<MethodInfo> overrideSet = new HashSet<>(); Set<MethodInfo> overrideSet = new HashSet<>();
resolveOverridingInternal(dex, cls, mth.getMethodInfo().makeSignature(false), overrideSet, cls); String mthSignature = mth.getMethodInfo().makeSignature(false);
ClassNode cls = mth.getParentClass();
resolveOverridingInternal(mth.dex(), cls, mthSignature, overrideSet, cls);
if (overrideSet.size() > 1) { if (overrideSet.size() > 1) {
OverridedMethodsNode overrideNode = null; OverridedMethodsNode overrideNode = null;
for (MethodInfo _mth : overrideSet) { for (MethodInfo _mth : overrideSet) {
...@@ -223,34 +221,42 @@ public class Deobfuscator { ...@@ -223,34 +221,42 @@ public class Deobfuscator {
} }
} }
} }
} else {
overrideSet.clear();
} }
overrideSet.clear();
} }
private void processClass(DexNode dex, ClassNode cls) { private void processClass(ClassNode cls) {
ClassInfo clsInfo = cls.getClassInfo(); ClassInfo clsInfo = cls.getClassInfo();
String fullName = getClassFullName(clsInfo); String fullName = getClassFullName(clsInfo);
if (!fullName.equals(clsInfo.getFullName())) { if (!fullName.equals(clsInfo.getFullName())) {
clsInfo.rename(dex, fullName); clsInfo.rename(cls.dex().root(), fullName);
} }
for (FieldNode field : cls.getFields()) { for (FieldNode field : cls.getFields()) {
renameField(field);
}
for (MethodNode mth : cls.getMethods()) {
renameMethod(mth);
}
for (ClassNode innerCls : cls.getInnerClasses()) {
processClass(innerCls);
}
}
public void renameField(FieldNode field) {
FieldInfo fieldInfo = field.getFieldInfo(); FieldInfo fieldInfo = field.getFieldInfo();
String alias = getFieldAlias(field); String alias = getFieldAlias(field);
if (alias != null) { if (alias != null) {
fieldInfo.setAlias(alias); fieldInfo.setAlias(alias);
} }
} }
for (MethodNode mth : cls.getMethods()) {
MethodInfo methodInfo = mth.getMethodInfo(); public void renameMethod(MethodNode mth) {
String alias = getMethodAlias(mth); String alias = getMethodAlias(mth);
if (alias != null) { if (alias != null) {
methodInfo.setAlias(alias); mth.getMethodInfo().setAlias(alias);
} }
if (mth.isVirtual()) { if (mth.isVirtual()) {
resolveOverriding(dex, cls, mth); resolveOverriding(mth);
}
} }
} }
...@@ -311,7 +317,7 @@ public class Deobfuscator { ...@@ -311,7 +317,7 @@ public class Deobfuscator {
return prefix + clsInfo.getShortName(); return prefix + clsInfo.getShortName();
} }
private void doClass(ClassNode cls) { private void preProcessClass(ClassNode cls) {
ClassInfo classInfo = cls.getClassInfo(); ClassInfo classInfo = cls.getClassInfo();
String pkgFullName = classInfo.getPackage(); String pkgFullName = classInfo.getPackage();
PackageNode pkg = getPackageNode(pkgFullName, true); PackageNode pkg = getPackageNode(pkgFullName, true);
...@@ -320,13 +326,14 @@ public class Deobfuscator { ...@@ -320,13 +326,14 @@ public class Deobfuscator {
String alias = deobfPresets.getForCls(classInfo); String alias = deobfPresets.getForCls(classInfo);
if (alias != null) { if (alias != null) {
clsMap.put(classInfo, new DeobfClsInfo(this, cls, pkg, alias)); clsMap.put(classInfo, new DeobfClsInfo(this, cls, pkg, alias));
return; } else {
if (!clsMap.containsKey(classInfo)
&& shouldRename(classInfo.getShortName())) {
makeClsAlias(cls);
} }
if (clsMap.containsKey(classInfo)) {
return;
} }
if (shouldRename(classInfo.getShortName())) { for (ClassNode innerCls : cls.getInnerClasses()) {
makeClsAlias(cls); preProcessClass(innerCls);
} }
} }
...@@ -361,21 +368,33 @@ public class Deobfuscator { ...@@ -361,21 +368,33 @@ public class Deobfuscator {
if (sourceFileAttr == null) { if (sourceFileAttr == null) {
return null; return null;
} }
if (cls.getClassInfo().isInner()) {
return null;
}
String name = sourceFileAttr.getFileName(); String name = sourceFileAttr.getFileName();
if (name.endsWith(".java")) { if (name.endsWith(".java")) {
name = name.substring(0, name.length() - ".java".length()); name = name.substring(0, name.length() - ".java".length());
} else if (name.endsWith(".kt")) {
name = name.substring(0, name.length() - ".kt".length());
}
if (!NameMapper.isValidIdentifier(name) || NameMapper.isReserved(name)) {
return null;
}
for (DeobfClsInfo deobfClsInfo : clsMap.values()) {
if (deobfClsInfo.getAlias().equals(name)) {
return null;
} }
if (NameMapper.isValidIdentifier(name)
&& !NameMapper.isReserved(name)) {
// TODO: check if no class with this name exists or already renamed
cls.remove(AType.SOURCE_FILE);
return name;
} }
ClassNode otherCls = cls.dex().root().searchClassByName(cls.getPackage() + "." + name);
if (otherCls != null) {
return null; return null;
} }
cls.remove(AType.SOURCE_FILE);
return name;
}
@Nullable @Nullable
public String getFieldAlias(FieldNode field) { private String getFieldAlias(FieldNode field) {
FieldInfo fieldInfo = field.getFieldInfo(); FieldInfo fieldInfo = field.getFieldInfo();
String alias = fldMap.get(fieldInfo); String alias = fldMap.get(fieldInfo);
if (alias != null) { if (alias != null) {
...@@ -393,7 +412,7 @@ public class Deobfuscator { ...@@ -393,7 +412,7 @@ public class Deobfuscator {
} }
@Nullable @Nullable
public String getMethodAlias(MethodNode mth) { private String getMethodAlias(MethodNode mth) {
MethodInfo methodInfo = mth.getMethodInfo(); MethodInfo methodInfo = mth.getMethodInfo();
String alias = mthMap.get(methodInfo); String alias = mthMap.get(methodInfo);
if (alias != null) { if (alias != null) {
......
package jadx.core.dex.info; package jadx.core.dex.info;
import java.io.File;
import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.nodes.DexNode; import jadx.core.dex.nodes.DexNode;
import jadx.core.dex.nodes.RootNode;
import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.exceptions.JadxRuntimeException;
import java.io.File;
public final class ClassInfo { public final class ClassInfo {
private final ArgType type; private final ArgType type;
...@@ -17,50 +18,50 @@ public final class ClassInfo { ...@@ -17,50 +18,50 @@ public final class ClassInfo {
// class info after rename (deobfuscation) // class info after rename (deobfuscation)
private ClassInfo alias; private ClassInfo alias;
private ClassInfo(DexNode dex, ArgType type) { private ClassInfo(RootNode root, ArgType type) {
this(dex, type, true); this(root, type, true);
} }
private ClassInfo(DexNode dex, ArgType type, boolean inner) { private ClassInfo(RootNode root, ArgType type, boolean inner) {
if (!type.isObject() || type.isGeneric()) { if (!type.isObject() || type.isGeneric()) {
throw new JadxRuntimeException("Not class type: " + type); throw new JadxRuntimeException("Not class type: " + type);
} }
this.type = type; this.type = type;
this.alias = this; this.alias = this;
splitNames(dex, inner); splitNames(root, inner);
} }
public static ClassInfo fromType(DexNode dex, ArgType type) { public static ClassInfo fromType(RootNode root, ArgType type) {
if (type.isArray()) { if (type.isArray()) {
type = ArgType.OBJECT; type = ArgType.OBJECT;
} }
ClassInfo cls = dex.root().getInfoStorage().getCls(type); ClassInfo cls = root.getInfoStorage().getCls(type);
if (cls != null) { if (cls != null) {
return cls; return cls;
} }
cls = new ClassInfo(dex, type); cls = new ClassInfo(root, type);
return dex.root().getInfoStorage().putCls(cls); return root.getInfoStorage().putCls(cls);
} }
public static ClassInfo fromDex(DexNode dex, int clsIndex) { public static ClassInfo fromDex(DexNode dex, int clsIndex) {
if (clsIndex == DexNode.NO_INDEX) { if (clsIndex == DexNode.NO_INDEX) {
return null; return null;
} }
return fromType(dex, dex.getType(clsIndex)); return fromType(dex.root(), dex.getType(clsIndex));
} }
public static ClassInfo fromName(DexNode dex, String clsName) { public static ClassInfo fromName(RootNode root, String clsName) {
return fromType(dex, ArgType.object(clsName)); return fromType(root, ArgType.object(clsName));
} }
public static ClassInfo extCls(DexNode dex, ArgType type) { public static ClassInfo extCls(RootNode root, ArgType type) {
ClassInfo classInfo = fromName(dex, type.getObject()); ClassInfo classInfo = fromName(root, type.getObject());
return classInfo.alias; return classInfo.alias;
} }
public void rename(DexNode dex, String fullName) { public void rename(RootNode root, String fullName) {
ClassInfo newAlias = new ClassInfo(dex, ArgType.object(fullName), isInner()); ClassInfo newAlias = new ClassInfo(root, ArgType.object(fullName), isInner());
if (!alias.getFullName().equals(newAlias.getFullName())) { if (!alias.getFullName().equals(newAlias.getFullName())) {
this.alias = newAlias; this.alias = newAlias;
} }
...@@ -74,7 +75,7 @@ public final class ClassInfo { ...@@ -74,7 +75,7 @@ public final class ClassInfo {
return alias; return alias;
} }
private void splitNames(DexNode dex, boolean canBeInner) { private void splitNames(RootNode root, boolean canBeInner) {
String fullObjectName = type.getObject(); String fullObjectName = type.getObject();
String clsName; String clsName;
int dot = fullObjectName.lastIndexOf('.'); int dot = fullObjectName.lastIndexOf('.');
...@@ -93,7 +94,7 @@ public final class ClassInfo { ...@@ -93,7 +94,7 @@ public final class ClassInfo {
parClsName = clsName.substring(0, sep); parClsName = clsName.substring(0, sep);
} }
parentClass = fromName(dex, parClsName); parentClass = fromName(root, parClsName);
clsName = clsName.substring(sep + 1); clsName = clsName.substring(sep + 1);
} else { } else {
parentClass = null; parentClass = null;
...@@ -111,10 +112,10 @@ public final class ClassInfo { ...@@ -111,10 +112,10 @@ public final class ClassInfo {
} }
public String getFullPath() { public String getFullPath() {
ClassInfo alias = getAlias(); ClassInfo usedAlias = getAlias();
return alias.getPackage().replace('.', File.separatorChar) return usedAlias.getPackage().replace('.', File.separatorChar)
+ File.separatorChar + File.separatorChar
+ alias.getNameWithoutPackage().replace('.', '_'); + usedAlias.getNameWithoutPackage().replace('.', '_');
} }
public String getFullName() { public String getFullName() {
...@@ -160,8 +161,8 @@ public final class ClassInfo { ...@@ -160,8 +161,8 @@ public final class ClassInfo {
return parentClass != null; return parentClass != null;
} }
public void notInner(DexNode dex) { public void notInner(RootNode root) {
splitNames(dex, false); splitNames(root, false);
} }
public ArgType getType() { public ArgType getType() {
......
...@@ -65,7 +65,7 @@ public class DexNode implements IDexNode { ...@@ -65,7 +65,7 @@ public class DexNode implements IDexNode {
ClassNode parent = resolveClass(clsInfo.getParentClass()); ClassNode parent = resolveClass(clsInfo.getParentClass());
if (parent == null) { if (parent == null) {
clsMap.remove(clsInfo); clsMap.remove(clsInfo);
clsInfo.notInner(cls.dex()); clsInfo.notInner(root);
clsMap.put(clsInfo, cls); clsMap.put(clsInfo, cls);
} else { } else {
parent.addInnerClass(cls); parent.addInnerClass(cls);
...@@ -78,16 +78,21 @@ public class DexNode implements IDexNode { ...@@ -78,16 +78,21 @@ public class DexNode implements IDexNode {
} }
@Nullable @Nullable
public ClassNode resolveClass(ClassInfo clsInfo) { ClassNode resolveClassLocal(ClassInfo clsInfo) {
return clsMap.get(clsInfo); return clsMap.get(clsInfo);
} }
@Nullable @Nullable
public ClassNode resolveClass(ClassInfo clsInfo) {
return root.resolveClass(clsInfo);
}
@Nullable
public ClassNode resolveClass(@NotNull ArgType type) { public ClassNode resolveClass(@NotNull ArgType type) {
if (type.isGeneric()) { if (type.isGeneric()) {
type = ArgType.object(type.getObject()); type = ArgType.object(type.getObject());
} }
return resolveClass(ClassInfo.fromType(this, type)); return resolveClass(ClassInfo.fromType(root, type));
} }
@Nullable @Nullable
...@@ -99,20 +104,8 @@ public class DexNode implements IDexNode { ...@@ -99,20 +104,8 @@ public class DexNode implements IDexNode {
return null; return null;
} }
/**
* Search method in class hierarchy.
*/
@Nullable
public MethodNode deepResolveMethod(@NotNull MethodInfo mth) {
ClassNode cls = resolveClass(mth.getDeclClass());
if (cls == null) {
return null;
}
return deepResolveMethod(cls, mth.makeSignature(false));
}
@Nullable @Nullable
private MethodNode deepResolveMethod(@NotNull ClassNode cls, String signature) { MethodNode deepResolveMethod(@NotNull ClassNode cls, String signature) {
for (MethodNode m : cls.getMethods()) { for (MethodNode m : cls.getMethods()) {
if (m.getMethodInfo().getShortId().startsWith(signature)) { if (m.getMethodInfo().getShortId().startsWith(signature)) {
return m; return m;
......
...@@ -5,6 +5,7 @@ import java.io.InputStream; ...@@ -5,6 +5,7 @@ import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -17,6 +18,7 @@ import jadx.core.clsp.ClspGraph; ...@@ -17,6 +18,7 @@ import jadx.core.clsp.ClspGraph;
import jadx.core.dex.info.ClassInfo; import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.ConstStorage; import jadx.core.dex.info.ConstStorage;
import jadx.core.dex.info.InfoStorage; import jadx.core.dex.info.InfoStorage;
import jadx.core.dex.info.MethodInfo;
import jadx.core.utils.ErrorsCounter; import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.StringUtils; import jadx.core.utils.StringUtils;
import jadx.core.utils.android.AndroidResourcesUtils; import jadx.core.utils.android.AndroidResourcesUtils;
...@@ -144,10 +146,10 @@ public class RootNode { ...@@ -144,10 +146,10 @@ public class RootNode {
return classes; return classes;
} }
public ClassNode searchClassByName(String fullName) { @Nullable
public ClassNode resolveClass(ClassInfo clsInfo) {
for (DexNode dexNode : dexNodes) { for (DexNode dexNode : dexNodes) {
ClassInfo clsInfo = ClassInfo.fromName(dexNode, fullName); ClassNode cls = dexNode.resolveClassLocal(clsInfo);
ClassNode cls = dexNode.resolveClass(clsInfo);
if (cls != null) { if (cls != null) {
return cls; return cls;
} }
...@@ -155,6 +157,12 @@ public class RootNode { ...@@ -155,6 +157,12 @@ public class RootNode {
return null; return null;
} }
@Nullable
public ClassNode searchClassByName(String fullName) {
ClassInfo clsInfo = ClassInfo.fromName(this, fullName);
return resolveClass(clsInfo);
}
public List<ClassNode> searchClassByShortName(String shortName) { public List<ClassNode> searchClassByShortName(String shortName) {
List<ClassNode> list = new ArrayList<>(); List<ClassNode> list = new ArrayList<>();
for (DexNode dexNode : dexNodes) { for (DexNode dexNode : dexNodes) {
...@@ -167,6 +175,15 @@ public class RootNode { ...@@ -167,6 +175,15 @@ public class RootNode {
return list; return list;
} }
@Nullable
public MethodNode deepResolveMethod(@NotNull MethodInfo mth) {
ClassNode cls = resolveClass(mth.getDeclClass());
if (cls == null) {
return null;
}
return cls.dex().deepResolveMethod(cls, mth.makeSignature(false));
}
public List<DexNode> getDexNodes() { public List<DexNode> getDexNodes() {
return dexNodes; return dexNodes;
} }
......
...@@ -63,7 +63,7 @@ public class ClassModifier extends AbstractVisitor { ...@@ -63,7 +63,7 @@ public class ClassModifier extends AbstractVisitor {
// remove fields if it is synthetic and type is a outer class // remove fields if it is synthetic and type is a outer class
for (FieldNode field : cls.getFields()) { for (FieldNode field : cls.getFields()) {
if (field.getAccessFlags().isSynthetic() && field.getType().isObject()) { if (field.getAccessFlags().isSynthetic() && field.getType().isObject()) {
ClassInfo clsInfo = ClassInfo.fromType(cls.dex(), field.getType()); ClassInfo clsInfo = ClassInfo.fromType(cls.root(), field.getType());
ClassNode fieldsCls = cls.dex().resolveClass(clsInfo); ClassNode fieldsCls = cls.dex().resolveClass(clsInfo);
ClassInfo parentClass = cls.getClassInfo().getParentClass(); ClassInfo parentClass = cls.getClassInfo().getParentClass();
if (fieldsCls != null if (fieldsCls != null
......
...@@ -96,7 +96,7 @@ public class DependencyCollector extends AbstractVisitor { ...@@ -96,7 +96,7 @@ public class DependencyCollector extends AbstractVisitor {
private static void addDep(DexNode dex, Set<ClassNode> depList, ArgType type) { private static void addDep(DexNode dex, Set<ClassNode> depList, ArgType type) {
if (type != null) { if (type != null) {
if (type.isObject()) { if (type.isObject()) {
addDep(dex, depList, ClassInfo.fromName(dex, type.getObject())); addDep(dex, depList, ClassInfo.fromName(dex.root(), type.getObject()));
ArgType[] genericTypes = type.getGenericTypes(); ArgType[] genericTypes = type.getGenericTypes();
if (type.isGeneric() && genericTypes != null) { if (type.isGeneric() && genericTypes != null) {
for (ArgType argType : genericTypes) { for (ArgType argType : genericTypes) {
......
...@@ -71,7 +71,7 @@ public class RenameVisitor extends AbstractVisitor { ...@@ -71,7 +71,7 @@ public class RenameVisitor extends AbstractVisitor {
if (!clsNames.add(clsFileName.toLowerCase())) { if (!clsNames.add(clsFileName.toLowerCase())) {
String newShortName = deobfuscator.getClsAlias(cls); String newShortName = deobfuscator.getClsAlias(cls);
String newFullName = classInfo.makeFullClsName(newShortName, true); String newFullName = classInfo.makeFullClsName(newShortName, true);
classInfo.rename(cls.dex(), newFullName); classInfo.rename(cls.root(), newFullName);
clsNames.add(classInfo.getAlias().getFullPath().toLowerCase()); clsNames.add(classInfo.getAlias().getFullPath().toLowerCase());
} }
} }
...@@ -89,12 +89,12 @@ public class RenameVisitor extends AbstractVisitor { ...@@ -89,12 +89,12 @@ public class RenameVisitor extends AbstractVisitor {
newShortName = "C" + clsName; newShortName = "C" + clsName;
} }
if (newShortName != null) { if (newShortName != null) {
classInfo.rename(cls.dex(), classInfo.makeFullClsName(newShortName, true)); classInfo.rename(cls.root(), classInfo.makeFullClsName(newShortName, true));
} }
if (classInfo.getAlias().getPackage().isEmpty()) { if (classInfo.getAlias().getPackage().isEmpty()) {
String fullName = classInfo.makeFullClsName(classInfo.getAlias().getShortName(), true); String fullName = classInfo.makeFullClsName(classInfo.getAlias().getShortName(), true);
String newFullName = Consts.DEFAULT_PACKAGE_NAME + "." + fullName; String newFullName = Consts.DEFAULT_PACKAGE_NAME + "." + fullName;
classInfo.rename(cls.dex(), newFullName); classInfo.rename(cls.root(), newFullName);
} }
} }
...@@ -103,7 +103,7 @@ public class RenameVisitor extends AbstractVisitor { ...@@ -103,7 +103,7 @@ public class RenameVisitor extends AbstractVisitor {
for (FieldNode field : cls.getFields()) { for (FieldNode field : cls.getFields()) {
FieldInfo fieldInfo = field.getFieldInfo(); FieldInfo fieldInfo = field.getFieldInfo();
if (!names.add(fieldInfo.getAlias())) { if (!names.add(fieldInfo.getAlias())) {
fieldInfo.setAlias(deobfuscator.makeFieldAlias(field)); deobfuscator.renameField(field);
} }
} }
} }
...@@ -114,22 +114,10 @@ public class RenameVisitor extends AbstractVisitor { ...@@ -114,22 +114,10 @@ public class RenameVisitor extends AbstractVisitor {
if (mth.contains(AFlag.DONT_GENERATE)) { if (mth.contains(AFlag.DONT_GENERATE)) {
continue; continue;
} }
MethodInfo methodInfo = mth.getMethodInfo(); String signature = mth.getMethodInfo().makeSignature(false);
String signature = makeMethodSignature(methodInfo);
if (!names.add(signature)) { if (!names.add(signature)) {
methodInfo.setAlias(deobfuscator.makeMethodAlias(mth)); deobfuscator.renameMethod(mth);
} }
} }
} }
private static String makeMethodSignature(MethodInfo methodInfo) {
StringBuilder signature = new StringBuilder();
signature.append(methodInfo.getAlias());
signature.append('(');
for (ArgType arg : methodInfo.getArgumentsTypes()) {
signature.append(TypeGen.signature(arg));
}
signature.append(')');
return signature.toString();
}
} }
...@@ -55,8 +55,7 @@ public class AndroidResourcesUtils { ...@@ -55,8 +55,7 @@ public class AndroidResourcesUtils {
if (dexNodes.isEmpty()) { if (dexNodes.isEmpty()) {
return null; return null;
} }
DexNode firstDex = dexNodes.get(0); ClassInfo r = ClassInfo.fromName(root, clsName);
ClassInfo r = ClassInfo.fromName(firstDex, clsName); return new ClassNode(dexNodes.get(0), r);
return new ClassNode(firstDex, r);
} }
} }
...@@ -8,6 +8,8 @@ import java.io.IOException; ...@@ -8,6 +8,8 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileAttribute;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.List; import java.util.List;
...@@ -74,6 +76,16 @@ public class FileUtils { ...@@ -74,6 +76,16 @@ public class FileUtils {
return temp; return temp;
} }
public static File createTempDir(String suffix) {
try {
Path path = Files.createTempDirectory("jadx-tmp-" + System.nanoTime() + "-" + suffix);
path.toFile().deleteOnExit();
return path.toFile();
} catch (IOException e) {
throw new JadxRuntimeException("Failed to create temp directory with suffix: " + suffix);
}
}
public static void copyStream(InputStream input, OutputStream output) throws IOException { public static void copyStream(InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[READ_BUFFER_SIZE]; byte[] buffer = new byte[READ_BUFFER_SIZE];
while (true) { while (true) {
......
...@@ -48,7 +48,7 @@ public abstract class IntegrationTest extends TestUtils { ...@@ -48,7 +48,7 @@ public abstract class IntegrationTest extends TestUtils {
private static final String TEST_DIRECTORY = "src/test/java"; private static final String TEST_DIRECTORY = "src/test/java";
private static final String TEST_DIRECTORY2 = "jadx-core/" + TEST_DIRECTORY; private static final String TEST_DIRECTORY2 = "jadx-core/" + TEST_DIRECTORY;
private JadxArgs args; protected JadxArgs args;
protected boolean deleteTmpFiles = true; protected boolean deleteTmpFiles = true;
protected boolean withDebugInfo = true; protected boolean withDebugInfo = true;
...@@ -113,27 +113,31 @@ public abstract class IntegrationTest extends TestUtils { ...@@ -113,27 +113,31 @@ public abstract class IntegrationTest extends TestUtils {
return cls; return cls;
} }
private void decompile(JadxDecompiler jadx, ClassNode cls) { protected void decompile(JadxDecompiler jadx, ClassNode cls) {
List<IDexTreeVisitor> passes = Jadx.getPassesList(jadx.getArgs()); List<IDexTreeVisitor> passes = Jadx.getPassesList(jadx.getArgs());
ProcessClass.process(cls, passes, new CodeGen()); ProcessClass.process(cls, passes, new CodeGen());
} }
private void decompileWithoutUnload(JadxDecompiler d, ClassNode cls) { protected void decompileWithoutUnload(JadxDecompiler d, ClassNode cls) {
cls.load(); cls.load();
List<IDexTreeVisitor> passes = Jadx.getPassesList(d.getArgs()); List<IDexTreeVisitor> passes = Jadx.getPassesList(d.getArgs());
for (IDexTreeVisitor visitor : passes) { for (IDexTreeVisitor visitor : passes) {
DepthTraversal.visit(visitor, cls); DepthTraversal.visit(visitor, cls);
} }
generateClsCode(cls);
// don't unload class
}
protected void generateClsCode(ClassNode cls) {
try { try {
new CodeGen().visit(cls); new CodeGen().visit(cls);
} catch (CodegenException e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
fail(e.getMessage()); fail(e.getMessage());
} }
// don't unload class
} }
private static void checkCode(ClassNode cls) { protected static void checkCode(ClassNode cls) {
assertTrue("Inconsistent cls: " + cls, assertTrue("Inconsistent cls: " + cls,
!cls.contains(AFlag.INCONSISTENT_CODE) && !cls.contains(AType.JADX_ERROR)); !cls.contains(AFlag.INCONSISTENT_CODE) && !cls.contains(AType.JADX_ERROR));
for (MethodNode mthNode : cls.getMethods()) { for (MethodNode mthNode : cls.getMethods()) {
...@@ -370,6 +374,13 @@ public abstract class IntegrationTest extends TestUtils { ...@@ -370,6 +374,13 @@ public abstract class IntegrationTest extends TestUtils {
this.unloadCls = false; this.unloadCls = false;
} }
protected void enableDeobfuscation() {
args.setDeobfuscationOn(true);
args.setDeobfuscationForceSave(true);
args.setDeobfuscationMinLength(2);
args.setDeobfuscationMaxLength(64);
}
// Use only for debug purpose // Use only for debug purpose
@Deprecated @Deprecated
protected void setOutputCFG() { protected void setOutputCFG() {
......
package jadx.tests.integration.deobf;
import org.junit.Test;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
public class TestMthRename extends IntegrationTest {
public static class TestCls {
public static abstract class TestAbstractCls {
public abstract void a();
}
public void test(TestAbstractCls a) {
a.a();
}
}
@Test
public void test() {
noDebugInfo();
enableDeobfuscation();
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
assertThat(code, containsString("public abstract void m0a();"));
assertThat(code, not(containsString("public abstract void a();")));
assertThat(code, containsString(".m0a();"));
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