Archaeology

UDIF-format Disk Images

The UDIF Disk Image Trailer Format

The DiskImages.framework is private, but through a combination of disassembly, references in the open-source Security.framework, and the prior work of Jonathan Levin, we've deduced the following format for the fixed-length trailer of a UDIF-format disk image:

typedef struct _UDIFFileTrailer
{
    uint32_t fUDIFSignature;                // magic 0x6b6f6c79 ("koly")
    uint32_t fUDIFVersion;                  // current version is 4
    uint32_t fUDIFHeaderSize;               // size of this struct, always 512
    uint32_t fUDIFFlags;
    uint64_t fUDIFRunningDataForkOffset;    // for segmented disk images, the aggregate (logical) offset of this segment's data fork
    uint64_t fUDIFDataForkOffset;           // start of data fork (usually 0 for beginning of file, but not for the bootable package)
    uint64_t fUDIFDataForkLength;           // size of data fork (usually up to the XMLOffset these days, since no resource fork)
    uint64_t fUDIFRsrcForkOffset;           // start of resource fork
    uint64_t fUDIFRsrcForkLength;           // size of resource fork (usually 0 these days)
    uint32_t fUDIFSegmentNumber;            // remember segmented disk images?
    uint32_t fUDIFSegmentCount;             // remember segmented disk images?
    uuid_t   fUDIFSegmentID;                // remember segmented disk images?
    uint32_t fUDIFDataForkChecksum[34];
    uint64_t fUDIFXMLOffset;                // start of XML property list
    uint64_t fUDIFXMLLength;                // size of XML property list
    // There was 120 bytes of reserved space here, and the code-sign offsets are inserted into the middle of it!
    uint8_t  reserved1a[64];                // still 64 bytes of reserved
    uint64_t fUDIFCodeSignOffset;           // start of code-signing superblob from start of image file
    uint64_t fUDIFCodeSignLength;           // size of code-signing superblob
    uint8_t  reserved1b[40];                // another 40 bytes reserved remaining
    uint32_t fUDIFMasterChecksum[34];
    uint32_t fUDIFImageVariant;
    uint64_t fUDIFSectorCount;
    
    uint8_t  fPadding[12];                  // padding to maintain a strict 512-byte trailer
    
} __attribute__((__packed__)) UDIFFileTrailer;
For the above, we've used the field names as extracted from the debug logging function _DI_logUDIFFileHeader().

For our purposes, we were most interested in how code signatures are handled, via the new(ish) fUDIFCodeSignOffset and fUDIFCodeSignLength fields. Apparently, prior to OS X 10.11 (El Capitan), there was one 120-byte block of unused space in the trailer; when code signing support was added for El Capitan, the new fields were added in the middle of this block.