> ## Content Index
> Fetch the complete content index at: https://connortumbleson.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Apktool: Fixing Bug 713
- URL: https://connortumbleson.com/2015/02/16/fixing-apktool-bug713/
- Published: 2015-02-16T19:16:54.000Z
- Updated: 2018-08-22T01:19:23.000Z
- Author: Connor Tumbleson
- Tags: Apktool

![](https://connortumbleson.com/content/images/2015/02/bugs-1.png)  
*This is my first technical blog exploring the path of fixing one of Apktool's more complicated bugs*

Around December of 2014, Lollipop builds of LG started being leaked to the public. I got a bug report, shortly after, saying that decoding had stopped working in Apktool. Already having previously [patched](https://github.com/iBotPeaches/Apktool/pull/97/files?ref=connortumbleson.com) Lollipop support I was quite confused in what had broken.

So lets step in and see what the problem is.

```language-bash
$apktool if lge-res.apk -t bug713
I: Framework installed to: /home/ibotpeaches/apktool/framework/0-bug713.apk
$apktool if framework-res.apk -t bug713
I: Framework installed to: /home/ibotpeaches/apktool/framework/1-bug713.apk

```

Then lets do the decode.

```language-bash
$apktool d UnifiedEULA.apk -t bug713
I: Using Apktool 2.0.0-RC3 on UnifiedEULA.apk
I: Loading resource table
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /home/ibotpeaches/apktool/framework/1-bug713.apk
W: Could not decode attr value, using undecoded value instead: ns=android, name=label, value=0x7f080000
W: Could not decode attr value, using undecoded value instead: ns=android, name=icon, value=0x7f02000c
W: Could not decode attr value, using undecoded value instead: ns=android, name=label, value=0x7f08001e
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
Exception in thread "main" brut.androlib.err.UndefinedResObject: resource spec: 0x7f080000

```

Wait what? Why did `lge-res.apk` install as `0-bug713.apk`? The leading integer represents the packageId, and I haven't ever seen a valid packageId of 0 before. Generally Android uses 1 for `framework-res.apk` and 2-9 for other framework files. So we have spotted our first error in that `lge-res.apk` is installing incorrectly.

Secondly, `UnifiedEULA.apk` is failing to decode with a few resources. If we examine the first resource `0x7f080000`. We can pull that resourceId apart to understand it.

- `0x7f` \= `packageId`
- `0x08` \= `typeId`
- `0x0000` \= `entryId`

So a packageId of `0x7f` represents a local package. This means the resource table we are looking for is present in this APK (`UnifiedEULA`). So why didn't it find it? Lets double check using aapt (Android Asset Packaging Tool) to make sure this resource is in fact here.

```language-bash
$aapt d resources UnifiedEULA.apk | grep '0x7f080000'
  spec resource 0x7f080000 com.lge.eula:string/app_name: flags=0x00000004
    resource 0x7f080000 com.lge.eula:string/app_name: t=0x03 d=0x00000060 (s=0x0008 r=0x00)

```

So yes, the resource we are looking for is infact in this APK. This points to a fault in the decoding process of Apktool.

**So why is lge-res installing as pkgId 0?**

Lets go back to our trustworthy aapt and see what it has to say.

```language-bash
$aapt d resources lge-res.apk | more
  Package Groups (1)
   Package Group 0 id=0x02 packageCount=1 name=com.lge
    Package 0 id=0x00 name=com.lge

```

Uh what. How come aapt is reporting the packageId as `0x02` but Apktool is identifying it as `0x00`?

Lets take a peek into the source of Apktool and see if a mistake is occurring.

![](https://connortumbleson.com/content/images/2015/02/boom.png)

Well thats not good. Reading the `int` directly from the stream reports as `0` as well. So lets take a look at a hex dump of the `resources.arsc` file.

![](https://connortumbleson.com/content/images/2015/02/o2oRkgK--1-.png)

As you can see the int (4 bytes prior to highlighted packageName) is `0`. So this means we have a change in AOSP that has changed the basic storage of packageIds.

I started to look at the release documents of Lollipop but found nothing that had anything to do with packageIds. So off to the repository I go. I generally look in `platform_frameworks_base` and the subfolder `tools/aapt`. This gave me about \~100 commits to look through between Kitkat and now.

I started skimming the commit messages and spotted "[Shared library resource support](https://github.com/android/platform%5Fframeworks%5Fbase/commit/de898ff42912bd7ca1bfb099cd439562496765a4?ref=connortumbleson.com)". This sounded like something related and sure enough the commit message confirmed.

```language-git
Shared libraries can now export resources for applications to use.
    
Exporting resources works the same way the framework exports
resources, by defining the public symbols in res/values/public.xml.
    
Building a shared library requires aapt to be invoked with the
--shared-lib option. Shared libraries will be assigned a package
ID of 0x00 at build-time. At runtime, all loaded shared libraries
will be assigned a new package ID.
    
Currently, shared libraries should not import other shared libraries,
as those dependencies will not be loaded at runtime.
    
At runtime, reflection is used to update the package ID of resource
symbols in the shared library's R class file. The package name of
the R class file is assumed to be the same as the shared library's
package name declared in its manifest. This will be customizable in
a future commit.
    
See /tests/SharedLibrary/ for examples of a shared library and its
client.
    
Bug:12724178
Change-Id: I60c0cb8ab87849f8f8a1a13431562fe8603020a7

```

So incase you missed it. Check out the 3rd paragraph.

> Building a shared library requires aapt to be invoked with the  
> `--shared-lib` option. **Shared libraries will be assigned a package** 
> **ID of 0x00 at build-time**. At runtime, all loaded shared libraries will be assigned a new package ID.

So we have found our culprit. This APK is using this new method of shared library resources. Thus, its packageId is set at runtime instead of buildtime.

The problem still remains though that our APKs can't decode unless they know the packageId of the resources. If you remember from above though, aapt had correctly determined the packageId of `0x02`. How did it do that?

We take a look at the `libs/androidfw/ResourceTypes.cpp` file.

```language-git
ResTable::ResTable()
-    : mError(NO_INIT)
+    : mError(NO_INIT), mNextPackageId(2)

```

As you can see from the diff report. The packageId is literally just hardcoded as 2.

So I patched Apktool quite abruptly with.

```language-java
if (id == 0) {
    // This means we are dealing with a Library Package, we should just temporarily
    // set the packageId to the next available id . This will be set at runtime regardless, but
    // for Apktool's use we need a non-zero packageId.
    // AOSP indicates 0x02 is next, as 0x01 is system and 0x7F is private.
    id = 2;
}

```

Would it be that simple? Lets try again.

```language-bash
$apktool if lge-res.apk -t bug713
I: Framework installed to: /home/ibotpeaches/apktool/framework/2-bug713.apk

```

Good good. We have a correct packageId now. Lets try the decode again. I'll save you the stacktrace and just tell you. It failed, with the same error as before.

So why aren't resources being decoded? In Apktool we have two sets that hold all the resources decoded.

```language-java
private final Set<ResPackage> mMainPackages = new LinkedHashSet<ResPackage>();
private final Set<ResPackage> mFramePackages = new LinkedHashSet<ResPackage>();

```

with each `ResPackage` containing a Map of resources indexed by the resourceId.

```language-java
private final Map<ResID, ResResSpec> mResSpecs = new LinkedHashMap<ResID, ResResSpec>();

```

Each `ResResSpec` contains

```language-java
public ResResSpec(ResID id, String name, ResPackage pkg, ResType type) {
    this.mId = id;
    this.mName = name;
    this.mPackage = pkg;
    this.mType = type;
}

```

So I set a breakpoint during this failure and was astounded. The `mMainPackages` count for `mResSpecs` was at 0\. We had 0 `ResResSpecs`. So decoding was failing badly. Badly enough that not even a single resource was decoded.

So I went as far back into the Apktool procedure where `mResSpecs` was populated. Back in the process of Apktool, during decoding of the `ResPackage`, we read the `ResTypes` which in turn reads the configs (`readConfigs`), which in turn reads the resources (`readEntry`) of that configuration.

```language-java
while (mHeader.type == Header.TYPE_TYPE) {
    readType();
}

```

So why was this check (shown above) failing? `Header.TYPE_TYPE` was `0x0202`, and `mHeader.type` was `0x0203` and Apktool has no support for whatever that was corresponding to.

It appears we have something new, so back to the source (`include/androidfw/ResourceTypes.h`) we go.

```language-git
-    RES_TABLE_TYPE_SPEC_TYPE    = 0x0202
+    RES_TABLE_TYPE_SPEC_TYPE    = 0x0202,
+    RES_TABLE_LIBRARY_TYPE      = 0x0203

```

We have found the new type and its called `LIBRARY_TYPE`. This type is before `TYPE_SPEC_TYPE` in the current APK. So Apktool is failing because it has no support for these. So referencing the linked commit above I found these additional structs.

```language-cpp
/**
 * A package-id to package name mapping for any shared libraries used
 * in this resource table. The package-id's encoded in this resource
 * table may be different than the id's assigned at runtime. We must
 * be able to translate the package-id's based on the package name.
 */
struct ResTable_lib_header
{
    struct ResChunk_header header;

    // The number of shared libraries linked in this resource table.
    uint32_t count;
};

/**
 * A shared library package-id to package name entry.
 */
struct ResTable_lib_entry
{
    // The package-id this shared library was assigned at build time.
    // We use a uint32 to keep the structure aligned on a uint32 boundary.
    uint32_t packageId;

    // The package name of the shared library. \0 terminated.
    char16_t packageName[128];
};

```

So in short. If we encounter a chunk with a value of `0x0203` or `TYPE_LIBRARY` in the header, we then need to iterate over `count` and read the `packageId` & `packageName` for each count. Adding a quick patch into the `brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java` file.

We add the following function.

```language-java
private void readLibraryType() throws AndrolibException, IOException {
    checkChunkType(Header.TYPE_LIBRARY);
    int libraryCount = mIn.readInt();

    int packageId;
    String packageName;

    for (int i = 0; i < libraryCount; i++) {
        packageId = mIn.readInt();
        packageName = mIn.readNullEndedString(128, true);
        LOGGER.info(String.format("Decoding Shared Library (%s), pkgId: %d", packageName, packageId));
    }
}

```

With the check added in `readPackage()` we are left with this new functionality.

```language-git
     mPkg = new ResPackage(mResTable, id, name);
     nextChunk();
         
+    while (mHeader.type == Header.TYPE_LIBRARY) {
+        readLibraryType();
+    }

     while (mHeader.type == Header.TYPE_TYPE) {
         readType();
     }

```

This full commit may be found [here](https://github.com/iBotPeaches/Apktool/commit/e9d21f84af8522ef797a4016b0266f394b9a5650?ref=connortumbleson.com). So we now are going to check for `TYPE_LIBRARY` and `TYPE_TYPE` respectively. Time to test again with our previously broken `UnifiedEULA.apk`.

```language-bash
$apktool d UnifiedEULA.apk -t bug713
I: Using Apktool 2.0.0-RC3 on UnifiedEULA.apk
I: Loading resource table...
I: Decoding Shared Library (com.lge), pkgId: 2
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /home/ibotpeaches/apktool/framework/1-bug713.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...
$

```

Now lets check if the shared resource is correctly referenced during rebuild.

```language-bash
$ apktool b UnifiedEULA
I: Using Apktool 2.0.0-RC3
I: Checking whether sources has changed...
I: Smaling smali folder into classes.dex...
I: Checking whether resources has changed...
I: Building resources...
I: Building apk file...
$

```

It built! So we correctly found the undocumented feature of "shared library resources" and added preliminary support for it.

That was the journey of fixing bug 713 of Apktool. While writing about it was quite easy, there was lots of delays in the original patch while I looked for commits, source, etc.

Thanks for the read and hope you liked my first technical writeup. Comments/critiques good or bad are appreciated!.