]> git.saurik.com Git - patcyh.git/blob - patch.hpp
For some reason, lsd crashes on iOS 8.3 with this.
[patcyh.git] / patch.hpp
1 /* patcyh - you should pronounce it like patch
2 * Copyright (C) 2015 Jay Freeman (saurik)
3 */
4
5 /* GNU General Public License, Version 3 {{{ */
6 /*
7 * Cydia is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation, either version 3 of the License,
10 * or (at your option) any later version.
11 *
12 * Cydia is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Cydia. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #ifndef PATCH_HPP
23 #define PATCH_HPP
24
25 #include <string>
26
27 #include <dlfcn.h>
28
29 #include <sys/mman.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32
33 #include <mach-o/loader.h>
34
35 #define LIBUICACHE "/usr/lib/libpatcyh.dylib"
36
37 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"));
38
39 template <typename Header>
40 static bool PatchInstall(bool uninstall, void *data) {
41 Header *header(reinterpret_cast<Header *>(data));
42
43 load_command *command(reinterpret_cast<load_command *>(header + 1));
44 for (size_t i(0); i != header->ncmds; ++i, command = reinterpret_cast<load_command *>(reinterpret_cast<uint8_t *>(command) + command->cmdsize)) {
45 if (command->cmdsize > sizeof(Header) + header->sizeofcmds - (reinterpret_cast<uint8_t *>(command) - reinterpret_cast<uint8_t *>(header))) {
46 fprintf(stderr, "load command is to long to fit in header\n");
47 return false;
48 }
49
50 if (command->cmd != LC_LOAD_DYLIB)
51 continue;
52
53 dylib_command *load(reinterpret_cast<dylib_command *>(command));
54 const char *name(reinterpret_cast<char *>(command) + load->dylib.name.offset);
55 if (strcmp(name, LIBUICACHE) != 0)
56 continue;
57
58 if (!uninstall)
59 return true;
60
61 if (i != header->ncmds - 1) {
62 fprintf(stderr, "load command not in final position %zd %zd\n", i, header->ncmds);
63 return false;
64 }
65
66 if (reinterpret_cast<uint8_t *>(command) + command->cmdsize != reinterpret_cast<uint8_t *>(header + 1) + header->sizeofcmds) {
67 fprintf(stderr, "load command header size integrity fail\n");
68 return false;
69 }
70
71 --header->ncmds;
72 header->sizeofcmds -= command->cmdsize;
73 memset(command, 0, command->cmdsize);
74
75 return true;
76 }
77
78 if (reinterpret_cast<uint8_t *>(command) != reinterpret_cast<uint8_t *>(header + 1) + header->sizeofcmds) {
79 fprintf(stderr, "load command header size integrity fail\n");
80 return false;
81 }
82
83 if (uninstall)
84 return true;
85
86 dylib_command *load(reinterpret_cast<dylib_command *>(command));
87 memset(load, 0, sizeof(*load));
88 load->cmd = LC_LOAD_DYLIB;
89
90 load->cmdsize = sizeof(*load) + sizeof(LIBUICACHE);
91 load->cmdsize = (load->cmdsize + 15) / 16 * 16;
92 memset(load + 1, 0, load->cmdsize - sizeof(*load));
93
94 dylib *dylib(&load->dylib);
95 dylib->name.offset = sizeof(*load);
96 memcpy(load + 1, LIBUICACHE, sizeof(LIBUICACHE));
97
98 ++header->ncmds;
99 header->sizeofcmds += load->cmdsize;
100
101 return true;
102 }
103
104 static bool Patch(const std::string &path, const std::string &service, bool uninstall, bool abort) {
105 if (!abort && system("ldid --") != 0) {
106 fprintf(stderr, "this package requires ldid to be installed\n");
107 return false;
108 }
109
110 int fd(open(path.c_str(), O_RDWR));
111 if (fd == -1)
112 return false;
113
114 struct stat stat;
115 if (fstat(fd, &stat) == -1) {
116 close(fd);
117 return false;
118 }
119
120 size_t size(stat.st_size);
121 void *data(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
122 close(fd);
123 if (data == MAP_FAILED)
124 return false;
125
126 bool changed(false);
127 uint32_t magic(*reinterpret_cast<uint32_t *>(data));
128 switch (magic) {
129 case MH_MAGIC:
130 changed = PatchInstall<mach_header>(uninstall, data);
131 break;
132 case MH_MAGIC_64:
133 changed = PatchInstall<mach_header_64>(uninstall, data);
134 break;
135 default:
136 fprintf(stderr, "unknown header magic on installd: %08x\n", magic);
137 return false;
138 }
139
140 munmap(data, size);
141
142 if (changed) {
143 system(("ldid -s " + path + "").c_str());
144 system(("cp -af " + path + " " + path + "_").c_str());
145 system(("mv -f " + path + "_ " + path + "").c_str());
146 system(("launchctl stop " + service + "").c_str());
147 }
148
149 return true;
150 }
151
152
153 static bool PatchInstall(bool uninstall, bool abort) {
154 return Patch("/usr/libexec/installd", "com.apple.mobile.installd", uninstall, abort);
155 }
156
157 static bool PatchLaunch(bool uninstall, bool abort) {
158 return Patch("/usr/libexec/lsd", "com.apple.lsd", uninstall, abort);
159 }
160
161 #endif//PATCH_HPP