New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

APKTool 2.0.2 - ClassCastException ResStringValue -> ResAttr #1060

Closed
kvandermast opened this Issue Oct 14, 2015 · 12 comments

Comments

Projects
None yet
5 participants
@kvandermast

We are using a MobileIron Store to distribute our enterprise apps to the employees. We just released a new version and the service team is unable to upload the APK to the Store. I can trace it back to MobileIron decompile the APK (God knows why).

When I try to decompile the apk via command line, it throws the ClassCastException:

$ ./apktool d ~/Desktop/APK-Playground/fancyapp.apk 
I: Using Apktool 2.0.2 on fancyapp.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /Users/ecas/Library/apktool/framework/1.apk
Exception in thread "main" java.lang.ClassCastException: brut.androlib.res.data.value.ResStringValue cannot be cast to brut.androlib.res.data.value.ResAttr
    at brut.androlib.res.decoder.ResAttrDecoder.decode(ResAttrDecoder.java:38)
    at brut.androlib.res.decoder.AXmlResourceParser.getAttributeValue(AXmlResourceParser.java:369)
    at org.xmlpull.v1.wrapper.classic.XmlPullParserDelegate.getAttributeValue(XmlPullParserDelegate.java:69)
    at org.xmlpull.v1.wrapper.classic.StaticXmlSerializerWrapper.writeStartTag(StaticXmlSerializerWrapper.java:267)
    at org.xmlpull.v1.wrapper.classic.StaticXmlSerializerWrapper.event(StaticXmlSerializerWrapper.java:211)
    at brut.androlib.res.decoder.XmlPullStreamDecoder$1.event(XmlPullStreamDecoder.java:83)
    at brut.androlib.res.decoder.XmlPullStreamDecoder.decode(XmlPullStreamDecoder.java:141)
    at brut.androlib.res.decoder.XmlPullStreamDecoder.decodeManifest(XmlPullStreamDecoder.java:153)
    at brut.androlib.res.decoder.ResFileDecoder.decodeManifest(ResFileDecoder.java:140)
    at brut.androlib.res.AndrolibResources.decodeManifestWithResources(AndrolibResources.java:199)
    at brut.androlib.Androlib.decodeManifestWithResources(Androlib.java:140)
    at brut.androlib.ApkDecoder.decode(ApkDecoder.java:100)
    at brut.apktool.Main.cmdDecode(Main.java:165)
    at brut.apktool.Main.main(Main.java:81)

Environment:

s$ java -version
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)

Android build tools:

  • compileSDKVersion 23
  • buildToolsVersion '21.1.2'
  • minSdkVersion 16
  • targetSDKVersion 23
  • minifyEnabled & proguard enabled

Let me know if you need more information.

Regards,
Kris

@CunningLogic

This comment has been minimized.

Show comment
Hide comment
@CunningLogic

CunningLogic Oct 14, 2015

Can you share this apk?

Can you share this apk?

@kvandermast

This comment has been minimized.

Show comment
Hide comment
@kvandermast

kvandermast Oct 14, 2015

Hmm, I'm afraid not (NDA and other legal restrictions). I'll try to wiz-up an app which I can share (using the same config, but without the code).

Hmm, I'm afraid not (NDA and other legal restrictions). I'll try to wiz-up an app which I can share (using the same config, but without the code).

@CunningLogic

This comment has been minimized.

Show comment
Hide comment
@CunningLogic

CunningLogic Oct 14, 2015

If you can whip up one with the same error, ill take a look

If you can whip up one with the same error, ill take a look

@kvandermast

This comment has been minimized.

Show comment
Hide comment
@kvandermast

kvandermast Oct 15, 2015

Well, the good news is that the Android app I tried to whip-up doesn't have this problem. I've taken the liberty of downloading the APKTool sources and followed the stacktrace to where the exception is thrown.

I updated the code to:

