Commit da41efa3 authored by Skylot's avatar Skylot

fix: force rename by checks from RenameVisitor (#432)

parent 9e0cd2e1
...@@ -243,6 +243,10 @@ public class Deobfuscator { ...@@ -243,6 +243,10 @@ public class Deobfuscator {
} }
} }
public void forceRenameField(FieldNode field) {
field.getFieldInfo().setAlias(makeFieldAlias(field));
}
public void renameMethod(MethodNode mth) { public void renameMethod(MethodNode mth) {
String alias = getMethodAlias(mth); String alias = getMethodAlias(mth);
if (alias != null) { if (alias != null) {
...@@ -253,6 +257,13 @@ public class Deobfuscator { ...@@ -253,6 +257,13 @@ public class Deobfuscator {
} }
} }
public void forceRenameMethod(MethodNode mth) {
mth.getMethodInfo().setAlias(makeMethodAlias(mth));
if (mth.isVirtual()) {
resolveOverriding(mth);
}
}
public void addPackagePreset(String origPkgName, String pkgAlias) { public void addPackagePreset(String origPkgName, String pkgAlias) {
PackageNode pkg = getPackageNode(origPkgName, true); PackageNode pkg = getPackageNode(origPkgName, true);
pkg.setAlias(pkgAlias); pkg.setAlias(pkgAlias);
......
...@@ -65,6 +65,10 @@ public final class FieldInfo { ...@@ -65,6 +65,10 @@ public final class FieldInfo {
return !name.equals(alias); return !name.equals(alias);
} }
public boolean equalsNameAndType(FieldInfo other) {
return name.equals(other.name) && type.equals(other.type);
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {
......
...@@ -321,6 +321,15 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode { ...@@ -321,6 +321,15 @@ public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
return null; return null;
} }
public FieldNode searchFieldByNameAndType(FieldInfo field) {
for (FieldNode f : fields) {
if (f.getFieldInfo().equalsNameAndType(field)) {
return f;
}
}
return null;
}
public FieldNode searchFieldByName(String name) { public FieldNode searchFieldByName(String name) {
for (FieldNode f : fields) { for (FieldNode f : fields) {
if (f.getName().equals(name)) { if (f.getName().equals(name)) {
......
...@@ -150,16 +150,15 @@ public class DexNode implements IDexNode { ...@@ -150,16 +150,15 @@ public class DexNode implements IDexNode {
@Nullable @Nullable
FieldNode deepResolveField(@NotNull ClassNode cls, FieldInfo fieldInfo) { FieldNode deepResolveField(@NotNull ClassNode cls, FieldInfo fieldInfo) {
FieldNode field = cls.searchFieldByName(fieldInfo.getName()); FieldNode field = cls.searchFieldByNameAndType(fieldInfo);
if (field != null) { if (field != null) {
return field; return field;
} }
FieldNode found;
ArgType superClass = cls.getSuperClass(); ArgType superClass = cls.getSuperClass();
if (superClass != null) { if (superClass != null) {
ClassNode superNode = resolveClass(superClass); ClassNode superNode = resolveClass(superClass);
if (superNode != null) { if (superNode != null) {
found = deepResolveField(superNode, fieldInfo); FieldNode found = deepResolveField(superNode, fieldInfo);
if (found != null) { if (found != null) {
return found; return found;
} }
...@@ -168,7 +167,7 @@ public class DexNode implements IDexNode { ...@@ -168,7 +167,7 @@ public class DexNode implements IDexNode {
for (ArgType iFaceType : cls.getInterfaces()) { for (ArgType iFaceType : cls.getInterfaces()) {
ClassNode iFaceNode = resolveClass(iFaceType); ClassNode iFaceNode = resolveClass(iFaceType);
if (iFaceNode != null) { if (iFaceNode != null) {
found = deepResolveField(iFaceNode, fieldInfo); FieldNode found = deepResolveField(iFaceNode, fieldInfo);
if (found != null) { if (found != null) {
return found; return found;
} }
......
...@@ -12,6 +12,7 @@ import jadx.core.Consts; ...@@ -12,6 +12,7 @@ import jadx.core.Consts;
import jadx.core.deobf.Deobfuscator; import jadx.core.deobf.Deobfuscator;
import jadx.core.deobf.NameMapper; import jadx.core.deobf.NameMapper;
import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.info.AccessInfo;
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.nodes.ClassNode; import jadx.core.dex.nodes.ClassNode;
...@@ -19,7 +20,6 @@ import jadx.core.dex.nodes.DexNode; ...@@ -19,7 +20,6 @@ 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 jadx.core.dex.nodes.RootNode; import jadx.core.dex.nodes.RootNode;
import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.files.FileUtils; import jadx.core.utils.files.FileUtils;
import jadx.core.utils.files.InputFile; import jadx.core.utils.files.InputFile;
...@@ -49,20 +49,12 @@ public class RenameVisitor extends AbstractVisitor { ...@@ -49,20 +49,12 @@ public class RenameVisitor extends AbstractVisitor {
checkClasses(root, isCaseSensitive); checkClasses(root, isCaseSensitive);
} }
@Override
public boolean visit(ClassNode cls) throws JadxException {
checkFields(cls);
checkMethods(cls);
for (ClassNode inner : cls.getInnerClasses()) {
visit(inner);
}
return false;
}
private void checkClasses(RootNode root, boolean caseSensitive) { private void checkClasses(RootNode root, boolean caseSensitive) {
Set<String> clsNames = new HashSet<>(); Set<String> clsNames = new HashSet<>();
for (ClassNode cls : root.getClasses(true)) { for (ClassNode cls : root.getClasses(true)) {
checkClassName(cls); checkClassName(cls);
checkFields(cls);
checkMethods(cls);
if (!caseSensitive) { if (!caseSensitive) {
ClassInfo classInfo = cls.getClassInfo(); ClassInfo classInfo = cls.getClassInfo();
String clsFileName = classInfo.getAlias().getFullPath(); String clsFileName = classInfo.getAlias().getFullPath();
...@@ -103,7 +95,7 @@ public class RenameVisitor extends AbstractVisitor { ...@@ -103,7 +95,7 @@ public class RenameVisitor extends AbstractVisitor {
FieldInfo fieldInfo = field.getFieldInfo(); FieldInfo fieldInfo = field.getFieldInfo();
String fieldName = fieldInfo.getAlias(); String fieldName = fieldInfo.getAlias();
if (!names.add(fieldName) || !NameMapper.isValidIdentifier(fieldName)) { if (!names.add(fieldName) || !NameMapper.isValidIdentifier(fieldName)) {
deobfuscator.renameField(field); deobfuscator.forceRenameField(field);
} }
} }
} }
...@@ -111,12 +103,16 @@ public class RenameVisitor extends AbstractVisitor { ...@@ -111,12 +103,16 @@ public class RenameVisitor extends AbstractVisitor {
private void checkMethods(ClassNode cls) { private void checkMethods(ClassNode cls) {
Set<String> names = new HashSet<>(); Set<String> names = new HashSet<>();
for (MethodNode mth : cls.getMethods()) { for (MethodNode mth : cls.getMethods()) {
if (mth.contains(AFlag.DONT_GENERATE) || mth.getAccessFlags().isConstructor()) { AccessInfo accessFlags = mth.getAccessFlags();
if (accessFlags.isConstructor()
|| accessFlags.isBridge()
|| accessFlags.isSynthetic()
|| mth.contains(AFlag.DONT_GENERATE)) {
continue; continue;
} }
String signature = mth.getMethodInfo().makeSignature(false); String signature = mth.getMethodInfo().makeSignature(false);
if (!names.add(signature) || !NameMapper.isValidIdentifier(mth.getAlias())) { if (!names.add(signature) || !NameMapper.isValidIdentifier(mth.getAlias())) {
deobfuscator.renameMethod(mth); deobfuscator.forceRenameMethod(mth);
} }
} }
} }
......
package jadx.tests.integration.names;
import org.junit.Test;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.SmaliTest;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.junit.Assert.assertThat;
public class TestDuplicatedNames extends SmaliTest {
/*
public static class TestCls {
public Object fieldName;
public String fieldName;
public Object run() {
return this.fieldName;
}
public String run() {
return this.fieldName;
}
}
*/
@Test
public void test() {
commonChecks();
}
@Test
public void testWithDeobf() {
enableDeobfuscation();
commonChecks();
}
private void commonChecks() {
ClassNode cls = getClassNodeFromSmaliWithPath("names", "TestDuplicatedNames");
String code = cls.getCode().toString();
assertThat(code, containsOne("Object fieldName;"));
assertThat(code, containsOne("String f0fieldName"));
assertThat(code, containsOne("this.fieldName"));
assertThat(code, containsOne("this.f0fieldName"));
assertThat(code, containsOne("public Object run() {"));
assertThat(code, containsOne("public String m0run() {"));
}
}
.class public LTestDuplicatedNames;
.super Ljava/lang/Object;
.source "TestDuplicatedNames.java"
# instance fields
.field public fieldName:Ljava/lang/String;
.field public fieldName:Ljava/lang/Object;
# direct methods
.method public constructor <init>()V
.registers 1
.prologue
.line 3
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public run()Ljava/lang/String;
.registers 2
.prologue
iget-object v0, p0, LTestDuplicatedNames;->fieldName:Ljava/lang/String;
return-object v0
.end method
.method public run()Ljava/lang/Object;
.registers 2
.prologue
iget-object v0, p0, LTestDuplicatedNames;->fieldName:Ljava/lang/Object;
return-object v0
.end method
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