Articles index

The Mystery of the Phantom App Updates

November 24, 2017

By Jeff Johnson (hire me and/or buy Underpass)

Starting on November 17, many iOS and tvOS apps that had not been updated for a year or two years suddenly received phantom updates in the App Store, without any action by the developers of those apps. The version numbers of the apps did not change. For some of the updates, the release notes were the same as the previous update. For others, the release notes said, "This update is signed with Apple's latest signing certificate. No new features are included." Some people speculated that Bitcode recompilation was performed on the apps. So far, Apple has not published any press release or documentation explaining why it updated all of these apps.

One of my purchased iOS apps received a phantom update. What really caught my attention was that I had personally worked on this app, Airfoil Satellite by Rogue Amoeba Software. Before now, Airfoil Satellite was last updated in March 2016, while I was still at the company. The new phantom update had the same version number 1.1.1 as before, and the release notes were also the same as before. I believe that Bitcode was enabled for the app. Bitcode is enabled by default for iOS apps, and I don't recall any reason for us to have disabled it for Airfoil Satellite.

Unfortunately, to the dismay of many people, Apple removed iOS app purchase and sync from iTunes 12.7. However, after the backlash, Apple quietly released iTunes 12.6.3 ostensibly for "certain business partners". Fortunately, I had installed iTunes 12.6.3, which greatly aided my investigation. iTunes downloads an iOS app as an .ipa file, which is an archive format. You can unarchive an app in Finder simply by changing the file extension from .ipa to .zip, which allows the built-in Archive Utility to recognize the file format.

I made a copy of the old Airfoil Satellite .ipa from ~/Music/iTunes/Mobile Applications and then updated the app in iTunes to download the new .ipa for comparison. After I unarchived the two app versions, I compared the folder hierarchies using FileMerge, which is part of the Xcode developer tools. Inside the Airfoil bundles there were some minor changes to the resource rules in _CodeSignature/CodeResources. There were changes to the files in the SC_Info folder, which is added to the app by Apple for their DRM. And of course the executable file was changed.

It seemed unlikely that the resource rules were the reason for the app update. The app's resources — e.g., images, Interface Builder files — were completely unchanged, so the updated _CodeSignature/CodeResources was merely a side effect of the app getting re-signed. Thus, the app's executable file became the main target of my investigation. An executable is signed with a code signing certificate. Certificates form a "chain of trust", where the validity of one certificate is guaranteed by another certificate, with the chain ultimately linking to a "root" certificate that is trusted by the system. You can reveal an app's certificate chain with the following command in Terminal:

$ codesign --display --extract-certificates [path-to-executable]

This command produces 3 files. The signing cert is codesign0, the intermediate cert is codesign1, and the root cert is codesign2. To examine the certs, I created a new keychain in Keychain Access and dragged in the 3 files from Finder. Creating a new keychain is useful because duplicate certs may not get imported into an existing keychain. From the older version of Airfoil Satellite, the signing cert Apple iPhone OS Application Signing is valid from May 2008 to May 2020. So it doesn't expire soon, but 2020 isn't too far in the future. The intermediate cert Apple iPhone Certification Authority is valid from April 2007 to April 2022, and the root cert Apple Root CA is valid from April 2006 to February 2035.

Next I examined the certs from the new version of Airfoil Satellite. The root cert is the same as before. The new intermediate cert is valid from May 2017 to December 2030, so it expires 8 years later than the old intermediate cert. The new signing cert is valid from July 2017 to August 2019. Wait… what?!? The new signing cert expires 9 months earlier than the old signing cert. Thus, if the pending expiration date were the reason for the app updates, then we're going in the wrong direction of time here.

As an experiment, for the sake of SCIENCE, I set the date forward on my iPhone to August 2, 2031, which seems to be the latest date that iOS would allow. Then I rebooted the device and attempted to launch apps, including Airfoil Satellite. Lo and behold, it worked! So there you have it, folks, definitive proof that expired signing certs do not prevent an app from launching on iOS. Thus, cert expiration does not appear to be a good reason for Apple to ship phantom app updates.

Moreover, I decided to take a look at an older app in my library that didn't receive a phantom update: Apple's own AirPort Utility. This app was last updated in September 2014, and it hasn't (yet) received a phantom App Store update. It turns out that AirPort Utility is code signed with the exact same certificate chain as the old version of Airfoil Satellite. So if there is a problem with the old signing certs, whether expiration or something else, the problem still exists with AirPort Utility. Presumably this fact would also rule out the (highly unlikely) possibility of private key compromise.

The mystery remains why Apple would need to ship phantom app updates with a new signing cert. As far as I can tell, it makes no sense. Consequently, it's worth exploring the possibility that the app updates were recompiled with Bitcode for some reason. One reason for Bitcode would be in case Apple added a new microprocessor architecture, but this is not the case currently. iPhone X and iPhone 8 have a new processor, but the A11 is just a faster chip, it doesn't use a whole new architecture. The old and new versions of Airfoil Satellite both contain the same processor architectures, armv7 and arm64, so nothing was added to the executables in that respect.

You can analyze app executables in Terminal with the command-line tool otool. The old and new versions of Airfoil Satellite are mostly the same. Only 2 things have changed: the code signature, of course, since the app was signed with a new cert, and the __TEXT,__text section, which contains the machine instructions to be executed by the app. In App Store apps, the __text section is encrypted with Apple's DRM. I've been told that you can't decrypt it without a jailbroken device, which I don't have, so I wasn't able to compare the disassembly of the old and new versions of Airfoil Satellite. Curiously, though, the __text section is exactly the same size in the old and new versions of Airfoil Satellite, for each architecture. You can see the sizes of the sections and other interesting details with the following Terminal command:

$ otool -l [path-to-executable]

It's conceivable that recompiling the Bitcode would result in the same assembly size as before, but in my opinion that's unlikely. It's even more unlikely that this would result in some kind of significant runtime performance gain, which would be the only good reason I can think of for shipping a new Bitcode compile, absent a new processor architecture. Most likely, the matching __text sizes indicate that the same machine instructions as before were simply encrypted with a new key.

Mystery unsolved. Mission unaccomplished. I'm still quite puzzled why Apple shipped all of these phantom app updates. I ask my faithful and unfaithful readers to help out with the investigation. I only had one example to analyze. If you received a phantom app update, especially if you're the developer of the app, follow my steps and compare the two versions. Even if you can't decrypt the __text, compare the sizes. The same size once is just a coincidence. The same size twice is … just a coincidence too, carrying a smoking gun.

Articles index