00001
00002
00003
00004
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
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
00044 const void *image;
00045 unsigned long imageSize;
00046 mach_error_t err = machImageForPointer( threadEntry, &image, &imageSize );
00047
00048
00049 if( stackSize == 0 )
00053 stackSize = 16 * 1024;
00054
00055
00056 mach_port_t remoteTask = 0;
00057 if( !err )
00058 err = task_for_pid( mach_task_self(), targetProcess, &remoteTask );
00059
00066
00067 vm_address_t remoteStack = (vm_address_t)NULL;
00068 if( !err )
00069 err = vm_allocate( remoteTask, &remoteStack, stackSize, 1 );
00070
00071
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
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
00092 ptrdiff_t threadEntryOffset, imageOffset;
00093 if( !err ) {
00094
00095 ASSERT_CAST( void*, threadEntry );
00096 threadEntryOffset = ((void*) threadEntry) - image;
00097
00098 ASSERT_CAST( void*, remoteCode );
00099 imageOffset = ((void*) remoteCode) - image;
00100 }
00101
00102
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
00182
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 ;
00194 *size = sb.st_size;
00195 }
00196 return err_none;
00197 }
00198 }
00199
00200 return err_threadEntry_image_not_found;
00201 }