]> git.saurik.com Git - cycript.git/blob - Mach/Inject.cpp
Port to Substrate: use cynject (this is GPL-safe).
[cycript.git] / Mach / Inject.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2014 Jay Freeman (saurik)
3 */
4
5 /* GNU Affero General Public License, Version 3 {{{ */
6 /*
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include <string>
23
24 #include <dlfcn.h>
25
26 #include "Exception.hpp"
27 #include "Pooling.hpp"
28
29 #if defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__))
30 #include <sys/fcntl.h>
31 #include <sys/mman.h>
32
33 #include <mach-o/loader.h>
34
35 #define CS_OPS_PIDOFFSET 6
36
37 extern "C" int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize);
38 extern "C" int proc_pidpath(int pid, void *buffer, uint32_t buffersize);
39 #endif
40
41 int main(int argc, char * const argv[], char const * const envp[]);
42 extern "C" char *MSmain0(int argc, char *argv[]);
43
44 static std::string LibraryFor(void *address) {
45 Dl_info info;
46 _assert(dladdr(address, &info) != 0);
47 return info.dli_fname;
48 }
49
50 template <typename Type_>
51 Type_ *shift(Type_ *data, size_t size) {
52 return reinterpret_cast<Type_ *>(reinterpret_cast<uint8_t *>(data) + size);
53 }
54
55 void InjectLibrary(pid_t pid) {
56 auto cynject(LibraryFor(reinterpret_cast<void *>(&main)));
57 auto slash(cynject.rfind('/'));
58 _assert(slash != std::string::npos);
59 cynject = cynject.substr(0, slash) + "/cynject";
60
61 auto library(LibraryFor(reinterpret_cast<void *>(&MSmain0)));
62
63 #if defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__))
64 off_t offset;
65 _assert(csops(pid, CS_OPS_PIDOFFSET, &offset, sizeof(offset)) != -1);
66
67 char path[PATH_MAX];
68 int writ(proc_pidpath(pid, path, sizeof(path)) != 0);
69 _assert(writ != 0);
70
71 auto fd(_syscall(open(path, O_RDONLY)));
72
73 auto page(getpagesize());
74 auto size(page * 4);
75 auto map(_syscall(mmap(NULL, size, PROT_READ, MAP_SHARED, fd, offset)));
76
77 _syscall(close(fd)); // XXX: _scope
78
79 auto header(reinterpret_cast<mach_header *>(map));
80 auto command(reinterpret_cast<load_command *>(header + 1));
81
82 switch (header->magic) {
83 case MH_MAGIC_64:
84 command = shift(command, sizeof(uint32_t));
85 case MH_MAGIC:
86 break;
87 default:
88 _assert(false);
89 }
90
91 bool ios(false);
92 for (decltype(header->ncmds) i(0); i != header->ncmds; ++i) {
93 if (command->cmd == LC_VERSION_MIN_IPHONEOS)
94 ios = true;
95 command = shift(command, command->cmdsize);
96 }
97
98 _syscall(munmap(map, size)); // XXX: _scope
99
100 auto length(library.size());
101 _assert(length >= 6);
102 length -= 6;
103
104 _assert(library.substr(length) == ".dylib");
105 library = library.substr(0, length);
106 library += ios ? "-sim" : "-sys";
107 library += ".dylib";
108 #endif
109
110 CYPool pool;
111 int status(system(pool.sprintf(1024, "%s %u %s %u", cynject.c_str(), pid, library.c_str(), getpid())));
112 _assert(status == 0);
113 }