Changeset 217 for trunk/Cocoa/F-Script Anywhere/Source/mach_inject
- Timestamp:
- 05/09/06 05:56:05 (19 years ago)
- Location:
- trunk/Cocoa/F-Script Anywhere/Source/mach_inject
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Cocoa/F-Script Anywhere/Source/mach_inject/mach_inject.c
r153 r217 1 /**************************************************************************************** 2 mach_inject.c $Revision: 1.1.1.1 $ 3 4 Copyright (c) 2003 Red Shed Software. All rights reserved. 5 by Jonathan 'Wolf' Rentzsch (jon * redshed * net) 6 7 ************************************************************************************/ 8 9 #ifdef __cplusplus 10 extern "C" { 11 #endif 1 /******************************************************************************* 2 mach_inject.c 3 Copyright (c) 2003-2005 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com> 4 Some rights reserved: <http://creativecommons.org/licenses/by/2.0/> 5 6 ***************************************************************************/ 12 7 13 8 #include "mach_inject.h" 14 9 15 #include <mach-o/dyld.h> 16 #include <mach-o/getsect.h> 17 #include <mach/message.h> 18 #include <mach/mach.h> 19 #include <sys/stat.h> 20 #include <assert.h> 21 #include <stdio.h> 22 #include <errno.h> 23 24 /* doesn't show up, for some reason */ 25 void bzero(void *, size_t); 26 27 #ifdef __cplusplus 28 } 29 #endif 30 31 #ifndef COMPILE_TIME_ASSERT 10 #include <mach-o/dyld.h> 11 #include <mach-o/getsect.h> 12 #include <mach/mach.h> 13 #include <sys/stat.h> 14 #include <sys/errno.h> 15 #include <assert.h> 16 #include <stdlib.h> // for malloc() 17 #include <stdio.h> // for printf() 18 #include <mach-o/fat.h> // for fat structure decoding 19 #include <mach-o/arch.h> // to know which is local arch 20 #include <fcntl.h> // for open/close 21 // for mmap() 22 #include <sys/types.h> 23 #include <sys/mman.h> 24 25 #ifndef COMPILE_TIME_ASSERT( exp ) 32 26 #define COMPILE_TIME_ASSERT( exp ) { switch (0) { case 0: case (exp):; } } 33 27 #endif 34 #define ASSERT_CAST( CAST_TO, CAST_FROM ) COMPILE_TIME_ASSERT( sizeof(CAST_TO)==sizeof(CAST_FROM) ) 35 36 /**************************************************************************************** 28 #define ASSERT_CAST( CAST_TO, CAST_FROM ) \ 29 COMPILE_TIME_ASSERT( sizeof(CAST_TO)==sizeof(CAST_FROM) ) 30 31 #if defined(__i386__) 32 void* fixedUpImageFromImage ( 33 const void *image, 34 unsigned long imageSize, 35 unsigned int jumpTableOffset, 36 unsigned int jumpTableSize, 37 ptrdiff_t fixUpOffset); 38 #endif /* __i386__ */ 39 40 /******************************************************************************* 37 41 * 38 42 * Interface 39 43 * 40 ******************************************************************************* *********/44 *******************************************************************************/ 41 45 #pragma mark - 42 46 #pragma mark (Interface) … … 48 52 size_t paramSize, 49 53 pid_t targetProcess, 50 vm_size_t stackSize ) {51 ;//assertCodePtr( threadEntry ); 52 ;//assertPtrIfNotNull( paramBlock);53 ;//assertPositive( targetProcess);54 ;//assertIsTrue( stackSize == 0 || stackSize > 1024 );54 vm_size_t stackSize ) 55 { 56 assert( threadEntry ); 57 assert( targetProcess > 0 ); 58 assert( stackSize == 0 || stackSize > 1024 ); 55 59 56 60 // Find the image. 57 61 const void *image; 58 62 unsigned long imageSize; 59 mach_error_t err = machImageForPointer( threadEntry, &image, &imageSize ); 60 63 unsigned int jumpTableOffset; 64 unsigned int jumpTableSize; 65 mach_error_t err = machImageForPointer( threadEntry, &image, &imageSize, &jumpTableOffset, &jumpTableSize ); 66 61 67 // Initialize stackSize to default if requested. 62 68 if( stackSize == 0 ) 63 /** @bug We only want an 8K default, fix the plop-in-the-middle code below. */ 69 /** @bug 70 We only want an 8K default, fix the plop-in-the-middle code below. 71 */ 64 72 stackSize = 16 * 1024; 65 73 66 74 // Convert PID to Mach Task ref. 67 75 mach_port_t remoteTask = 0; 68 if( !err ) 76 if( !err ) { 69 77 err = task_for_pid( mach_task_self(), targetProcess, &remoteTask ); 70 71 /** @todo Would be nice to just allocate one block for both the remote stack 72 *and* the remoteCode (including the parameter data block once that's 73 written. 78 #if defined(__i386__) 79 if (err == 5) fprintf(stderr, "Could not access task for pid %d. You probably need to add user to procmod group\n", targetProcess); 80 #endif 81 } 82 83 /** @todo 84 Would be nice to just allocate one block for both the remote stack 85 *and* the remoteCode (including the parameter data block once that's 86 written. 74 87 */ 75 88 76 89 // Allocate the remoteStack. 77 vm_address_t remoteStack = NULL;90 vm_address_t remoteStack = (vm_address_t)NULL; 78 91 if( !err ) 79 92 err = vm_allocate( remoteTask, &remoteStack, stackSize, 1 ); 80 93 81 94 // Allocate the code. 82 vm_address_t remoteCode = NULL;95 vm_address_t remoteCode = (vm_address_t)NULL; 83 96 if( !err ) 84 97 err = vm_allocate( remoteTask, &remoteCode, imageSize, 1 ); 85 98 if( !err ) { 86 99 ASSERT_CAST( pointer_t, image ); 100 #if defined (__ppc__) || defined (__ppc64__) 87 101 err = vm_write( remoteTask, remoteCode, (pointer_t) image, imageSize ); 102 #elif defined (__i386__) 103 // on intel, jump table use relative jump instructions (jmp), which means 104 // the offset needs to be corrected. We thus copy the image and fix the offset by hand. 105 ptrdiff_t fixUpOffset = (ptrdiff_t) (image - remoteCode); 106 void * fixedUpImage = fixedUpImageFromImage(image, imageSize, jumpTableOffset, jumpTableSize, fixUpOffset); 107 err = vm_write( remoteTask, remoteCode, (pointer_t) fixedUpImage, imageSize ); 108 free(fixedUpImage); 109 #endif 88 110 } 89 111 90 112 // Allocate the paramBlock if specified. 91 vm_address_t remoteParamBlock = NULL;113 vm_address_t remoteParamBlock = (vm_address_t)NULL; 92 114 if( !err && paramBlock != NULL && paramSize ) { 93 115 err = vm_allocate( remoteTask, &remoteParamBlock, paramSize, 1 ); 94 116 if( !err ) { 95 117 ASSERT_CAST( pointer_t, paramBlock ); 96 err = vm_write( remoteTask, remoteParamBlock, (pointer_t) paramBlock, paramSize ); 118 err = vm_write( remoteTask, remoteParamBlock, 119 (pointer_t) paramBlock, paramSize ); 97 120 } 98 121 } … … 101 124 ptrdiff_t threadEntryOffset, imageOffset; 102 125 if( !err ) { 103 ;//assertIsWithinRange( threadEntry, image, image+imageSize);126 //assert( (void*)threadEntry >= image && (void*)threadEntry <= (image+imageSize) ); 104 127 ASSERT_CAST( void*, threadEntry ); 105 threadEntryOffset = (( long) threadEntry) - (long)image;128 threadEntryOffset = ((void*) threadEntry) - image; 106 129 107 130 ASSERT_CAST( void*, remoteCode ); 108 imageOffset = (( long) remoteCode) - (long)image;131 imageOffset = ((void*) remoteCode) - image; 109 132 } 110 133 111 134 // Allocate the thread. 112 135 thread_act_t remoteThread; 136 #if defined (__ppc__) || defined (__ppc64__) 113 137 if( !err ) { 114 138 ppc_thread_state_t remoteThreadState; 115 139 116 /** @bug Stack math should be more sophisticated than this (ala redzone). */ 140 /** @bug 141 Stack math should be more sophisticated than this (ala redzone). 142 */ 117 143 remoteStack += stackSize / 2; 118 144 … … 139 165 remoteThreadState.lr = (unsigned int) 0xDEADBEEF; 140 166 167 #if 0 141 168 printf( "remoteCode start: %p\n", (void*) remoteCode ); 142 169 printf( "remoteCode size: %ld\n", imageSize ); 143 170 printf( "remoteCode pc: %p\n", (void*) remoteThreadState.srr0 ); 144 printf( "remoteCode end: %p\n", (void*) (((char*)remoteCode)+imageSize) ); 171 printf( "remoteCode end: %p\n", 172 (void*) (((char*)remoteCode)+imageSize) ); 145 173 fflush(0); 174 #endif 146 175 147 176 err = thread_create_running( remoteTask, PPC_THREAD_STATE, … … 149 178 &remoteThread ); 150 179 } 180 #elif defined (__i386__) 181 if( !err ) { 182 183 i386_thread_state_t remoteThreadState; 184 bzero( &remoteThreadState, sizeof(remoteThreadState) ); 185 186 vm_address_t dummy_thread_struct = remoteStack; 187 remoteStack += (stackSize / 2); // this is the real stack 188 // (*) increase the stack, since we're simulating a CALL instruction, which normally pushes return address on the stack 189 remoteStack -= 4; 190 191 #define PARAM_COUNT 4 192 #define STACK_CONTENTS_SIZE ((1+PARAM_COUNT) * sizeof(unsigned int)) 193 unsigned int stackContents[1 + PARAM_COUNT]; // 1 for the return address and 1 for each param 194 // first entry is return address (see above *) 195 stackContents[0] = 0xDEADBEEF; // invalid return address. 196 // then we push function parameters one by one. 197 stackContents[1] = imageOffset; 198 stackContents[2] = remoteParamBlock; 199 stackContents[3] = paramSize; 200 // We use the remote stack we allocated as the fake thread struct. We should probably use a dedicated memory zone. 201 // We don't fill it with 0, vm_allocate did it for us 202 stackContents[4] = dummy_thread_struct; 203 204 // push stackContents 205 err = vm_write( remoteTask, remoteStack, 206 (pointer_t) stackContents, STACK_CONTENTS_SIZE); 207 208 // set remote Program Counter 209 remoteThreadState.eip = (unsigned int) (remoteCode); 210 remoteThreadState.eip += threadEntryOffset; 211 212 // set remote Stack Pointer 213 ASSERT_CAST( unsigned int, remoteStack ); 214 remoteThreadState.esp = (unsigned int) remoteStack; 215 216 #if 0 217 printf( "remoteCode start: %p\n", (void*) remoteCode ); 218 printf( "remoteCode size: %ld\n", imageSize ); 219 printf( "remoteCode pc: %p\n", (void*) remoteThreadState.eip ); 220 printf( "remoteCode end: %p\n", 221 (void*) (((char*)remoteCode)+imageSize) ); 222 fflush(0); 223 #endif 224 // create thread and launch it 225 err = thread_create_running( remoteTask, i386_THREAD_STATE, 226 (thread_state_t) &remoteThreadState, i386_THREAD_STATE_COUNT, 227 &remoteThread ); 228 } 229 #else 230 #error architecture not supported 231 #endif 151 232 152 233 if( err ) { … … 166 247 const void *pointer, 167 248 const void **image, 168 unsigned long *size ) { 169 ;//assertCodePtr( pointer ); 170 ;//assertPtr( image ); 171 ;//assertPtr( size ); 249 unsigned long *size, 250 unsigned int *jumpTableOffset, 251 unsigned int *jumpTableSize ) 252 { 253 assert( pointer ); 254 assert( image ); 255 assert( size ); 172 256 173 257 unsigned long p = (unsigned long) pointer; 258 259 if (jumpTableOffset && jumpTableSize) { 260 *jumpTableOffset = 0; 261 *jumpTableSize = 0; 262 } 174 263 175 264 unsigned long imageIndex, imageCount = _dyld_image_count(); 176 265 for( imageIndex = 0; imageIndex < imageCount; imageIndex++ ) { 177 struct mach_header *header = _dyld_get_image_header( imageIndex ); 178 const struct section *section = getsectbynamefromheader( header, SEG_TEXT, SECT_TEXT ); 266 const struct mach_header *header = _dyld_get_image_header( imageIndex ); 267 const struct section *section = getsectbynamefromheader( header, 268 SEG_TEXT, 269 SECT_TEXT ); 179 270 long start = section->addr + _dyld_get_image_vmaddr_slide( imageIndex ); 180 271 long stop = start + section->size; 181 272 if( p >= start && p <= stop ) { 182 // It is tru ly insane we have to stat() the file system in order to183 // discover the size of an in-memory data structure.184 c har *imageName = _dyld_get_image_name( imageIndex );185 ;//assertPath( imageName );273 // It is truely insane we have to stat() the file system in order 274 // to discover the size of an in-memory data structure. 275 const char *imageName = _dyld_get_image_name( imageIndex ); 276 assert( imageName ); 186 277 struct stat sb; 187 278 if( stat( imageName, &sb ) ) … … 194 285 ;//assertUInt32( st_size ); 195 286 *size = sb.st_size; 287 288 // needed for Universal binaries. Check if file is fat and get image size from there. 289 int fd = open (imageName, O_RDONLY); 290 size_t mapSize = *size; 291 char * fileImage = mmap (NULL, mapSize, PROT_READ, MAP_FILE, fd, 0); 292 293 struct fat_header* fatHeader = (struct fat_header *)fileImage; 294 if (fatHeader->magic == OSSwapBigToHostInt32(FAT_MAGIC)) { 295 //printf("This is a fat binary\n"); 296 uint32_t archCount = OSSwapBigToHostInt32(fatHeader->nfat_arch); 297 298 NXArchInfo const *localArchInfo = NXGetLocalArchInfo(); 299 300 struct fat_arch* arch = (struct fat_arch *)(fileImage + sizeof(struct fat_header)); 301 struct fat_arch* matchingArch = NULL; 302 303 int archIndex = 0; 304 for (archIndex = 0; archIndex < archCount; archIndex++) { 305 cpu_type_t cpuType = OSSwapBigToHostInt32(arch[archIndex].cputype); 306 cpu_subtype_t cpuSubtype = OSSwapBigToHostInt32(arch[archIndex].cpusubtype); 307 308 if (localArchInfo->cputype == cpuType) { 309 matchingArch = arch + archIndex; 310 if (localArchInfo->cpusubtype == cpuSubtype) break; 311 } 312 } 313 314 if (matchingArch) { 315 *size = OSSwapBigToHostInt32(matchingArch->size); 316 //printf ("found arch-specific size : %p\n", *size); 317 } 318 } 319 320 munmap (fileImage, mapSize); 321 close (fd); 322 } 323 if (jumpTableOffset && jumpTableSize) { 324 const struct section * jumpTableSection = getsectbynamefromheader( header, 325 "__IMPORT", 326 "__jump_table" ); 327 if (jumpTableSection) { 328 *jumpTableOffset = jumpTableSection->offset; 329 *jumpTableSize = jumpTableSection->size; 330 } 196 331 } 197 332 return err_none; … … 201 336 return err_threadEntry_image_not_found; 202 337 } 338 339 #if defined(__i386__) 340 void* fixedUpImageFromImage ( 341 const void *image, 342 unsigned long imageSize, 343 unsigned int jumpTableOffset, 344 unsigned int jumpTableSize, 345 ptrdiff_t fixUpOffset) 346 { 347 // first copy the full image 348 void *fixedUpImage = (void *) malloc ((size_t)imageSize); 349 bcopy(image, fixedUpImage, imageSize); 350 351 // address of jump table in copied image 352 void *jumpTable = fixedUpImage + jumpTableOffset; 353 // each JMP instruction is 5 bytes (E9 xx xx xx xx) where E9 is the opcode for JMP 354 int jumpTableCount = jumpTableSize / 5; 355 356 // skip first "E9" 357 jumpTable++; 358 359 int entry=0; 360 for (entry = 0; entry < jumpTableCount; entry++) { 361 unsigned int jmpValue = *((unsigned int *)jumpTable); 362 jmpValue += fixUpOffset; 363 *((unsigned int *)jumpTable) = jmpValue; 364 jumpTable+=5; 365 } 366 367 return fixedUpImage; 368 } 369 #endif /* __i386__ */ -
trunk/Cocoa/F-Script Anywhere/Source/mach_inject/mach_inject.h
r153 r217 1 /**************************************************************************************** 2 mach_inject.h $Revision: 1.1.1.1 $ 1 /******************************************************************************* 2 mach_inject.h 3 Copyright (c) 2003-2005 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com> 4 Some rights reserved: <http://creativecommons.org/licenses/by/2.0/> 5 6 ***************************************************************************/ 3 7 4 Copyright (c) 2003 Red Shed Software. All rights reserved. 5 by Jonathan 'Wolf' Rentzsch (jon * redshed * net) 8 /***************************************************************************//** 9 @mainpage mach_inject 10 @author Jonathan 'Wolf' Rentzsch: <http://rentzsch.com> 6 11 7 ************************************************************************************/ 8 9 /************************************************************************************/ /** 10 @mainpage mach_inject 11 @author Jonathan 'Wolf' Rentzsch (jon * redshed * net) 12 13 This package, coded in C to the Mach API, allows you to "inject" code into an 14 arbitrary process. "Injection" means both 1) copying over the necessary code into the 15 target's address space and 2) remotely creating a new thread to execute the code. 12 This package, coded in C to the Mach API, allows you to "inject" code into 13 an arbitrary process. "Injection" means both 1) copying over the necessary 14 code into the target's address space and 2) remotely creating a new thread 15 to execute the code. 16 16 17 *************************************************************************** *********/17 ***************************************************************************/ 18 18 19 19 #ifndef _mach_inject_ 20 20 #define _mach_inject_ 21 21 22 #ifdef __cplusplus23 extern "C" {24 #endif25 26 22 #include <sys/types.h> 27 23 #include <mach/error.h> 28 24 #include <mach/vm_types.h> 29 #include <stddef.h> 25 #include <stddef.h> // for ptrdiff_t 26 27 #ifdef __cplusplus 28 extern "C" { 29 #endif 30 30 31 31 #define err_threadEntry_image_not_found (err_local|1) 32 #define err_threadEntry_init_failed (err_local|2)33 32 34 33 #define INJECT_ENTRY injectEntry 35 34 #define INJECT_ENTRY_SYMBOL "injectEntry" 36 35 37 typedef void (*mach_inject_entry)( ptrdiff_t codeOffset, void *paramBlock, size_t paramSize ); 36 typedef void (*mach_inject_entry)( ptrdiff_t codeOffset, void *paramBlock, 37 size_t paramSize, void* dummy_pthread_data ); 38 38 39 /*************************************************************************** *********//**39 /***************************************************************************//** 40 40 Starts executing threadEntry in a new thread in the process specified by 41 41 targetProcess. 42 42 43 @param threadEntry -> Required pointer to injected thread's entry point. 44 @param paramBlock -> Optional pointer to block of memory to pass to the 45 injected thread. 43 @param threadEntry -> Required pointer to injected thread's entry 44 point. 45 @param paramBlock -> Optional pointer to block of memory to pass to 46 the injected thread. 46 47 @param paramSize -> Optional size of paramBlock. 47 48 @param targetProcess -> Required target process ID. 48 @param stackSize -> Optional stack size of threadEntry's thread. Set to zero49 for default (currently 8K usable).49 @param stackSize -> Optional stack size of threadEntry's thread. Set 50 to zero for default (currently 8K usable). 50 51 @result <- mach_error_t 51 52 52 *************************************************************************** *********/53 ***************************************************************************/ 53 54 54 55 mach_error_t … … 60 61 vm_size_t stackSize ); 61 62 62 /*************************************************************************** *********//**63 /***************************************************************************//** 63 64 Given a pointer, returns its Mach-O image and image size. 64 65 65 @param pointer -> Required pointer. 66 @param image <- Optional returned pointer to image (really a mach_header). 67 @param size <- Optional returned size of the image. 68 @result <- mach_error_t 66 @param pointer -> Required pointer. 67 @param image <- Optional returned pointer to image (really a 68 mach_header). 69 @param size <- Optional returned size of the image. 70 @param jumpTableOffset <- Optional returned offset of jump table within image (useful on intel) 71 @param jumpTableSize <- Optional returned size of jump table (useful on intel) 72 @result <- mach_error_t 69 73 70 *************************************************************************** *********/74 ***************************************************************************/ 71 75 72 76 mach_error_t … … 74 78 const void *pointer, 75 79 const void **image, 76 unsigned long *size ); 80 unsigned long *size, 81 unsigned int *jumpTableOffset, 82 unsigned int *jumpTableSize ); 77 83 78 #ifdef 79 }84 #ifdef __cplusplus 85 } 80 86 #endif 81 82 87 #endif // _mach_inject_
Note:
See TracChangeset
for help on using the changeset viewer.