..

Google's hidden JAR in Android Applications


Android applications that integrate the Google Play Services Ads library starting from version 10.0.0 include an encrypted JAR file containing an additional DEX file, which implements extra tracking. Although this functionality was not triggered in any of the applications I examined, the presence of this functionality raises some questions.


While examining the decompiled Java code of a random Android application, I came across some unusual encryption and decryption routines, along with a number of encrypted strings. Digging deeper, I found a huge base64-encoded string:

LKUWgWkzisgs8+2GWY/EzJjqacF7VIkG9Ha+T8/c0Rv2WrdKu19V6/aqlLTu/u/jI7vON1i5NPPShQvA6QJ9WdT...

What caught my attention was that this encrypted string was embedded within a class from the Google Play Services Ads library (which means you can see that code if you decompile any of the libraries from Maven - Play Services Ads, starting from version 10.0.0). After inspecting the encryption routine, I uncovered some interesting findings:

┌──────────────────────┐
│ encoded_data: string │
└──────────┬───────────┘
           │ base64.decode
           │
┌──────────▼───┬────────────────────────┐
│ iv: byte[16] │ encrypted_data: byte[] │
└──────────┬───┴────────────────┬───────┘
           │                    │
           ▼                    │
      AES/CBC/PKCS5 ◄───────────┘
           │
           │
┌──────────▼───┐
│ data: byte[] │
└──────────────┘

Upon decrypting the data, it became clear that it represented a JAR (Java Archive) file, which contained a single file: classes.dex. Using the decryption method outlined earlier, I was able to extract the following when attempting to decrypt an example string with Python:

['META-INF/', 'META-INF/MANIFEST.MF', 'classes.dex']

At this point, the intention behind this JAR file became clear. Some other interesting classes revealed the workflow:

  • The file is first decrypted using the method described above and temporarily saved to the /cache or /dex directory (private app files).
  • Then, the only file inside, classes.dex, is extracted and loaded using an InMemoryDexClassLoader.
  • Before resuming the DEX file gets deleted
  • The classes contained within this DEX file are responsible for gathering additional tracking data—because, of course, that’s what they do.

Important: Although the functionality to load extra classes is present, the Android application in question did not actually load any additional DEX files. Why this functionality exists in the first place, I have no idea.


Name Description
MotionEvent Collects information about a given MotionEvent. By default, the following information is extracted: elapsedTime, pressure, windowObscured, historicalPressure, x, y, touchMajor, historicalTouchMajor, toolType, deviceId
uptimeMillis Queries information about the uptime since last boot of the device.
availableProcessors The amount of available processors
date THe current date as a timestamp
screen:width/height/orientation The device’s screen-width, height and orientation
battery:status/level Information about the current battery status. The returned array contains information about the current battery status, charging level and temperature.
model the constant according to the current model (either NORMAL_DEVICE, ROOTED_DEVICE or EMULATOR_DEVICE)
usbStatus Whether the device is connected via a USB-cable.
adbEnabled Whether ADB is enabled
android-id Android-ID (AAID)
usesProxy Whether the running app is using a global HTTP-Proxy
processInfo Whether the app is running in foreground

I won’t be that guy who tells you to search for the keys by yourself. Here’s a complete list up to version 21.4.X:

