Open baltpeter opened 2 months ago
The iOS apps that I have on hand (all downloaded from the app store), have an iTunesMetadata.plist
file that looks just like what we are looking for. Here's an example:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>MacUIRequiredDeviceCapabilities</key>
<dict>
<key>arm64</key>
<true/>
</dict>
<key>UIRequiredDeviceCapabilities</key>
<dict>
<key>arm64</key>
<true/>
</dict>
<key>apple-id</key>
<string>abc@icloud.com</string>
<key>artistId</key>
<integer>281941100</integer>
<key>artistName</key>
<string>Bloomberg Finance LP</string>
<key>bundleDisplayName</key>
<string>Bloomberg</string>
<key>bundleShortVersionString</key>
<string>5.69.0</string>
<key>bundleVersion</key>
<string>3266194</string>
<key>copyright</key>
<string>© Bloomberg L.P.</string>
<key>drmVersionNumber</key>
<integer>0</integer>
<key>fileExtension</key>
<string>.app</string>
<key>gameCenterEnabled</key>
<false/>
<key>gameCenterEverEnabled</key>
<false/>
<key>genre</key>
<string>News</string>
<key>genreId</key>
<integer>6009</integer>
<key>hasOrEverHasHadIAP</key>
<true/>
<key>itemId</key>
<integer>281941097</integer>
<key>itemName</key>
<string>Bloomberg: Business News</string>
<key>kind</key>
<string>software</string>
<key>playlistName</key>
<string>Bloomberg Finance LP</string>
<key>product-type</key>
<string>ios-app</string>
<key>rating</key>
<dict>
<key>content</key>
<string>Advisory.NO.TRUE_GAMBLING , Advisory.NO.GAMBLING_CONTESTS and Advisory.NO.UNRESTRICTED_WEB_ACCESS</string>
<key>label</key>
<string>4+</string>
<key>rank</key>
<integer>100</integer>
<key>system</key>
<string>itunes-games</string>
</dict>
<key>releaseDate</key>
<string>2019-02-01T08:00:00Z</string>
<key>requiresRosetta</key>
<false/>
<key>runsOnAppleSilicon</key>
<true/>
<key>runsOnIntel</key>
<false/>
<key>s</key>
<integer>143443</integer>
<key>software-platform</key>
<string>ios</string>
<key>softwareIcon57x57URL</key>
<string>https://is2-ssl.mzstatic.com/image/thumb/Purple116/v4/d9/ec/35/d9ec3598-9db4-ef73-e7de-5da9863518e6/AppIcon-0-0-1x_U007emarketing-0-0-0-7-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/114x114bb.jpg</string>
<key>softwareIconNeedsShine</key>
<false/>
<key>softwareSupportedDeviceIds</key>
<array>
<integer>2</integer>
<integer>9</integer>
<integer>4</integer>
</array>
<key>softwareVersionBundleId</key>
<string>com.bloomberg.Bloomberg</string>
<key>softwareVersionExternalIdentifier</key>
<integer>847839440</integer>
<key>softwareVersionExternalIdentifiers</key>
<array>
<integer>10992</integer>
<integer>21242</integer>
<integer>294794</integer>
<integer>493163</integer>
<integer>1154963</integer>
<integer>1323563</integer>
<integer>1468803</integer>
<integer>1478344</integer>
<integer>1607362</integer>
<integer>1698583</integer>
<integer>1741745</integer>
<integer>1836081</integer>
<integer>1889054</integer>
<integer>1910403</integer>
<integer>1964132</integer>
<integer>2110833</integer>
<integer>2209612</integer>
<integer>2564521</integer>
<integer>2778106</integer>
<integer>2843541</integer>
<integer>3066209</integer>
<integer>3124625</integer>
<integer>3225082</integer>
<integer>3263940</integer>
<integer>3321795</integer>
<integer>3459605</integer>
<integer>3649073</integer>
<integer>3808125</integer>
<integer>3895935</integer>
<integer>4005183</integer>
<integer>4050663</integer>
<integer>4212102</integer>
<integer>4352583</integer>
<integer>7115631</integer>
<integer>7374923</integer>
<integer>14060260</integer>
<integer>51622652</integer>
<integer>73762652</integer>
<integer>244582844</integer>
<integer>306772964</integer>
<integer>355842641</integer>
<integer>386272692</integer>
<integer>518922646</integer>
<integer>591032673</integer>
<integer>597022697</integer>
<integer>614703182</integer>
<integer>646922650</integer>
<integer>661362683</integer>
<integer>693013996</integer>
<integer>730452810</integer>
<integer>749123468</integer>
<integer>755332750</integer>
<integer>776622680</integer>
<integer>810914842</integer>
<integer>811130357</integer>
<integer>811445595</integer>
<integer>811535406</integer>
<integer>811689997</integer>
<integer>811827009</integer>
<integer>811968285</integer>
<integer>812205164</integer>
<integer>812512200</integer>
<integer>812877726</integer>
<integer>813139137</integer>
<integer>813516953</integer>
<integer>813680781</integer>
<integer>813944394</integer>
<integer>814209438</integer>
<integer>815386087</integer>
<integer>815956508</integer>
<integer>816107575</integer>
<integer>816140570</integer>
<integer>816148663</integer>
<integer>816275381</integer>
<integer>816357848</integer>
<integer>816664875</integer>
<integer>816774705</integer>
<integer>816949878</integer>
<integer>817135995</integer>
<integer>817257857</integer>
<integer>817351469</integer>
<integer>817467912</integer>
<integer>817555116</integer>
<integer>818141801</integer>
<integer>818313438</integer>
<integer>818845438</integer>
<integer>819087154</integer>
<integer>819984767</integer>
<integer>820257255</integer>
<integer>820398137</integer>
<integer>820740072</integer>
<integer>821657543</integer>
<integer>821708116</integer>
<integer>822040722</integer>
<integer>822176464</integer>
<integer>822304553</integer>
<integer>822526063</integer>
<integer>822572872</integer>
<integer>822625493</integer>
<integer>822677648</integer>
<integer>822764899</integer>
<integer>822874773</integer>
<integer>823330440</integer>
<integer>823681197</integer>
<integer>823933243</integer>
<integer>823969249</integer>
<integer>824086550</integer>
<integer>824231771</integer>
<integer>825405200</integer>
<integer>825516711</integer>
<integer>825568914</integer>
<integer>825800882</integer>
<integer>825845855</integer>
<integer>826155030</integer>
<integer>826192540</integer>
<integer>826223419</integer>
<integer>826326951</integer>
<integer>826364292</integer>
<integer>826594231</integer>
<integer>826635250</integer>
<integer>826708681</integer>
<integer>826751991</integer>
<integer>826788459</integer>
<integer>826934248</integer>
<integer>827211308</integer>
<integer>827253956</integer>
<integer>827432827</integer>
<integer>827466182</integer>
<integer>827565809</integer>
<integer>827681659</integer>
<integer>827759307</integer>
<integer>827850348</integer>
<integer>827963934</integer>
<integer>827993773</integer>
<integer>828154093</integer>
<integer>828323814</integer>
<integer>828497578</integer>
<integer>828585442</integer>
<integer>828700453</integer>
<integer>828766157</integer>
<integer>828970543</integer>
<integer>829077067</integer>
<integer>829187285</integer>
<integer>829311279</integer>
<integer>829506734</integer>
<integer>829593801</integer>
<integer>829609241</integer>
<integer>829883094</integer>
<integer>830094665</integer>
<integer>830379216</integer>
<integer>830475567</integer>
<integer>830508876</integer>
<integer>830885618</integer>
<integer>831272694</integer>
<integer>831521482</integer>
<integer>831678487</integer>
<integer>831795102</integer>
<integer>831995899</integer>
<integer>832133598</integer>
<integer>832329295</integer>
<integer>832576398</integer>
<integer>832634100</integer>
<integer>832864140</integer>
<integer>833115864</integer>
<integer>833439251</integer>
<integer>833912202</integer>
<integer>833937027</integer>
<integer>833970683</integer>
<integer>834158169</integer>
<integer>834309082</integer>
<integer>834404922</integer>
<integer>834443876</integer>
<integer>834636844</integer>
<integer>834640362</integer>
<integer>834818832</integer>
<integer>835045141</integer>
<integer>835094139</integer>
<integer>835202299</integer>
<integer>835369365</integer>
<integer>835590493</integer>
<integer>835786537</integer>
<integer>836023547</integer>
<integer>836088947</integer>
<integer>836200242</integer>
<integer>836321200</integer>
<integer>836373594</integer>
<integer>836598828</integer>
<integer>836797280</integer>
<integer>837001632</integer>
<integer>837276800</integer>
<integer>837565142</integer>
<integer>837589674</integer>
<integer>837861559</integer>
<integer>838085546</integer>
<integer>838250997</integer>
<integer>838454352</integer>
<integer>838538531</integer>
<integer>839116992</integer>
<integer>839347069</integer>
<integer>839468892</integer>
<integer>839803201</integer>
<integer>840167584</integer>
<integer>840379763</integer>
<integer>840554745</integer>
<integer>840768317</integer>
<integer>840980853</integer>
<integer>841219428</integer>
<integer>841601636</integer>
<integer>842009827</integer>
<integer>842221990</integer>
<integer>842425731</integer>
<integer>842629536</integer>
<integer>842829918</integer>
<integer>843023602</integer>
<integer>843230972</integer>
<integer>843477729</integer>
<integer>843742581</integer>
<integer>843952104</integer>
<integer>844178627</integer>
<integer>844252257</integer>
<integer>844431671</integer>
<integer>844716233</integer>
<integer>845028803</integer>
<integer>845311036</integer>
<integer>845594234</integer>
<integer>845829944</integer>
<integer>846447442</integer>
<integer>846788771</integer>
<integer>847015166</integer>
<integer>847246950</integer>
<integer>847336002</integer>
<integer>847526858</integer>
<integer>847839440</integer>
</array>
<key>userName</key>
<string>abc@icloud.com</string>
<key>vendorId</key>
<integer>8949</integer>
<key>versionRestrictions</key>
<integer>0</integer>
</dict>
</plist>
Information that I can see immediately:
apple-id
).artistId
)bundleId
here, usually called adam_id
by Apple)
https://apps.apple.com/app/id<bundleId>
Currently[^dma], there of course aren't exactly many ways of distributing apps for iOS. However, tweaks and apps for jailbroken devices are a thing. So, while I would assume that "presence of iTunesMetadata.plist
" iff "app was downloaded from the App Store", we'll have to verify that.
[^dma]: I guess, we'll have to re-evaluate that once the first "DMA App Stores" pop up. :D
I've downloaded a whole bunch of IPAs from various… unofficial sources. None of them had an iTunesMetadata.plist
file.
On Android, meanwhile this is a lot harder (impossible, maybe?).
We can verify an app's signature using keytool -printcert -jarfile <app.apk>
(https://security.stackexchange.com/a/226815).
For some apps, this will output a signature from Google:
❯ keytool -printcert -jarfile be.stib.mivb.mobile-203137.apk
Signer #1:
Certificate #1:
Owner: CN=Android, OU=Android, O=Google Inc., L=Mountain View, ST=California, C=US
Issuer: CN=Android, OU=Android, O=Google Inc., L=Mountain View, ST=California, C=US
Serial number: 583ce60a3e6050859f1b5ca6a563c1c217272cd7
Valid from: Tue Jun 12 17:12:40 CEST 2018 until: Fri Jun 12 17:12:40 CEST 2048
Certificate fingerprints:
SHA1: CF:9F:C9:31:79:42:D9:21:51:D3:C9:8B:E6:8B:E3:BB:97:2A:77:9C
SHA256: AB:D9:92:5E:3A:D9:D1:E9:C4:6C:E4:A8:43:4D:2C:72:19:08:B4:A9:7B:0B:77:E7:2C:8F:D6:69:32:09:AB:06
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 4096-bit RSA key
Version: 3
Extensions:
#1: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:true
PathLen: no limit
]
And it also makes it possible to identify F-Droid apps:
❯ keytool -printcert -jarfile org.mozilla.fennec_fdroid_1092020.apk
Signer #1:
Certificate #1:
Owner: CN=FDroid, OU=FDroid, O=fdroid.org, L=ORG, ST=ORG, C=UK
Issuer: CN=FDroid, OU=FDroid, O=fdroid.org, L=ORG, ST=ORG, C=UK
Serial number: 53f12705
Valid from: Sun Feb 01 18:48:32 CET 2015 until: Thu Jun 19 19:48:32 CEST 2042
Certificate fingerprints:
SHA1: F5:54:5E:C2:F9:68:1D:40:BA:42:11:A0:96:7A:3B:BD:4F:4B:F5:4B
SHA256: 06:66:53:58:EF:D8:BA:05:BE:23:6A:47:A1:2C:B0:95:8D:7D:75:DD:93:9D:77:C2:B3:1F:53:98:53:7E:BD:C5
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3
Extensions:
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 7B 90 A2 0F E4 70 F3 8A E4 E5 77 6B F2 B6 73 45 .....p....wk..sE
0010: BA 19 15 E3 ....
]
]
However, this does not work for all apps from the Play Store, some are self-signed or unsigned(?):
❯ keytool -printcert -jarfile com.digibites.accubattery-201004.apk
Signer #1:
Certificate #1:
Owner: O=Digibites Technology, L=Rotterdam, ST=Zuid-Holland, C=NL
Issuer: O=Digibites Technology, L=Rotterdam, ST=Zuid-Holland, C=NL
Serial number: 2525ae18
Valid from: Tue Mar 22 12:13:51 CET 2016 until: Wed Feb 27 12:13:51 CET 2115
Certificate fingerprints:
SHA1: 7C:AC:F9:2E:A3:02:DE:15:D6:5A:CA:84:9D:FF:A3:3F:F6:D2:96:12
SHA256: 64:A5:40:DE:F3:35:EF:35:08:80:CB:66:08:C9:26:5B:B4:CB:F7:FB:DE:40:D3:D8:C0:6A:EB:99:7C:27:63:5E
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3
Extensions:
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 32 95 C1 8A 67 16 D3 22 EC E6 56 B9 32 89 80 0F 2...g.."..V.2...
0010: 60 0B 53 F9 `.S.
]
]
❯ keytool -printcert -jarfile com.airbnb.android-28003318.apk
Not a signed jar file
And for the other Android app formats we support:
XAPK: When downloaded from APKPure, these appear to have ZIP file comments indicating such (zipinfo -v <file.xapk>
):
Raw APKs from APKPure appear to retain their original signature, which makes sense. And I feel like it is also fair to classify them as coming from the Play Store in this case, since they are literally the exact same file.
❯ keytool -printcert -jarfile STIB-MIVB_2.7.3_Apkpure.apk
Signer #1:
Certificate #1:
Owner: CN=Android, OU=Android, O=Google Inc., L=Mountain View, ST=California, C=US
Issuer: CN=Android, OU=Android, O=Google Inc., L=Mountain View, ST=California, C=US
Serial number: 583ce60a3e6050859f1b5ca6a563c1c217272cd7
Valid from: Tue Jun 12 17:12:40 CEST 2018 until: Fri Jun 12 17:12:40 CEST 2048
Certificate fingerprints:
SHA1: CF:9F:C9:31:79:42:D9:21:51:D3:C9:8B:E6:8B:E3:BB:97:2A:77:9C
SHA256: AB:D9:92:5E:3A:D9:D1:E9:C4:6C:E4:A8:43:4D:2C:72:19:08:B4:A9:7B:0B:77:E7:2C:8F:D6:69:32:09:AB:06
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 4096-bit RSA key
Version: 3
Extensions:
#1: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:true
PathLen: no limit
]
APKM files from APKMirror contain an APKM_installer.url
:
[InternetShortcut]
URL=https://www.apkmirror.com/installer
They are also signed:
❯ keytool -printcert -jarfile de.exaring.waipu_2024.7.0-627905_2arch_1dpi_14lang_cd16c95160d887e6b0dec2086eb1aa31_apkmirror.com.apkm
Signer #1:
Certificate #1:
Owner: CN=APKMirror.com, OU=APKMirror.com, O=APKMirror.com, L=San Francisco, ST=California, C=US
Issuer: CN=APKMirror.com, OU=APKMirror.com, O=APKMirror.com, L=San Francisco, ST=California, C=US
Serial number: 1449abd5
Valid from: Wed Jul 24 16:20:09 CEST 2019 until: Fri Jun 30 16:20:09 CEST 2119
Certificate fingerprints:
SHA1: E6:FF:20:92:50:78:84:16:6D:18:74:BC:BD:6C:77:5B:33:4D:8C:2A
SHA256: 7B:1A:6D:25:E5:E8:71:1A:6E:79:28:3D:F1:0C:64:8B:47:A4:20:C4:E5:41:3C:2C:51:35:1A:8C:A5:08:DE:25
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3
Extensions:
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 71 B1 93 3F E0 23 7E F8 5B 6B 22 73 B3 99 47 F0 q..?.#..[k"s..G.
0010: 5B 7A 87 EA [z..
]
]
Raw APKs also retain their signature:
❯ keytool -printcert -jarfile com.bonial.kaufda_24.8.1-1039328_minAPI23\(arm64-v8a,armeabi-v7a,x86,x86_64\)\(nodpi\)_apkmirror.com.apk
Signer #1:
Certificate #1:
Owner: CN=kaufDA.de, OU=kaufDA, O=Juno Internet GmbH, L=Berlin, ST=Berlin
Issuer: CN=kaufDA.de, OU=kaufDA, O=Juno Internet GmbH, L=Berlin, ST=Berlin
Serial number: 4c359512
Valid from: Thu Jul 08 11:06:26 CEST 2010 until: Mon Jul 02 11:06:26 CEST 2035
Certificate fingerprints:
SHA1: A9:B7:8D:CE:CE:46:98:F3:B8:32:02:01:D7:79:EE:AC:8D:39:90:B8
SHA256: F2:B5:1D:2C:85:66:91:81:8C:01:F9:B9:3C:91:30:34:31:2A:F8:E7:C6:3C:0B:0E:0A:58:2E:73:9D:2E:C7:64
Signature algorithm name: SHA1withRSA (weak)
Subject Public Key Algorithm: 1024-bit RSA key (weak)
Version: 3
Warning:
The certificate uses the SHA1withRSA signature algorithm which is considered a security risk. This algorithm will be disabled in a future update.
The certificate uses a 1024-bit RSA key which is considered a security risk. This key size will be disabled in a future update.
Oh, actually: it seems like a good idea to also include the signature in the app meta. That way we could show that we performed the analysis on an unmodified app as distributed by the developer.
While it would definitely be useful to have all this information extracted automatically, this seems like a bigger rabbit hole than we should be going down right now. Let's put this on the back burner for now.
Can we get this data from the app files?
See https://github.com/tweaselORG/cyanoacrylate/issues/39 for why we need that.