After we upload an app to App Store, Apple will encrypt the app using its own FairPlay DRM. This is reflected in LC_ENCRYPTION_INFO_64
load command.
struct encryption_info_command_64 {
uint32_t cmd; /* LC_ENCRYPTION_INFO_64 */
uint32_t cmdsize; /* sizeof(struct encryption_info_command_64) */
uint32_t cryptoff; /* file offset of encrypted range */
uint32_t cryptsize; /* file size of encrypted range */
uint32_t cryptid; /* which enryption system, 0 means not-encrypted yet */
uint32_t pad; /* padding to make this struct's size a multiple of 8 bytes */
};
The field cryptoff
and cryptsize
define the range that is or will be encrypted. From the one app I looked, this range entirely falls into __TEXT
segment. It starts with the first section (__TEXT,__text) and ends with the second last section, excluding (__TEXT,__oslogstring). I think we can safely say only code in __TEXT
segment are encrypted.
I have compared the app binary before uploading to App Store and the binary downloaded from App Store using Apple Configurator 2. The field cryptid
is changed from 0 to 1, while other fields remain unchanged. According to the source code of dyld
, this bit is used to indicate whether the binary is FairPlay encrypted.
Also from the dyld source code, mremap_encrypted
is the method that is used for decryption. There is a tool called UnFairPlay which is using that method to decrypt an encrypted binary.
As FairPlay is a closed-source algorithm, there isn't much articles online talking about how it actually works.