]> git.saurik.com Git - ldid.git/blobdiff - ldid.cpp
Detect "non-standard" Mach-O binaries to codesign.
[ldid.git] / ldid.cpp
index 62b74988e897e4f440a1a2369c164eec267bed10..ce9dec15eb175f17aa7c23b121a6b970d5c0fa2e 100644 (file)
--- a/ldid.cpp
+++ b/ldid.cpp
@@ -459,15 +459,30 @@ struct encryption_info_command {
 #define BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED      0xb0
 #define BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0xc0
 
-inline void get(std::streambuf &stream, void *data, size_t size) {
-    _assert(stream.sgetn(static_cast<char *>(data), size) == size);
+static std::streamsize read(std::streambuf &stream, void *data, size_t size) {
+    auto writ(stream.sgetn(static_cast<char *>(data), size));
+    _assert(writ >= 0);
+    return writ;
 }
 
-inline void put(std::streambuf &stream, const void *data, size_t size) {
+static inline void get(std::streambuf &stream, void *data, size_t size) {
+    _assert(read(stream, data, size) == size);
+}
+
+static inline void put(std::streambuf &stream, const void *data, size_t size) {
     _assert(stream.sputn(static_cast<const char *>(data), size) == size);
 }
 
-inline void pad(std::streambuf &stream, size_t size) {
+static size_t most(std::streambuf &stream, void *data, size_t size) {
+    size_t total(size);
+    while (size > 0)
+        if (auto writ = read(stream, data, size))
+            size -= writ;
+        else break;
+    return total - size;
+}
+
+static inline void pad(std::streambuf &stream, size_t size) {
     char padding[size];
     memset(padding, 0, size);
     put(stream, padding, size);
@@ -1679,7 +1694,7 @@ void DiskFolder::Find(const std::string &root, const std::string &base, const Fu
         else
             code(base + name, fun([&](const Functor<void (std::streambuf &, std::streambuf &)> &code) {
                 std::string access(root + base + name);
-                _assert_(Open(access, fun([&](std::streambuf &data) {
+                _assert_(Open(access, fun([&](std::streambuf &data, const void *flag) {
                     NullBuffer save;
                     code(data, save);
                 })), "open(): %s", access.c_str());
@@ -1687,20 +1702,20 @@ void DiskFolder::Find(const std::string &root, const std::string &base, const Fu
     }
 }
 
-void DiskFolder::Save(const std::string &path, const Functor<void (std::streambuf &)> &code) {
+void DiskFolder::Save(const std::string &path, const void *flag, const Functor<void (std::streambuf &)> &code) {
     std::filebuf save;
     auto from(Path(path));
     commit_[from] = Temporary(save, from);
     code(save);
 }
 
-bool DiskFolder::Open(const std::string &path, const Functor<void (std::streambuf &)> &code) {
+bool DiskFolder::Open(const std::string &path, const Functor<void (std::streambuf &, const void *)> &code) {
     std::filebuf data;
     auto result(data.open(Path(path).c_str(), std::ios::binary | std::ios::in));
     if (result == NULL)
         return false;
     _assert(result == &data);
-    code(data);
+    code(data, NULL);
     return true;
 }
 
@@ -1715,11 +1730,11 @@ SubFolder::SubFolder(Folder &parent, const std::string &path) :
 {
 }
 
-void SubFolder::Save(const std::string &path, const Functor<void (std::streambuf &)> &code) {
-    return parent_.Save(path_ + path, code);
+void SubFolder::Save(const std::string &path, const void *flag, const Functor<void (std::streambuf &)> &code) {
+    return parent_.Save(path_ + path, flag, code);
 }
 
-bool SubFolder::Open(const std::string &path, const Functor<void (std::streambuf &)> &code) {
+bool SubFolder::Open(const std::string &path, const Functor<void (std::streambuf &, const void *)> &code) {
     return parent_.Open(path_ + path, code);
 }
 
@@ -1727,40 +1742,64 @@ void SubFolder::Find(const std::string &path, const Functor<void (const std::str
     return parent_.Find(path_ + path, code);
 }
 
+std::string UnionFolder::Map(const std::string &path) {
+    auto remap(remaps_.find(path));
+    if (remap == remaps_.end())
+        return path;
+    return remap->second;
+}
+
+void UnionFolder::Map(const std::string &path, const Functor<void (const std::string &, const Functor<void (const Functor<void (std::streambuf &, std::streambuf &)> &)> &)> &code, const std::string &file, const Functor<void (const Functor<void (std::streambuf &, const void *)> &)> &save) {
+    if (file.size() >= path.size() && file.substr(0, path.size()) == path)
+        code(file.substr(path.size()), fun([&](const Functor<void (std::streambuf &, std::streambuf &)> &code) {
+            save(fun([&](std::streambuf &data, const void *flag) {
+                parent_.Save(file, flag, fun([&](std::streambuf &save) {
+                    code(data, save);
+                }));
+            }));
+        }));
+}
+
 UnionFolder::UnionFolder(Folder &parent) :
     parent_(parent)
 {
 }
 
-void UnionFolder::Save(const std::string &path, const Functor<void (std::streambuf &)> &code) {
-    return parent_.Save(path, code);
+void UnionFolder::Save(const std::string &path, const void *flag, const Functor<void (std::streambuf &)> &code) {
+    return parent_.Save(Map(path), flag, code);
 }
 
-bool UnionFolder::Open(const std::string &path, const Functor<void (std::streambuf &)> &code) {
-    auto file(files_.find(path));
-    if (file == files_.end())
-        return parent_.Open(path, code);
+bool UnionFolder::Open(const std::string &path, const Functor<void (std::streambuf &, const void *)> &code) {
+    auto file(resets_.find(path));
+    if (file == resets_.end())
+        return parent_.Open(Map(path), code);
+    auto &entry(file->second);
 
-    auto &data(file->second);
+    auto &data(entry.first);
     data.pubseekpos(0, std::ios::in);
-    code(data);
+    code(data, entry.second);
     return true;
 }
 
 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(path + name) == files_.end())
+        if (deletes_.find(path + name) == deletes_.end())
             code(name, save);
     }));
 
-    for (auto &file : files_)
-        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);
-                }));
+    for (auto &reset : resets_)
+        Map(path, code, reset.first, fun([&](const Functor<void (std::streambuf &, const void *)> &code) {
+            auto &entry(reset.second);
+            entry.first.pubseekpos(0, std::ios::in);
+            code(entry.first, entry.second);
+        }));
+
+    for (auto &remap : remaps_)
+        Map(path, code, remap.first, fun([&](const Functor<void (std::streambuf &, const void *)> &code) {
+            parent_.Open(remap.second, fun([&](std::streambuf &data, const void *flag) {
+                code(data, flag);
             }));
+        }));
 }
 
 #ifndef LDID_NOTOOLS
@@ -1883,9 +1922,10 @@ struct RuleCode {
 };
 
 #ifndef LDID_NOPLIST
-void Sign(std::streambuf &buffer, std::vector<char> &hash, std::streambuf &save, const std::string &identifier, const std::string &entitlements, const std::string &key, const Slots &slots) {
+static void Sign(const uint8_t *prefix, size_t size, std::streambuf &buffer, std::vector<char> &hash, std::streambuf &save, const std::string &identifier, const std::string &entitlements, const std::string &key, const Slots &slots) {
     // XXX: this is a miserable fail
     std::stringbuf temp;
+    put(temp, prefix, size);
     copy(buffer, temp);
     auto data(temp.str());
 
@@ -1899,7 +1939,7 @@ std::string Bundle(const std::string &root, Folder &folder, const std::string &k
 
     static const std::string info("Info.plist");
 
-    _assert_(folder.Open(info, fun([&](std::streambuf &buffer) {
+    _assert_(folder.Open(info, fun([&](std::streambuf &buffer, const void *flag) {
         plist_d(buffer, fun([&](plist_t node) {
             executable = plist_s(plist_dict_get_item(node, "CFBundleExecutable"));
             identifier = plist_s(plist_dict_get_item(node, "CFBundleIdentifier"));
@@ -1914,7 +1954,7 @@ std::string Bundle(const std::string &root, Folder &folder, const std::string &k
     auto &rules1(versions[""]);
     auto &rules2(versions["2"]);
 
-    folder.Open(signature, fun([&](std::streambuf &buffer) {
+    folder.Open(signature, fun([&](std::streambuf &buffer, const void *) {
         plist_d(buffer, fun([&](plist_t node) {
             // XXX: maybe attempt to preserve existing rules
         }));
@@ -1949,7 +1989,6 @@ std::string Bundle(const std::string &root, Folder &folder, const std::string &k
     std::map<std::string, std::vector<char>> local;
 
     static Expression nested("^PlugIns/[^/]*\\.appex/Info\\.plist$");
-    static Expression dylib("^[^/]*\\.dylib$");
 
     folder.Find("", fun([&](const std::string &name, const Functor<void (const Functor<void (std::streambuf &, std::streambuf &)> &)> &code) {
         if (!nested(name))
@@ -1969,13 +2008,33 @@ std::string Bundle(const std::string &root, Folder &folder, const std::string &k
             return;
 
         code(fun([&](std::streambuf &data, std::streambuf &save) {
-            if (dylib(name)) {
-                Slots slots;
-                Sign(data, hash, save, identifier, "", key, slots);
-            } else {
-                HashProxy proxy(hash, save);
-                copy(data, proxy);
-            }
+            union {
+                struct {
+                    uint32_t magic;
+                    uint32_t count;
+                };
+
+                uint8_t bytes[8];
+            } header;
+
+            auto size(most(data, &header.bytes, sizeof(header.bytes)));
+            if (size == sizeof(header.bytes))
+                switch (Swap(header.magic)) {
+                    case FAT_MAGIC:
+                        // Java class file format
+                        if (Swap(header.count) >= 40)
+                            break;
+                    case FAT_CIGAM:
+                    case MH_MAGIC: case MH_MAGIC_64:
+                    case MH_CIGAM: case MH_CIGAM_64:
+                        Slots slots;
+                        Sign(header.bytes, size, data, hash, save, identifier, "", key, slots);
+                        return;
+                }
+
+            HashProxy proxy(hash, save);
+            put(proxy, header.bytes, size);
+            copy(data, proxy);
         }));
 
         _assert(hash.size() == LDID_SHA1_DIGEST_LENGTH);
@@ -2046,7 +2105,7 @@ std::string Bundle(const std::string &root, Folder &folder, const std::string &k
             }
     }
 
-    folder.Save(signature, fun([&](std::streambuf &save) {
+    folder.Save(signature, NULL, fun([&](std::streambuf &save) {
         HashProxy proxy(local[signature], save);
         char *xml(NULL);
         uint32_t size;
@@ -2055,12 +2114,12 @@ std::string Bundle(const std::string &root, Folder &folder, const std::string &k
         put(proxy, xml, size);
     }));
 
-    folder.Open(executable, fun([&](std::streambuf &buffer) {
-        folder.Save(executable, fun([&](std::streambuf &save) {
+    folder.Open(executable, fun([&](std::streambuf &buffer, const void *flag) {
+        folder.Save(executable, flag, fun([&](std::streambuf &save) {
             Slots slots;
             slots[1] = local.at(info);
             slots[3] = local.at(signature);
-            Sign(buffer, local[executable], save, identifier, entitlements, key, slots);
+            Sign(NULL, 0, buffer, local[executable], save, identifier, entitlements, key, slots);
         }));
     }));