Gatekeeper has been generous to a fault in the past. Once an app had passed its first-run checks, in most circumstances it was left well alone, and didn’t undergo further thorough checks. For apps that updated themselves, this was a great help, as the updater could change them extensively without having to sign them again. However, it also allowed malicious modifications, and the strange situation that XProtect malware signature updates weren’t applied to existing apps. This all changes as of macOS Ventura, as this article explains.
When a quarantined app is run for the first time, in addition to it being translocated to a distant folder, five sets of checks are run:
- The app’s signing certificate is checked, to ensure its validity, and its chain of trust to Apple’s root certificate. If it’s not signed by Apple or a Developer ID Application certificate, then an ad hoc certificate is expected on Apple silicon systems.
- The app’s integrity is checked against its secure hashes (cdhashes) to ensure that protected parts of the app haven’t been altered since signing.
- The app is scanned for malware signatures, according to the current list provided by XProtect.
- Notarization is checked, preferably in a ticket stapled to the app, but if that’s not available (as with command tools), it’s checked with Apple’s records.
- App sandbox, entitlements and hardening are also checked, as they determine the runtime environment to be provided.
For some years, once an app had cleared those initial checks, they wouldn’t be repeated unless it was moved, or something set its quarantine flag. This allowed many apps with broken signatures or failed cdhashes to continue to run normally.
Every time you run an app or other executable code, such as a command tool, those first run checks are now repeated, although not quite in the same depth, and with slightly greater tolerance for minor errors, it appears. This is easy to demonstrate.
Create a folder in a convenient location such as ~/Documents, and copy to that an existing signed app. Because older macOS is sensitive to changing the location of apps, open the app from that folder and verify that it runs correctly. Quit it, then modify one byte within it. For example, using a text editor change a character in the copyright information in the app’s Info.plist, or using a binary editor alter a character of text within the app binary in Contents/MacOS.
If you’re lucky, you might see a rejection alert when you try run the app.
In some cases, you may be allowed to try Command-Click and the Open command to try bypassing this refusal, and that may even give you a second chance.
If you try to open the app from there, it should be crashed immediately because of its signature error.
Check the signature
Although I have some utilities that will check signatures, by far the best is Apparency from Mothers Ruin. Once fully installed, this adds QuickLook preview information about app signatures, and a button to view that item in Apparency.
This shows how Apparency reports an app I crafted to check whether macOS had fixed a longstanding vulnerability in signature checking. Code signatures apply to different architectures, including Intel and Apple silicon. For some time, Gatekeeper checks didn’t cover all architectures correctly, a failure which could have been exploited. This crafted version of my app Cormorant contains two conflicting signatures, as recognised by Apparency.
It can also give more detailed information about errors and certificates.
When an app has been crashed by macOS, the next place to turn to is the crash log, one of the few valuable features of Console.
In this case, Cormorant was being run in translocation, as shown in the Path given at the top. The Exception Type and Termination Reason given make it clear the app was crashed by macOS because of its code signature error.
At one time, this type of event was recorded in great detail in the Unified log. Now all you’ll see there is a single entry from the kernel starting
CODE SIGNING: process 85820[Cormorant]: rejecting invalid page at address 0x10ed37000 from offset 0xa000 …
exited with exit reason (namespace: 3 code: 0x2) - OS_REASON_CODESIGNING
Certificate expiry dates are a little more complicated than you might expect, and depend on the type and purpose of certificate. For ordinary app and other executable signing, a Developer ID Application certificate is used, and remains valid for Gatekeeper even though the certificate has long expired. The crucial date in this case is when the app was signed: so long as the Developer ID Application certificate was valid at that time, then Gatekeeper will accept the certificate many years later.
That isn’t true of certificates used to sign Installer packages, which are a different type, Developer ID Installer. Those are required to be valid when you try to install that package, so old packages will have expired certificates that can no longer be used.
If you read my article about adding custom icons to apps, you may now be wondering why they don’t break the code signing of those apps when they place a file named Icon? inside the app bundle. Custom icons escape code signatures on two counts:
- the Icon? file is installed at the top level in the app bundle, which isn’t included in its signature coverage,
- the Icon? file contains no data at all, just two extended attributes, which aren’t included in cdhashes, something that also applies to quarantine flags, which would break signatures otherwise.
Does any of this have any relevance to the real world of malware, though?
Of the three anti-malware protection measures introduced recently in XProtect and XProtect Remediator, two struggle with Ventura’s new behaviours. Honkbox has been distributed inside pirated copies of apps like Final Cut Pro, normally obtained using apps that don’t set a quarantine flag. As Ventura now checks those signatures thoroughly, it will detect the app’s broken signature and refuse to run it, even though the quarantine flag isn’t set. KeySteal’s installer’s revoked signature should be detected by older versions of macOS, but will certainly be detected by Ventura even if run with SIP disabled and Gatekeeper/XProtect turned off.
This all makes it harder for malware to get past the protections in macOS.