Archaeology
Supported Binary Formats
Looking for something specific? The User Guide, Formats, Reversing Topics and FAQ are indexed within the app — open Archaeology, click on the Help menu (Command-?), and type in the Search field. Results listed under Help Topics link directly to the appropriate section here.
BER-encoded ASN.1
Format Name | BER-encoded ASN.1 |
---|---|
Format Type | An ITU Standard |
Format Specification | |
API Used By Archaeology | macOS version of libcrypto (part of LibreSSL) |
Other APIs and Tools |
|
Searchable | No |
Examples |
|
ASN.1 is a language for defining a data structure, along with rules for how to serialize that data to a binary format — BER is the most basic binary encoding, and DER is a subset of BER (so everything that is DER-encoded is also BER-encoded).
Among many other things, ASN.1 is used to define the format of X.509 certificates, and of the Crytpographic Message Syntax (CMS) that packages a signature with the certificate that created it and related metadata. X.509 and CMS are IETF standards, but you'll also find custom ASN.1 formats used on macOS — some that are documented (like App Store receipts) and some that are not (like the DER-encoded version of entitlements in a code signature).
There are various tools that deal with these specific formats, of course. Certificate Assistant — or the openssl(1)
x509
command — can show information about a X.509 certificate file. The security(1)
cms
command can show information about an arbitrary CMS file. The Profiles pref pane can some specific information about
configuration profiles. Or Quick Look can show some specific information about provisioning profiles.
Archaeology shows the ASN.1 at a lower-level, without assuming (or knowing) anything about the specific data structure definition. This can be useful when you don't have an ASN.1 definition for a file, when the domain-specific tool (like Certificate Assistant) abstracts away the details you want to see, or where there are simply no specific tools available (as for App Store receipts).
For example, we can open the CMS from a macOS code signature, and see attributes such as the (self-declared) Signing Time:
On the right, the info pane shows details about the selected item, using ASN.1 terminology. The Offset shows where this item was found within the containing file (or the containing chunk of data). The Length is given as two numbers: the first is the size of the ASN.1 tag and length header, and the second is the size of the value. (Note that if you show the value info — or if you copy or export the data — only the value part is operated upon.)
For some ASN.1 tags, Archaeology shows an alternate representation of the value, just for convenience. For example, if a BIT STRING is 64 bits or fewer, the info pane shows the value Formatted As a 64-bit integer, with the first bit in the string presumed to be the least-significant one. The integer is shown in hexadecimal by default, but you can click on this number to cycle the display between hexadecimal, decimal and octal representations.
Often, an ASN.1 item will contain another chunk of data in another format, and you can use Archaeology to decode that.
For example, we can open a provisioning profile (another kind of CMS), and find the “payload”:
At this level, the selected OCTET STRING is arbitrary binary data, but we can try to decode it and see what we get. In this case, using Go > Decode Item (Cmd-Down Arrow) gives us the property list inside:
In turn, a provisioning profile property list typically contains one or more DeveloperCertificates, which we can decode again to get the ASN.1 for an X.509 certificate:
If we select the root of an X.509 certificate structure (the top-level SEQUENCE in this example), Archaeology will recognize it as such, and we can click Go > Show As Certificate (Cmd-Option-V) to examine the certificate using the standard macOS certificate view:
Verifying a CMS Signature
For any CMS-format signature, Archaeology can show how macOS would evaluate the validity of the signature and the trust of the signing certificate. For example, this works with code signatures, and with configuration or provisioning profiles.
Select the root of a CMS structure — probably the top-level SEQUENCE in the ASN.1 view — and choose Go > Verify CMS Signature (Cmd-Option-V):
Here, you can configure the verification, and see the result at the bottom:
- The applicable trust settings policy is an Apple-defined collection of requirements for trusting a certificate for a specific purpose. Apple X.509 Basic Policy is the most generic, and is generally fulfilled as long as the certificate chain leads to a trusted “anchor,” e.g. in the System Root keychain. Use the pop-up menu to see other common trust policies, or to enter a custom trust policy OID. Some trust policies add more stringent root certificate requirements (mostly, that it be an Apple Root CA), or more specific pinning requirements. Trust policies might also require specific extensions to be present on a certificate, indicating that Apple issued it for a specific purpose — such as Developer ID signing, or App Store signing.
- The certificate revocation checking options allow you to control what type of revocation checks are or are not allowed. Allowing OCSP and CRL (but only “best attempt”) is the typical default when macOS is checking certificate trust.
- In order to verify the actual signature, Archaeology must be able to find the signed data to verify against.
This is the “thing” that was actually signed — usually a small bit of data (like a
cryptographic digest, such as SHA-256) that uniquely identifies that “thing.”
For some CMS signatures, the signed thing is the payload actually embedded in the CMS. For example, with a configuration profile, the payload is the contained property list. In such cases, Archaeology will say that the “CMS message encapsulates the signed data,” and nothing more is required here.
For other types of CMS signatures, the signed thing is external. This is the case for a code signature, where the code signing digest or cdhash is the signed thing, and lives outside of the CMS, as the Code Directory. If you decoded the CMS from another file or from a Security::SuperBlob, Archaeology might be able to automatically find the Code Directory to use, shown as “retrieved X bytes from Code Signature > Code Directory” or some such.
If Archaeology doesn't automatically find the right thing, you can use Read From File to get the thing from a file, or Paste From Clipboard to get it from the clipboard (whether copied from elsewhere in Archaeology, or as a hex-encoded string from another app).
As you change these parameters, Archaeology will re-evaluate the signature and certificate trust, and show the result at the bottom. Click Show Details to get more information about any verification errors, and to see the certificate chain and trust information:
Annotating ASN.1 With Comments
Even when you have the ASN.1 definition for a particular file — such as the IETF RFC for CMS files — it can still be challenging to keep track of what item of data means what. For this reason, Archaeology allows you to annotate comments onto individual items as you puzzle out the pieces of the ASN.1.
To add or change a comment, click in the Comments column — or press Return to edit the comment for the selected item:
In the above example, we've annotated the pieces of the CMS that identify the signed payload (or “encapsulated content”), using the ASN.1 definition from RFC 5652:
SignedData ::= SEQUENCE { version CMSVersion, digestAlgorithms DigestAlgorithmIdentifiers, encapContentInfo EncapsulatedContentInfo, certificates [0] IMPLICIT CertificateSet OPTIONAL, crls [1] IMPLICIT RevocationInfoChoices OPTIONAL, signerInfos SignerInfos } EncapsulatedContentInfo ::= SEQUENCE { eContentType ContentType, -- i.e. Data eContent [0] EXPLICIT OCTET STRING OPTIONAL } ContentType ::= OBJECT IDENTIFIER
Archaeology saves the comments you add this way, and will restore them when you decode the identical ASN.1 data again. (The comments are sideband data, and are linked to the ASN.1 data by a hash. So, they will be restored only when the ASN.1 data is 100% identical to one that was annotated.)
Cocoa Keyed Archive
Format Name | Cocoa Keyed Archive |
---|---|
Format Type | An Apple-proprietary format |
Format Specification | None, but see our reverse-engineering notes |
API Used By Archaeology | None. Archaeology uses NSPropertyListSerialization to get a property list, and interprets from there |
Other APIs and Tools | None |
Searchable | Yes, by class name, instance UID, key, or value |
Examples |
|
Apps and macOS services often persist their in-memory object models using a Cocoa Keyed Archive, which is the
serialized data created by the Foundation NSKeyedArchiver
class. While you can't reconstruct the actual object model without the app-specific code that created it, you
can often tell quite a bit from class and key names, and by asking Archaeology to further decode any chunks of data.
As explained here, a Cocoa Keyed Archive is a binary-serialized property list, but it has some special types, and tracing more than one or two object references is extremely tedious.
Archaeology interprets this property list as an object graph, and presents it in a column-based browser view
(an NSBrowser
), which makes it much easier to traverse relationships:
Each column represents an instance of the named CLASS, which might be either app-specific or an Apple framework class. The UID is a unique integer that identifies that instance.
When you select a key, Archaeology shows the associated value, which might be another instance, or it might be a primitive type.
Primitives will show their TYPE as a Cocoa class name. (This is often some private Core Foundation subclass
of the one you'd expect — for example, __NSCFString
is a private subclass of NSString
.) When the
VALUE is an integer, you can click on the displayed number to change the radix that Archaeology uses, cycling between
decimal, hexadecimal and octal.
An object archive will often have back-references: the graph is not necessarily acyclic. So, as you navigate the objects, you may well loop back to where you've been. Archaeology doesn't try to detect or flag this (yet). If things are looking familiar, you can always check the UID to see if two instances are actually the same object.
Simplification of Foundation Collections
Cocoa Keyed Archives typically include standard Foundation collections, such as NSArray
or
NSDictionary
. The way that these are archived can be a chore to interpret, so by default, Archaeology
tries to simplify them for easier navigation.
An NSArray
is archived as an NS.objects
key that leads to a
list of the actual objects. Unless you're interested in the structure of the NSArray
itself,
this just adds an extra click, so Archaeology pulls the actual objects to be directly
inside the array.
Likewise, an NSDictionary
is archived as two parallel lists, as NS.keys
and NS.objects
: the key and value at the same index constitute a pair. That's efficient
for archiving, but makes navigating the dictionary tedious. Here, Archaeology pulls each
key up to the NSDictionary
itself, and associates it to the corresponding value. This makes the keys
of the dictionary behave more like the properties of an object, and is usually easier to navigate.
For this simplification of anNSDictionary
, all of the keys must be strings. If a dictionary has non-string keys, you may still seeNS.keys
andNS.objects
.
If you want to see the actual archived representation, you can disable this simplification by unchecking File > Re-open With Options > Simplify collections in archives. You can also change this option directly from the File > Open dialog.
Alternate String Formatting of Primitives
Some standard Foundation types have an obvious representation in a Cocoa Keyed Archive, but others are quite opaque, or just not in the most convenient form. For a few common-but-obscurely-encoded types, Archaeology will create a sibling key with a more readable representation.
For example, an NSDate
is encoded with an NS.time
key, which is the number of
seconds since January 1, 2001. Archaeology adds a sibling key — with the
“➔ formatted date” suffix — containing a nicely-formatted date and time.
Even more obscurely, an NSIndexPath
is encoded as a chunk of data, containing a series of
variable-length integers (each index encoded using 7 bits per byte, in Little Endian order, with the high bit
cleared in the most significant byte). Here, Archaeology adds a sibling key
— with the “➔ indexes” suffix — containing a nicely-formatted series of indexes.
The original keys are always left intact, so you can see what the archive actually contains.
You can disable these alternate representations by unchecking File > Re-open With Options > Format strings and dates in archives. You can also change this option directly from the File > Open dialog.
Searching Cocoa Keyed Archives
Since a Cocoa Keyed Archive can be quite complex, Archaeology allows you to search the object graph.
Click in the search field (or use Cmd-F), enter text and press Return. The search results appear at the bottom of the window. Select a search result to show the matching object:
By default, Archaeology searches all of the string-type primitive values for the given text. But you can also search on other aspects of the object graph, such as keys or class names. Click the search button inside the search field to change the search criteria.
UIKit NIB Archive
Format Name | UIKit NIB Archive |
---|---|
Format Type | An Apple-proprietary format |
Format Specification | None, but see our reverse-engineering notes |
API Used By Archaeology | None. Archaeology interprets raw data stream |
Other APIs and Tools | None |
Searchable | Yes, by class name, instance UID, key, or value |
Examples | Compiled NIB files (as built with Xcode 13 or later, and targeting macOS 10.13 or later) |
As it says in the Xcode 13 Release Notes,
“Storyboards and XIBs for macOS compile using UINibEncoder to reduce file sizes and improve runtime performance. When deploying an App before macOS 10.13, Xcode generates a backward compatible nib for the older OSes.”
This alternate compiled NIB format — which clearly comes from iOS — serves the same purpose as a Cocoa Keyed Archive: to serialize an object graph. Archaeology decodes it and presents the object model in a browser, exactly as described above for a Cocoa Keyed Archive.
Some of the details of how specific types are archived will differ, but navigating the model is pretty much identical.
Note that, when Xcode decides it must create a “backward compatible nib,” this means a NIB Package, which you can also open with Archaeology, and then decode the different representations inside.
URL Bookmark
Format Name | URL Bookmark |
---|---|
Format Type | An Apple-proprietary format |
Format Specification | None, but see our reverse-engineering notes |
API Used By Archaeology | None. Archaeology interprets raw data stream |
Other APIs and Tools | None |
Searchable | No |
Examples | Rarely exist as standalone files, but often embedded in preference property lists, or in Cocoa Keyed Archives |
Applications commonly store paths in the form of URL bookmarks, both to make them more resilient against moving and renaming of the file (especially when the app is not running) and to maintain access that would otherwise be prevented by sandboxing.
A detailed discussion of the different kinds of URL bookmarks is here.
Bookmarks are mostly a collection of key-value pairs, and most significantly contain volume and inode information for the target file path:
A bookmark can be security-scoped, which allows an app with access to a specific file to save and regain that access later. This type of bookmark will resolve only for the app and user that originally created it, which is the “security scope” of the bookmark. (See a very detailed explanation of security-scoped bookmarks here.)
In the above example, the bookmark is security-scoped, and you can ask Archaeology to verify that scope. Choose Go > Verify Security Scope (Cmd-Option-V):
Here, you can configure the verification, and see the result at the bottom:
- Choose the type of security scope used by this bookmark. (This information is not encoded in the bookmark data itself, so Archaeology can't help here.) You will probably want application scope, meaning a specific app and user; document scope is uncommon.
- For application scope, click Choose Application to select the actual application, which fetches the code signing identifier.
- Also for application scope, click Find in Keychain to fetch the user-specific secret key for scoped bookmarks. This is a 32-byte key randomly chosen by the macOS ScopedBookmarkAgent: it is used to bind the security-scoped bookmark to the current user. macOS will prompt that “Archaeology wants to use your confidential information stored in ‘com.apple.scopedbookmarksagent.xpc’ in your keychain.”
Once all of the parameters are configured, Archaeology will evaluate the security scope, and show the result at the bottom.
If you choose document scope in step 1, you'll instead need to click
Choose Document to locate the document itself. This will attempt to fetch
the document-specific secret from an extended attribute on the document, which is what demonstrates
access to the scope. However, we've seen inconsistencies with Archaeology being able to read this xattr,
so you may get an “operation not permitted” error. If you can get the contents of the
com.apple.security.private.scoped-bookmark-key
xattr into a file in some other way,
you can then Option-click the Choose Document button and select that file,
and Archaeology will read the key that way.
Security::SuperBlob
Format Name | Security::SuperBlob |
---|---|
Format Type | An Apple-proprietary format |
Format Specification | None, although the relevant Security.framework code is available; also, see our reverse-engineering notes |
API Used By Archaeology | None. Archaeology interprets raw data stream |
Other APIs and Tools | The SecStaticCode API from Security.framework shows data from the Security::SuperBlob where
appropriate, but doesn't provide visibility into the actual structure |
Searchable | No |
Examples | Rarely exist as standalone files, but usually embedded in Mach-O binaries, as well as in signed disk images |
The Security::SuperBlob
is used to store code signature data in Mach-O binaries (as well as in disk images).
Archaeology allows you to open these — or more commonly, decode them from a Mach-O binary
or a bundle — so you can inspect the different pieces of the code signature:
Archaeology shows all of the components of the code signature, which are explained in much depth here.
- The Code Directory is not decodable by Archaeology, but it does show the SHA-256 digest, which is also known as the code signing identity or the cdhash.
- The Internal Requirements can be decoded further, as described below under Code Signing Requirement.
- The Entitlements can be decoded as an XML-format macOS Property List.
- The DER-encoded Entitlements can be decoded as BER-encoded ASN.1. This ASN.1 structure is a dictionary representation, which is managed by the (private) libCoreEntitlements.dylib, as detailed here. To view the entitlements in this dictionary form, select the top-level object and choose Go > Show As Dictionary.
- The various LaunchConstraint items, if any, can be decoded further, as described below under Launch Constraint.
- The CMS Signature can be decoded as BER-encoded ASN.1.
The keyhole icon next to the CMS Signature indicates that you can go directly to the Verify CMS Signature sheet (without having to decode the signature as ASN.1 first). Archaeology recognizes that the Code Directory constitutes the “signed data to verify” — as indicated by the key icon — and automatically adds that to the verification flow.
Code Signing Requirement
Format Name | Code Signing Requirement |
---|---|
Format Type | An Apple-proprietary format |
Format Specification | The binary (compiled) form of a code signing requirement is not documented, although the relevant Security.framework code is available; there is documentation for the domain-specific language that compiles into a code signing requirement, as well as some more recent discussion of how code signing requirements are formulated and used. |
API Used By Archaeology | None. Archaeology interprets the compiled requirement from the raw data stream, to enable enhanced presentation and evaluation |
Other APIs and Tools |
|
Searchable | No |
Examples | Can exist as a standalone file, e.g. as created by csreq(1) , but more often found
inside the Security::SuperBlob that stores a code signature, e.g. inside a Mach-O binary.
Also commonly stored by macOS to control access to an app-specific resource — for example, an App Sandbox container is linked
to the owning app via a code signing requirement, which is stored in the (hidden) .com.apple.containermanagerd.metadata.plist file,
under the MCMMetadataInfo.Identity key-path. |
Inside almost every code signature — that is, a Security::SuperBlob — you will find another Security::SuperBlob named Internal Requirements. If you decode this, you will usually find a single item named designated, which is the “designated requirement” of the code. (There can be other requirement types, which is why this intermediate superblob exists, but none of the other types appear to be used in current practice.)
If you decode the designated item as a Code Signing Requirement, Archaeology decompiles it into a Boolean expression, and applies syntax highlighting for readability:
Archaeology also adds comments that explain the less obvious constructs of the language, and that show the names associated with common certificate extension OID values.
To see the code signing requirement in action, you can ask Archaeology to evaluate it against a selected app, bundle or executable. By default, if you open a requirement by decoding an app or executable, Archaeology will automatically evaluate it against that executable:
In addition to showing the overall result of evaluating the requirement, Archaeology also shows how each individual term was evaluated. A term shown in green text evaluated to true, and one shown in red text evaluated to false; terms not highlighted were not evaluated, usually because a previous result short-circuited that term. If you move the pointer over a highlighted term, a tooltip will show the actual value that was used in the evaluation of that term.
If Archaeology can't determine the target code automatically, or if you just want to evaluate the requirement against a different app or executable, click Choose Code to select it.
Launch Constraint
Format Name | Launch Constraint |
---|---|
Format Type | An Apple-defined BER-encoded ASN.1 format |
Format Specification | The binary form of a launch constraint is not documented, but see our reverse-engineering notes. The binary form is compiled from requirements in the “constraint dictionary” form |
API Used By Archaeology | Archaeology uses SecAsn1Decode() to deserialize the constraint dictionary, and then converts it to a Boolean expression |
Other APIs and Tools | None public. libCoreEntitlements.dylib manages the dictionary serialization (which is also used for DER-encoded entitlements), and libTLE.dylib (“trusted launch environment”) manages the constraint dictionary representation, and is used by AppleMobileFileIntegrity.kext to evaluate constraints. Both of these are private libraries. |
Searchable | No |
Examples | Found, if at all, inside the Security::SuperBlob that stores a code signature, e.g. inside a Mach-O binary |
A launch constraint is a set of requirements that must be met before the associated code can start. Launch constraints appeared in their initial form in macOS 13 (Ventura), and were publicly described and documented beginning in macOS 14 (Sonoma).
A launch constraint is defined by constructing a property list in an Apple-defined “constraint dictionary” format,
and supplying that to codesign(1)
, typically via an Xcode build setting. Every launch constraint has
an associated type, given by the specific codesign(1)
option (e.g.
‑‑launch‑constraint‑self
)
or Xcode build setting (e.g. LAUNCH_CONSTRAINT_PARENT
). This type determines which process
— relative to the code being launched — must meet the requirements of the constraint:
- The Launch Constraint for Parent
must be met by the process that directly launches the code, i.e. using
posix_spawn(2)
orexecve(2)
. For a launchd daemon or agent, or an XPC service, this ought to belaunchd(8)
. - The Launch Constraint for Responsible Process must be met by the process that triggered the code to launch, which might be different from the process doing the spawn. For an XPC service, the responsible process is the app that uses that service. Otherwise, it tends to be the same as the code itself; in particular, a launchd daemon or agent does not get a distinct responsible process, perhaps because a single launchd job can be shared by multiple clients.
- The Launch Constraint for Self must be met by the code itself.
- The Library Load Constraint
must be met by each library that is dynamically loaded by the code. This applies only if the
com.apple.security.cs.disable-library-validation
entitlement is used to disable the library validation feature of the hardened runtime, and is a way of relaxing such validation selectively instead of entirely.
Note that it is always the launching of the code that contains the constraint that is gated, even though 3 of the 4 types are requirements that other code must meet.
When you decode a Security::SuperBlob for a code signature, Archaeology will show any launch constraints by type:
When you decode one of these launch constraints, Archaeology translates it into a Boolean expression, using a bespoke syntax that is heavily patterned after the Code Signing Requirement language. It shows the constraint in this form, with syntax highlighting and some (hopefully) helpful comments:
This Boolean expression syntax is our attempt to make the launch constraint easier to read and more succinct than Apple's property list format. macOS does not create or understand this format for launch constraints.
To see the launch constraint in action, you can ask Archaeology to evaluate it against a selected app, bundle or executable. Click Choose Code to select the executable that makes sense for the type of launch constraint — this might be the executable that contains the constraint, the app that contains the XPC service, some dylib, or perhaps /sbin/launchd. Archaeology will evaluate the constraint against the selected executable, and show the result:
Archaeology also shows how each individual term was evaluated. A term shown in green text evaluated to true, and one shown in red text evaluated to false; terms not highlighted were not evaluated, usually because a previous result short-circuited that term. If you move the pointer over a highlighted term, a tooltip will show the actual value that was used in the evaluation of that term.
Since macOS doesn't provide any public API for evaluating launch constraints, Archaeology can only approximate how the macOS kernel will check the constraint. We believe it to be accurate for most “facts,” but there may be subtle differences, since Archaeology is determining facts in userspace, without any additional context. In particular, note thaton-authorized-authapfs-volume
is not supported at all (evaluation will fail if this is referenced), andlaunch-type
is always assumed to be zero.
Archaeology defaults to this Boolean expression view for launch constraints, but you can also view a constraint in its original DER-encoded form. Go back to the constraint in the SuperBlob and use Go > Decode Item As > BER-encoded ASN.1. At this point, you can also view the constraint in the Apple-defined property list format, by choosing Go > Show As Dictionary.
Notarization Ticket
Format Name | Notarization Ticket |
---|---|
Format Type | An Apple-proprietary format |
Format Specification | None, but see our reverse-engineering notes |
API Used By Archaeology | None. Archaeology interprets raw data stream |
Other APIs and Tools | None. The spctl(8) tool can check notarization status, but tickets are abstracted away |
Searchable | No |
Examples |
|
A notarization ticket is an Apple-signed file that communicates the notarization state of an app. It can be “stapled” (i.e. attached) to apps or other containers, but this is not strictly required, since macOS is able to query notarization status from Apple servers.
Notarization tickets primarily contain digests that identify notarized components, along with an Apple signature:
If you open a bare ticket, Archaeology won't be able to show how each digest corresponds to a component. But if you open a stapled app bundle, and then decode the ticket from there, Archaeology will attempt to match each digest to a component of the app, as shown above. (It's not uncommon for there to be a single unidentified digest in the ticket, probably corresponding the disk image that the developer used to submit the app to Apple's notarization service.)
Click the Show Details button to see information about the Apple certificate that was used to sign the actual ticket.
See much more about notarization tickets here.
In the absence of a stapled notarization ticket, macOS uses the digest of the app bundle to fetch a ticket from Apple servers. (Actually, macOS often retreives a ticket even if one is stapled, presumably to check if the notarization has been revoked. These days, a stapled ticket probably functions mostly as a fallback, for the scenario where your computer is offline when you first open an app.)Regardless of where a ticket comes from — stapling or fetched from Apple servers — the information it contains is cached in /var/db/SystemPolicyConfiguration/Tickets, an SQLite database used by
syspolicyd(8)
to make execution policy decisions. The ticket itself isn't stored, though: the data in the ticket is used to populate thetickets
table (one row per ticket) and thehashes
table (one row per digest, with a foreign key back to thetickets
table).As such, stapled tickets may be the only ones you ever encounter in the wild — unless you're stapling your own:
stapler(1)
will leave the ticket in a temporary directory, but you'll see the path in its verbose output.
macOS Property List
Format Name | macOS Property List |
---|---|
Format Type | An Apple-proprietary format |
Format Specification | Property List Programming Topics |
API Used By Archaeology | NSPropertyListSerialization |
Other APIs and Tools | Numerous first- and third-party tools and apps, including Xcode, plutil(1) and PlistBuddy(8) |
Searchable | Yes, by key or value |
Property lists are, of course, a well-established and well-supported format.
Archaeology supports property lists primarily because they often contain chunks of data in one of the other (less well-supported) formats — such as Cocoa Keyed Archives or URL Bookmarks. Also, they often are contained within one of those other formats — such as BER-encoded ASN.1 that is used for a configuration or provisioning profile.
In the macOS Property List view, you can easily copy specific bits of data to the clipboard. Control-click on an item, and depending on the type of that item, you can choose to Copy Key, Copy Value and/or Copy Data Value as Hex.You can also choose to Copy as XML Property List, which copies the item as new property list. If the item is a dictionary key, Archaeology captures both the key and value in a new dictionary, instead of just copying the value and dropping the key (as Xcode's property list editor does).
You can also copy a
plutil(1)
orPlistBuddy(8)
command that extracts the item value, directly from the originally opened file. This can be handy for pasting into a script or the Terminal, perhaps as the first stage of a pipeline.
JSON
Format Name | JSON (JavaScript Object Notation) |
---|---|
Format Type | An industry standard |
Format Specification | e.g. RFC 7159 |
API Used By Archaeology | NSJSONSerialization |
Other APIs and Tools | Legion |
Searchable | Yes, by key or value |
As with Property Lists, Arcaheology can open JSON files primarily because they can contain — or be contained in — various of the other supported formats.
File Table of Contents
In addition to the primary formats described above, Archaeology can directly open a number of other file and directory formats, largely because they often contain data in one of the primary formats. Archaeology calls these file tables-of-contents or file TOCs, because they act somewhat like lists of decodable chunks of data.
Mach-O Binary
Format Name | File Table of Contents — Mach-O Binary |
---|---|
Format Type | A mostly Apple-specific executable format, originating from the Mach kernel and NeXTSTEP |
Format Specification | Apple has long since abandoned such documentation, but there are many other explainers on the Internet |
API Used By Archaeology | <mach-o/loader.h> |
Searchable | No |
Archaeology can open standalone Mach-O binaries — executables, dylibs and so on — because they typically contain other chunks of decodable data. Most significantly, a Mach-O binary will usually contain a code signature, in the form of a Security::SuperBlob for each processor architecture.
Mach-O binaries might also contain embedded Info.plist files and/or launchd configuration files, and Archaeology will show these where present (and of course, decode them as Property Lists).
Archaeology also shows some general information from the Mach-O headers and load commands for each architecture,
including things like deployment targets and linked libraries. This is information that you'd typically need to
get from otool(1)
(with its hard-to-remember option syntax) or the more modern objdump(1)
(with its
even harder-to-remember option syntax).
Bundle
Format Name | File Table of Contents — Bundle |
---|---|
Format Type | An Apple-defined directory structure |
Format Specification | Bundle Programming Guide |
API Used By Archaeology | NSBundle |
Searchable | No |
As with Mach-O binaries, Archaeology opens bundles because they contain many other interesting bits of decodable data. Archaeology shows information about the main executable of the bundle: this includes the code signature and other pieces, just as for standalone Mach-O binaries described above.
Archaeology also shows any compiled NIBs or storyboards (decodable as either Cocoa Keyed Archives or UIKit NIB Archives), the Info.plist file, any App Store receipt and/or provisioning profile (both decodable as BER-encoded ASN.1), any stapled notarization ticket, and the _CodeSignature/CodeResources property list that seals resources into the code signature.
Archaeology also looks inside the bundle for any nested bundles, as well as standalone Mach-O binaries (such as dylibs), and shows these hierarchically.
For an app bundle, you can get a higher-level view of this information by using Apparency. If you already have it installed, choose File > Open With Apparency.
NIB and Storyboard Packages
Format Name | File Table of Contents — Compiled IB Package |
---|---|
Format Type | An Apple-defined directory structure |
Format Specification | None |
API Used By Archaeology | None |
Searchable | No |
When Xcode compiles a XIB file, it usually produces a single NIB file — in modern times, a file using the UIKit NIB Archive format. However, depending on the macOS deployment target, it might also produce a package of multiple NIB files in different formats, with names like keyedobjects-####.nib.
Likewise, when Xcode compiles a Storyboard, it produces a package with multiple NIB files, along with an Info.plist file.
You can open either of these types of packages in Archaeology — or access them when opening a bundle that contains them. Archaeology will show each of the individual NIB files as data, and you can recursively decode these. You can also decode the Info.plist to see how the pieces of the Storyboard are tied together.
UDIF Disk Image
Format Name | File Table of Contents — UDIF Disk Image |
---|---|
Format Type | An Apple-proprietary format |
Format Specification | None, but see our reverse-engineering notes |
API Used By Archaeology | None |
Searchable | No |
Archaeology can open UDIF-format disk images, mostly so you can get at the code signature inside. If there's a Disk Image Code Signature item, you can decode that to get a Security::SuperBlob, and see the code signature components.
There might also be a notarization ticket stapled to the disk image, which will also be found inside the superblob.
xar Archive — e.g. macOS Installer Package
Format Name | File Table of Contents — xar Archive |
---|---|
Format Type | An Apple-originated archive format, open-sourced long ago and mostly deprecated now |
Format Specification | None canonical, although the xar code is available; also see the old Google Code project. |
API Used By Archaeology | macOS version of libxar |
Searchable | No |
Archaeology can open xar archives — including modern macOS Installer Packages — so you can see the signature-related details.
A xar will often have two different “styles” of signature: an older “RSA” style is a bare RSA signature of the xar TOC (or a digest thereof). The newer “CMS” style is a CMS signature in BER-encoded ASN.1 format. (The macOS Installer uses the latter if it's present; the former exists mostly for older versions of macOS.)
For either style, you can decode the (claimed) certificate chain that created the signature, and if you select the signature data, you can choose Go > Verify Signature (Cmd-Option-V) to evaluate the validity and trust of the signature.
There might also be be a notarization ticket stapled to the xar (which, unlike with a disk image, is stored separately from the signature).
Archaeology won't show the actual archive contents, which isn't what it is trying to do. If the xar is a macOS Installer Package, you can get much more — and higher-level — information by using Suspicious Package. If you already have it installed, choose File > Open With Suspicious Package.
Saved Application State
Format Name | File Table of Contents — Saved Application State |
---|---|
Format Type | An Apple-proprietary format |
Format Specification | None, but see our reverse-engineering notes |
API Used By Archaeology | None. Archaeology interprets files directly |
Searchable | No |
For Archaeology to properly interpret the files in a savedState directory, you must open the directory itself, not the individual files inside. The files are all inter-related, and since Archaeology is sandboxed, it can't read them all unless you open the actual directory. This can be a bit confusing, since macOS treats the savedState directory as a folder (not as a “package”). From the File > Open dialog, select the directory itself and click Open.
These directories, with the savedState extension, are found under your home folder at Library/Saved Application State — or for a sandboxed application, under the app's “container” at under Library/Containers/com.example.bundle-identifier/Data/Library/Saved Application State.
The savedState directories are where macOS stores information for the “Resume” feature — that is, the preservation of state when quitting an app (i.e. System Settings > Desktop & Dock > Windows & Apps > Close windows when quitting an application is disabled; or on macOS 12, System Preferences > General > Close windows when quitting an app) or when restarting your computer (i.e. in the restart confirmation dialog, Reopen windows when logging back in is checked).
Among other information, these directories contain the state data saved by both Cocoa and by the
application itself, in the form of Cocoa Keyed Archives. macOS stores individual
chunks of state data under NSUserInterfaceItemIdentifier
s, such as _NSDocument
and _NSWindow
. Application-specific data is usually stored under other identifiers (although
some app data may also live in the _NSDocument
chunk).
Archaeology lists all of the encoded data chunks under Decrypted Object Archives, because they live in the data.data file in encrypted form — for mysterious reasons, because the encryption keys are right next door, in the windows.plist file. Anyway, Archaeology extracts and decrypts the chunks, and then you can decode them as needed.
The savedState directory might also contain a “snapshot” for the app window: this
is actually a screenshot of the window as it last existed, which is sometimes used after restart to
“fake” immediate restoration while the real work takes place. These screenshots live in the
window_#.data files, but in a rather arcane form: they are raw CGImage
data that is
zlib-compressed and then AES-128-CBC-encrypted, using a key that is randomly chosen by talagent(8)
and stored in your keychain. If you select the Window Snapshot item and use
Go > Quick Look Item, Archaeology will undo all of that business and show you the
actual image; you'll be prompted to Allow access to the keychain item, which is
required for the decryption step.
At this point, you might be asking yourself “why the $%^& did you implement that?” To which the answer is because it was there. Some people play video games. ¯\_(ツ)_/¯
XCFramework
Format Name | File Table of Contents — XCFramework |
---|---|
Format Type | An Apple-defined, bundle-based format |
Format Specification | None, but this blog post is informative. For background on how xcframeworks are created, see here. |
API Used By Archaeology | None. Archaeology interprets files directly |
Searchable | No |
Introduced in Xcode 11, an xcframework is a way of packaging together multiple binary frameworks, each of which is compiled for a different Apple platform. This is supposed to make it easier to distribute and use third-party SDKs in binary form. (We've never been on either side of that equation, so have no experience or opinion on whether or not those goals are achieved!)
Archaeology can always open an individual framework, no matter where it lives, since a framework is a kind of bundle. But for convenience, you can also ask Archaeology to open the xcframework, and see each contained framework by its target platform. If the xcframework itself is code-signed, Archaeology will show the usual information about the code signature; although signing xcframeworks was possible before (because basically any bundle can be “code-signed”), Xcode 15 actually uses the code signature to detect any changes in the distribution signing certificate.
In addition to frameworks, an xcframework bundle can also be used to distribute dynamic libraries (e.g. libSomething.dylib) or static archives (e.g. libSomething.a), along with their header files. Of these, Archaeology will properly show any dynamic libraries, but it won't show any information about static archives, since it doesn't know anything about these objects even outside of an xcframework. So if you open an xcframework and see no platforms, you might want to decode the top-level Info Property List to see what is referenced.
Apple Wallet Package
Format Name | File Table of Contents — Apple Wallet Package |
---|---|
Format Type | An Apple-defined directory structure |
Format Specification | Wallet Passes |
API Used By Archaeology | None |
Searchable | No |
These directories, with the pkpass extension, represents the “passes” shown by Apple Wallet. You'll probably find a bunch of them under your home folder at Library/Library/Mobile Documents/com~apple~shoebox/UbiquitousCards (although macOS likes to hide this folder and its contents, such as in Finder and Open dialogs).
Archaelogy can open a pkpass directory — although you may need to use the trowel tool from the Terminal — and show the JSON and other files inside. Perhaps most interestingly, you can select the signature and choose Go > Verify Signature (Cmd-Option-V) to get information about the certificate that signed the pass.