Ignore:
Timestamp:
05/09/06 05:56:05 (18 years ago)
Author:
rchin
Message:
  • Updated to new mach_inject with support for x86
  • Updated nib files to 10.2+ format so that future updates to the f-script framework won't break fsa
  • Adjusted some code to work with the new x86 mach_inject (sends an additional argument)
  • Updates code to work with newer defines in cctools
File:
1 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        ***************************************************************************/
    127
    138#include        "mach_inject.h"
    149
    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 )
    3226        #define COMPILE_TIME_ASSERT( exp ) { switch (0) { case 0: case (exp):; } }
    3327#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__)
     32void* 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/*******************************************************************************
    3741*       
    3842*       Interface
    3943*       
    40 ****************************************************************************************/
     44*******************************************************************************/
    4145#pragma mark    -
    4246#pragma mark    (Interface)
     
    4852                size_t                                  paramSize,
    4953                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 );
    5559       
    5660        //      Find the image.
    5761        const void              *image;
    5862        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
    6167        //      Initialize stackSize to default if requested.
    6268        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                */
    6472                stackSize = 16 * 1024;
    6573       
    6674        //      Convert PID to Mach Task ref.
    6775        mach_port_t     remoteTask = 0;
    68         if( !err )
     76        if( !err ) {
    6977                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.
    7487        */
    7588       
    7689        //      Allocate the remoteStack.
    77         vm_address_t remoteStack = NULL;
     90        vm_address_t remoteStack = (vm_address_t)NULL;
    7891        if( !err )
    7992                err = vm_allocate( remoteTask, &remoteStack, stackSize, 1 );
    8093       
    8194        //      Allocate the code.
    82         vm_address_t remoteCode = NULL;
     95        vm_address_t remoteCode = (vm_address_t)NULL;
    8396        if( !err )
    8497                err = vm_allocate( remoteTask, &remoteCode, imageSize, 1 );
    8598        if( !err ) {
    8699                ASSERT_CAST( pointer_t, image );
     100#if defined (__ppc__) || defined (__ppc64__)
    87101                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
    88110        }
    89111       
    90112        //      Allocate the paramBlock if specified.
    91         vm_address_t remoteParamBlock = NULL;
     113        vm_address_t remoteParamBlock = (vm_address_t)NULL;
    92114        if( !err && paramBlock != NULL && paramSize ) {
    93115                err = vm_allocate( remoteTask, &remoteParamBlock, paramSize, 1 );
    94116                if( !err ) {
    95117                        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 );
    97120                }
    98121        }
     
    101124        ptrdiff_t       threadEntryOffset, imageOffset;
    102125        if( !err ) {
    103                 ;//assertIsWithinRange( threadEntry, image, image+imageSize );
     126                //assert( (void*)threadEntry >= image && (void*)threadEntry <= (image+imageSize) );
    104127                ASSERT_CAST( void*, threadEntry );
    105                 threadEntryOffset = ((long) threadEntry) - (long) image;
     128                threadEntryOffset = ((void*) threadEntry) - image;
    106129               
    107130                ASSERT_CAST( void*, remoteCode );
    108                 imageOffset = ((long) remoteCode) - (long) image;
     131                imageOffset = ((void*) remoteCode) - image;
    109132        }
    110133       
    111134        //      Allocate the thread.
    112135        thread_act_t remoteThread;
     136#if defined (__ppc__) || defined (__ppc64__)
    113137        if( !err ) {
    114138                ppc_thread_state_t remoteThreadState;
    115139               
    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                */
    117143                remoteStack += stackSize / 2;
    118144               
     
    139165                remoteThreadState.lr = (unsigned int) 0xDEADBEEF;
    140166               
     167#if 0
    141168                printf( "remoteCode start: %p\n", (void*) remoteCode );
    142169                printf( "remoteCode size: %ld\n", imageSize );
    143170                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) );
    145173                fflush(0);
     174#endif
    146175               
    147176                err = thread_create_running( remoteTask, PPC_THREAD_STATE,
     
    149178                                &remoteThread );
    150179        }
     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
    151232       
    152233        if( err ) {
     
    166247                const void *pointer,
    167248                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 );
    172256       
    173257        unsigned long p = (unsigned long) pointer;
     258       
     259        if (jumpTableOffset && jumpTableSize) {
     260                *jumpTableOffset = 0;
     261                *jumpTableSize = 0;
     262        }
    174263       
    175264        unsigned long imageIndex, imageCount = _dyld_image_count();
    176265        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 );
    179270                long start = section->addr + _dyld_get_image_vmaddr_slide( imageIndex );
    180271                long stop = start + section->size;
    181272                if( p >= start && p <= stop ) {
    182                         //      It is truly insane we have to stat() the file system in order to
    183                         //      discover the size of an in-memory data structure.
    184                         char *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 );
    186277                        struct stat sb;
    187278                        if( stat( imageName, &sb ) )
     
    194285                                ;//assertUInt32( st_size );
    195286                                *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                                }
    196331                        }
    197332                        return err_none;
     
    201336        return err_threadEntry_image_not_found;
    202337}
     338
     339#if defined(__i386__)
     340void* 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__ */
Note: See TracChangeset for help on using the changeset viewer.