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