Ramblings of a Tampa developer

Every so often I run into Apktool used in the public eye and the creativity or use-case is always very interesting. Seeing it used for automated translations, static analysis and a variety of mass analytical research when bulk examining applications.

However, this time I doubted what I found until I triple checked my work and then asked a friend to confirm and thus this blog post.

Before we get into it, we need to look into some history/context of an Apktool feature. If you were to dump the resources of an application (without Apktool). We would use a tool known as Android Asset Packaging Tool (AAPT), which is crucial to building applications but also has a few helper functions for viewing a compiled application.

I've done a post about AAPT before, but this time we are only interested in dumping resources.

aapt d resources 
....
spec resource 0x7f0d00a2 com.nianticproject.ingress:id/textview_track_name
spec resource 0x7f0d00a3 com.nianticproject.ingress:id/gridview
INVALID TYPE CONFIG FOR RESOURCE 0x7f0d00a4
spec resource 0x7f0d00a5 com.nianticproject.ingress:id/placeholder

So what we are interested in is the line about "INVALID TYPE CONFIG", which can mean a variety of things depending on the situation.

  • No package identifier for resource number
  • No known package when getting name from resource number
  • No type identifier when getting name from resource number
  • Bad identifier when getting name from resource number
  • No packages found from resource
  • Bad index for the resource

So basically, unless you understand and debug the low level of Android build tools - you probably don't know why a single resource experiences this behavior. However, we can't just remove this resource because then if we rebuild the application without constant resource identifiers - we might shift all resources by however many ids we remove.

So reverse engineering tools (Like Apktool) that have to rebuild applications after disassembly need to do something with these bugged resources. So here is where Apktool comes in. It generates dummy resources so the resource table isn't malformed due to removing resources.

For the resource above, Apktool would generate something like this.

spec resource 0x7f0d00a4 com.nianticproject.ingress:id/APKTOOL_DUMMY_a4

Since we know the type information, we generate a resource in that same class (or in the case of the above resource - an ID.

<item type="id" name="APKTOOL_DUMMY_a4" />

So now Apktool continues to function and the application can be rebuilt without destroying the resource table.

So now onward to the point of this blog post. Ingress v.131.2 was the last version of Ingress before Ingress Prime went public. When Ingress Prime went public they simply released the major "2.0" over the existing 1.0 application. This upset many, because Ingress Prime did not have feature parity yet with "1.0".

Niantic announced that it would re-release Ingress "1.0" under "Scanner [REDACTED]" as soon as possible. So agents could continue to use the old version while the new version gained feature parity.

It appears Niantic used Apktool to release Scanner [REDACTED].

From the information we learned above about dummy resources. We can dump and grep for Apktool resource names from the old version (1.131.2) and the [redacted] version of 1.134.5.

➜  Desktop aapt d resources com.nianticproject.ingress_1.131.2-11312_minAPI14\(armeabi,armeabi-v7a\)\(nodpi\)_apkmirror.com | grep 'APKTOOL'
➜  Desktop aapt d resources com.nianticlabs.ingress.prime.qa_1.134.5-3013405_minAPI14\(armeabi,armeabi-v7a\)\(nodpi\)_apkmirror.com.apk| grep 'APKTOOL'
      spec resource 0x7f020034 com.nianticproject.ingress:drawable/APKTOOL_DUMMY_34: flags=0x40000000
      spec resource 0x7f020039 com.nianticproject.ingress:drawable/APKTOOL_DUMMY_39: flags=0x40000000
      spec resource 0x7f02003b com.nianticproject.ingress:drawable/APKTOOL_DUMMY_3b: flags=0x40000000
      spec resource 0x7f020071 com.nianticproject.ingress:drawable/APKTOOL_DUMMY_71: flags=0x40000000

Which as you can see. Has 0 results for Ingress v1.0 and too many to count for Scanner [REDACTED].

So why did they do this?

We need to understand package names to answer that question. Ingress classic lived under the package name - "com.nianticproject.ingress" and so when Ingress Prime (a entire new client) was released it also had to inherit that package name.

So I think you see the problem. In order to re-release an old version as a new version they needed to pick a new package name. Since you can't have two applications on the Google Play Store with same package name. With legacy Android projects, changing something as root level as package name isn't easy. You probably can complete it in a few steps though, as shown here on StackOverflow.

However, with Apktool you could do it in just a few steps and don't need even the source of the application or a fancy IDE. However, the amount of changes that could occur from reverse-engineering an application and rebuilding is too much to trust using Apktool for a production application.

However, Niantic did just that.

They renamed "com.nianticproject.ingress" to "com.nianticlabs.ingress.prime.qa" and released it here and Apktool unintentionally left its fingerprint throughout the application as they used it.

If Niantic stumbles upon this post, feel free to reach out. Curious if I was correct in my research on why Apktool was used.

md5 sums

6d8b9df531a9d9158f30bdb51149ce20  com.nianticproject.ingress_1.131.2-11312_minAPI14(armeabi,armeabi-v7a)(nodpi)_apkmirror.com.apk

d609aa9d023486ed15d078b3731c734b  com.nianticlabs.ingress.prime.qa_1.134.5-3013405_minAPI14(armeabi,armeabi-v7a)(nodpi)_apkmirror.com.apk