includes/dmg/attribution.h (48 lines of code) (raw):

#ifndef ATTRIBUTION_H #define ATTRIBUTION_H #include "abstractfile.h" #include "common.h" #include <stdint.h> #define ATTR_SIGNATURE 0x61747472 // 'attr' /** * An "attributable" DMG or a DMG "structured for attribution" has: * - either one or two BZ_RAW raw blocks * - a serialized form of the `AttributionResource` data structure * tucked into the `Name` in the `plst` section of the XML plist * which describes the raw block * * An "attributable" DMG can be "attributed" inexpensively: bytes in the raw * block of an "attributable" DMG can be changed and the DMG's internal * checksums updated without parsing and/or decompressing the entire DMG file. */ // We need: // - the BZ_RAW block offset and size // - the CRCs before and after the BZ_RAW block // - the BZIP checksum offset // - the two DMG 'koly' block checksum offsets // fUDIFDataForkChecksum: 0x430e7 // fUDIFMasterChecksum: 0x431f7 // There's a UDIF checksum (34 bytes?) in each <blkx> dict, which is // part of a Base64 encoded struct. We can Base64 decode to bytes, // swizzle the 4 bytes of the checksum, and then Base64 encode back // to the same number of bytes. /* <dict> */ /* <key>blkx</key> */ /* <array> */ /* <dict> */ /* <key>Attributes</key> */ /* <string>0x0050</string> */ /* <key>CFName</key> */ /* <string>Driver Descriptor Map (DDM : 0)</string> */ /* <key>Data</key> */ /* <data> */ /* bWlzaAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAA */ /* AAII/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA */ /* AAIAAAAgXDMYCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA */ /* AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA */ /* AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA */ /* AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA */ /* AAAAAAACgAAABgAAAAAAAAAAAAAAAAAAAAAAAAABAAAA */ /* AAAAAAAAAAAAAAAANf////8AAAAAAAAAAAAAAAEAAAAA */ /* AAAAAAAAAAAAAAA1AAAAAAAAAAA= */ /* </data> */ /* <key>ID</key> */ /* <string>-1</string> */ /* <key>Name</key> */ /* <string>Driver Descriptor Map (DDM : 0)</string> */ /* </dict> */ /** * Binary representation of data needed to quickly "attribute" a DMG that is * structured for attribution. */ typedef struct AttributionResource { uint32_t signature; /* Set to 'attr'. */ uint32_t version; /* Set to 1. */ uint32_t beforeCompressedChecksum; /* CRC of compressed bytes before raw block. */ uint64_t beforeCompressedLength; /* Number of compressed bytes before raw block. */ uint32_t beforeUncompressedChecksum; /* CRC of uncompressed bytes before raw block. */ uint64_t beforeUncompressedLength; /* Number of uncompressed bytes before raw block. */ uint64_t rawPos; /* Position, in bytes, from start of file to raw block. */ uint64_t rawLength; /* Length, in bytes, of raw block. */ uint32_t rawChecksum; /* CRC of bytes in raw block. */ uint32_t afterCompressedChecksum; /* CRC of compressed bytes after raw block. */ uint64_t afterCompressedLength; /* Number of compressed bytes after raw block. */ uint32_t afterUncompressedChecksum; /* CRC of uncompressed bytes after raw block. */ uint64_t afterUncompressedLength; /* Number of uncompressed bytes after raw block. */ } __attribute__ ((packed)) AttributionResource; typedef struct AbstractAttribution AbstractAttribution; enum ShouldKeepRaw { KeepNoneRaw, KeepCurrentRaw, KeepCurrentAndNextRaw, KeepRemainingRaw, }; typedef void (*BeforeMainBlkxFunc)(AbstractAttribution* attribution, AbstractFile* abstractOut, ChecksumToken* dataForkToken); typedef enum ShouldKeepRaw (*ShouldKeepRawFunc)(AbstractAttribution* attribution, const void* data, size_t len, const void* nextData, size_t nextLen); typedef void (*ObserveBuffersFunc)(AbstractAttribution* attribution, int didKeepRaw, const void* uncompressedData, size_t uncompressedLen, const void* compressedData, size_t compressedLen); typedef void (*AfterMainBlkxFunc)(AbstractAttribution* attribution, AbstractFile* abstractOut, ChecksumToken* dataForkToken, AttributionResource* attributionResource); struct AbstractAttribution { // Use this to persist state during operation. void* data; // Return non-zero if the given buffer should be a raw block (type `BLOCK_RAW`). ShouldKeepRawFunc shouldKeepRaw; // Invoked for each BLKX run with the uncompressed and compressed data. ObserveBuffersFunc observeBuffers; // Invoked once immediately before the main BLKX is inserted. BeforeMainBlkxFunc beforeMainBlkx; // Invoked once immediately after the main BLKX is inserted. AfterMainBlkxFunc afterMainBlkx; }; #ifdef __cplusplus extern "C" { #endif // Return an `AbstractAttribution` structure (instance) that will preserve the // *unique* instance of the given string sentinel. If no instance, or more // than one instance, of the given sentinel is found, attribution will fail. AbstractAttribution* createAbstractAttributionPreservingSentinel(const char* sentinel); // Copy an "attributable" DMG -- one structured for attribution -- to the // given output, write `len` of the given `bytes` over the `sentinel`. int updateAttribution(AbstractFile* abstractIn, AbstractFile* abstractOut, const char* sentinel, const char* bytes, size_t len); #ifdef __cplusplus } #endif #endif