1 /* Cycript - Optimizing JavaScript Compiler/Runtime 
   2  * Copyright (C) 2009-2013  Jay Freeman (saurik) 
   5 /* GNU General Public License, Version 3 {{{ */ 
   7  * Cycript is free software: you can redistribute it and/or modify 
   8  * it under the terms of the GNU General Public License as published 
   9  * by the Free Software Foundation, either version 3 of the License, 
  10  * or (at your option) any later version. 
  12  * Cycript is distributed in the hope that it will be useful, but 
  13  * WITHOUT ANY WARRANTY; without even the implied warranty of 
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  15  * GNU General Public License for more details. 
  17  * You should have received a copy of the GNU General Public License 
  18  * along with Cycript.  If not, see <http://www.gnu.org/licenses/>. 
  24 #include <mach/mach.h> 
  27 #include "TargetConditionals.h" 
  30 #ifdef TARGET_OS_IPHONE 
  31 #include <mach/vm_map.h> 
  32 #define mach_vm_allocate vm_allocate 
  33 #define mach_vm_protect vm_protect 
  34 #define mach_vm_write vm_write 
  35 #define mach_vm_address_t vm_address_t 
  37 #include <mach/mach_vm.h> 
  40 #include <mach/machine/thread_status.h> 
  47 #include "Exception.hpp" 
  48 #include "Pooling.hpp" 
  49 #include "Trampoline.t.hpp" 
  51 extern "C" void CYHandleServer(pid_t
); 
  53 void InjectLibrary(pid_t pid
) { 
  55     _assert(dladdr(reinterpret_cast<void *>(&CYHandleServer
), &addr
) != 0); 
  56     const char *library(addr
.dli_fname
); 
  58     mach_port_t 
self(mach_task_self()), task
; 
  59     _krncall(task_for_pid(self
, pid
, &task
)); 
  61     mach_msg_type_number_t count
; 
  64     count 
= TASK_DYLD_INFO_COUNT
; 
  65     _krncall(task_info(task
, TASK_DYLD_INFO
, reinterpret_cast<task_info_t
>(&info
), &count
)); 
  66     _assert(count 
== TASK_DYLD_INFO_COUNT
); 
  67     _assert(info
.all_image_info_addr 
!= 0); 
  70     _krncall(thread_create(task
, &thread
)); 
  72 #if defined (__i386__) || defined(__x86_64__) 
  73     x86_thread_state_t state
; 
  74 #elif defined(__arm__) 
  75     arm_thread_state_t state
; 
  80     memset(&state
, 0, sizeof(state
)); 
  81     mach_msg_type_number_t 
read(MACHINE_THREAD_STATE_COUNT
); 
  82     _krncall(thread_get_state(thread
, MACHINE_THREAD_STATE
, reinterpret_cast<thread_state_t
>(&state
), &read
)); 
  83     _assert(read 
== MACHINE_THREAD_STATE_COUNT
); 
  85     Trampoline 
*trampoline
; 
  89 #if defined(__i386__) || defined(__x86_64__) 
  90     switch (state
.tsh
.flavor
) { 
  91         case i386_THREAD_STATE
: 
  92             trampoline 
= &Trampoline_i386_
; 
  96         case x86_THREAD_STATE64
: 
  97             trampoline 
= &Trampoline_x86_64_
; 
 104 #elif defined(__arm__) 
 105     trampoline 
= &Trampoline_armv6_
; 
 109     #error XXX: implement 
 112     static const size_t Stack_(8 * 1024); 
 113     size_t length(strlen(library
) + 1), depth(sizeof(Baton
) + length
); 
 114     depth 
= (depth 
+ align 
+ 1) / align 
* align
; 
 117     uint8_t *local(pool
.malloc
<uint8_t>(depth
)); 
 118     Baton 
*baton(reinterpret_cast<Baton 
*>(local
)); 
 120     baton
->dyld 
= info
.all_image_info_addr
; 
 121     baton
->pid 
= getpid(); 
 122     memcpy(baton
->library
, library
, length
); 
 124     mach_vm_size_t 
size(depth 
+ Stack_
); 
 125     mach_vm_address_t stack
; 
 126     _krncall(mach_vm_allocate(task
, &stack
, size
, true)); 
 128     mach_vm_address_t 
data(stack 
+ Stack_
); 
 129     _krncall(mach_vm_write(task
, data
, reinterpret_cast<mach_vm_address_t
>(baton
), depth
)); 
 131     mach_vm_address_t code
; 
 132     _krncall(mach_vm_allocate(task
, &code
, trampoline
->size_
, true)); 
 133     _krncall(mach_vm_write(task
, code
, reinterpret_cast<mach_vm_address_t
>(trampoline
->data_
), trampoline
->size_
)); 
 134     _krncall(mach_vm_protect(task
, code
, trampoline
->size_
, false, VM_PROT_READ 
| VM_PROT_EXECUTE
)); 
 136     uint32_t frame
[push
]; 
 137     if (sizeof(frame
) != 0) 
 138         memset(frame
, 0, sizeof(frame
)); 
 140 #if defined(__i386__) || defined(__x86_64__) 
 141     switch (state
.tsh
.flavor
) { 
 142         case i386_THREAD_STATE
: 
 144             state
.uts
.ts32
.__eip 
= code 
+ trampoline
->entry_
; 
 145             state
.uts
.ts32
.__esp 
= stack 
+ Stack_ 
- sizeof(frame
); 
 147         case x86_THREAD_STATE64
: 
 148             state
.uts
.ts64
.__rdi 
= data
; 
 149             state
.uts
.ts64
.__rip 
= code 
+ trampoline
->entry_
; 
 150             state
.uts
.ts64
.__rsp 
= stack 
+ Stack_ 
- sizeof(frame
); 
 155 #elif defined(__arm__) 
 157     state
.__pc 
= code 
+ trampoline
->entry_
; 
 158     state
.__sp 
= stack 
+ Stack_ 
- sizeof(frame
); 
 160     if ((state
.__pc 
& 0x1) != 0) { 
 162         state
.__cpsr 
|= 0x20; 
 165     #error XXX: implement 
 168     if (sizeof(frame
) != 0) 
 169         _krncall(mach_vm_write(task
, stack 
+ Stack_ 
- sizeof(frame
), reinterpret_cast<mach_vm_address_t
>(frame
), sizeof(frame
))); 
 171     _krncall(thread_set_state(thread
, MACHINE_THREAD_STATE
, reinterpret_cast<thread_state_t
>(&state
), MACHINE_THREAD_STATE_COUNT
)); 
 172     _krncall(thread_resume(thread
)); 
 174     _krncall(mach_port_deallocate(self
, task
));