Commit bc8ad4df authored by skylot's avatar skylot

Merge pull request #64 from NeoSpb/fix_deobfuscator

Fix deobfuscator
parents c923d19b 53ac3ec5
...@@ -64,6 +64,9 @@ public class JadxCLIArgs implements IJadxArgs { ...@@ -64,6 +64,9 @@ public class JadxCLIArgs implements IJadxArgs {
@Parameter(names = {"--deobf-rewrite-cfg"}, description = "force to save deobfuscation map") @Parameter(names = {"--deobf-rewrite-cfg"}, description = "force to save deobfuscation map")
protected boolean deobfuscationForceSave = false; protected boolean deobfuscationForceSave = false;
@Parameter(names = {"--deobf-use-sourcename"}, description = "use source file name as class name alias")
protected boolean deobfuscationUseSourceNameAsAlias = false;
@Parameter(names = {"-h", "--help"}, description = "print this help", help = true) @Parameter(names = {"-h", "--help"}, description = "print this help", help = true)
protected boolean printHelp = false; protected boolean printHelp = false;
...@@ -242,4 +245,9 @@ public class JadxCLIArgs implements IJadxArgs { ...@@ -242,4 +245,9 @@ public class JadxCLIArgs implements IJadxArgs {
public boolean isDeobfuscationForceSave() { public boolean isDeobfuscationForceSave() {
return deobfuscationForceSave; return deobfuscationForceSave;
} }
@Override
public boolean useSourceNameAsClassAlias() {
return deobfuscationUseSourceNameAsAlias;
}
} }
...@@ -68,4 +68,9 @@ public class DefaultJadxArgs implements IJadxArgs { ...@@ -68,4 +68,9 @@ public class DefaultJadxArgs implements IJadxArgs {
public boolean isDeobfuscationForceSave() { public boolean isDeobfuscationForceSave() {
return false; return false;
} }
@Override
public boolean useSourceNameAsClassAlias() {
return false;
}
} }
...@@ -28,4 +28,6 @@ public interface IJadxArgs { ...@@ -28,4 +28,6 @@ public interface IJadxArgs {
int getDeobfuscationMaxLength(); int getDeobfuscationMaxLength();
boolean isDeobfuscationForceSave(); boolean isDeobfuscationForceSave();
boolean useSourceNameAsClassAlias();
} }
...@@ -6,13 +6,17 @@ import jadx.core.dex.attributes.nodes.SourceFileAttr; ...@@ -6,13 +6,17 @@ 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.FieldInfo;
import jadx.core.dex.info.MethodInfo; 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.DexNode; import jadx.core.dex.nodes.DexNode;
import jadx.core.dex.nodes.FieldNode; import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
...@@ -40,11 +44,16 @@ public class Deobfuscator { ...@@ -40,11 +44,16 @@ public class Deobfuscator {
private final Map<FieldInfo, String> fldMap = new HashMap<FieldInfo, String>(); private final Map<FieldInfo, String> fldMap = new HashMap<FieldInfo, String>();
private final Map<MethodInfo, String> mthMap = new HashMap<MethodInfo, String>(); private final Map<MethodInfo, String> mthMap = new HashMap<MethodInfo, String>();
private final Map<MethodInfo, OverridedMethodsNode> ovrdMap = new HashMap<MethodInfo, OverridedMethodsNode>();
private final List<OverridedMethodsNode> ovrd = new ArrayList<OverridedMethodsNode>();
private final PackageNode rootPackage = new PackageNode(""); private final PackageNode rootPackage = new PackageNode("");
private final Set<String> pkgSet = new TreeSet<String>(); 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 final boolean useSourceNameAsAlias;
private int pkgIndex = 0; private int pkgIndex = 0;
private int clsIndex = 0; private int clsIndex = 0;
private int fldIndex = 0; private int fldIndex = 0;
...@@ -56,6 +65,7 @@ public class Deobfuscator { ...@@ -56,6 +65,7 @@ public class Deobfuscator {
this.minLength = args.getDeobfuscationMinLength(); this.minLength = args.getDeobfuscationMinLength();
this.maxLength = args.getDeobfuscationMaxLength(); this.maxLength = args.getDeobfuscationMaxLength();
this.useSourceNameAsAlias = args.useSourceNameAsClassAlias();
this.deobfPresets = new DeobfPresets(this, deobfMapFile); this.deobfPresets = new DeobfPresets(this, deobfMapFile);
} }
...@@ -95,6 +105,32 @@ public class Deobfuscator { ...@@ -95,6 +105,32 @@ public class Deobfuscator {
processClass(dexNode, cls); processClass(dexNode, cls);
} }
} }
postProcess();
}
private void postProcess() {
int id = 1;
for (OverridedMethodsNode o : ovrd) {
Iterator<MethodInfo> it = o.getMethods().iterator();
if (it.hasNext()) {
MethodInfo mth = it.next();
if (mth.isRenamed() && !mth.isAliasFromPreset()) {
mth.setAlias(String.format("mo%d%s", id, makeName(mth.getName())));
}
String firstMethodAlias = mth.getAlias();
while (it.hasNext()) {
mth = it.next();
if (!mth.getAlias().equals(firstMethodAlias)) {
mth.setAlias(firstMethodAlias);
}
}
}
id++;
}
} }
void clear() { void clear() {
...@@ -102,6 +138,98 @@ public class Deobfuscator { ...@@ -102,6 +138,98 @@ public class Deobfuscator {
clsMap.clear(); clsMap.clear();
fldMap.clear(); fldMap.clear();
mthMap.clear(); mthMap.clear();
ovrd.clear();
ovrdMap.clear();
}
@Nullable
private static ClassNode resolveOverridingInternal(DexNode dex, ClassNode cls, String signature,
Set<MethodInfo> overrideSet, ClassNode rootClass) {
ClassNode result = null;
for (MethodNode m : cls.getMethods()) {
if (m.getMethodInfo().getShortId().startsWith(signature)) {
result = cls;
if (!overrideSet.contains(m.getMethodInfo())) {
overrideSet.add(m.getMethodInfo());
}
break;
}
}
ArgType superClass = cls.getSuperClass();
if (superClass != null) {
ClassNode superNode = dex.resolveClass(superClass);
if (superNode != null) {
ClassNode clsWithMth = resolveOverridingInternal(dex, superNode, signature, overrideSet, rootClass);
if (clsWithMth != null) {
if ((result != null) && (result != cls)) {
if (clsWithMth != result) {
LOG.warn(String.format("Multiple overriding '%s' from '%s' and '%s' in '%s'",
signature,
result.getFullName(), clsWithMth.getFullName(),
rootClass.getFullName()));
}
} else {
result = clsWithMth;
}
}
}
}
for (ArgType iFaceType : cls.getInterfaces()) {
ClassNode iFaceNode = dex.resolveClass(iFaceType);
if (iFaceNode != null) {
ClassNode clsWithMth = resolveOverridingInternal(dex, iFaceNode, signature, overrideSet, rootClass);
if (clsWithMth != null) {
if ((result != null) && (result != cls)) {
if (clsWithMth != result) {
LOG.warn(String.format("Multiple overriding '%s' from '%s' and '%s' in '%s'",
signature,
result.getFullName(), clsWithMth.getFullName(),
rootClass.getFullName()));
}
} else {
result = clsWithMth;
}
}
}
}
return result;
}
private void resolveOverriding(DexNode dex, ClassNode cls, MethodNode mth) {
Set<MethodInfo> overrideSet = new HashSet<MethodInfo>();
resolveOverridingInternal(dex, cls, mth.getMethodInfo().makeSignature(false), overrideSet, cls);
if (overrideSet.size() > 1) {
OverridedMethodsNode overrideNode = null;
for (MethodInfo _mth : overrideSet) {
if (ovrdMap.containsKey(_mth)) {
overrideNode = ovrdMap.get(_mth);
break;
}
}
if (overrideNode == null) {
overrideNode = new OverridedMethodsNode(overrideSet);
ovrd.add(overrideNode);
}
for (MethodInfo _mth : overrideSet) {
if (!ovrdMap.containsKey(_mth)) {
ovrdMap.put(_mth, overrideNode);
if (!overrideNode.contains(_mth)) {
overrideNode.add(_mth);
}
}
}
} else {
overrideSet.clear();
overrideSet = null;
}
} }
private void processClass(DexNode dex, ClassNode cls) { private void processClass(DexNode dex, ClassNode cls) {
...@@ -123,6 +251,10 @@ public class Deobfuscator { ...@@ -123,6 +251,10 @@ public class Deobfuscator {
if (alias != null) { if (alias != null) {
methodInfo.setAlias(alias); methodInfo.setAlias(alias);
} }
if (mth.isVirtual()) {
resolveOverriding(dex, cls, mth);
}
} }
} }
...@@ -212,7 +344,12 @@ public class Deobfuscator { ...@@ -212,7 +344,12 @@ public class Deobfuscator {
private String makeClsAlias(ClassNode cls) { private String makeClsAlias(ClassNode cls) {
ClassInfo classInfo = cls.getClassInfo(); ClassInfo classInfo = cls.getClassInfo();
String alias = getAliasFromSourceFile(cls); String alias = null;
if (this.useSourceNameAsAlias) {
alias = getAliasFromSourceFile(cls);
}
if (alias == null) { if (alias == null) {
String clsName = classInfo.getShortName(); String clsName = classInfo.getShortName();
alias = String.format("C%04d%s", clsIndex++, makeName(clsName)); alias = String.format("C%04d%s", clsIndex++, makeName(clsName));
...@@ -269,6 +406,7 @@ public class Deobfuscator { ...@@ -269,6 +406,7 @@ public class Deobfuscator {
alias = deobfPresets.getForMth(methodInfo); alias = deobfPresets.getForMth(methodInfo);
if (alias != null) { if (alias != null) {
mthMap.put(methodInfo, alias); mthMap.put(methodInfo, alias);
methodInfo.setAliasFromPreset(true);
return alias; return alias;
} }
if (shouldRename(mth.getName())) { if (shouldRename(mth.getName())) {
......
package jadx.core.deobf;
import jadx.core.dex.info.MethodInfo;
import java.util.Set;
/* package */ class OverridedMethodsNode {
private Set<MethodInfo> methods;
public OverridedMethodsNode(Set<MethodInfo> methodsSet) {
methods = methodsSet;
}
public boolean contains(MethodInfo mth) {
return methods.contains(mth);
}
public void add(MethodInfo mth) {
methods.add(mth);
}
public Set<MethodInfo> getMethods() {
return methods;
}
}
...@@ -18,11 +18,13 @@ public final class MethodInfo { ...@@ -18,11 +18,13 @@ public final class MethodInfo {
private final ClassInfo declClass; private final ClassInfo declClass;
private final String shortId; private final String shortId;
private String alias; private String alias;
private boolean aliasFromPreset;
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; alias = name;
aliasFromPreset = false;
declClass = ClassInfo.fromDex(dex, mthId.getDeclaringClassIndex()); declClass = ClassInfo.fromDex(dex, mthId.getDeclaringClassIndex());
ProtoId proto = dex.getProtoId(mthId.getProtoIndex()); ProtoId proto = dex.getProtoId(mthId.getProtoIndex());
...@@ -109,6 +111,14 @@ public final class MethodInfo { ...@@ -109,6 +111,14 @@ public final class MethodInfo {
return !name.equals(alias); return !name.equals(alias);
} }
public boolean isAliasFromPreset() {
return aliasFromPreset;
}
public void setAliasFromPreset(boolean value) {
aliasFromPreset = value;
}
@Override @Override
public int hashCode() { public int hashCode() {
int result = declClass.hashCode(); int result = declClass.hashCode();
......
...@@ -86,10 +86,10 @@ public class ClassNode extends LineAttrNode implements ILoadable { ...@@ -86,10 +86,10 @@ public class ClassNode extends LineAttrNode implements ILoadable {
fields = new ArrayList<FieldNode>(fieldsCount); fields = new ArrayList<FieldNode>(fieldsCount);
for (Method mth : clsData.getDirectMethods()) { for (Method mth : clsData.getDirectMethods()) {
methods.add(new MethodNode(this, mth)); methods.add(new MethodNode(this, mth, false));
} }
for (Method mth : clsData.getVirtualMethods()) { for (Method mth : clsData.getVirtualMethods()) {
methods.add(new MethodNode(this, mth)); methods.add(new MethodNode(this, mth, true));
} }
for (Field f : clsData.getStaticFields()) { for (Field f : clsData.getStaticFields()) {
......
...@@ -56,6 +56,7 @@ public class MethodNode extends LineAttrNode implements ILoadable { ...@@ -56,6 +56,7 @@ public class MethodNode extends LineAttrNode implements ILoadable {
private int codeSize; private int codeSize;
private int debugInfoOffset; private int debugInfoOffset;
private boolean noCode; private boolean noCode;
private boolean methodIsVirtual;
private ArgType retType; private ArgType retType;
private RegisterArg thisArg; private RegisterArg thisArg;
...@@ -71,12 +72,13 @@ public class MethodNode extends LineAttrNode implements ILoadable { ...@@ -71,12 +72,13 @@ public class MethodNode extends LineAttrNode implements ILoadable {
private List<ExceptionHandler> exceptionHandlers = Collections.emptyList(); private List<ExceptionHandler> exceptionHandlers = Collections.emptyList();
private List<LoopInfo> loops = Collections.emptyList(); private List<LoopInfo> loops = Collections.emptyList();
public MethodNode(ClassNode classNode, Method mthData) { public MethodNode(ClassNode classNode, Method mthData, boolean isVirtual) {
this.mthInfo = MethodInfo.fromDex(classNode.dex(), mthData.getMethodIndex()); this.mthInfo = MethodInfo.fromDex(classNode.dex(), mthData.getMethodIndex());
this.parentClass = classNode; this.parentClass = classNode;
this.accFlags = new AccessInfo(mthData.getAccessFlags(), AFType.METHOD); this.accFlags = new AccessInfo(mthData.getAccessFlags(), AFType.METHOD);
this.noCode = mthData.getCodeOffset() == 0; this.noCode = mthData.getCodeOffset() == 0;
this.methodData = noCode ? null : mthData; this.methodData = noCode ? null : mthData;
this.methodIsVirtual = isVirtual;
} }
@Override @Override
...@@ -538,6 +540,10 @@ public class MethodNode extends LineAttrNode implements ILoadable { ...@@ -538,6 +540,10 @@ public class MethodNode extends LineAttrNode implements ILoadable {
return result; return result;
} }
public boolean isVirtual() {
return methodIsVirtual;
}
public int getRegsCount() { public int getRegsCount() {
return regsCount; return regsCount;
} }
......
...@@ -30,7 +30,13 @@ public class RenameVisitor extends AbstractVisitor { ...@@ -30,7 +30,13 @@ public class RenameVisitor extends AbstractVisitor {
@Override @Override
public void init(RootNode root) { public void init(RootNode root) {
IJadxArgs args = root.getArgs(); IJadxArgs args = root.getArgs();
File deobfMapFile = new File(args.getOutDir(), "deobf_map.jobf");
final String firstInputFileName = root.getDexNodes().get(0).getInputFile().getFile().getAbsolutePath();
final String inputPath = org.apache.commons.io.FilenameUtils.getFullPathNoEndSeparator(
firstInputFileName);
final String inputName = org.apache.commons.io.FilenameUtils.getBaseName(firstInputFileName);
File deobfMapFile = new File(inputPath, inputName + ".jobf");
deobfuscator = new Deobfuscator(args, root.getDexNodes(), deobfMapFile); deobfuscator = new Deobfuscator(args, root.getDexNodes(), deobfMapFile);
boolean deobfuscationOn = args.isDeobfuscationOn(); boolean deobfuscationOn = args.isDeobfuscationOn();
if (deobfuscationOn) { if (deobfuscationOn) {
......
...@@ -132,6 +132,10 @@ public class JadxSettings extends JadxCLIArgs { ...@@ -132,6 +132,10 @@ public class JadxSettings extends JadxCLIArgs {
this.deobfuscationForceSave = deobfuscationForceSave; this.deobfuscationForceSave = deobfuscationForceSave;
} }
public void setUseSourceNameAsClassAlias(boolean useSourceNameAsAlias) {
this.deobfuscationUseSourceNameAsAlias = useSourceNameAsAlias;
}
public Font getFont() { public Font getFont() {
if (fontStr.isEmpty()) { if (fontStr.isEmpty()) {
return DEFAULT_FONT; return DEFAULT_FONT;
......
...@@ -141,11 +141,21 @@ public class JadxSettingsWindow extends JDialog { ...@@ -141,11 +141,21 @@ public class JadxSettingsWindow extends JDialog {
} }
}); });
JCheckBox deobfSourceAlias = new JCheckBox();
deobfSourceAlias.setSelected(settings.useSourceNameAsClassAlias());
deobfSourceAlias.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
settings.setUseSourceNameAsClassAlias(e.getStateChange() == ItemEvent.SELECTED);
needReload();
}
});
SettingsGroup deobfGroup = new SettingsGroup(NLS.str("preferences.deobfuscation")); SettingsGroup deobfGroup = new SettingsGroup(NLS.str("preferences.deobfuscation"));
deobfGroup.addRow(NLS.str("preferences.deobfuscation_on"), deobfOn); deobfGroup.addRow(NLS.str("preferences.deobfuscation_on"), deobfOn);
deobfGroup.addRow(NLS.str("preferences.deobfuscation_force"), deobfForce); deobfGroup.addRow(NLS.str("preferences.deobfuscation_force"), deobfForce);
deobfGroup.addRow(NLS.str("preferences.deobfuscation_min_len"), minLen); deobfGroup.addRow(NLS.str("preferences.deobfuscation_min_len"), minLen);
deobfGroup.addRow(NLS.str("preferences.deobfuscation_max_len"), maxLen); deobfGroup.addRow(NLS.str("preferences.deobfuscation_max_len"), maxLen);
deobfGroup.addRow(NLS.str("preferences.deobfuscation_source_alias"), deobfSourceAlias);
deobfGroup.end(); deobfGroup.end();
return deobfGroup; return deobfGroup;
} }
......
...@@ -62,6 +62,7 @@ preferences.deobfuscation_on=Enable deobfuscation ...@@ -62,6 +62,7 @@ preferences.deobfuscation_on=Enable deobfuscation
preferences.deobfuscation_force=Force rewrite deobfuscation map file preferences.deobfuscation_force=Force rewrite deobfuscation map file
preferences.deobfuscation_min_len=Minimum name length preferences.deobfuscation_min_len=Minimum name length
preferences.deobfuscation_max_len=Maximum name length preferences.deobfuscation_max_len=Maximum name length
preferences.deobfuscation_source_alias=Use source file name as class name alias
preferences.save=Save preferences.save=Save
preferences.cancel=Cancel preferences.cancel=Cancel
......
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