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
  • CMSDecoder et al from Security.framework (a wrapper around the Mozilla NSS library)
  • macOS (LibreSSL) version of openssl(1), specifically the asn1parse command
Searchable No
Examples
  • X.509 certificates (RFC 5280)
    • e.g. cer files exported from Keychain Access, or dragged out of any standard trust sheet.
  • Cryptographic Message Syntax (CMS) signatures (RFC 5652)
    • e.g. signature contained in a code signature superblob
    • e.g. configuration and provisioning profiles
  • App Store receipts
  • DER-encoded entitlements contained in a code signature superblob

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: ASN.1 view of code signature CMS

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”: ASN.1 view of provisioning profile CMS

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: property list view of provisioning profile payload

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: ASN.1 view of provisioning profile 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: macOS certificate view of provisioning profile certificate

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): Verify CMS Signature sheet

Here, you can configure the verification, and see the result at the bottom:

  1. 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.
  2. 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.
  3. 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: Verify CMS Signature details

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: Editing an ASN.1 comment

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
  • Compiled NIB files (as built with Xcode 12 or earlier, or targeting macOS 10.12 or earlier)
  • Stored state for various macOS services, such as sharedfilelistd or backgroundtaskmanagement
  • State stored by individual apps, either in standalone files or embedded in property lists such as preference files
  • Restorable state from a Saved Application State directory.

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: Browsing a Cocoa Keyed Archive

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 an NSDictionary, all of the keys must be strings. If a dictionary has non-string keys, you may still see NS.keys and NS.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.

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: Searching a Cocoa Keyed Archive

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 Search button in toolbar search field 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: URL Bookmark view

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): Verify Security Scope view

Here, you can configure the verification, and see the result at the bottom:

  1. 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.
  2. For application scope, click Choose Application to select the actual application, which fetches the code signing identifier.
  3. 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: Security::SuperBlob view

Archaeology shows all of the components of the code signature, which are explained in much depth here.

The keyhole icon Signature data indicator image 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 Signed data indicator image — 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
  • The csreq(1) tool can be used to convert between the text and binary forms
  • The SecRequirement API from Security.framework can also be used to convert between the text and binary forms
  • The SecStaticCodeCheckValidityWithErrors() function can be used to test code against a (compiled) requirement
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: Code Signing Requirement view

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: Code Signing Requirement evaluation view

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:

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: Security::SuperBlob view with launch constraints

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: Launch Constraint view

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: Launch Constraint evaluation view

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 that on-authorized-authapfs-volume is not supported at all (evaluation will fail if this is referenced), and launch-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
  • In application bundle at Contents/CodeResources (if stapled)
  • Embedded in the Security::SuperBlob of a stapled disk image
  • Appended to a stapled macOS Installer Package

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: Notarization Ticket view

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 the tickets table (one row per ticket) and the hashes table (one row per digest, with a foreign key back to the tickets 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) or PlistBuddy(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 NSUserInterfaceItemIdentifiers, 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.