Commit 3314de8d authored by Skylot's avatar Skylot

core: rename fields and methods in deobfuscation pass.

parent 8dab9b83
...@@ -16,12 +16,12 @@ public final class JavaField implements JavaNode { ...@@ -16,12 +16,12 @@ public final class JavaField implements JavaNode {
@Override @Override
public String getName() { public String getName() {
return field.getName(); return field.getAlias();
} }
@Override @Override
public String getFullName() { public String getFullName() {
return parent.getFullName() + "." + field.getName(); return parent.getFullName() + "." + getName();
} }
@Override @Override
......
...@@ -17,7 +17,7 @@ public final class JavaMethod implements JavaNode { ...@@ -17,7 +17,7 @@ public final class JavaMethod implements JavaNode {
@Override @Override
public String getName() { public String getName() {
return mth.getName(); return mth.getAlias();
} }
@Override @Override
......
...@@ -108,10 +108,8 @@ public class Jadx { ...@@ -108,10 +108,8 @@ public class Jadx {
passes.add(new DependencyCollector()); passes.add(new DependencyCollector());
if (args.isDeobfuscationOn()) {
passes.add(new RenameVisitor()); passes.add(new RenameVisitor());
} }
}
return passes; return passes;
} }
......
...@@ -53,10 +53,6 @@ public final class ProcessClass { ...@@ -53,10 +53,6 @@ public final class ProcessClass {
static void processDependencies(ClassNode cls, List<IDexTreeVisitor> passes) { static void processDependencies(ClassNode cls, List<IDexTreeVisitor> passes) {
for (ClassNode depCls : cls.getDependencies()) { for (ClassNode depCls : cls.getDependencies()) {
if (cls.getTopParentClass() == cls) {
// ignore inner classes of this class
continue;
}
process(depCls, passes, null); process(depCls, passes, null);
} }
} }
......
...@@ -337,7 +337,7 @@ public class ClassGen { ...@@ -337,7 +337,7 @@ public class ClassGen {
code.startLine(f.getAccessFlags().makeString()); code.startLine(f.getAccessFlags().makeString());
useType(code, f.getType()); useType(code, f.getType());
code.add(' '); code.add(' ');
code.add(f.getName()); code.add(f.getAlias());
FieldValueAttr fv = f.get(AType.FIELD_VALUE); FieldValueAttr fv = f.get(AType.FIELD_VALUE);
if (fv != null) { if (fv != null) {
code.add(" = "); code.add(" = ");
......
...@@ -157,7 +157,7 @@ public class InsnGen { ...@@ -157,7 +157,7 @@ public class InsnGen {
if (fieldNode != null) { if (fieldNode != null) {
code.attachAnnotation(fieldNode); code.attachAnnotation(fieldNode);
} }
code.add(field.getName()); code.add(field.getAlias());
} }
public static void makeStaticFieldAccess(CodeWriter code, FieldInfo field, ClassGen clsGen) { public static void makeStaticFieldAccess(CodeWriter code, FieldInfo field, ClassGen clsGen) {
...@@ -179,7 +179,7 @@ public class InsnGen { ...@@ -179,7 +179,7 @@ public class InsnGen {
if (fieldNode != null) { if (fieldNode != null) {
code.attachAnnotation(fieldNode); code.attachAnnotation(fieldNode);
} }
code.add(field.getName()); code.add(field.getAlias());
} }
protected void staticField(CodeWriter code, FieldInfo field) { protected void staticField(CodeWriter code, FieldInfo field) {
...@@ -612,7 +612,7 @@ public class InsnGen { ...@@ -612,7 +612,7 @@ public class InsnGen {
if (callMthNode != null) { if (callMthNode != null) {
code.attachAnnotation(callMthNode); code.attachAnnotation(callMthNode);
} }
code.add(callMth.getName()); code.add(callMth.getAlias());
generateMethodArguments(code, insn, k, callMthNode); generateMethodArguments(code, insn, k, callMthNode);
} }
......
...@@ -90,7 +90,7 @@ public class MethodGen { ...@@ -90,7 +90,7 @@ public class MethodGen {
} else { } else {
classGen.useType(code, mth.getReturnType()); classGen.useType(code, mth.getReturnType());
code.add(' '); code.add(' ');
code.add(mth.getName()); code.add(mth.getAlias());
} }
code.add('('); code.add('(');
......
...@@ -245,7 +245,7 @@ public class RegionGen extends InsnGen { ...@@ -245,7 +245,7 @@ public class RegionGen extends InsnGen {
if (k instanceof FieldNode) { if (k instanceof FieldNode) {
FieldNode fn = (FieldNode) k; FieldNode fn = (FieldNode) k;
if (fn.getParentClass().isEnum()) { if (fn.getParentClass().isEnum()) {
code.add(fn.getName()); code.add(fn.getAlias());
} else { } else {
staticField(code, fn.getFieldInfo()); staticField(code, fn.getFieldInfo());
// print original value, sometimes replace with incorrect field // print original value, sometimes replace with incorrect field
......
package jadx.core.deobf;
import jadx.core.dex.nodes.ClassNode;
class DeobfClsInfo {
private final Deobfuscator deobfuscator;
private final ClassNode cls;
private final PackageNode pkg;
private final String alias;
public DeobfClsInfo(Deobfuscator deobfuscator, ClassNode cls, PackageNode pkg, String alias) {
this.deobfuscator = deobfuscator;
this.cls = cls;
this.pkg = pkg;
this.alias = alias;
}
public String makeNameWithoutPkg() {
String prefix;
ClassNode parentClass = cls.getParentClass();
if (parentClass != cls) {
DeobfClsInfo parentDeobfClsInfo = deobfuscator.getClsMap().get(parentClass.getClassInfo());
if (parentDeobfClsInfo != null) {
prefix = parentDeobfClsInfo.makeNameWithoutPkg();
} else {
prefix = deobfuscator.getNameWithoutPackage(parentClass.getClassInfo());
}
prefix += Deobfuscator.INNER_CLASS_SEPARATOR;
} else {
prefix = "";
}
return prefix + (this.alias != null ? this.alias : this.cls.getShortName());
}
public String getFullName() {
return pkg.getFullAlias() + Deobfuscator.CLASS_NAME_SEPARATOR + makeNameWithoutPkg();
}
public ClassNode getCls() {
return cls;
}
public PackageNode getPkg() {
return pkg;
}
public String getAlias() {
return alias;
}
}
package jadx.core.deobf;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.FieldInfo;
import jadx.core.dex.info.MethodInfo;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class DeobfPresets {
private static final Logger LOG = LoggerFactory.getLogger(DeobfPresets.class);
private static final String MAP_FILE_CHARSET = "UTF-8";
private final Deobfuscator deobfuscator;
private final File deobfMapFile;
private final Map<String, String> clsPresetMap = new HashMap<String, String>();
private final Map<String, String> fldPresetMap = new HashMap<String, String>();
private final Map<String, String> mthPresetMap = new HashMap<String, String>();
public DeobfPresets(Deobfuscator deobfuscator, File deobfMapFile) {
this.deobfuscator = deobfuscator;
this.deobfMapFile = deobfMapFile;
}
/**
* Loads deobfuscator presets
*/
public void load() {
if (!deobfMapFile.exists()) {
return;
}
LOG.info("Loading obfuscation map from: {}", deobfMapFile.getAbsoluteFile());
try {
List<String> lines = FileUtils.readLines(deobfMapFile, MAP_FILE_CHARSET);
for (String l : lines) {
l = l.trim();
if (l.isEmpty() || l.startsWith("#")) {
continue;
}
String[] va = splitAndTrim(l);
if (va.length != 2) {
continue;
}
String origName = va[0];
String alias = va[1];
if (l.startsWith("p ")) {
deobfuscator.addPackagePreset(origName, alias);
} else if (l.startsWith("c ")) {
clsPresetMap.put(origName, alias);
} else if (l.startsWith("f ")) {
fldPresetMap.put(origName, alias);
} else if (l.startsWith("m ")) {
mthPresetMap.put(origName, alias);
}
}
} catch (IOException e) {
LOG.error("Failed to load deobfuscation map file '{}'", deobfMapFile.getAbsolutePath(), e);
}
}
private static String[] splitAndTrim(String str) {
String[] v = str.substring(2).split("=");
for (int i = 0; i < v.length; i++) {
v[i] = v[i].trim();
}
return v;
}
public void save(boolean forceSave) {
try {
if (deobfMapFile.exists()) {
if (forceSave) {
dumpMapping();
} else {
LOG.warn("Deobfuscation map file '{}' exists. Use command line option '--deobf-rewrite-cfg' to rewrite it",
deobfMapFile.getAbsolutePath());
}
} else {
dumpMapping();
}
} catch (IOException e) {
LOG.error("Failed to load deobfuscation map file '{}'", deobfMapFile.getAbsolutePath(), e);
}
}
/**
* Saves DefaultDeobfuscator presets
*/
private void dumpMapping() throws IOException {
List<String> list = new ArrayList<String>();
// packages
for (PackageNode p : deobfuscator.getRootPackage().getInnerPackages()) {
for (PackageNode pp : p.getInnerPackages()) {
dfsPackageName(list, p.getName(), pp);
}
if (p.hasAlias()) {
list.add(String.format("p %s = %s", p.getName(), p.getAlias()));
}
}
// classes
for (DeobfClsInfo deobfClsInfo : deobfuscator.getClsMap().values()) {
if (deobfClsInfo.getAlias() != null) {
list.add(String.format("c %s = %s",
deobfClsInfo.getCls().getClassInfo().getFullName(), deobfClsInfo.getAlias()));
}
}
for (FieldInfo fld : deobfuscator.getFldMap().keySet()) {
list.add(String.format("f %s = %s", fld.getFullId(), fld.getAlias()));
}
for (MethodInfo mth : deobfuscator.getMthMap().keySet()) {
list.add(String.format("m %s = %s", mth.getFullId(), mth.getAlias()));
}
Collections.sort(list);
FileUtils.writeLines(deobfMapFile, MAP_FILE_CHARSET, list);
list.clear();
}
private static void dfsPackageName(List<String> list, String prefix, PackageNode node) {
for (PackageNode pp : node.getInnerPackages()) {
dfsPackageName(list, prefix + '.' + node.getName(), pp);
}
if (node.hasAlias()) {
list.add(String.format("p %s.%s = %s", prefix, node.getName(), node.getAlias()));
}
}
public String getForCls(ClassInfo cls) {
return clsPresetMap.get(cls.getFullName());
}
public String getForFld(FieldInfo fld) {
return fldPresetMap.get(fld.getFullId());
}
public String getForMth(MethodInfo mth) {
return mthPresetMap.get(mth.getFullId());
}
public void clear() {
clsPresetMap.clear();
fldPresetMap.clear();
mthPresetMap.clear();
}
public Map<String, String> getClsPresetMap() {
return clsPresetMap;
}
public Map<String, String> getFldPresetMap() {
return fldPresetMap;
}
public Map<String, String> getMthPresetMap() {
return mthPresetMap;
}
}
...@@ -4,21 +4,22 @@ import jadx.api.IJadxArgs; ...@@ -4,21 +4,22 @@ import jadx.api.IJadxArgs;
import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AType;
import jadx.core.dex.attributes.nodes.SourceFileAttr; import jadx.core.dex.attributes.nodes.SourceFileAttr;
import jadx.core.dex.info.ClassInfo; import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.FieldInfo;
import jadx.core.dex.info.MethodInfo;
import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.DexNode; 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.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import org.apache.commons.io.FileUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -27,56 +28,60 @@ public class Deobfuscator { ...@@ -27,56 +28,60 @@ public class Deobfuscator {
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
private static final String MAP_FILE_CHARSET = "UTF-8"; public static final String CLASS_NAME_SEPARATOR = ".";
private static final String CLASS_NAME_SEPARATOR = "."; public static final String INNER_CLASS_SEPARATOR = "$";
private static final String INNER_CLASS_SEPARATOR = "$";
private final Map<ClassInfo, DeobfClsInfo> clsMap = new HashMap<ClassInfo, DeobfClsInfo>();
private final IJadxArgs args; private final IJadxArgs args;
private final File deobfMapFile;
@NotNull @NotNull
private final List<DexNode> dexNodes; private final List<DexNode> dexNodes;
private final DeobfPresets deobfPresets;
private final Map<ClassInfo, DeobfClsInfo> clsMap = new HashMap<ClassInfo, DeobfClsInfo>();
private final Map<FieldInfo, String> fldMap = new HashMap<FieldInfo, String>();
private final Map<MethodInfo, String> mthMap = new HashMap<MethodInfo, String>();
private final PackageNode rootPackage = new PackageNode("");
private final Set<String> pkgSet = new TreeSet<String>();
private final int maxLength; private final int maxLength;
private final int minLength; private final int minLength;
private int pkgIndex = 0; private int pkgIndex = 0;
private int clsIndex = 0; private int clsIndex = 0;
private int fldIndex = 0;
private final PackageNode rootPackage = new PackageNode(""); private int mthIndex = 0;
private final Set<String> pkgSet = new TreeSet<String>();
private Map<String, String> preLoadClsMap = Collections.emptyMap();
public Deobfuscator(IJadxArgs args, @NotNull List<DexNode> dexNodes, File deobfMapFile) { public Deobfuscator(IJadxArgs args, @NotNull List<DexNode> dexNodes, File deobfMapFile) {
this.args = args; this.args = args;
this.dexNodes = dexNodes; this.dexNodes = dexNodes;
this.deobfMapFile = deobfMapFile;
this.minLength = args.getDeobfuscationMinLength(); this.minLength = args.getDeobfuscationMinLength();
this.maxLength = args.getDeobfuscationMaxLength(); this.maxLength = args.getDeobfuscationMaxLength();
this.deobfPresets = new DeobfPresets(this, deobfMapFile);
} }
public void execute() { public void execute() {
if (deobfMapFile.exists() && !args.isDeobfuscationForceSave()) { if (!args.isDeobfuscationForceSave()) {
try { deobfPresets.load();
load(); initIndexes();
} catch (IOException e) {
LOG.error("Failed to load deobfuscation map file '{}'", deobfMapFile.getAbsolutePath(), e);
}
} }
process(); process();
try { deobfPresets.save(args.isDeobfuscationForceSave());
if (deobfMapFile.exists()) { clear();
if (args.isDeobfuscationForceSave()) {
save();
} else {
LOG.warn("Deobfuscation map file '{}' exists. Use command line option '--deobf-rewrite-cfg' to rewrite it",
deobfMapFile.getAbsolutePath());
} }
} else {
save(); private void initIndexes() {
pkgIndex = pkgSet.size();
clsIndex = deobfPresets.getClsPresetMap().size();
fldIndex = deobfPresets.getFldPresetMap().size();
mthIndex = deobfPresets.getMthPresetMap().size();
}
private void preProcess() {
for (DexNode dexNode : dexNodes) {
for (ClassNode cls : dexNode.getClasses()) {
doClass(cls);
} }
} catch (IOException e) {
LOG.error("Failed to load deobfuscation map file '{}'", deobfMapFile.getAbsolutePath(), e);
} }
} }
...@@ -85,20 +90,47 @@ public class Deobfuscator { ...@@ -85,20 +90,47 @@ public class Deobfuscator {
if (DEBUG) { if (DEBUG) {
dumpAlias(); dumpAlias();
} }
preLoadClsMap.clear();
preLoadClsMap = Collections.emptyMap();
for (DexNode dexNode : dexNodes) { for (DexNode dexNode : dexNodes) {
for (ClassNode classNode : dexNode.getClasses()) { for (ClassNode cls : dexNode.getClasses()) {
ClassInfo clsInfo = classNode.getClassInfo(); processClass(dexNode, cls);
}
}
}
void clear() {
deobfPresets.clear();
clsMap.clear();
fldMap.clear();
mthMap.clear();
}
private void processClass(DexNode dex, ClassNode cls) {
ClassInfo clsInfo = cls.getClassInfo();
String fullName = getClassFullName(clsInfo); String fullName = getClassFullName(clsInfo);
if (!fullName.equals(clsInfo.getFullName())) { if (!fullName.equals(clsInfo.getFullName())) {
clsInfo.rename(dexNode, fullName); clsInfo.rename(dex, fullName);
} }
for (FieldNode field : cls.getFields()) {
FieldInfo fieldInfo = field.getFieldInfo();
String alias = getFieldAlias(field);
if (alias != null) {
fieldInfo.setAlias(alias);
}
}
for (MethodNode mth : cls.getMethods()) {
MethodInfo methodInfo = mth.getMethodInfo();
String alias = getMethodAlias(mth);
if (alias != null) {
methodInfo.setAlias(alias);
} }
} }
} }
public void addPackagePreset(String origPkgName, String pkgAlias) {
PackageNode pkg = getPackageNode(origPkgName, true);
pkg.setAlias(pkgAlias);
}
/** /**
* Gets package node for full package name * Gets package node for full package name
* *
...@@ -134,41 +166,7 @@ public class Deobfuscator { ...@@ -134,41 +166,7 @@ public class Deobfuscator {
return result; return result;
} }
private final class DeobfClsInfo { String getNameWithoutPackage(ClassInfo clsInfo) {
public final ClassNode cls;
public final PackageNode pkg;
public final String alias;
public DeobfClsInfo(ClassNode cls, PackageNode pkg, String alias) {
this.cls = cls;
this.pkg = pkg;
this.alias = alias;
}
public String makeNameWithoutPkg() {
String prefix;
ClassNode parentClass = cls.getParentClass();
if (parentClass != cls) {
DeobfClsInfo parentDeobfClsInfo = clsMap.get(parentClass.getClassInfo());
if (parentDeobfClsInfo != null) {
prefix = parentDeobfClsInfo.makeNameWithoutPkg();
} else {
prefix = getNameWithoutPackage(parentClass.getClassInfo());
}
prefix += INNER_CLASS_SEPARATOR;
} else {
prefix = "";
}
return prefix + (this.alias != null ? this.alias : this.cls.getShortName());
}
public String getFullName() {
return pkg.getFullAlias() + CLASS_NAME_SEPARATOR + makeNameWithoutPkg();
}
}
private String getNameWithoutPackage(ClassInfo clsInfo) {
String prefix; String prefix;
ClassInfo parentClsInfo = clsInfo.getParentClass(); ClassInfo parentClsInfo = clsInfo.getParentClass();
if (parentClsInfo != null) { if (parentClsInfo != null) {
...@@ -191,18 +189,17 @@ public class Deobfuscator { ...@@ -191,18 +189,17 @@ public class Deobfuscator {
PackageNode pkg = getPackageNode(pkgFullName, true); PackageNode pkg = getPackageNode(pkgFullName, true);
doPkg(pkg, pkgFullName); doPkg(pkg, pkgFullName);
String fullName = classInfo.getFullName(); String alias = deobfPresets.getForCls(classInfo);
if (preLoadClsMap.containsKey(fullName)) { if (alias != null) {
String alias = preLoadClsMap.get(fullName); clsMap.put(classInfo, new DeobfClsInfo(this, cls, pkg, alias));
clsMap.put(classInfo, new DeobfClsInfo(cls, pkg, alias));
return; return;
} }
if (clsMap.containsKey(classInfo)) { if (clsMap.containsKey(classInfo)) {
return; return;
} }
if (shouldRename(classInfo.getShortName())) { if (shouldRename(classInfo.getShortName())) {
String alias = makeClsAlias(cls); alias = makeClsAlias(cls);
clsMap.put(classInfo, new DeobfClsInfo(cls, pkg, alias)); clsMap.put(classInfo, new DeobfClsInfo(this, cls, pkg, alias));
} }
} }
...@@ -224,6 +221,54 @@ public class Deobfuscator { ...@@ -224,6 +221,54 @@ public class Deobfuscator {
return String.format("C%04d%s", clsIndex++, makeName(clsName)); return String.format("C%04d%s", clsIndex++, makeName(clsName));
} }
@Nullable
public String getFieldAlias(FieldNode field) {
FieldInfo fieldInfo = field.getFieldInfo();
String alias = fldMap.get(fieldInfo);
if (alias != null) {
return alias;
}
alias = deobfPresets.getForFld(fieldInfo);
if (alias != null) {
fldMap.put(fieldInfo, alias);
return alias;
}
if (shouldRename(field.getName())) {
return makeFieldAlias(field);
}
return null;
}
@Nullable
public String getMethodAlias(MethodNode mth) {
MethodInfo methodInfo = mth.getMethodInfo();
String alias = mthMap.get(methodInfo);
if (alias != null) {
return alias;
}
alias = deobfPresets.getForMth(methodInfo);
if (alias != null) {
mthMap.put(methodInfo, alias);
return alias;
}
if (shouldRename(mth.getName())) {
return makeMethodAlias(mth);
}
return null;
}
public String makeFieldAlias(FieldNode field) {
String alias = String.format("f%d%s", fldIndex++, makeName(field.getName()));
fldMap.put(field.getFieldInfo(), alias);
return alias;
}
public String makeMethodAlias(MethodNode mth) {
String alias = String.format("m%d%s", mthIndex++, makeName(mth.getName()));
mthMap.put(mth.getMethodInfo(), alias);
return alias;
}
private void doPkg(PackageNode pkg, String fullName) { private void doPkg(PackageNode pkg, String fullName) {
if (pkgSet.contains(fullName)) { if (pkgSet.contains(fullName)) {
return; return;
...@@ -246,14 +291,6 @@ public class Deobfuscator { ...@@ -246,14 +291,6 @@ public class Deobfuscator {
} }
} }
private void preProcess() {
for (DexNode dexNode : dexNodes) {
for (ClassNode cls : dexNode.getClasses()) {
doClass(cls);
}
}
}
private boolean shouldRename(String s) { private boolean shouldRename(String s) {
return s.length() > maxLength return s.length() > maxLength
|| s.length() < minLength || s.length() < minLength
...@@ -305,80 +342,6 @@ public class Deobfuscator { ...@@ -305,80 +342,6 @@ public class Deobfuscator {
} }
} }
/**
* Loads deobfuscator presets
*
* @throws IOException
*/
private void load() throws IOException {
if (!deobfMapFile.exists()) {
return;
}
LOG.info("Loading obfuscation map from: {}", deobfMapFile.getAbsoluteFile());
List<String> lines = FileUtils.readLines(deobfMapFile, MAP_FILE_CHARSET);
for (String l : lines) {
l = l.trim();
if (l.startsWith("p ")) {
String[] va = splitAndTrim(l);
if (va.length == 2) {
PackageNode pkg = getPackageNode(va[0], true);
pkg.setAlias(va[1]);
}
} else if (l.startsWith("c ")) {
String[] va = splitAndTrim(l);
if (va.length == 2) {
if (preLoadClsMap.isEmpty()) {
preLoadClsMap = new HashMap<String, String>();
}
preLoadClsMap.put(va[0], va[1]);
}
}
}
}
private static String[] splitAndTrim(String str) {
String[] v = str.substring(2).split("=");
for (int i = 0; i < v.length; i++) {
v[i] = v[i].trim();
}
return v;
}
private static void dfsPackageName(List<String> list, String prefix, PackageNode node) {
for (PackageNode pp : node.getInnerPackages()) {
dfsPackageName(list, prefix + '.' + node.getName(), pp);
}
if (node.hasAlias()) {
list.add(String.format("p %s.%s=%s", prefix, node.getName(), node.getAlias()));
}
}
/**
* Saves DefaultDeobfuscator presets
*/
private void save() throws IOException {
List<String> list = new ArrayList<String>();
// packages
for (PackageNode p : rootPackage.getInnerPackages()) {
for (PackageNode pp : p.getInnerPackages()) {
dfsPackageName(list, p.getName(), pp);
}
if (p.hasAlias()) {
list.add(String.format("p %s=%s", p.getName(), p.getAlias()));
}
}
// classes
for (DeobfClsInfo deobfClsInfo : clsMap.values()) {
if (deobfClsInfo.alias != null) {
list.add(String.format("c %s=%s",
deobfClsInfo.cls.getClassInfo().getFullName(), deobfClsInfo.alias));
}
}
Collections.sort(list);
FileUtils.writeLines(deobfMapFile, MAP_FILE_CHARSET, list);
list.clear();
}
private String getPackageName(String packageName) { private String getPackageName(String packageName) {
final PackageNode pkg = getPackageNode(packageName, false); final PackageNode pkg = getPackageNode(packageName, false);
if (pkg != null) { if (pkg != null) {
...@@ -406,4 +369,20 @@ public class Deobfuscator { ...@@ -406,4 +369,20 @@ public class Deobfuscator {
} }
return getPackageName(clsInfo.getPackage()) + CLASS_NAME_SEPARATOR + getClassName(clsInfo); return getPackageName(clsInfo.getPackage()) + CLASS_NAME_SEPARATOR + getClassName(clsInfo);
} }
public Map<ClassInfo, DeobfClsInfo> getClsMap() {
return clsMap;
}
public Map<FieldInfo, String> getFldMap() {
return fldMap;
}
public Map<MethodInfo, String> getMthMap() {
return mthMap;
}
public PackageNode getRootPackage() {
return rootPackage;
}
} }
...@@ -88,7 +88,8 @@ public class NameMapper { ...@@ -88,7 +88,8 @@ public class NameMapper {
} }
public static boolean isAllCharsPrintable(String str) { public static boolean isAllCharsPrintable(String str) {
for (int i = 0; i < str.length(); i++) { int len = str.length();
for (int i = 0; i < len; i++) {
if (!isPrintableChar(str.charAt(i))) { if (!isPrintableChar(str.charAt(i))) {
return false; return false;
} }
......
...@@ -7,11 +7,11 @@ import java.util.Stack; ...@@ -7,11 +7,11 @@ import java.util.Stack;
public class PackageNode { public class PackageNode {
private static final char SEPARATOR_CHAR = '.';
private PackageNode parentPackage; private PackageNode parentPackage;
private List<PackageNode> innerPackages = Collections.emptyList(); private List<PackageNode> innerPackages = Collections.emptyList();
private static final char separatorChar = '.';
private final String packageName; private final String packageName;
private String packageAlias; private String packageAlias;
...@@ -34,7 +34,7 @@ public class PackageNode { ...@@ -34,7 +34,7 @@ public class PackageNode {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
result.append(pp.pop().getName()); result.append(pp.pop().getName());
while (pp.size() > 0) { while (pp.size() > 0) {
result.append(separatorChar); result.append(SEPARATOR_CHAR);
result.append(pp.pop().getName()); result.append(pp.pop().getName());
} }
cachedPackageFullName = result.toString(); cachedPackageFullName = result.toString();
...@@ -63,7 +63,7 @@ public class PackageNode { ...@@ -63,7 +63,7 @@ public class PackageNode {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
result.append(pp.pop().getAlias()); result.append(pp.pop().getAlias());
while (pp.size() > 0) { while (pp.size() > 0) {
result.append(separatorChar); result.append(SEPARATOR_CHAR);
result.append(pp.pop().getAlias()); result.append(pp.pop().getAlias());
} }
cachedPackageFullAlias = result.toString(); cachedPackageFullAlias = result.toString();
......
package jadx.core.dex.info; package jadx.core.dex.info;
import jadx.core.codegen.TypeGen;
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;
...@@ -10,11 +11,13 @@ public final class FieldInfo { ...@@ -10,11 +11,13 @@ public final class FieldInfo {
private final ClassInfo declClass; private final ClassInfo declClass;
private final String name; private final String name;
private final ArgType type; private final ArgType type;
private String alias;
private FieldInfo(ClassInfo declClass, String name, ArgType type) { private FieldInfo(ClassInfo declClass, String name, ArgType type) {
this.declClass = declClass; this.declClass = declClass;
this.name = name; this.name = name;
this.type = type; this.type = type;
this.alias = name;
} }
public static FieldInfo from(DexNode dex, ClassInfo declClass, String name, ArgType type) { public static FieldInfo from(DexNode dex, ClassInfo declClass, String name, ArgType type) {
...@@ -42,6 +45,22 @@ public final class FieldInfo { ...@@ -42,6 +45,22 @@ public final class FieldInfo {
return declClass; return declClass;
} }
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public String getFullId() {
return declClass.getFullName() + "." + name + ":" + TypeGen.signature(type);
}
public boolean isRenamed() {
return !name.equals(alias);
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {
......
...@@ -17,10 +17,12 @@ public final class MethodInfo { ...@@ -17,10 +17,12 @@ public final class MethodInfo {
private final List<ArgType> args; private final List<ArgType> args;
private final ClassInfo declClass; private final ClassInfo declClass;
private final String shortId; private final String shortId;
private String alias;
private MethodInfo(DexNode dex, int mthIndex) { private MethodInfo(DexNode dex, int mthIndex) {
MethodId mthId = dex.getMethodId(mthIndex); MethodId mthId = dex.getMethodId(mthIndex);
name = dex.getString(mthId.getNameIndex()); name = dex.getString(mthId.getNameIndex());
alias = name;
declClass = ClassInfo.fromDex(dex, mthId.getDeclaringClassIndex()); declClass = ClassInfo.fromDex(dex, mthId.getDeclaringClassIndex());
ProtoId proto = dex.getProtoId(mthId.getProtoIndex()); ProtoId proto = dex.getProtoId(mthId.getProtoIndex());
...@@ -91,6 +93,18 @@ public final class MethodInfo { ...@@ -91,6 +93,18 @@ public final class MethodInfo {
return name.equals("<clinit>"); return name.equals("<clinit>");
} }
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public boolean isRenamed() {
return !name.equals(alias);
}
@Override @Override
public int hashCode() { public int hashCode() {
int result = declClass.hashCode(); int result = declClass.hashCode();
......
...@@ -42,6 +42,10 @@ public class FieldNode extends LineAttrNode { ...@@ -42,6 +42,10 @@ public class FieldNode extends LineAttrNode {
return fieldInfo.getName(); return fieldInfo.getName();
} }
public String getAlias() {
return fieldInfo.getAlias();
}
public ArgType getType() { public ArgType getType() {
return type; return type;
} }
......
...@@ -369,6 +369,10 @@ public class MethodNode extends LineAttrNode implements ILoadable { ...@@ -369,6 +369,10 @@ public class MethodNode extends LineAttrNode implements ILoadable {
return mthInfo.getName(); return mthInfo.getName();
} }
public String getAlias() {
return mthInfo.getAlias();
}
public ClassNode getParentClass() { public ClassNode getParentClass() {
return parentClass; return parentClass;
} }
......
...@@ -2,6 +2,9 @@ package jadx.core.dex.visitors; ...@@ -2,6 +2,9 @@ package jadx.core.dex.visitors;
import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.AType;
import jadx.core.dex.info.ClassInfo; import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.FieldInfo;
import jadx.core.dex.instructions.IndexInsnNode;
import jadx.core.dex.instructions.InvokeNode;
import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.InsnWrapArg; import jadx.core.dex.instructions.args.InsnWrapArg;
...@@ -73,6 +76,21 @@ public class DependencyCollector extends AbstractVisitor { ...@@ -73,6 +76,21 @@ public class DependencyCollector extends AbstractVisitor {
addDep(dex, depList, arg.getType()); addDep(dex, depList, arg.getType());
} }
} }
processCustomInsn(dex, depList, insnNode);
}
private static void processCustomInsn(DexNode dex, Set<ClassNode> depList, InsnNode insn) {
if (insn instanceof IndexInsnNode) {
Object index = ((IndexInsnNode) insn).getIndex();
if (index instanceof FieldInfo) {
addDep(dex, depList, ((FieldInfo) index).getDeclClass());
} else if (index instanceof ArgType) {
addDep(dex, depList, (ArgType) index);
}
} else if (insn instanceof InvokeNode) {
ClassInfo declClass = ((InvokeNode) insn).getCallMth().getDeclClass();
addDep(dex, depList, declClass);
}
} }
private static void addDep(DexNode dex, Set<ClassNode> depList, ArgType type) { private static void addDep(DexNode dex, Set<ClassNode> depList, ArgType type) {
...@@ -94,15 +112,14 @@ public class DependencyCollector extends AbstractVisitor { ...@@ -94,15 +112,14 @@ public class DependencyCollector extends AbstractVisitor {
private static void addDep(DexNode dex, Set<ClassNode> depList, ClassInfo clsInfo) { private static void addDep(DexNode dex, Set<ClassNode> depList, ClassInfo clsInfo) {
if (clsInfo != null) { if (clsInfo != null) {
ClassNode node = dex.resolveClass(clsInfo); ClassNode node = dex.resolveClass(clsInfo);
if (node != null) { addDep(dex, depList, node);
depList.add(node);
}
} }
} }
private static void addDep(DexNode dex, Set<ClassNode> depList, ClassNode clsNode) { private static void addDep(DexNode dex, Set<ClassNode> depList, ClassNode clsNode) {
if (clsNode != null) { if (clsNode != null) {
depList.add(clsNode); // add only top classes
depList.add(clsNode.getTopParentClass());
} }
} }
} }
package jadx.core.dex.visitors; package jadx.core.dex.visitors;
import jadx.api.IJadxArgs;
import jadx.core.codegen.TypeGen;
import jadx.core.deobf.Deobfuscator; import jadx.core.deobf.Deobfuscator;
import jadx.core.dex.attributes.AFlag;
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.ClassNode;
import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.RootNode; import jadx.core.dex.nodes.RootNode;
import jadx.core.utils.exceptions.JadxException; import jadx.core.utils.exceptions.JadxException;
import java.io.File; import java.io.File;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.io.FilenameUtils; import org.jetbrains.annotations.NotNull;
public class RenameVisitor extends AbstractVisitor { public class RenameVisitor extends AbstractVisitor {
@NotNull
private Deobfuscator deobfuscator; private Deobfuscator deobfuscator;
@Override @Override
public void init(RootNode root) { public void init(RootNode root) {
String firstInputFileName = root.getDexNodes().get(0).getInputFile().getFile().getAbsolutePath(); IJadxArgs args = root.getArgs();
String inputPath = FilenameUtils.getFullPathNoEndSeparator(firstInputFileName); File deobfMapFile = new File(args.getOutDir(), "deobf_map.jobf");
String inputName = FilenameUtils.getBaseName(firstInputFileName); deobfuscator = new Deobfuscator(args, root.getDexNodes(), deobfMapFile);
if (args.isDeobfuscationOn()) {
File deobfMapFile = new File(inputPath, inputName + ".jobf");
deobfuscator = new Deobfuscator(root.getArgs(), root.getDexNodes(), deobfMapFile);
// TODO: check classes for case sensitive names (issue #24) // TODO: check classes for case sensitive names (issue #24)
// TODO: sometimes can be used source file name from 'SourceFileAttr'
deobfuscator.execute(); deobfuscator.execute();
} }
}
@Override @Override
public boolean visit(ClassNode cls) throws JadxException { public boolean visit(ClassNode cls) throws JadxException {
// TODO: rename fields and methods checkFields(cls);
checkMethods(cls);
for (ClassNode inner : cls.getInnerClasses()) {
visit(inner);
}
return false; return false;
} }
private void checkFields(ClassNode cls) {
Set<String> names = new HashSet<String>();
for (FieldNode field : cls.getFields()) {
FieldInfo fieldInfo = field.getFieldInfo();
if (!names.add(fieldInfo.getAlias())) {
fieldInfo.setAlias(deobfuscator.makeFieldAlias(field));
}
}
}
private void checkMethods(ClassNode cls) {
Set<String> names = new HashSet<String>();
for (MethodNode mth : cls.getMethods()) {
if (mth.contains(AFlag.DONT_GENERATE)) {
continue;
}
MethodInfo methodInfo = mth.getMethodInfo();
String signature = makeMethodSignature(methodInfo);
if (!names.add(signature)) {
methodInfo.setAlias(deobfuscator.makeMethodAlias(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();
}
} }
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