From ec4c25d4140e861d6860310466d5baff59381aa1 Mon Sep 17 00:00:00 2001 From: "Jay Freeman (saurik)" Date: Fri, 26 Jun 2015 19:36:24 -0700 Subject: [PATCH] Initial version of patcyh, carved from uikittools. --- .gitignore | 6 ++ control | 12 ++++ control.sh | 5 ++ extrainst_.mm | 46 ++++++++++++++++ makefile | 35 ++++++++++++ patch.hpp | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++ patcyh.mm | 58 +++++++++++++++++++ postrm.mm | 42 ++++++++++++++ version.sh | 4 ++ 9 files changed, 358 insertions(+) create mode 100644 .gitignore create mode 100644 control create mode 100755 control.sh create mode 100644 extrainst_.mm create mode 100644 makefile create mode 100644 patch.hpp create mode 100644 patcyh.mm create mode 100644 postrm.mm create mode 100755 version.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d0ba9cb --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +_ +debs +extrainst_ +postrm +*.dylib +*.deb diff --git a/control b/control new file mode 100644 index 0000000..0137d70 --- /dev/null +++ b/control @@ -0,0 +1,12 @@ +Package: com.saurik.patcyh +Priority: optional +Section: System +Maintainer: Jay Freeman (saurik) +Architecture: iphoneos-arm +Version: +Description: patch for installd to support uikittools +Name: Patcyh +Author: Jay Freeman (saurik) +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 index 0000000..537cb66 --- /dev/null +++ b/control.sh @@ -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 index 0000000..45e70b5 --- /dev/null +++ b/extrainst_.mm @@ -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 . +**/ +/* }}} */ + +#import + +#include +#include +#include +#include +#include + +#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 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 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 . +**/ +/* }}} */ + +#ifndef PATCH_HPP +#define PATCH_HPP + +#include + +#include +#include +#include + +#include + +#define INSTALLD "/usr/libexec/installd" +#define LIBUICACHE "/usr/lib/libpatcyh.dylib" + +static void *(*$memmem)(const void *, size_t, const void *, size_t) = reinterpret_cast(dlsym(RTLD_DEFAULT, "memmem")); + +template +static bool PatchInstall(bool uninstall, void *data) { + Header *header(reinterpret_cast
(data)); + + load_command *command(reinterpret_cast(header + 1)); + for (size_t i(0); i != header->ncmds; ++i, command = reinterpret_cast(reinterpret_cast(command) + command->cmdsize)) { + if (command->cmdsize > sizeof(Header) + header->sizeofcmds - (reinterpret_cast(command) - reinterpret_cast(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(command)); + const char *name(reinterpret_cast(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(command) + command->cmdsize != reinterpret_cast(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(command) != reinterpret_cast(header + 1) + header->sizeofcmds) { + fprintf(stderr, "load command header size integrity fail\n"); + return false; + } + + if (uninstall) + return true; + + dylib_command *load(reinterpret_cast(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(data)); + switch (magic) { + case MH_MAGIC: + changed = PatchInstall(uninstall, data); + break; + case MH_MAGIC_64: + changed = PatchInstall(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 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 . +**/ +/* }}} */ + +#include +#include + +@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 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(method_getImplementation(method)); + method_setImplementation(method, reinterpret_cast(&$MIFileManager$urlsForItemsInDirectoryAtURL$ignoringSymlinks$error$)); +} diff --git a/postrm.mm b/postrm.mm new file mode 100644 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 . +**/ +/* }}} */ + +#include + +#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 index 0000000..1e204f3 --- /dev/null +++ b/version.sh @@ -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 -- 2.47.2