public class ResAttrDecoder {
    public String decode(int type, int value, String rawValue, int attrResId)
            throws AndrolibException {
        ResScalarValue resValue = mCurrentPackage.getValueFactory().factory(
                type, value, rawValue);

        String decoded = null;
        if (attrResId > 0) {
            try {
                ResTable resTable = getCurrentPackage().getResTable();

                ResResource o = resTable.getResSpec(attrResId).getDefaultResource();

                try {
                    ResAttr attr = (ResAttr) getCurrentPackage().getResTable()
                            .getResSpec(attrResId).getDefaultResource().getValue();

                    decoded = attr.convertToResXmlFormat(resValue);
                } catch (ClassCastException e) {
                    System.out.println("DECODING ---------------------------------------------");
                    System.out.println("ResValue : " + resValue.toString());
                    System.out.println("Fullname: " + resTable.getResSpec(attrResId).getFullName());
                    System.out.println("Trying to decode RawValue: " + rawValue);


                    ResStringValue val = (ResStringValue) o.getValue();

                    System.out.println("ResStringValue: " + val.toString());
                    System.out.println("Value contains : " + val.encodeAsResXmlValue());

                    decoded = val.encodeAsResXmlValue();

                }

            } catch (UndefinedResObject ex) {
                // ignored
            }
        }

        return decoded != null ? decoded : resValue.encodeAsResXmlAttr();
    }
...

And I get this as output:

DECODING ---------------------------------------------
ResValue : ResScalarValue{mType='bool', mRawValue='null'}
Fullname: android:attr/private_resource_pad22
Trying to decode RawValue: null
ResStringValue: ResScalarValue{mType='string', mRawValue='padding'}
Value contains : padding

It also gets this error after parsing the "application" tag of the manifest. Strangely enough, I have no values or attributes defined as "padding", nor the private_resource_pad22.

Could it be related to any of the libraries which are included?

    compile 'com.android.support:support-v4:23.0.1'
    compile 'com.android.support:appcompat-v7:23.0.1'
    compile 'com.android.support:design:23.0.1'
    compile 'com.google.android.gms:play-services:7.8.0'
    compile 'com.google.android.gms:play-services-gcm:7.8.0'
    compile 'com.google.android.gms:play-services-wearable:7.8.0'
    compile 'com.jakewharton:butterknife:6.1.0'
    compile 'com.squareup.okhttp:okhttp:2.4.0'
    compile 'javax.inject:javax.inject:1'
    compile 'javax.annotation:javax.annotation-api:1.2'
    apt 'com.google.dagger:dagger-compiler:2.0'
    compile 'com.google.dagger:dagger:2.0'
    provided 'org.glassfish:javax.annotation:10.0-b28'

Well, the good news is that the Android app I tried to whip-up doesn't have this problem. I've taken the liberty of downloading the APKTool sources and followed the stacktrace to where the exception is thrown.

I updated the code to:

public class ResAttrDecoder {
    public String decode(int type, int value, String rawValue, int attrResId)
            throws AndrolibException {
        ResScalarValue resValue = mCurrentPackage.getValueFactory().factory(
                type, value, rawValue);

        String decoded = null;
        if (attrResId > 0) {
            try {
                ResTable resTable = getCurrentPackage().getResTable();

                ResResource o = resTable.getResSpec(attrResId).getDefaultResource();

                try {
                    ResAttr attr = (ResAttr) getCurrentPackage().getResTable()
                            .getResSpec(attrResId).getDefaultResource().getValue();

                    decoded = attr.convertToResXmlFormat(resValue);
                } catch (ClassCastException e) {
                    System.out.println("DECODING ---------------------------------------------");
                    System.out.println("ResValue : " + resValue.toString());
                    System.out.println("Fullname: " + resTable.getResSpec(attrResId).getFullName());
                    System.out.println("Trying to decode RawValue: " + rawValue);


                    ResStringValue val = (ResStringValue) o.getValue();

                    System.out.println("ResStringValue: " + val.toString());
                    System.out.println("Value contains : " + val.encodeAsResXmlValue());

                    decoded = val.encodeAsResXmlValue();

                }

            } catch (UndefinedResObject ex) {
                // ignored
            }
        }

        return decoded != null ? decoded : resValue.encodeAsResXmlAttr();
    }
...

And I get this as output:

DECODING ---------------------------------------------
ResValue : ResScalarValue{mType='bool', mRawValue='null'}
Fullname: android:attr/private_resource_pad22
Trying to decode RawValue: null
ResStringValue: ResScalarValue{mType='string', mRawValue='padding'}
Value contains : padding

It also gets this error after parsing the "application" tag of the manifest. Strangely enough, I have no values or attributes defined as "padding", nor the private_resource_pad22.

Could it be related to any of the libraries which are included?

