#define _scope(function) \
_scope_(__COUNTER__, function)
+#define CPU_ARCH_MASK uint32_t(0xff000000)
+#define CPU_ARCH_ABI64 uint32_t(0x01000000)
+
+#define CPU_TYPE_ANY uint32_t(-1)
+#define CPU_TYPE_VAX uint32_t( 1)
+#define CPU_TYPE_MC680x0 uint32_t( 6)
+#define CPU_TYPE_X86 uint32_t( 7)
+#define CPU_TYPE_MC98000 uint32_t(10)
+#define CPU_TYPE_HPPA uint32_t(11)
+#define CPU_TYPE_ARM uint32_t(12)
+#define CPU_TYPE_MC88000 uint32_t(13)
+#define CPU_TYPE_SPARC uint32_t(14)
+#define CPU_TYPE_I860 uint32_t(15)
+#define CPU_TYPE_POWERPC uint32_t(18)
+
+#define CPU_TYPE_I386 CPU_TYPE_X86
+
+#define CPU_TYPE_ARM64 (CPU_ARCH_ABI64 | CPU_TYPE_ARM)
+#define CPU_TYPE_POWERPC64 (CPU_ARCH_ABI64 | CPU_TYPE_POWERPC)
+#define CPU_TYPE_X86_64 (CPU_ARCH_ABI64 | CPU_TYPE_X86)
+
struct fat_header {
uint32_t magic;
uint32_t nfat_arch;
#define LC_DYLD_INFO_ONLY uint32_t(0x22 | LC_REQ_DYLD)
#define LC_ENCRYPTION_INFO_64 uint32_t(0x2c)
+union Version {
+ struct {
+ uint8_t patch;
+ uint8_t minor;
+ uint16_t major;
+ } _packed;
+
+ uint32_t value;
+};
+
struct dylib {
uint32_t name;
uint32_t timestamp;
uint32_t flags;
uint32_t reserved1;
uint32_t reserved2;
+ uint32_t reserved3;
} _packed;
struct linkedit_data_command {
return Swap(static_cast<uint64_t>(value));
}
-template <typename Target_>
-class Pointer;
-
class Swapped {
protected:
bool swapped_;
return load_commands;
}
- std::vector<segment_command *> GetSegments(const char *segment_name) const {
- std::vector<struct segment_command *> segment_commands;
-
- _foreach (load_command, GetLoadCommands()) {
- if (Swap(load_command->cmd) == LC_SEGMENT) {
- segment_command *segment_command = reinterpret_cast<struct segment_command *>(load_command);
- if (strncmp(segment_command->segname, segment_name, 16) == 0)
- segment_commands.push_back(segment_command);
- }
- }
-
- return segment_commands;
- }
-
- std::vector<segment_command_64 *> GetSegments64(const char *segment_name) const {
- std::vector<struct segment_command_64 *> segment_commands;
-
- _foreach (load_command, GetLoadCommands()) {
- if (Swap(load_command->cmd) == LC_SEGMENT_64) {
- segment_command_64 *segment_command = reinterpret_cast<struct segment_command_64 *>(load_command);
- if (strncmp(segment_command->segname, segment_name, 16) == 0)
- segment_commands.push_back(segment_command);
- }
- }
-
- return segment_commands;
- }
-
- std::vector<section *> GetSections(const char *segment_name, const char *section_name) const {
- std::vector<section *> 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;
- }
+ void ForSection(const ldid::Functor<void (const char *, const char *, void *, size_t)> &code) const {
+ _foreach (load_command, GetLoadCommands())
+ switch (Swap(load_command->cmd)) {
+ case LC_SEGMENT: {
+ auto segment(reinterpret_cast<struct segment_command *>(load_command));
+ code(segment->segname, NULL, GetOffset<void>(segment->fileoff), segment->filesize);
+ auto section(reinterpret_cast<struct section *>(segment + 1));
+ for (uint32_t i(0), e(Swap(segment->nsects)); i != e; ++i, ++section)
+ code(segment->segname, section->sectname, GetOffset<void>(segment->fileoff + section->offset), section->size);
+ } break;
- template <typename Target_>
- Pointer<Target_> GetPointer(uint32_t address, const char *segment_name = NULL) const {
- 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<Target_>(this, reinterpret_cast<Target_ *>(address - Swap(section->addr) + Swap(section->offset) + (char *) mach_header_));
- }
- }
+ case LC_SEGMENT_64: {
+ auto segment(reinterpret_cast<struct segment_command_64 *>(load_command));
+ code(segment->segname, NULL, GetOffset<void>(segment->fileoff), segment->filesize);
+ auto section(reinterpret_cast<struct section_64 *>(segment + 1));
+ for (uint32_t i(0), e(Swap(segment->nsects)); i != e; ++i, ++section)
+ code(segment->segname, section->sectname, GetOffset<void>(segment->fileoff + section->offset), section->size);
+ } break;
}
-
- next_command:
- load_command = (struct load_command *) ((char *) load_command + Swap(load_command->cmdsize));
- }
-
- return Pointer<Target_>(this);
}
template <typename Target_>
- Pointer<Target_> GetOffset(uint32_t offset) {
- return Pointer<Target_>(this, reinterpret_cast<Target_ *>(offset + (uint8_t *) mach_header_));
+ Target_ *GetOffset(uint32_t offset) const {
+ return reinterpret_cast<Target_ *>(offset + (uint8_t *) mach_header_);
}
};
}
};
-template <typename Target_>
-class Pointer {
- private:
- const MachHeader *framework_;
- const Target_ *pointer_;
-
- public:
- Pointer(const MachHeader *framework = NULL, const Target_ *pointer = NULL) :
- framework_(framework),
- pointer_(pointer)
- {
- }
-
- operator const Target_ *() const {
- return pointer_;
- }
-
- const Target_ *operator ->() const {
- return pointer_;
- }
-
- Pointer<Target_> &operator ++() {
- ++pointer_;
- return *this;
- }
-
- template <typename Value_>
- Value_ Swap(Value_ value) {
- return framework_->Swap(value);
- }
-};
-
#define CSMAGIC_REQUIREMENT uint32_t(0xfade0c00)
#define CSMAGIC_REQUIREMENTS uint32_t(0xfade0c01)
#define CSMAGIC_CODEDIRECTORY uint32_t(0xfade0c02)
LDID_SHA1(static_cast<const uint8_t *>(data), size, hash);
}
+static void sha1(std::vector<char> &hash, const void *data, size_t size) {
+ hash.resize(LDID_SHA1_DIGEST_LENGTH);
+ sha1(reinterpret_cast<uint8_t *>(hash.data()), data, size);
+}
+
struct CodesignAllocation {
FatMachHeader mach_header_;
uint32_t offset_;
}
};
+#ifndef LDID_NOTOOLS
class File {
private:
int file_;
return std::string(static_cast<char *>(data_), size_);
}
};
+#endif
namespace ldid {
-static void Allocate(const void *idata, size_t isize, std::streambuf &output, const Functor<size_t (size_t)> &allocate, const Functor<size_t (std::streambuf &output, size_t, const std::string &, const char *)> &save) {
+static void Allocate(const void *idata, size_t isize, std::streambuf &output, const Functor<size_t (const MachHeader &, size_t)> &allocate, const Functor<size_t (const MachHeader &, std::streambuf &output, size_t, const std::string &, const char *)> &save) {
FatHeader source(const_cast<void *>(idata), isize);
size_t offset(0);
size = end;
}
- size_t alloc(allocate(size));
+ size_t alloc(allocate(mach_header, size));
auto *fat_arch(mach_header.GetFatArch());
- uint32_t align(fat_arch == NULL ? 0 : source.Swap(fat_arch->align));
+ uint32_t align;
+
+ if (fat_arch != NULL)
+ align = source.Swap(fat_arch->align);
+ else switch (mach_header.GetCPUType()) {
+ case CPU_TYPE_POWERPC:
+ case CPU_TYPE_POWERPC64:
+ case CPU_TYPE_X86:
+ case CPU_TYPE_X86_64:
+ align = 0xc;
+ break;
+ case CPU_TYPE_ARM:
+ case CPU_TYPE_ARM64:
+ align = 0xe;
+ break;
+ default:
+ align = 0x0;
+ break;
+ }
+
offset = Align(offset, 1 << align);
uint32_t limit(size);
break;
size_t size(mach_header.Swap(allocation.limit_ + allocation.alloc_ - mach_header.Swap(segment_command->fileoff)));
segment_command->filesize = size;
- segment_command->vmsize = Align(size, PageSize_);
+ segment_command->vmsize = Align(size, 1 << allocation.align_);
} break;
case LC_SEGMENT_64: {
break;
size_t size(mach_header.Swap(allocation.limit_ + allocation.alloc_ - mach_header.Swap(segment_command->fileoff)));
segment_command->filesize = size;
- segment_command->vmsize = Align(size, PageSize_);
+ segment_command->vmsize = Align(size, 1 << allocation.align_);
} break;
}
pad(output, allocation.limit_ - allocation.size_);
position += allocation.limit_ - allocation.size_;
- size_t saved(save(output, allocation.limit_, overlap, top));
+ size_t saved(save(mach_header, output, allocation.limit_, overlap, top));
if (allocation.alloc_ > saved)
pad(output, allocation.alloc_ - saved);
position += allocation.alloc_;
}
};
+#ifndef LDID_NOTOOLS
static bool Starts(const std::string &lhs, const std::string &rhs) {
return lhs.size() >= rhs.size() && lhs.compare(0, rhs.size(), rhs) == 0;
}
_syscall(rename(temp.c_str(), path.c_str()));
}
+#endif
namespace ldid {
void Sign(const void *idata, size_t isize, std::streambuf &output, const std::string &identifier, const std::string &entitlements, const std::string &key, const Slots &slots) {
- Allocate(idata, isize, output, fun([&](size_t size) -> size_t {
+ Allocate(idata, isize, output, fun([&](const MachHeader &mach_header, size_t size) -> size_t {
size_t alloc(sizeof(struct SuperBlob));
uint32_t special(0);
_foreach (slot, slots)
special = std::max(special, slot.first);
+ mach_header.ForSection(fun([&](const char *segment, const char *section, void *data, size_t size) {
+ if (strcmp(segment, "__TEXT") == 0 && section != NULL && strcmp(section, "__info_plist") == 0)
+ special = std::max(special, CSSLOT_INFOSLOT);
+ }));
+
uint32_t normal((size + PageSize_ - 1) / PageSize_);
alloc = Align(alloc + (special + normal) * LDID_SHA1_DIGEST_LENGTH, 16);
return alloc;
- }), fun([&](std::streambuf &output, size_t limit, const std::string &overlap, const char *top) -> size_t {
+ }), fun([&](const MachHeader &mach_header, std::streambuf &output, size_t limit, const std::string &overlap, const char *top) -> size_t {
Blobs blobs;
if (true) {
if (true) {
std::stringbuf data;
+ Slots posts(slots);
+
+ mach_header.ForSection(fun([&](const char *segment, const char *section, void *data, size_t size) {
+ if (strcmp(segment, "__TEXT") == 0 && section != NULL && strcmp(section, "__info_plist") == 0)
+ sha1(posts[CSSLOT_INFOSLOT], data, size);
+ }));
+
uint32_t special(0);
_foreach (blob, blobs)
special = std::max(special, blob.first);
- _foreach (slot, slots)
+ _foreach (slot, posts)
special = std::max(special, slot.first);
uint32_t normal((limit + PageSize_ - 1) / PageSize_);
sha1((uint8_t *) (hashes - blob.first), local, Swap(local->length));
}
- _foreach (slot, slots) {
+ _foreach (slot, posts) {
_assert(sizeof(*hashes) == slot.second.size());
memcpy(hashes - slot.first, slot.second.data(), slot.second.size());
}
}));
}
+#ifndef LDID_NOTOOLS
static void Unsign(void *idata, size_t isize, std::streambuf &output) {
- Allocate(idata, isize, output, fun([](size_t size) -> size_t {
+ Allocate(idata, isize, output, fun([](const MachHeader &mach_header, size_t size) -> size_t {
return 0;
- }), fun([](std::streambuf &output, size_t limit, const std::string &overlap, const char *top) -> size_t {
+ }), fun([](const MachHeader &mach_header, std::streambuf &output, size_t limit, const std::string &overlap, const char *top) -> size_t {
return 0;
}));
}
void DiskFolder::Find(const std::string &path, const Functor<void (const std::string &, const Functor<void (const Functor<void (std::streambuf &, std::streambuf &)> &)> &)>&code) {
Find(path, "", code);
}
+#endif
SubFolder::SubFolder(Folder &parent, const std::string &path) :
parent_(parent),
void UnionFolder::Find(const std::string &path, const Functor<void (const std::string &, const Functor<void (const Functor<void (std::streambuf &, std::streambuf &)> &)> &)> &code) {
parent_.Find(path, fun([&](const std::string &name, const Functor<void (const Functor<void (std::streambuf &, std::streambuf &)> &)> &save) {
- if (files_.find(name) == files_.end())
+ if (files_.find(path + name) == files_.end())
code(name, save);
}));
for (auto &file : files_)
- code(file.first, fun([&](const Functor<void (std::streambuf &, std::streambuf &)> &code) {
- parent_.Save(file.first, fun([&](std::streambuf &save) {
- file.second.pubseekpos(0, std::ios::in);
- code(file.second, save);
+ if (file.first.size() >= path.size() && file.first.substr(0, path.size()) == path)
+ code(file.first.substr(path.size()), fun([&](const Functor<void (std::streambuf &, std::streambuf &)> &code) {
+ parent_.Save(file.first, fun([&](std::streambuf &save) {
+ file.second.pubseekpos(0, std::ios::in);
+ code(file.second, save);
+ }));
}));
- }));
}
+#ifndef LDID_NOTOOLS
static size_t copy(std::streambuf &source, std::streambuf &target) {
size_t total(0);
for (;;) {
}
#endif
+#endif
}
+#ifndef LDID_NOTOOLS
int main(int argc, char *argv[]) {
#ifndef LDID_NOSMIME
OpenSSL_add_all_algorithms();
bool flag_A(false);
bool flag_a(false);
+ bool flag_u(false);
+
uint32_t flag_CPUType(_not(uint32_t));
uint32_t flag_CPUSubtype(_not(uint32_t));
char *arge;
unsigned number(strtoul(slot, &arge, 0));
_assert(arge == colon);
- std::vector<char> &hash(slots[number]);
- hash.resize(LDID_SHA1_DIGEST_LENGTH);
- sha1(reinterpret_cast<uint8_t *>(hash.data()), file.data(), file.size());
+ sha1(slots[number], file.data(), file.size());
} break;
case 'D': flag_D = true; break;
break;
case 'K':
- key.open(argv[argi] + 2, O_RDONLY, PROT_READ, MAP_PRIVATE);
+ if (argv[argi][2] != '\0')
+ key.open(argv[argi] + 2, O_RDONLY, PROT_READ, MAP_PRIVATE);
break;
#ifndef LDID_NOFLAGT
} break;
#endif
+ case 'u': {
+ flag_u = true;
+ } break;
+
case 'I': {
flag_I = argv[argi] + 2;
} break;
signature = reinterpret_cast<struct linkedit_data_command *>(load_command);
else if (cmd == LC_ENCRYPTION_INFO || cmd == LC_ENCRYPTION_INFO_64)
encryption = reinterpret_cast<struct encryption_info_command *>(load_command);
+ else if (cmd == LC_LOAD_DYLIB) {
+ volatile struct dylib_command *dylib_command(reinterpret_cast<struct dylib_command *>(load_command));
+ const char *name(reinterpret_cast<const char *>(load_command) + mach_header.Swap(dylib_command->dylib.name));
+
+ if (strcmp(name, "/System/Library/Frameworks/UIKit.framework/UIKit") == 0) {
+ if (flag_u) {
+ Version version;
+ version.value = mach_header.Swap(dylib_command->dylib.current_version);
+ printf("uikit=%u.%u.%u\n", version.major, version.minor, version.patch);
+ }
+ }
+ }
#ifndef LDID_NOFLAGT
else if (cmd == LC_ID_DYLIB) {
volatile struct dylib_command *dylib_command(reinterpret_cast<struct dylib_command *>(load_command));
return filee;
}
+#endif