X-Git-Url: https://git.saurik.com/ldid.git/blobdiff_plain/a960f39234fdc2738d3ad2de3de785f4287b6cb9..ab113d2205a8e142ffccfe3b385877a7330009b9:/ldid.cpp diff --git a/ldid.cpp b/ldid.cpp index 869e849..ff9358d 100644 --- a/ldid.cpp +++ b/ldid.cpp @@ -1,5 +1,5 @@ -/* JocStrap - Java/Objective-C Bootstrap - * Copyright (C) 2007 Jay Freeman (saurik) +/* ldid - (Mach-O) Link-Loader Identity Editor + * Copyright (C) 2007-2010 Jay Freeman (saurik) */ /* @@ -78,6 +78,11 @@ struct mach_header { #define MH_MAGIC 0xfeedface #define MH_CIGAM 0xcefaedfe +#define MH_MAGIC_64 0xfeedfacf +#define MH_CIGAM_64 0xcffaedfe + +#define MH_DYLDLINK 0x4 + #define MH_EXECUTE 0x2 #define MH_DYLIB 0x6 #define MH_BUNDLE 0x8 @@ -88,13 +93,14 @@ struct load_command { uint32_t cmdsize; } _packed; -#define LC_REQ_DYLD 0x80000000 +#define LC_REQ_DYLD uint32_t(0x80000000) -#define LC_LOAD_DYLIB 0x0c -#define LC_ID_DYLIB 0x0d -#define LC_UUID 0x1b -#define LC_CODE_SIGNATURE 0x1d -#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) +#define LC_SEGMENT uint32_t(0x01) +#define LC_LOAD_DYLIB uint32_t(0x0c) +#define LC_ID_DYLIB uint32_t(0x0d) +#define LC_UUID uint32_t(0x1b) +#define LC_CODE_SIGNATURE uint32_t(0x1d) +#define LC_REEXPORT_DYLIB uint32_t(0x1f | LC_REQ_DYLD) struct dylib { uint32_t name; @@ -115,6 +121,34 @@ struct uuid_command { uint8_t uuid[16]; } _packed; +struct segment_command { + uint32_t cmd; + uint32_t cmdsize; + char segname[16]; + uint32_t vmaddr; + uint32_t vmsize; + uint32_t fileoff; + uint32_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; +}; + +struct section { + char sectname[16]; + char segname[16]; + uint32_t addr; + uint32_t size; + uint32_t offset; + uint32_t align; + uint32_t reloff; + uint32_t nreloc; + uint32_t flags; + uint32_t reserved1; + uint32_t reserved2; +}; + struct linkedit_data_command { uint32_t cmd; uint32_t cmdsize; @@ -144,12 +178,14 @@ int32_t Swap_(int32_t value) { return Swap_(static_cast(value)); } +bool little_(true); + uint16_t Swap(uint16_t value) { - return true ? Swap_(value) : value; + return little_ ? Swap_(value) : value; } uint32_t Swap(uint32_t value) { - return true ? Swap_(value) : value; + return little_ ? Swap_(value) : value; } int16_t Swap(int16_t value) { @@ -160,12 +196,19 @@ int32_t Swap(int32_t value) { return Swap(static_cast(value)); } +template +class Pointer; + class Framework { private: void *base_; size_t size_; - mach_header *mach_header_; + + struct mach_header *mach_header_; + struct load_command *load_command_; + bool swapped_; + bool bits64_; public: uint16_t Swap(uint16_t value) const { @@ -210,9 +253,27 @@ class Framework { } found: - if (Swap(mach_header_->magic) == MH_CIGAM) - swapped_ = !swapped_; - else _assert(Swap(mach_header_->magic) == MH_MAGIC); + switch (Swap(mach_header_->magic)) { + case MH_CIGAM: + swapped_ = !swapped_; + case MH_MAGIC: + bits64_ = false; + break; + + case MH_CIGAM_64: + swapped_ = !swapped_; + case MH_MAGIC_64: + bits64_ = true; + break; + + default: + _assert(false); + } + + void *post = mach_header_ + 1; + if (bits64_) + post = (uint32_t *) post + 1; + load_command_ = (struct load_command *) post; _assert( Swap(mach_header_->filetype) == MH_EXECUTE || @@ -229,14 +290,22 @@ class Framework { return base_; } - size_t GetSize() { + size_t GetSize() const { return size_; } + uint32_t GetCPUType() const { + return Swap(mach_header_->cputype); + } + + uint16_t GetCPUSubtype() const { + return Swap(mach_header_->cpusubtype) & 0xff; + } + std::vector GetLoadCommands() { std::vector load_commands; - struct load_command *load_command = reinterpret_cast(mach_header_ + 1); + struct load_command *load_command = load_command_; for (uint32_t cmd = 0; cmd != Swap(mach_header_->ncmds); ++cmd) { load_commands.push_back(load_command); load_command = (struct load_command *) ((uint8_t *) load_command + Swap(load_command->cmdsize)); @@ -244,15 +313,113 @@ class Framework { return load_commands; } + + std::vector GetSegments(const char *segment_name) { + std::vector segment_commands; + + _foreach (load_command, GetLoadCommands()) + if (Swap((*load_command)->cmd) == LC_SEGMENT) { + segment_command *segment_command = reinterpret_cast(*load_command); + if (strncmp(segment_command->segname, segment_name, 16) == 0) + segment_commands.push_back(segment_command); + } + + return segment_commands; + } + + std::vector
GetSections(const char *segment_name, const char *section_name) { + std::vector
sections; + + _foreach (segment, GetSegments(segment_name)) { + section *section = (struct section *) (*segment + 1); + + uint32_t sect; + for (sect = 0; sect != Swap((*segment)->nsects); ++sect) { + if (strncmp(section->sectname, section_name, 16) == 0) + sections.push_back(section); + ++section; + } + } + + return sections; + } + + template + Pointer GetPointer(uint32_t address, const char *segment_name = NULL) { + load_command *load_command = (struct load_command *) (mach_header_ + 1); + uint32_t cmd; + + for (cmd = 0; cmd != Swap(mach_header_->ncmds); ++cmd) { + if (Swap(load_command->cmd) == LC_SEGMENT) { + segment_command *segment_command = (struct segment_command *) load_command; + if (segment_name != NULL && strncmp(segment_command->segname, segment_name, 16) != 0) + goto next_command; + + section *sections = (struct section *) (segment_command + 1); + + uint32_t sect; + for (sect = 0; sect != Swap(segment_command->nsects); ++sect) { + section *section = §ions[sect]; + //printf("%s %u %p %p %u\n", segment_command->segname, sect, address, section->addr, section->size); + if (address >= Swap(section->addr) && address < Swap(section->addr) + Swap(section->size)) { + //printf("0x%.8x %s\n", address, segment_command->segname); + return Pointer(this, reinterpret_cast(address - Swap(section->addr) + Swap(section->offset) + (char *) mach_header_)); + } + } + } + + next_command: + load_command = (struct load_command *) ((char *) load_command + Swap(load_command->cmdsize)); + } + + return Pointer(this); + } + + template + Pointer GetOffset(uint32_t offset) { + return Pointer(this, reinterpret_cast(offset + (uint8_t *) mach_header_)); + } }; -#define CSMAGIC_CODEDIRECTORY 0xfade0c02 -#define CSMAGIC_EMBEDDED_SIGNATURE 0xfade0cc0 -#define CSMAGIC_ENTITLEMENTS 0xfade7171 +template +class Pointer { + private: + const Framework *framework_; + const Target_ *pointer_; -#define CSSLOT_CODEDIRECTORY 0 -#define CSSLOT_REQUIREMENTS 2 -#define CSSLOT_ENTITLEMENTS 5 + public: + Pointer(const Framework *framework = NULL, const Target_ *pointer = NULL) : + framework_(framework), + pointer_(pointer) + { + } + + operator const Target_ *() const { + return pointer_; + } + + const Target_ *operator ->() const { + return pointer_; + } + + Pointer &operator ++() { + ++pointer_; + return *this; + } + + template + Value_ Swap(Value_ value) { + return framework_->Swap(value); + } +}; + +#define CSMAGIC_CODEDIRECTORY uint32_t(0xfade0c02) +#define CSMAGIC_EMBEDDED_SIGNATURE uint32_t(0xfade0cc0) +#define CSMAGIC_ENTITLEMENTS uint32_t(0xfade7171) + +#define CSSLOT_CODEDIRECTORY uint32_t(0) +#define CSSLOT_REQUIREMENTS uint32_t(2) +#define CSSLOT_ENTITLEMENTS uint32_t(5) struct BlobIndex { uint32_t type; @@ -298,10 +465,18 @@ void sha1(uint8_t *hash, uint8_t *data, size_t size) { } int main(int argc, const char *argv[]) { + union { + uint16_t word; + uint8_t byte[2]; + } endian = {1}; + + little_ = endian.byte[0]; + bool flag_R(false); bool flag_t(false); bool flag_p(false); bool flag_u(false); + bool flag_e(false); bool flag_T(false); @@ -314,10 +489,14 @@ int main(int argc, const char *argv[]) { const void *xmld(NULL); size_t xmls(0); + uintptr_t noffset(_not(uintptr_t)); + uintptr_t woffset(_not(uintptr_t)); + std::vector files; 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); @@ -331,6 +510,7 @@ 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 'e': flag_e = true; break; case 's': _assert(!flag_S); @@ -357,6 +537,18 @@ int main(int argc, const char *argv[]) { } } break; + case 'n': { + char *arge; + noffset = strtoul(argv[argi] + 2, &arge, 0); + _assert(arge == argv[argi] + strlen(argv[argi])); + } break; + + case 'w': { + char *arge; + woffset = strtoul(argv[argi] + 2, &arge, 0); + _assert(arge == argv[argi] + strlen(argv[argi])); + } break; + default: goto usage; break; @@ -371,7 +563,6 @@ int main(int argc, const char *argv[]) { const char *path(file->c_str()); const char *base = strrchr(path, '/'); char *temp(NULL), *dir; - mode_t mode = 0; if (base != NULL) dir = strndup_(path, base++ - path + 1); @@ -389,6 +580,8 @@ int main(int argc, const char *argv[]) { size_t size = _not(size_t); const char *arch; { Framework framework(path); + framework->flags = framework.Swap(framework.Swap(framework->flags) | MH_DYLDLINK); + _foreach (load_command, framework.GetLoadCommands()) { uint32_t cmd(framework.Swap((*load_command)->cmd)); if (cmd == LC_CODE_SIGNATURE) { @@ -402,10 +595,31 @@ int main(int argc, const char *argv[]) { if (size == _not(size_t)) size = framework.GetSize(); - switch (framework->cputype) { - case 12: switch (framework->cpusubtype) { + switch (framework.GetCPUType()) { + case 7: switch (framework.GetCPUSubtype()) { + case 3: arch = "i386"; break; + default: arch = NULL; break; + } break; + + case 12: switch (framework.GetCPUSubtype()) { case 0: arch = "arm"; break; case 6: arch = "armv6"; break; + case 9: arch = "armv7"; break; + default: arch = NULL; break; + } break; + + case 18: switch (framework.GetCPUSubtype()) { + case 10: arch = "ppc7400"; break; + default: arch = NULL; break; + } break; + + case 16777223: switch (framework.GetCPUSubtype()) { + case 3: arch = "x86_64"; break; + default: arch = NULL; break; + } break; + + case 16777234: switch (framework.GetCPUSubtype()) { + case 0: arch = "ppc64"; break; default: arch = NULL; break; } break; @@ -437,6 +651,17 @@ int main(int argc, const char *argv[]) { if (flag_p) printf("path%zu='%s'\n", filei, file->c_str()); + if (woffset != _not(uintptr_t)) { + Pointer wvalue(framework.GetPointer(woffset)); + if (wvalue == NULL) + printf("(null) %p\n", reinterpret_cast(woffset)); + else + printf("0x%.08x\n", *wvalue); + } + + if (noffset != _not(uintptr_t)) + printf("%s\n", &*framework.GetPointer(noffset)); + _foreach (load_command, framework.GetLoadCommands()) { uint32_t cmd(framework.Swap((*load_command)->cmd)); @@ -476,6 +701,24 @@ 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); @@ -498,7 +741,7 @@ int main(int argc, const char *argv[]) { 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 % 0x1000); + sha1(hashes[pages - 1], top + 0x1000 * (pages - 1), ((data - 1) % 0x1000) + 1); } } @@ -524,14 +767,14 @@ int main(int argc, const char *argv[]) { offset += sizeof(struct CodeDirectory); directory->blob.magic = Swap(CSMAGIC_CODEDIRECTORY); - directory->version = Swap(0x00020001); - directory->flags = Swap(0); + directory->version = Swap(uint32_t(0x00020001)); + directory->flags = Swap(uint32_t(0)); directory->codeLimit = Swap(data); directory->hashSize = 0x14; directory->hashType = 0x01; directory->spare1 = 0x00; directory->pageSize = 0x0c; - directory->spare2 = Swap(0); + directory->spare2 = Swap(uint32_t(0)); directory->identOffset = Swap(offset - begin); strcpy(reinterpret_cast(blob + offset), base); @@ -553,7 +796,7 @@ int main(int argc, const char *argv[]) { 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 % 0x1000); + sha1(hashes[pages - 1], top + 0x1000 * (pages - 1), ((data - 1) % 0x1000) + 1); directory->hashOffset = Swap(offset - begin); offset += sizeof(*hashes) * pages; @@ -593,13 +836,29 @@ int main(int argc, const char *argv[]) { super->blob.length = Swap(offset); if (offset > size) { - fprintf(stderr, "offset (%zu) > size (%zu)\n", offset, size); + fprintf(stderr, "offset (%u) > size (%u)\n", offset, size); _assert(false); } //else fprintf(stderr, "offset (%zu) <= size (%zu)\n", offset, size); memset(blob + offset, 0, size - offset); } + if (flag_S) { + uint8_t *top = reinterpret_cast(framework.GetBase()); + size_t size = framework.GetSize(); + + char *copy; + asprintf(©, "%s.%s.cp", dir, base); + FILE *file = fopen(copy, "w+"); + size_t writ = fwrite(top, 1, size, file); + _assert(writ == size); + fclose(file); + + _syscall(unlink(temp)); + free(temp); + temp = copy; + } + if (temp) { struct stat info; _syscall(stat(path, &info));