X-Git-Url: https://git.saurik.com/ldid.git/blobdiff_plain/fdb119efae39fcc610592a4c913110f501ada783..e067acdcc9870305978666f6c1f277688893dc01:/ldid.cpp diff --git a/ldid.cpp b/ldid.cpp index 7c225e1..19bfcc7 100644 --- a/ldid.cpp +++ b/ldid.cpp @@ -36,6 +36,7 @@ */ #include "minimal/stdlib.h" +#include "minimal/string.h" #include "minimal/mapping.h" #include "sha1.h" @@ -45,11 +46,13 @@ #include #include +#include +#include struct fat_header { uint32_t magic; uint32_t nfat_arch; -}; +} _packed; #define FAT_MAGIC 0xcafebabe #define FAT_CIGAM 0xbebafeca @@ -60,7 +63,7 @@ struct fat_arch { uint32_t offset; uint32_t size; uint32_t align; -}; +} _packed; struct mach_header { uint32_t magic; @@ -70,19 +73,20 @@ struct mach_header { uint32_t ncmds; uint32_t sizeofcmds; uint32_t flags; -}; +} _packed; #define MH_MAGIC 0xfeedface #define MH_CIGAM 0xcefaedfe -#define MH_EXECUTE 0x2 -#define MH_DYLIB 0x6 -#define MH_BUNDLE 0x8 +#define MH_EXECUTE 0x2 +#define MH_DYLIB 0x6 +#define MH_BUNDLE 0x8 +#define MH_DYLIB_STUB 0x9 struct load_command { uint32_t cmd; uint32_t cmdsize; -}; +} _packed; #define LC_REQ_DYLD 0x80000000 @@ -97,26 +101,26 @@ struct dylib { uint32_t timestamp; uint32_t current_version; uint32_t compatibility_version; -}; +} _packed; struct dylib_command { uint32_t cmd; uint32_t cmdsize; struct dylib dylib; -}; +} _packed; struct uuid_command { uint32_t cmd; uint32_t cmdsize; uint8_t uuid[16]; -}; +} _packed; struct linkedit_data_command { uint32_t cmd; uint32_t cmdsize; uint32_t dataoff; uint32_t datasize; -}; +} _packed; uint16_t Swap_(uint16_t value) { return @@ -217,6 +221,10 @@ class Framework { ); } + struct mach_header *operator ->() const { + return mach_header_; + } + void *GetBase() { return base_; } @@ -238,25 +246,32 @@ class Framework { } }; -#define CSMAGIC_CODEDIRECTORY 0xfade0c02 +#define CSMAGIC_CODEDIRECTORY 0xfade0c02 #define CSMAGIC_EMBEDDED_SIGNATURE 0xfade0cc0 +#define CSMAGIC_ENTITLEMENTS 0xfade7171 + #define CSSLOT_CODEDIRECTORY 0 +#define CSSLOT_REQUIREMENTS 2 +#define CSSLOT_ENTITLEMENTS 5 struct BlobIndex { uint32_t type; uint32_t offset; -}; +} _packed; -struct SuperBlob { +struct Blob { uint32_t magic; uint32_t length; +} _packed; + +struct SuperBlob { + struct Blob blob; uint32_t count; struct BlobIndex index[]; -}; +} _packed; struct CodeDirectory { - uint32_t magic; - uint32_t length; + struct Blob blob; uint32_t version; uint32_t flags; uint32_t hashOffset; @@ -269,7 +284,7 @@ struct CodeDirectory { uint8_t spare1; uint8_t pageSize; uint32_t spare2; -}; +} _packed; extern "C" uint32_t hash(uint8_t *k, uint32_t length, uint32_t initval); @@ -287,16 +302,29 @@ int main(int argc, const char *argv[]) { bool flag_t(false); bool flag_p(false); bool flag_u(false); + bool flag_e(false); bool flag_T(false); + bool flag_S(false); + bool flag_s(false); bool timeh(false); uint32_t timev(0); + const void *xmld(NULL); + size_t xmls(0); + std::vector files; - _assert(argc != 0); + if (argc == 1) { + fprintf(stderr, "usage: %s -S[entitlements.xml] \n", argv[0]); + fprintf(stderr, " %s -e MobileSafari\n", argv[0]); + fprintf(stderr, " %s -S cat\n", argv[0]); + fprintf(stderr, " %s -Stfp.xml gdb\n", argv[0]); + exit(0); + } + for (int argi(1); argi != argc; ++argi) if (argv[argi][0] != '-') files.push_back(argv[argi]); @@ -305,7 +333,21 @@ int main(int argc, const char *argv[]) { case 't': flag_t = true; break; case 'u': flag_u = true; break; case 'p': flag_p = true; break; - case 'S': flag_S = true; break; + case 'e': flag_e = true; break; + + case 's': + _assert(!flag_S); + flag_s = true; + break; + + case 'S': + _assert(!flag_s); + flag_S = true; + if (argv[argi][2] != '\0') { + const char *xml = argv[argi] + 2; + xmld = map(xml, 0, _not(size_t), &xmls, true); + } + break; case 'T': { flag_T = true; @@ -334,7 +376,7 @@ int main(int argc, const char *argv[]) { char *temp(NULL), *dir; if (base != NULL) - dir = strndup(path, base++ - path + 1); + dir = strndup_(path, base++ - path + 1); else { dir = strdup(""); base = path; @@ -346,18 +388,42 @@ int main(int argc, const char *argv[]) { if (allocate == NULL) allocate = "codesign_allocate"; - size_t size; { + size_t size = _not(size_t); + const char *arch; { Framework framework(path); - size = framework.GetSize(); + _foreach (load_command, framework.GetLoadCommands()) { + uint32_t cmd(framework.Swap((*load_command)->cmd)); + if (cmd == LC_CODE_SIGNATURE) { + struct linkedit_data_command *signature = reinterpret_cast(*load_command); + size = framework.Swap(signature->dataoff); + _assert(size < framework.GetSize()); + break; + } + } + + if (size == _not(size_t)) + size = framework.GetSize(); + + switch (framework->cputype) { + case 12: switch (framework->cpusubtype) { + case 0: arch = "arm"; break; + case 6: arch = "armv6"; break; + default: arch = NULL; break; + } break; + + default: arch = NULL; break; + } } + _assert(arch != NULL); + pid_t pid = fork(); _syscall(pid); if (pid == 0) { char *ssize; - asprintf(&ssize, "%u", (sizeof(struct SuperBlob) + sizeof(struct BlobIndex) + sizeof(struct CodeDirectory) + strlen(base) + 1 + (size + 0x1000 - 1) / 0x1000 * 0x14 + 15) / 16 * 16); - printf("%s\n", ssize); - execlp(allocate, allocate, "-i", path, "-a", "arm", ssize, "-o", temp, NULL); + asprintf(&ssize, "%u", (sizeof(struct SuperBlob) + 2 * sizeof(struct BlobIndex) + sizeof(struct CodeDirectory) + strlen(base) + 1 + ((xmld == NULL ? CSSLOT_REQUIREMENTS : CSSLOT_ENTITLEMENTS) + (size + 0x1000 - 1) / 0x1000) * 0x14 + 0xc + (xmld == NULL ? 0 : 0x10 + xmls) + 15) / 16 * 16); + //printf("%s -i %s -a %s %s -o %s\n", allocate, path, arch, ssize, temp); + execlp(allocate, allocate, "-i", path, "-a", arch, ssize, "-o", temp, NULL); _assert(false); } @@ -412,6 +478,50 @@ int main(int argc, const char *argv[]) { } } + if (flag_e) { + _assert(signature != NULL); + + uint32_t data = framework.Swap(signature->dataoff); + uint32_t size = framework.Swap(signature->datasize); + + uint8_t *top = reinterpret_cast(framework.GetBase()); + uint8_t *blob = top + data; + struct SuperBlob *super = reinterpret_cast(blob); + + for (size_t index(0); index != Swap(super->count); ++index) + if (Swap(super->index[index].type) == CSSLOT_ENTITLEMENTS) { + uint32_t begin = Swap(super->index[index].offset); + struct Blob *entitlements = reinterpret_cast(blob + begin); + fwrite(entitlements + 1, 1, Swap(entitlements->length) - sizeof(struct Blob), stdout); + } + } + + if (flag_s) { + _assert(signature != NULL); + + uint32_t data = framework.Swap(signature->dataoff); + uint32_t size = framework.Swap(signature->datasize); + + uint8_t *top = reinterpret_cast(framework.GetBase()); + uint8_t *blob = top + data; + struct SuperBlob *super = reinterpret_cast(blob); + + for (size_t index(0); index != Swap(super->count); ++index) + if (Swap(super->index[index].type) == CSSLOT_CODEDIRECTORY) { + uint32_t begin = Swap(super->index[index].offset); + struct CodeDirectory *directory = reinterpret_cast(blob + begin); + + uint8_t (*hashes)[20] = reinterpret_cast(blob + begin + Swap(directory->hashOffset)); + uint32_t pages = Swap(directory->nCodeSlots); + + if (pages != 1) + for (size_t i = 0; i != pages - 1; ++i) + sha1(hashes[i], top + 0x1000 * i, 0x1000); + if (pages != 0) + sha1(hashes[pages - 1], top + 0x1000 * (pages - 1), ((data - 1) % 0x1000) + 1); + } + } + if (flag_S) { _assert(signature != NULL); @@ -421,9 +531,9 @@ int main(int argc, const char *argv[]) { uint8_t *top = reinterpret_cast(framework.GetBase()); uint8_t *blob = top + data; struct SuperBlob *super = reinterpret_cast(blob); - super->magic = Swap(CSMAGIC_EMBEDDED_SIGNATURE); + super->blob.magic = Swap(CSMAGIC_EMBEDDED_SIGNATURE); - uint32_t count = 1; + uint32_t count = xmld == NULL ? 2 : 3; uint32_t offset = sizeof(struct SuperBlob) + count * sizeof(struct BlobIndex); super->index[0].type = Swap(CSSLOT_CODEDIRECTORY); @@ -433,7 +543,7 @@ int main(int argc, const char *argv[]) { struct CodeDirectory *directory = reinterpret_cast(blob + begin); offset += sizeof(struct CodeDirectory); - directory->magic = Swap(CSMAGIC_CODEDIRECTORY); + directory->blob.magic = Swap(CSMAGIC_CODEDIRECTORY); directory->version = Swap(0x00020001); directory->flags = Swap(0); directory->codeLimit = Swap(data); @@ -447,31 +557,74 @@ int main(int argc, const char *argv[]) { strcpy(reinterpret_cast(blob + offset), base); offset += strlen(base) + 1; + uint32_t special = xmld == NULL ? CSSLOT_REQUIREMENTS : CSSLOT_ENTITLEMENTS; + directory->nSpecialSlots = Swap(special); + uint8_t (*hashes)[20] = reinterpret_cast(blob + offset); - uint32_t special = 0; + memset(hashes, 0, sizeof(*hashes) * special); + + offset += sizeof(*hashes) * special; + hashes += special; uint32_t pages = (data + 0x1000 - 1) / 0x1000; - directory->nSpecialSlots = Swap(special); directory->nCodeSlots = Swap(pages); if (pages != 1) for (size_t i = 0; i != pages - 1; ++i) - sha1(hashes[special + i], top + 0x1000 * i, 0x1000); + sha1(hashes[i], top + 0x1000 * i, 0x1000); if (pages != 0) - sha1(hashes[special + pages - 1], top + 0x1000 * (pages - 1), data % 0x1000); + sha1(hashes[pages - 1], top + 0x1000 * (pages - 1), ((data - 1) % 0x1000) + 1); directory->hashOffset = Swap(offset - begin); - offset += sizeof(*hashes) * (special + pages); - directory->length = Swap(offset - begin); + offset += sizeof(*hashes) * pages; + directory->blob.length = Swap(offset - begin); + + super->index[1].type = Swap(CSSLOT_REQUIREMENTS); + super->index[1].offset = Swap(offset); + + memcpy(blob + offset, "\xfa\xde\x0c\x01\x00\x00\x00\x0c\x00\x00\x00\x00", 0xc); + offset += 0xc; + + if (xmld != NULL) { + super->index[2].type = Swap(CSSLOT_ENTITLEMENTS); + super->index[2].offset = Swap(offset); + + uint32_t begin = offset; + struct Blob *entitlements = reinterpret_cast(blob + begin); + offset += sizeof(struct Blob); + + memcpy(blob + offset, xmld, xmls); + offset += xmls; + + entitlements->magic = Swap(CSMAGIC_ENTITLEMENTS); + entitlements->length = Swap(offset - begin); + } + + for (size_t index(0); index != count; ++index) { + uint32_t type = Swap(super->index[index].type); + if (type != 0 && type <= special) { + uint32_t offset = Swap(super->index[index].offset); + struct Blob *local = (struct Blob *) (blob + offset); + sha1((uint8_t *) (hashes - type), (uint8_t *) local, Swap(local->length)); + } + } super->count = Swap(count); - super->length = Swap(offset); + super->blob.length = Swap(offset); + + if (offset > size) { + fprintf(stderr, "offset (%u) > size (%u)\n", offset, size); + _assert(false); + } //else fprintf(stderr, "offset (%zu) <= size (%zu)\n", offset, size); - _assert(offset < size); memset(blob + offset, 0, size - offset); } if (temp) { + struct stat info; + _syscall(stat(path, &info)); + _syscall(chown(temp, info.st_uid, info.st_gid)); + _syscall(chmod(temp, info.st_mode)); _syscall(unlink(path)); _syscall(rename(temp, path)); free(temp);