]> git.saurik.com Git - cycript.git/blob - Mach/Inject.cpp
ace75cd032b3b9d9083b130ed149878992863e88
[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 <sstream>
23 #include <string>
24
25 #include <dlfcn.h>
26
27 #include "Exception.hpp"
28 #include "Pooling.hpp"
29
30 #if defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__))
31 #include <sys/fcntl.h>
32 #include <sys/mman.h>
33
34 #include <mach-o/loader.h>
35
36 #define CS_OPS_PIDOFFSET 6
37
38 extern "C" int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize);
39 extern "C" int proc_pidpath(int pid, void *buffer, uint32_t buffersize);
40 #endif
41
42 int main(int argc, char * const argv[], char const * const envp[]);
43 extern "C" char *MSmain0(int argc, char *argv[]);
44
45 static std::string LibraryFor(void *address) {
46 Dl_info info;
47 _assert(dladdr(address, &info) != 0);
48 return info.dli_fname;
49 }
50
51 template <typename Type_>
52 Type_ *shift(Type_ *data, size_t size) {
53 return reinterpret_cast<Type_ *>(reinterpret_cast<uint8_t *>(data) + size);
54 }
55
56 void InjectLibrary(int pid, int argc, const char *argv[]) {
57 auto cynject(LibraryFor(reinterpret_cast<void *>(&main)));
58 auto slash(cynject.rfind('/'));
59 _assert(slash != std::string::npos);
60 cynject = cynject.substr(0, slash) + "/cynject";
61
62 auto library(LibraryFor(reinterpret_cast<void *>(&MSmain0)));
63
64 #if defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__))
65 off_t offset;
66 _assert(csops(pid, CS_OPS_PIDOFFSET, &offset, sizeof(offset)) != -1);
67
68 char path[PATH_MAX];
69 int writ(proc_pidpath(pid, path, sizeof(path)) != 0);
70 _assert(writ != 0);
71
72 auto fd(_syscall(open(path, O_RDONLY)));
73
74 auto page(getpagesize());
75 auto size(page * 4);
76 auto map(_syscall(mmap(NULL, size, PROT_READ, MAP_SHARED, fd, offset)));
77
78 _syscall(close(fd)); // XXX: _scope
79
80 auto header(reinterpret_cast<mach_header *>(map));
81 auto command(reinterpret_cast<load_command *>(header + 1));
82
83 switch (header->magic) {
84 case MH_MAGIC_64:
85 command = shift(command, sizeof(uint32_t));
86 case MH_MAGIC:
87 break;
88 default:
89 _assert(false);
90 }
91
92 bool ios(false);
93 for (decltype(header->ncmds) i(0); i != header->ncmds; ++i) {
94 if (command->cmd == LC_VERSION_MIN_IPHONEOS)
95 ios = true;
96 command = shift(command, command->cmdsize);
97 }
98
99 _syscall(munmap(map, size)); // XXX: _scope
100
101 auto length(library.size());
102 _assert(length >= 6);
103 length -= 6;
104
105 _assert(library.substr(length) == ".dylib");
106 library = library.substr(0, length);
107 library += ios ? "-sim" : "-sys";
108 library += ".dylib";
109 #endif
110
111 std::ostringstream inject;
112 inject << cynject << " " << std::dec << pid << " " << library;
113 for (decltype(argc) i(0); i != argc; ++i)
114 inject << " " << argv[i];
115
116 _assert(system(inject.str().c_str()) == 0);
117 }