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