]> git.saurik.com Git - cycript.git/blob - Mach/Inject.cpp
6eb9dad11246bc8d71bdc8652a275f031e6413b2
[cycript.git] / Mach / Inject.cpp
1 #include <dlfcn.h>
2 #include <mach/mach.h>
3
4 extern "C" {
5 #include <mach-o/nlist.h>
6 }
7
8 #include <cstdio>
9 #include <pthread.h>
10 #include <unistd.h>
11
12 #include "Baton.hpp"
13 #include "Exception.hpp"
14 #include "Pooling.hpp"
15 #include "Trampoline.t.hpp"
16
17 extern "C" void _pthread_set_self(pthread_t);
18
19 template <typename Type_>
20 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
21 struct nlist &name(nl[index]);
22 uintptr_t value(name.n_value);
23 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
24 value |= 0x00000001;
25 function = reinterpret_cast<Type_>(value);
26 }
27
28 void InjectLibrary(pid_t pid) {
29 // XXX: break this into the build environment
30 const char *library("/usr/lib/libcycript.dylib");
31
32 static const size_t Stack_(8 * 1024);
33 size_t length(strlen(library) + 1), depth(sizeof(Baton) + length);
34 depth = (depth + sizeof(uintptr_t) + 1) / sizeof(uintptr_t) * sizeof(uintptr_t);
35
36 CYPool pool;
37 uint8_t *local(reinterpret_cast<uint8_t *>(apr_palloc(pool, depth)));
38 Baton *baton(reinterpret_cast<Baton *>(local));
39
40 struct nlist nl[2];
41 memset(nl, 0, sizeof(nl));
42 nl[0].n_un.n_name = (char *) "__pthread_set_self";
43 nlist("/usr/lib/libSystem.B.dylib", nl);
44 nlset(baton->_pthread_set_self, nl, 0);
45 _assert(baton->_pthread_set_self != NULL);
46
47 baton->pthread_create = &pthread_create;
48 baton->pthread_join = &pthread_join;
49
50 baton->dlopen = &dlopen;
51 baton->dlsym = &dlsym;
52
53 baton->mach_thread_self = &mach_thread_self;
54 baton->thread_terminate = &thread_terminate;
55
56 baton->pid = getpid();
57 memcpy(baton->library, library, length);
58
59 vm_size_t size(depth + Stack_);
60
61 mach_port_t self(mach_task_self()), task;
62 _krncall(task_for_pid(self, pid, &task));
63
64 vm_address_t data;
65 _krncall(vm_allocate(task, &data, size, true));
66 vm_address_t stack(data + depth);
67 vm_write(task, data, reinterpret_cast<vm_address_t>(baton), depth);
68
69 vm_address_t code;
70 _krncall(vm_allocate(task, &code, sizeof(Trampoline_), true));
71 vm_write(task, code, reinterpret_cast<vm_address_t>(Trampoline_), sizeof(Trampoline_));
72 _krncall(vm_protect(task, code, sizeof(Trampoline_), false, VM_PROT_READ | VM_PROT_EXECUTE));
73
74 thread_act_t thread;
75 _krncall(thread_create(task, &thread));
76
77 thread_state_flavor_t flavor;
78 mach_msg_type_number_t count;
79
80 #if defined(__arm__)
81 arm_thread_state_t state;
82 flavor = ARM_THREAD_STATE;
83 count = ARM_THREAD_STATE_COUNT;
84 #else
85 #error XXX: implement
86 #endif
87
88 memset(&state, 0, sizeof(state));
89
90 mach_msg_type_number_t read(count);
91 _krncall(thread_get_state(thread, flavor, reinterpret_cast<thread_state_t>(&state), &read));
92 _assert(count == count);
93
94 #if defined(__arm__)
95 state.r[0] = data;
96 state.r[1] = RTLD_LAZY | RTLD_GLOBAL;
97 state.sp = stack + Stack_;
98 state.pc = code;
99
100 if ((state.pc & 0x1) != 0) {
101 state.pc &= ~0x1;
102 state.cpsr |= 0x20;
103 }
104 #else
105 #error XXX: implement
106 #endif
107
108 _krncall(thread_set_state(thread, flavor, reinterpret_cast<thread_state_t>(&state), count));
109 _krncall(thread_resume(thread));
110
111 _krncall(mach_port_deallocate(self, task));
112 }