]> git.saurik.com Git - patcyh.git/commitdiff
Initial version of patcyh, carved from uikittools. v1.0.0
authorJay Freeman (saurik) <saurik@saurik.com>
Sat, 27 Jun 2015 02:36:24 +0000 (19:36 -0700)
committerJay Freeman (saurik) <saurik@saurik.com>
Sat, 27 Jun 2015 02:36:24 +0000 (19:36 -0700)
.gitignore [new file with mode: 0644]
control [new file with mode: 0644]
control.sh [new file with mode: 0755]
extrainst_.mm [new file with mode: 0644]
makefile [new file with mode: 0644]
patch.hpp [new file with mode: 0644]
patcyh.mm [new file with mode: 0644]
postrm.mm [new file with mode: 0644]
version.sh [new file with mode: 0755]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..d0ba9cb
--- /dev/null
@@ -0,0 +1,6 @@
+_
+debs
+extrainst_
+postrm
+*.dylib
+*.deb
diff --git a/control b/control
new file mode 100644 (file)
index 0000000..0137d70
--- /dev/null
+++ b/control
@@ -0,0 +1,12 @@
+Package: com.saurik.patcyh
+Priority: optional
+Section: System
+Maintainer: Jay Freeman (saurik) <saurik@saurik.com>
+Architecture: iphoneos-arm
+Version: 
+Description: patch for installd to support uikittools
+Name: Patcyh
+Author: Jay Freeman (saurik) <saurik@saurik.com>
+Depiction: http://cydia.saurik.com/info/com.saurik.patcyh/
+Depends: firmware (>= 8.3), coreutils-bin, ldid
+Tag: cydia::obsolete
diff --git a/control.sh b/control.sh
new file mode 100755 (executable)
index 0000000..537cb66
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+dir=$1
+dir=${dir:=_}
+sed -e "s@^\(Version:\).*@\1 $(./version.sh)@" control
+echo "Installed-Size: $(du -s "${dir}" | cut -f 1)"
diff --git a/extrainst_.mm b/extrainst_.mm
new file mode 100644 (file)
index 0000000..45e70b5
--- /dev/null
@@ -0,0 +1,46 @@
+/* patcyh - you should pronounce it like patch
+ * Copyright (C) 2015  Jay Freeman (saurik)
+*/
+
+/* GNU General Public License, Version 3 {{{ */
+/*
+ * Cydia is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * Cydia is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cydia.  If not, see <http://www.gnu.org/licenses/>.
+**/
+/* }}} */
+
+#import <Foundation/Foundation.h>
+
+#include <notify.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "patch.hpp"
+
+int main(int argc, const char *argv[]) {
+    if (argc < 2 || (
+        strcmp(argv[1], "install") != 0 &&
+        strcmp(argv[1], "upgrade") != 0 &&
+    true)) return 0;
+
+    NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
+
+    if (!PatchInstall(false, false))
+        return 1;
+    system("launchctl stop com.apple.mobile.installd");
+
+    [pool release];
+    return 0;
+}
diff --git a/makefile b/makefile
new file mode 100644 (file)
index 0000000..f30dc74
--- /dev/null
+++ b/makefile
@@ -0,0 +1,35 @@
+library := libpatcyh.dylib
+package := com.saurik.patcyh
+control := extrainst_ postrm
+
+all: $(library)
+
+clean:
+       rm -f $(library) $(control)
+
+.PHONY: all clean package
+
+flags := -Os -Werror
+flags += -framework CoreFoundation
+flags += -framework Foundation
+
+lib%.dylib: %.mm
+       cycc -i2.0 -o$@ -- -dynamiclib $(flags) $(filter-out %.hpp,$^) $($@) -lobjc
+
+%: %.mm patch.hpp
+       cycc -i2.0 -o$@ -- $(filter-out %.hpp,$^) $(flags) $($@)
+
+package: all $(control)
+       sudo rm -rf _
+       mkdir -p _/usr/lib
+       cp -a $(library) _/usr/lib
+       mkdir -p _/DEBIAN
+       ./control.sh _ >_/DEBIAN/control
+       cp -a extrainst_ _/DEBIAN/
+       cp -a postrm _/DEBIAN/
+       mkdir -p debs
+       ln -sf debs/$(package)_$$(./version.sh)_iphoneos-arm.deb $(package).deb
+       sudo chown -R 0 _
+       sudo chgrp -R 0 _
+       dpkg-deb -b _ $(package).deb
+       readlink $(package).deb
diff --git a/patch.hpp b/patch.hpp
new file mode 100644 (file)
index 0000000..658333e
--- /dev/null
+++ b/patch.hpp
@@ -0,0 +1,150 @@
+/* patcyh - you should pronounce it like patch
+ * Copyright (C) 2015  Jay Freeman (saurik)
+*/
+
+/* GNU General Public License, Version 3 {{{ */
+/*
+ * Cydia is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * Cydia is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cydia.  If not, see <http://www.gnu.org/licenses/>.
+**/
+/* }}} */
+
+#ifndef PATCH_HPP
+#define PATCH_HPP
+
+#include <dlfcn.h>
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <mach-o/loader.h>
+
+#define INSTALLD "/usr/libexec/installd"
+#define LIBUICACHE "/usr/lib/libpatcyh.dylib"
+
+static void *(*$memmem)(const void *, size_t, const void *, size_t) = reinterpret_cast<void *(*)(const void *, size_t, const void *, size_t)>(dlsym(RTLD_DEFAULT, "memmem"));
+
+template <typename Header>
+static bool PatchInstall(bool uninstall, void *data) {
+    Header *header(reinterpret_cast<Header *>(data));
+
+    load_command *command(reinterpret_cast<load_command *>(header + 1));
+    for (size_t i(0); i != header->ncmds; ++i, command = reinterpret_cast<load_command *>(reinterpret_cast<uint8_t *>(command) + command->cmdsize)) {
+        if (command->cmdsize > sizeof(Header) + header->sizeofcmds - (reinterpret_cast<uint8_t *>(command) - reinterpret_cast<uint8_t *>(header))) {
+            fprintf(stderr, "load command is to long to fit in header\n");
+            return false;
+        }
+
+        if (command->cmd != LC_LOAD_DYLIB)
+            continue;
+
+        dylib_command *load(reinterpret_cast<dylib_command *>(command));
+        const char *name(reinterpret_cast<char *>(command) + load->dylib.name.offset);
+        if (strcmp(name, LIBUICACHE) != 0)
+            continue;
+
+        if (!uninstall)
+            return true;
+
+        if (i != header->ncmds - 1) {
+            fprintf(stderr, "load command not in final position %zd %zd\n", i, header->ncmds);
+            return false;
+        }
+
+        if (reinterpret_cast<uint8_t *>(command) + command->cmdsize != reinterpret_cast<uint8_t *>(header + 1) + header->sizeofcmds) {
+            fprintf(stderr, "load command header size integrity fail\n");
+            return false;
+        }
+
+        --header->ncmds;
+        header->sizeofcmds -= command->cmdsize;
+        memset(command, 0, command->cmdsize);
+
+        return true;
+    }
+
+    if (reinterpret_cast<uint8_t *>(command) != reinterpret_cast<uint8_t *>(header + 1) + header->sizeofcmds) {
+        fprintf(stderr, "load command header size integrity fail\n");
+        return false;
+    }
+
+    if (uninstall)
+        return true;
+
+    dylib_command *load(reinterpret_cast<dylib_command *>(command));
+    memset(load, 0, sizeof(*load));
+    load->cmd = LC_LOAD_DYLIB;
+
+    load->cmdsize = sizeof(*load) + sizeof(LIBUICACHE);
+    load->cmdsize = (load->cmdsize + 15) / 16 * 16;
+    memset(load + 1, 0, load->cmdsize - sizeof(*load));
+
+    dylib *dylib(&load->dylib);
+    dylib->name.offset = sizeof(*load);
+    memcpy(load + 1, LIBUICACHE, sizeof(LIBUICACHE));
+
+    ++header->ncmds;
+    header->sizeofcmds += load->cmdsize;
+
+    return true;
+}
+
+static bool PatchInstall(bool uninstall, bool abort) {
+    if (!abort && system("ldid --") != 0) {
+        fprintf(stderr, "this package requires ldid to be installed\n");
+        return false;
+    }
+
+    int fd(open(INSTALLD, O_RDWR));
+    if (fd == -1)
+        return false;
+
+    struct stat stat;
+    if (fstat(fd, &stat) == -1) {
+        close(fd);
+        return false;
+    }
+
+    size_t size(stat.st_size);
+    void *data(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
+    close(fd);
+    if (data == MAP_FAILED)
+        return false;
+
+    bool changed(false);
+    uint32_t magic(*reinterpret_cast<uint32_t *>(data));
+    switch (magic) {
+        case MH_MAGIC:
+            changed = PatchInstall<mach_header>(uninstall, data);
+            break;
+        case MH_MAGIC_64:
+            changed = PatchInstall<mach_header_64>(uninstall, data);
+            break;
+        default:
+            fprintf(stderr, "unknown header magic on installd: %08x\n", magic);
+            return false;
+    }
+
+    munmap(data, size);
+
+    if (changed) {
+        system("ldid -s "INSTALLD"");
+        system("cp -af "INSTALLD" "INSTALLD"_");
+        system("mv -f "INSTALLD"_ "INSTALLD"");
+    }
+
+    return true;
+}
+
+#endif//PATCH_HPP
diff --git a/patcyh.mm b/patcyh.mm
new file mode 100644 (file)
index 0000000..7730cb7
--- /dev/null
+++ b/patcyh.mm
@@ -0,0 +1,58 @@
+/* patcyh - you should pronounce it like patch
+ * Copyright (C) 2015  Jay Freeman (saurik)
+*/
+
+/* GNU General Public License, Version 3 {{{ */
+/*
+ * Cydia is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * Cydia is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cydia.  If not, see <http://www.gnu.org/licenses/>.
+**/
+/* }}} */
+
+#include <objc/runtime.h>
+#include <Foundation/Foundation.h>
+
+@interface MIFileManager
++ (MIFileManager *) defaultManager;
+- (NSURL *) destinationOfSymbolicLinkAtURL:(NSURL *)url error:(NSError *)error;
+@end
+
+static Class $MIFileManager;
+
+static NSArray *(*_MIFileManager$urlsForItemsInDirectoryAtURL$ignoringSymlinks$error$)(MIFileManager *self, SEL _cmd, NSURL *url, BOOL ignoring, NSError *error);
+
+static NSArray *$MIFileManager$urlsForItemsInDirectoryAtURL$ignoringSymlinks$error$(MIFileManager *self, SEL _cmd, NSURL *url, BOOL ignoring, NSError *error) {
+    MIFileManager *manager(reinterpret_cast<MIFileManager *>([$MIFileManager defaultManager]));
+    NSURL *destiny([manager destinationOfSymbolicLinkAtURL:url error:NULL]);
+    if (destiny == nil)
+        return _MIFileManager$urlsForItemsInDirectoryAtURL$ignoringSymlinks$error$(self, _cmd, url, YES, error);
+
+    NSArray *prefix([url pathComponents]);
+    size_t skip([[destiny pathComponents] count]);
+    NSMutableArray *items([NSMutableArray array]);
+    for (NSURL *item in _MIFileManager$urlsForItemsInDirectoryAtURL$ignoringSymlinks$error$(self, _cmd, destiny, YES, error)) {
+        NSArray *components([item pathComponents]);
+        [items addObject:[NSURL fileURLWithPathComponents:[prefix arrayByAddingObjectsFromArray:[components subarrayWithRange:NSMakeRange(skip, [components count] - skip)]]]];
+    }
+
+    return items;
+}
+
+__attribute__((__constructor__))
+static void initialize() {
+    $MIFileManager = objc_getClass("MIFileManager");
+    SEL sel(@selector(urlsForItemsInDirectoryAtURL:ignoringSymlinks:error:));
+    Method method(class_getInstanceMethod($MIFileManager, sel));
+    _MIFileManager$urlsForItemsInDirectoryAtURL$ignoringSymlinks$error$ = reinterpret_cast<NSArray *(*)(MIFileManager *, SEL, NSURL *, BOOL, NSError *)>(method_getImplementation(method));
+    method_setImplementation(method, reinterpret_cast<IMP>(&$MIFileManager$urlsForItemsInDirectoryAtURL$ignoringSymlinks$error$));
+}
diff --git a/postrm.mm b/postrm.mm
new file mode 100644 (file)
index 0000000..57f18eb
--- /dev/null
+++ b/postrm.mm
@@ -0,0 +1,42 @@
+/* patcyh - you should pronounce it like patch
+ * Copyright (C) 2015  Jay Freeman (saurik)
+*/
+
+/* GNU General Public License, Version 3 {{{ */
+/*
+ * Cydia is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * Cydia is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cydia.  If not, see <http://www.gnu.org/licenses/>.
+**/
+/* }}} */
+
+#include <Foundation/Foundation.h>
+
+#include "patch.hpp"
+
+int main(int argc, const char *argv[]) {
+    if (argc < 2 || (
+        strcmp(argv[1], "abort-install") != 0 &&
+        strcmp(argv[1], "remove") != 0 &&
+    true)) return 0;
+
+    bool abort(strcmp(argv[1], "abort-install") == 0);
+
+    NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
+
+    if (!PatchInstall(true, abort))
+        return 1;
+    system("launchctl stop com.apple.mobile.installd");
+
+    [pool release];
+    return 0;
+}
diff --git a/version.sh b/version.sh
new file mode 100755 (executable)
index 0000000..1e204f3
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/bash
+echo -n "$(git describe --tags --dirty="+" --match="v*" | sed -e 's@-\([^-]*\)-\([^-]*\)$@+\1.\2@;s@^v@@')"
+grep '#define ForRelease 0' MobileCydia.mm &>/dev/null && echo -n '~srk'
+echo