Main Page | File List | File Members | Related Pages

mach_inject.c

Go to the documentation of this file.
00001  /******************************************************************************
00002     mach_inject.c
00003         Copyright (c) 2003-2005 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
00004         Some rights reserved: <http://creativecommons.org/licenses/by/2.0/>
00005 
00006     ***************************************************************************/
00007 
00008 #include    "mach_inject.h"
00009 
00010 #include <mach-o/dyld.h>
00011 #include <mach-o/getsect.h>
00012 #include <mach/mach.h>
00013 #include <sys/stat.h>
00014 #include <sys/errno.h>
00015 #include <assert.h>
00016 
00017 #ifndef COMPILE_TIME_ASSERT( exp )
00018     #define COMPILE_TIME_ASSERT( exp ) { switch (0) { case 0: case (exp):; } }
00019 #endif
00020 #define ASSERT_CAST( CAST_TO, CAST_FROM ) \
00021     COMPILE_TIME_ASSERT( sizeof(CAST_TO)==sizeof(CAST_FROM) )
00022 
00023 /*******************************************************************************
00024 *   
00025 *   Interface
00026 *   
00027 *******************************************************************************/
00028 #pragma mark    -
00029 #pragma mark    (Interface)
00030 
00031     mach_error_t
00032 mach_inject(
00033         const mach_inject_entry threadEntry,
00034         const void              *paramBlock,
00035         size_t                  paramSize,
00036         pid_t                   targetProcess,
00037         vm_size_t               stackSize )
00038 {
00039     assert( threadEntry );
00040     assert( targetProcess > 0 );
00041     assert( stackSize == 0 || stackSize > 1024 );
00042     
00043     //  Find the image.
00044     const void      *image;
00045     unsigned long   imageSize;
00046     mach_error_t    err = machImageForPointer( threadEntry, &image, &imageSize );
00047     
00048     //  Initialize stackSize to default if requested.
00049     if( stackSize == 0 )
00053         stackSize = 16 * 1024;
00054     
00055     //  Convert PID to Mach Task ref.
00056     mach_port_t remoteTask = 0;
00057     if( !err )
00058         err = task_for_pid( mach_task_self(), targetProcess, &remoteTask );
00059     
00066     //  Allocate the remoteStack.
00067     vm_address_t remoteStack = (vm_address_t)NULL;
00068     if( !err )
00069         err = vm_allocate( remoteTask, &remoteStack, stackSize, 1 );
00070     
00071     //  Allocate the code.
00072     vm_address_t remoteCode = (vm_address_t)NULL;
00073     if( !err )
00074         err = vm_allocate( remoteTask, &remoteCode, imageSize, 1 );
00075     if( !err ) {
00076         ASSERT_CAST( pointer_t, image );
00077         err = vm_write( remoteTask, remoteCode, (pointer_t) image, imageSize );
00078     }
00079     
00080     //  Allocate the paramBlock if specified.
00081     vm_address_t remoteParamBlock = (vm_address_t)NULL;
00082     if( !err && paramBlock != NULL && paramSize ) {
00083         err = vm_allocate( remoteTask, &remoteParamBlock, paramSize, 1 );
00084         if( !err ) {
00085             ASSERT_CAST( pointer_t, paramBlock );
00086             err = vm_write( remoteTask, remoteParamBlock,
00087                     (pointer_t) paramBlock, paramSize );
00088         }
00089     }
00090     
00091     //  Calculate offsets.
00092     ptrdiff_t   threadEntryOffset, imageOffset;
00093     if( !err ) {
00094         //assert( (void*)threadEntry >= image && (void*)threadEntry <= (image+imageSize) );
00095         ASSERT_CAST( void*, threadEntry );
00096         threadEntryOffset = ((void*) threadEntry) - image;
00097         
00098         ASSERT_CAST( void*, remoteCode );
00099         imageOffset = ((void*) remoteCode) - image;
00100     }
00101     
00102     //  Allocate the thread.
00103     thread_act_t remoteThread;
00104     if( !err ) {
00105         ppc_thread_state_t remoteThreadState;
00106         
00110         remoteStack += stackSize / 2;
00111         
00112         bzero( &remoteThreadState, sizeof(remoteThreadState) );
00113         
00114         ASSERT_CAST( unsigned int, remoteCode );
00115         remoteThreadState.srr0 = (unsigned int) remoteCode;
00116         remoteThreadState.srr0 += threadEntryOffset;
00117         assert( remoteThreadState.srr0 < (remoteCode + imageSize) );
00118         
00119         ASSERT_CAST( unsigned int, remoteStack );
00120         remoteThreadState.r1 = (unsigned int) remoteStack;
00121         
00122         ASSERT_CAST( unsigned int, imageOffset );
00123         remoteThreadState.r3 = (unsigned int) imageOffset;
00124         
00125         ASSERT_CAST( unsigned int, remoteParamBlock );
00126         remoteThreadState.r4 = (unsigned int) remoteParamBlock;
00127         
00128         ASSERT_CAST( unsigned int, paramSize );
00129         remoteThreadState.r5 = (unsigned int) paramSize;
00130         
00131         ASSERT_CAST( unsigned int, 0xDEADBEEF );
00132         remoteThreadState.lr = (unsigned int) 0xDEADBEEF;
00133         
00134 #if 0
00135         printf( "remoteCode start: %p\n", (void*) remoteCode );
00136         printf( "remoteCode size: %ld\n", imageSize );
00137         printf( "remoteCode pc: %p\n", (void*) remoteThreadState.srr0 );
00138         printf( "remoteCode end: %p\n",
00139             (void*) (((char*)remoteCode)+imageSize) );
00140         fflush(0);
00141 #endif
00142         
00143         err = thread_create_running( remoteTask, PPC_THREAD_STATE,
00144                 (thread_state_t) &remoteThreadState, PPC_THREAD_STATE_COUNT,
00145                 &remoteThread );
00146     }
00147     
00148     if( err ) {
00149         if( remoteParamBlock )
00150             vm_deallocate( remoteTask, remoteParamBlock, paramSize );
00151         if( remoteCode )
00152             vm_deallocate( remoteTask, remoteCode, imageSize );
00153         if( remoteStack )
00154             vm_deallocate( remoteTask, remoteStack, stackSize );
00155     }
00156     
00157     return err;
00158 }
00159 
00160     mach_error_t
00161 machImageForPointer(
00162         const void *pointer,
00163         const void **image,
00164         unsigned long *size )
00165 {
00166     assert( pointer );
00167     assert( image );
00168     assert( size );
00169     
00170     unsigned long p = (unsigned long) pointer;
00171     
00172     unsigned long imageIndex, imageCount = _dyld_image_count();
00173     for( imageIndex = 0; imageIndex < imageCount; imageIndex++ ) {
00174         const struct mach_header *header = _dyld_get_image_header( imageIndex );
00175         const struct section *section = getsectbynamefromheader( header,
00176                                                                     SEG_TEXT,
00177                                                                     SECT_TEXT );
00178         long start = section->addr + _dyld_get_image_vmaddr_slide( imageIndex );
00179         long stop = start + section->size;
00180         if( p >= start && p <= stop ) {
00181             //  It is truely insane we have to stat() the file system in order
00182             //  to discover the size of an in-memory data structure.
00183             const char *imageName = _dyld_get_image_name( imageIndex );
00184             assert( imageName );
00185             struct stat sb;
00186             if( stat( imageName, &sb ) )
00187                 return unix_err( errno );
00188             if( image ) {
00189                 ASSERT_CAST( void*, header );
00190                 *image = (void*) header;
00191             }
00192             if( size ) {
00193                 ;//assertUInt32( st_size );
00194                 *size = sb.st_size;
00195             }
00196             return err_none;
00197         }
00198     }
00199     
00200     return err_threadEntry_image_not_found;
00201 }

Generated on Sun Jun 12 22:08:05 2005 for mach_inject by doxygen 1.3.4