Version JAR name AES Key
v10_0 “1470286953684” “t2PZ/+5cxs0OItzPKdPmkcFYX6IMfjTFHkZNA+hRNgo=”
v10_2 “1478228129219” “pWgSmgxREOizVsrpWzv2FevgkMRzEzPQ2R2fRa7gjO4=”
v11_0 “1489418796403” “QZZCt2ftWILMiOv/bx0NwH1VFPjOT+QCiqkEm96fZOY=”
v11_2 “1493867303508” “/gWMIQhNeeE0o9ImzFWAkrkA4LURH3SPZZB9Qi7zn08=”
v11_4 “1496809943795” “XDnJYBO2E96/jOXCxl3pm4VcW8g69dVlp14eaOLilDs=”
v11_6 “1501670890290” “FUnu12BLeA90PMRjjzllkVEPyqHD6uiYJ0wfE9HQOe8=”
v11_8 “1505450608132” “WKdn2zzE+pFOb2FrixdUDF+m9GVRaxGTq2U3/uOmGmE=”
v12_0 “1510898742191” “fmyYtvp6GdfV8aXECqySf5usPZLp4lFIXsdmCOa6f3I=”
v15_0 “1521499837408” “fFhi0cTZpyVQYwMwl7BCfa0fa6esmkRUaNr4ktfJYZ8=”
v16_0 - v15_0
v17_0 “1529567361524” “qDz6YvDkhwdxUOtNXedEKNdh2XDWXqUECYckxUUtMRo=”
v17_1 - v17_0
v17_2 “1542658731108” “gjATLq4PR4tBy0NKJBUs0hq7sitSgRlGcsdxPuImAoM=”
v18_0 - v17_2
v18_1 “1557357152169” “L4Jx3nWfLteifbNgb1nlz1ddHDij7T6WG7cXq30PHqM=”
v18_2 “1561154238473” “uMy2E6ap9wVg3mVwKQNsrfJRJbtVQEp/VRd7Q09cmuU=”
v18_3 “1570054248636” “4V37Zv/fqUn78vx5Tt2zbOoOKYn7HiwHmwoLsVX89T8=”
v18_4 - v18_3
v19_0 “1571257279724” “ZXQfmMb0WIh6YWGswslNgWXzCL3/RF6Ojd69jZM1GPs=”
v19_1 “1582435991586” “WxtxskzIWp7xb2ZhbqdUNS00sGJjYhs08Ug4usVoMAE=”
v19_2 “1584479576572” “IJNS0zozPMEhxshZHhAgFyrxN+YsYMK+YdGkDew63Ko=”
v19_3 “1588462714860” “9q95/1/ZSgXD7f6ulHIPUr8z7TrGmKA5+GWSXv/CYFA=”
v19_4 - v19_3
v19_5 “1596060835607” “S0dK5C0YO8sTjhVyMGQOiXGsVVkG8T8dYSBak1Q84XU=”
v19_6 “1598581401714” “aYH2WgIueW3uUAtM9Jfb3Db35FHySfU4OZ5JZXgXCVg=”
v19_7 “1608138930680” “ll+nowuQKLxZSE4zpeTvUl3Gha6AS9UBIOMBB5g+5uQ=”
v19_8 “1610724645094” “pPUxBYyr76piI8i0eva67UkfRUCvzuFdlUmAk6Mi2Tw=”
v20_0 - v19_8
v20_1 “1613498354782” “AQZlye0Qf6I1JwsO6u2s3ZPB9yudAuKGNAQ9qUeSY1g=”
v20_2 “1616432909849” “RV61Zx08QI+r0KCLhOeBrJPnsMi/yhd3p5E5I04HG2U=”
v20_3 “1621276117097” “O5+EI9qd857uJNhBPBY+hYh5U8lug4S2akyjrXXZBPw=”
v20_4 “1624498498047” “BcYDljg1B827gWFuo6QrhFDPNyXbfMHz+vF2qZ+sQXs=”
v20_5 “1629828815138” “NYpdto3gBV8HiZtFXi3NN2dSfPyfe2T+8tUnAUjRH8A=”
v20_6 “1633031840514” “BcJJ7m9GnDZ5QH3kvN4kRXKQduFKSe4hbLIA7qGtn8k=”
v21_0 “1644353911296” “RP5LQuE/2876zTvAb2rVm25QfjxwoRyidjQTLjf0RRc=”
v21_1 “1651189566953” “kMdUJlXzMwplT8jSHASgWSZqedBabCsM4bGGMxTrHLk=”
v21_2 “1655145693758” “3ti3ezo40ryM1w4gfDBvjiqMuHkyKLnrJqm+zFKeNdY=”
v21_3 “1658186039475” “HeBkX9XaSpC6sV82I6X2HUgm82vH8VhIWt26LGkrI3A=”
v21_4 “1661804530683” “Mr/If/sfOJZdBhXPwMTpWZgVNQcYf180jXHJjh6tWS8=”