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.