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
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        ***************************************************************************/
    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__ */
  • 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        ***************************************************************************/
    37       
    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>
    611       
    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.
    1616
    17         ************************************************************************************/
     17        ***************************************************************************/
    1818
    1919#ifndef         _mach_inject_
    2020#define         _mach_inject_
    2121
    22 #ifdef __cplusplus
    23 extern "C" {
    24 #endif
    25 
    2622#include <sys/types.h>
    2723#include <mach/error.h>
    2824#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
    3030
    3131#define err_threadEntry_image_not_found                 (err_local|1)
    32 #define err_threadEntry_init_failed                             (err_local|2)
    3332
    3433#define INJECT_ENTRY            injectEntry
    3534#define INJECT_ENTRY_SYMBOL     "injectEntry"
    3635
    37 typedef void    (*mach_inject_entry)( ptrdiff_t codeOffset, void *paramBlock, size_t paramSize );
     36typedef void    (*mach_inject_entry)( ptrdiff_t codeOffset, void *paramBlock,
     37                                size_t paramSize, void* dummy_pthread_data );
    3838       
    39 /************************************************************************************//**
     39/***************************************************************************//**
    4040        Starts executing threadEntry in a new thread in the process specified by
    4141        targetProcess.
    4242       
    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.
    4647        @param  paramSize               ->      Optional size of paramBlock.
    4748        @param  targetProcess   ->      Required target process ID.
    48         @param  stackSize               ->      Optional stack size of threadEntry's thread. Set to zero
    49                                                                 for default (currently 8K usable).
     49        @param  stackSize               ->      Optional stack size of threadEntry's thread. Set
     50                                                                to zero for default (currently 8K usable).
    5051        @result                                 <-      mach_error_t
    5152
    52         ************************************************************************************/
     53        ***************************************************************************/
    5354
    5455        mach_error_t
     
    6061                vm_size_t                               stackSize );
    6162
    62 /************************************************************************************//**
     63/***************************************************************************//**
    6364        Given a pointer, returns its Mach-O image and image size.
    6465       
    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
    6973       
    70         ************************************************************************************/
     74        ***************************************************************************/
    7175
    7276        mach_error_t
     
    7478                const void *pointer,
    7579                const void **image,
    76                 unsigned long *size );
     80                unsigned long *size,
     81                unsigned int *jumpTableOffset,
     82                unsigned int *jumpTableSize );
    7783
    78 #ifdef __cplusplus
    79 }
     84#ifdef  __cplusplus
     85        }
    8086#endif
    81 
    8287#endif  //      _mach_inject_
Note: See TracChangeset for help on using the changeset viewer.