X-Git-Url: https://git.cameronkatri.com/ldid.git/blobdiff_plain/20e7eb2982bb3bcb05b1b055faf25e7e70a980e0..289ccbbc21b8bd076510cbc08392087389b59dea:/ldid.cpp diff --git a/ldid.cpp b/ldid.cpp index 01f53b4..c246539 100644 --- a/ldid.cpp +++ b/ldid.cpp @@ -93,15 +93,20 @@ struct load_command { uint32_t cmdsize; } _packed; -#define LC_REQ_DYLD uint32_t(0x80000000) - -#define LC_SEGMENT uint32_t(0x01) -#define LC_SYMTAB uint32_t(0x02) -#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) +#define LC_REQ_DYLD uint32_t(0x80000000) + +#define LC_SEGMENT uint32_t(0x01) +#define LC_SYMTAB uint32_t(0x02) +#define LC_DYSYMTAB uint32_t(0x0b) +#define LC_LOAD_DYLIB uint32_t(0x0c) +#define LC_ID_DYLIB uint32_t(0x0d) +#define LC_SEGMENT_64 uint32_t(0x19) +#define LC_UUID uint32_t(0x1b) +#define LC_CODE_SIGNATURE uint32_t(0x1d) +#define LC_SEGMENT_SPLIT_INFO uint32_t(0x1e) +#define LC_REEXPORT_DYLIB uint32_t(0x1f | LC_REQ_DYLD) +#define LC_DYLD_INFO uint32_t(0x22) +#define LC_DYLD_INFO_ONLY uint32_t(0x22 | LC_REQ_DYLD) struct dylib { uint32_t name; @@ -131,6 +136,91 @@ struct symtab_command { uint32_t strsize; } _packed; +struct dyld_info_command { + uint32_t cmd; + uint32_t cmdsize; + uint32_t rebase_off; + uint32_t rebase_size; + uint32_t bind_off; + uint32_t bind_size; + uint32_t weak_bind_off; + uint32_t weak_bind_size; + uint32_t lazy_bind_off; + uint32_t lazy_bind_size; + uint32_t export_off; + uint32_t export_size; +} _packed; + +struct dysymtab_command { + uint32_t cmd; + uint32_t cmdsize; + uint32_t ilocalsym; + uint32_t nlocalsym; + uint32_t iextdefsym; + uint32_t nextdefsym; + uint32_t iundefsym; + uint32_t nundefsym; + uint32_t tocoff; + uint32_t ntoc; + uint32_t modtaboff; + uint32_t nmodtab; + uint32_t extrefsymoff; + uint32_t nextrefsyms; + uint32_t indirectsymoff; + uint32_t nindirectsyms; + uint32_t extreloff; + uint32_t nextrel; + uint32_t locreloff; + uint32_t nlocrel; +} _packed; + +struct dylib_table_of_contents { + uint32_t symbol_index; + uint32_t module_index; +} _packed; + +struct dylib_module { + uint32_t module_name; + uint32_t iextdefsym; + uint32_t nextdefsym; + uint32_t irefsym; + uint32_t nrefsym; + uint32_t ilocalsym; + uint32_t nlocalsym; + uint32_t iextrel; + uint32_t nextrel; + uint32_t iinit_iterm; + uint32_t ninit_nterm; + uint32_t objc_module_info_addr; + uint32_t objc_module_info_size; +} _packed; + +struct dylib_reference { + uint32_t isym:24; + uint32_t flags:8; +} _packed; + +struct relocation_info { + int32_t r_address; + uint32_t r_symbolnum:24; + uint32_t r_pcrel:1; + uint32_t r_length:2; + uint32_t r_extern:1; + uint32_t r_type:4; +} _packed; + +struct nlist { + union { + char *n_name; + int32_t n_strx; + } n_un; + + uint8_t n_type; + uint8_t n_sect; + uint8_t n_desc; + uint32_t n_value; +} _packed; + struct segment_command { uint32_t cmd; uint32_t cmdsize; @@ -145,6 +235,20 @@ struct segment_command { uint32_t flags; }; +struct segment_command_64 { + uint32_t cmd; + uint32_t cmdsize; + char segname[16]; + uint64_t vmaddr; + uint64_t vmsize; + uint64_t fileoff; + uint64_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; +}; + struct section { char sectname[16]; char segname[16]; @@ -159,6 +263,20 @@ struct section { uint32_t reserved2; }; +struct section_64 { + char sectname[16]; + char segname[16]; + uint64_t addr; + uint64_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; @@ -321,12 +439,27 @@ class MachHeader : std::vector GetSegments(const char *segment_name) { std::vector segment_commands; - _foreach (load_command, GetLoadCommands()) + _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 GetSegments64(const char *segment_name) { + std::vector segment_commands; + + _foreach (load_command, GetLoadCommands()) { + if (Swap(load_command->cmd) == LC_SEGMENT_64) { + segment_command_64 *segment_command = reinterpret_cast(load_command); + if (strncmp(segment_command->segname, segment_name, 16) == 0) + segment_commands.push_back(segment_command); + } + } return segment_commands; } @@ -385,12 +518,30 @@ class MachHeader : } }; +class FatMachHeader : + public MachHeader +{ + private: + fat_arch *fat_arch_; + + public: + FatMachHeader(void *base, size_t size, fat_arch *fat_arch) : + MachHeader(base, size), + fat_arch_(fat_arch) + { + } + + fat_arch *GetFatArch() const { + return fat_arch_; + } +}; + class FatHeader : public Data { private: fat_header *fat_header_; - std::vector mach_headers_; + std::vector mach_headers_; public: FatHeader(void *base, size_t size) : @@ -403,7 +554,7 @@ class FatHeader : goto fat; } else if (Swap(fat_header_->magic) != FAT_MAGIC) { fat_header_ = NULL; - mach_headers_.push_back(MachHeader(base, size)); + mach_headers_.push_back(FatMachHeader(base, size, NULL)); } else fat: { size_t fat_narch = Swap(fat_header_->nfat_arch); fat_arch *fat_arch = reinterpret_cast(fat_header_ + 1); @@ -411,24 +562,28 @@ class FatHeader : for (arch = 0; arch != fat_narch; ++arch) { uint32_t arch_offset = Swap(fat_arch->offset); uint32_t arch_size = Swap(fat_arch->size); - mach_headers_.push_back(MachHeader((uint8_t *) base + arch_offset, size)); + mach_headers_.push_back(FatMachHeader((uint8_t *) base + arch_offset, arch_size, fat_arch)); ++fat_arch; } } } - std::vector &GetMachHeaders() { + std::vector &GetMachHeaders() { return mach_headers_; } bool IsFat() const { return fat_header_ != NULL; } + + struct fat_header *operator ->() const { + return fat_header_; + } }; -FatHeader Map(const char *path) { +FatHeader Map(const char *path, bool ro = false) { size_t size; - void *base(map(path, 0, _not(size_t), &size, false)); + void *base(map(path, 0, _not(size_t), &size, ro)); return FatHeader(base, size); } @@ -638,43 +793,57 @@ int main(int argc, const char *argv[]) { } if (flag_r) { - size_t clip(_not(size_t)); { + uint32_t clip(0); { FatHeader fat_header(Map(path)); _foreach (mach_header, fat_header.GetMachHeaders()) { mach_header->flags = mach_header.Swap(mach_header.Swap(mach_header->flags) | MH_DYLDLINK); - size_t size(_not(size_t)); { + uint32_t size(_not(uint32_t)); { _foreach (load_command, mach_header.GetLoadCommands()) { switch (mach_header.Swap(load_command->cmd)) { case LC_CODE_SIGNATURE: { struct linkedit_data_command *signature = reinterpret_cast(load_command); + memset(reinterpret_cast(mach_header.GetBase()) + mach_header.Swap(signature->dataoff), 0, mach_header.Swap(signature->datasize)); memset(signature, 0, sizeof(struct linkedit_data_command)); - mach_header->ncmds -= 1; - mach_header->sizeofcmds -= sizeof(struct linkedit_data_command); + mach_header->ncmds = mach_header.Swap(mach_header.Swap(mach_header->ncmds) - 1); + mach_header->sizeofcmds = mach_header.Swap(uint32_t(mach_header.Swap(mach_header->sizeofcmds) - sizeof(struct linkedit_data_command))); } break; case LC_SYMTAB: { struct symtab_command *symtab = reinterpret_cast(load_command); - size = symtab->stroff + symtab->strsize; + size = mach_header.Swap(symtab->stroff) + mach_header.Swap(symtab->strsize); } break; } } + } - _foreach (segment, const_cast(mach_header).GetSegments("__LINKEDIT")) { - segment->filesize -= mach_header.GetSize() - size; + _assert(size != _not(uint32_t)); - if (!fat_header.IsFat()) - clip = size; - else - _assert(false); - } + _foreach (segment, const_cast(mach_header).GetSegments("__LINKEDIT")) { + segment->filesize -= mach_header.GetSize() - size; + + if (fat_arch *fat_arch = mach_header.GetFatArch()) { + fat_arch->size = fat_header.Swap(size); + clip = std::max(clip, fat_header.Swap(fat_arch->offset) + size); + } else + clip = std::max(clip, size); + } + + _foreach (segment, const_cast(mach_header).GetSegments64("__LINKEDIT")) { + segment->filesize -= mach_header.GetSize() - size; + + if (fat_arch *fat_arch = mach_header.GetFatArch()) { + fat_arch->size = fat_header.Swap(size); + clip = std::max(clip, fat_header.Swap(fat_arch->offset) + size); + } else + clip = std::max(clip, size); } } } - if (clip != _not(size_t)) - _syscall(truncate(path, clip)); + _assert(clip != 0); + _syscall(truncate(path, clip)); } if (flag_S) { @@ -784,7 +953,7 @@ int main(int argc, const char *argv[]) { if (flag_p) printf("path%zu='%s'\n", filei, file.c_str()); - FatHeader fat_header(Map(temp == NULL ? path : temp)); + FatHeader fat_header(Map(temp == NULL ? path : temp, !(flag_R | flag_T | flag_s | flag_S))); struct linkedit_data_command *signature(NULL); _foreach (mach_header, fat_header.GetMachHeaders()) {