    compile 'com.android.support:support-v4:23.0.1'
    compile 'com.android.support:appcompat-v7:23.0.1'
    compile 'com.android.support:design:23.0.1'
    compile 'com.google.android.gms:play-services:7.8.0'
    compile 'com.google.android.gms:play-services-gcm:7.8.0'
    compile 'com.google.android.gms:play-services-wearable:7.8.0'
    compile 'com.jakewharton:butterknife:6.1.0'
    compile 'com.squareup.okhttp:okhttp:2.4.0'
    compile 'javax.inject:javax.inject:1'
    compile 'javax.annotation:javax.annotation-api:1.2'
    apt 'com.google.dagger:dagger-compiler:2.0'
    compile 'com.google.dagger:dagger:2.0'
    provided 'org.glassfish:javax.annotation:10.0-b28'
@iBotPeaches

This comment has been minimized.

Show comment
Hide comment
@iBotPeaches

iBotPeaches Oct 15, 2015

Owner

Yeah, I see the problem. Attributes should not be decoded as a ResStringValue as that is not part of the ResAttr. I could probably handle the conversion from ResStringValue to ResAttr, or catch the ClassCast exception and treat it as the raw ResValue, in which case will decode it via resValue.encodeAsResXmlAttr(), which will call encodeAsXmlValue and thus return the string of the attribute.

What you could do to help is dump the attrResId and then search aapt with the apk via aapt d --values resources name_of_private.apk | grep 'resource id'. Then remove the values/NDA stuff to let me see what aapt is reporting the value as before I go patching something incorrectly.

Owner

iBotPeaches commented Oct 15, 2015

Yeah, I see the problem. Attributes should not be decoded as a ResStringValue as that is not part of the ResAttr. I could probably handle the conversion from ResStringValue to ResAttr, or catch the ClassCast exception and treat it as the raw ResValue, in which case will decode it via resValue.encodeAsResXmlAttr(), which will call encodeAsXmlValue and thus return the string of the attribute.

What you could do to help is dump the attrResId and then search aapt with the apk via aapt d --values resources name_of_private.apk | grep 'resource id'. Then remove the values/NDA stuff to let me see what aapt is reporting the value as before I go patching something incorrectly.

@kvandermast

This comment has been minimized.

Show comment
Hide comment
@kvandermast

kvandermast Oct 15, 2015

Dumped the (int) value, which is 16844011. The grep didn't return any results though (not even for its hex-variant)...

...
                } catch (ClassCastException e) {
                    System.out.println("DECODING ---------------------------------------------");
                    System.out.println("AttrResId: " + attrResId);
                    System.out.println(">>> " + o.getResSpec().getId().toString());
...

Output:

DECODING ---------------------------------------------
AttrResId: 16844011
>>> 0x010104eb

Grep result:

$ ./build-tools/23.0.1/aapt d --values resources ~/private.apk | grep -i 16844011
(no output)
$ ./build-tools/23.0.1/aapt d --values resources ~/private.apk | grep -i 0x010104eb
(no output)

Dumped the (int) value, which is 16844011. The grep didn't return any results though (not even for its hex-variant)...

...
                } catch (ClassCastException e) {
                    System.out.println("DECODING ---------------------------------------------");
                    System.out.println("AttrResId: " + attrResId);
                    System.out.println(">>> " + o.getResSpec().getId().toString());
...

Output:

DECODING ---------------------------------------------
AttrResId: 16844011
>>> 0x010104eb

Grep result:

$ ./build-tools/23.0.1/aapt d --values resources ~/private.apk | grep -i 16844011
(no output)
$ ./build-tools/23.0.1/aapt d --values resources ~/private.apk | grep -i 0x010104eb
(no output)

iBotPeaches added a commit that referenced this issue Oct 15, 2015

@iBotPeaches

This comment has been minimized.

Show comment
Hide comment
@iBotPeaches

iBotPeaches Oct 15, 2015

Owner

^ Give that commit a shot.

Owner

iBotPeaches commented Oct 15, 2015

^ Give that commit a shot.

@kvandermast

This comment has been minimized.

Show comment
Hide comment
@kvandermast

kvandermast Oct 16, 2015

Works like a charm! Thanks 👍

Works like a charm! Thanks 👍

@iBotPeaches iBotPeaches added this to the 2.0.3 milestone Oct 16, 2015

@jeetjshah

This comment has been minimized.

Show comment
Hide comment
@jeetjshah

jeetjshah Mar 7, 2016

@kvandermast Has the service team been able to resolve the issue with uploading the to the MobileIron MDM? Our team is experiencing a similar issue at the moment.

@kvandermast Has the service team been able to resolve the issue with uploading the to the MobileIron MDM? Our team is experiencing a similar issue at the moment.

@kvandermast

This comment has been minimized.

Show comment
Hide comment
@kvandermast

kvandermast Mar 8, 2016

@jeetjshah the issue has been escalated to MobileIron, whom recognized the problem and are preparing a patch release to fix the issue. A release date has not been communicated. But tests on the development environment indicated that the problem was fixed with a new version of the tool.

@jeetjshah the issue has been escalated to MobileIron, whom recognized the problem and are preparing a patch release to fix the issue. A release date has not been communicated. But tests on the development environment indicated that the problem was fixed with a new version of the tool.

@carl-wallace

This comment has been minimized.

Show comment
Hide comment
@carl-wallace

carl-wallace Mar 8, 2016

I ran into this issue too. I tried versions of apktool until I got the same error as Mobile Iron (2.0.0-RC4). I finally noticed that I was failing on the same resource identifier as noted above. Googling this value got a hit on the android:fullBackupContent attribute that I had defined in the application element in AndroidManifest.xml (see http://developer.android.com/reference/android/R.attr.html). Removing that value from the manifest allows apktool 2.0.0RC4 to work and I can load it into Mobile Iron.

I ran into this issue too. I tried versions of apktool until I got the same error as Mobile Iron (2.0.0-RC4). I finally noticed that I was failing on the same resource identifier as noted above. Googling this value got a hit on the android:fullBackupContent attribute that I had defined in the application element in AndroidManifest.xml (see http://developer.android.com/reference/android/R.attr.html). Removing that value from the manifest allows apktool 2.0.0RC4 to work and I can load it into Mobile Iron.

@iBotPeaches

This comment has been minimized.

Show comment
Hide comment
@iBotPeaches

iBotPeaches Mar 8, 2016

Owner

A lot of bugs are happening related to casting types. The problem stems from styles.xml becoming a more robust file with support for booleans/references/parents/ids/strings/etc. These all have to be mapped in a format that we can write back out to the user.

The current fixes of simply identifying types and reacting is hacky but will work in short term. The issue this was reported for is fixed. If there are other apks that experience ClassCastExceptions from either Strings or Styles then open another bug with the apk referencing this one.

Owner

iBotPeaches commented Mar 8, 2016

A lot of bugs are happening related to casting types. The problem stems from styles.xml becoming a more robust file with support for booleans/references/parents/ids/strings/etc. These all have to be mapped in a format that we can write back out to the user.

The current fixes of simply identifying types and reacting is hacky but will work in short term. The issue this was reported for is fixed. If there are other apks that experience ClassCastExceptions from either Strings or Styles then open another bug with the apk referencing this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment