simplify icon indicating copy to clipboard operation
simplify copied to clipboard

[Bug] [SmaliVM] visitClassAnnotations() fail on parsing obfuscated member class names

Open fipso opened this issue 3 years ago • 3 comments

Some obfuscators tend to rename member classes to short random strings like "Ab" or "Bc".

.class public final Lde/fipso/test/container/ui/ContainerActivity;
.super Landroidx/appcompat/app/AppCompatActivity;
.source "ContainerActivity.kt"

# annotations
.annotation system Ldalvik/annotation/MemberClasses;
    value = {
        Lde/fipso/test/rL;
    }
.end annotation

visitInnerClasses() then fails to parse the inner and outer class name, because we are not using the default class name format with the $ as the separator. (java.lang.ArrayIndexOutOfBoundsException: 1 -> ClassBuilder.java:150);

EDIT: This could be a baksmali issue.

fipso avatar Jul 26 '21 18:07 fipso

Thanks for the report. I'm also leaning towards this being a dexlib issue. If you can't reproduce with just baksmali, can you share a Dex file which causes the issue?

CalebFenton avatar Jul 27 '21 04:07 CalebFenton

classes3.zip

Seems like this is a feature of the Axan Obfuscator, but again this could be a misbehaviour in the smali class name generation by baksmali or dexlib.

I was able to come up with a dirty fix for this problem. Basically, I am just passing the parents Class name as the outer class name and using the full member class name as the inner class name.

private void visitInnerClasses(String parentClassName, BuilderEncodedValues.BuilderTypeEncodedValue value,
                                   ClassWriter classWriter) {
        // String name, String outerName, String innerName, int access
        String internalName = value.getValue();
        String fullName = stripName(value.getValue());
        String[] parts = fullName.split("\\$", 2);
        String outerName;
        String innerName;
        if (parts.length == 2){
            outerName = parts[0];
            innerName = parts[1];
        }else{
            outerName = parentClassName;
            innerName = fullName;
        }

        System.out.println("visitInnerClasses(): " + outerName + "$" + innerName);

        boolean isAnonymous = innerName.equals("1") || Ints.tryParse(innerName) != null;
        if (isAnonymous) {
            innerName = null;
        }

        int innerAccess = classManager.getVirtualClass(internalName).getClassDef().getAccessFlags();
        classWriter.visitInnerClass(fullName, outerName, innerName, innerAccess);
    }

fipso avatar Jul 27 '21 09:07 fipso

Thanks for the extra detail and the fix. I'll have to read the java specs to see what's technically allowed and see if I can improve what you have here.

Also: I added smali syntax highlighting to github a while back so I changed your original comment to use it. :D

CalebFenton avatar Jul 29 '21 16:07 CalebFenton