Home | History | Annotate | Line # | Download | only in binpatch
binpatch.c revision 1.9
      1  1.9  thorpej /*	$NetBSD: binpatch.c,v 1.9 2002/05/31 20:52:14 thorpej Exp $	*/
      2  1.6   chopps 
      3  1.6   chopps /* Author: Markus Wild mw (at) eunet.ch ???   */
      4  1.6   chopps /* Modified: Rob Leland leland (at) mitre.org */
      5  1.3   chopps 
      6  1.1       mw #include <sys/types.h>
      7  1.1       mw #include <a.out.h>
      8  1.6   chopps #include <fcntl.h>
      9  1.1       mw #include <stdio.h>
     10  1.6   chopps #include <stdlib.h>
     11  1.6   chopps #include <string.h>
     12  1.6   chopps #include <unistd.h>
     13  1.5   chopps 
     14  1.5   chopps #ifdef __NetBSD__
     15  1.5   chopps /*
     16  1.5   chopps  * assume NMAGIC files are linked at 0 (for kernel)
     17  1.5   chopps  */
     18  1.5   chopps #undef N_TXTADDR
     19  1.5   chopps #define N_TXTADDR(ex) \
     20  1.5   chopps 	((N_GETMAGIC2(ex) == (ZMAGIC|0x10000) || N_GETMAGIC2(ex) == NMAGIC) ? \
     21  1.5   chopps 	0 : __LDPGSZ)
     22  1.5   chopps #endif
     23  1.1       mw 
     24  1.6   chopps 
     25  1.9  thorpej static char synusage[] =
     26  1.9  thorpej "NAME\n"
     27  1.9  thorpej "\t%s - Allows the patching of BSD binaries\n"
     28  1.9  thorpej "SYNOPSIS\n"
     29  1.9  thorpej "\t%s [-HELP]\n"
     30  1.9  thorpej "\t%s [-b|-w|-l] -s symbol[[[index]][=value]] binary\n"
     31  1.9  thorpej "\t%s [-b|-w|-l] [-o offset] -s symbol [-r value] binary\n"
     32  1.9  thorpej "\t%s [-b|-w|-l] [-o offset] -a address [-r value] binary\n";
     33  1.9  thorpej static char desusage[] =
     34  1.9  thorpej "DESCRIPTION\n"
     35  1.9  thorpej "\tAllows the patching of BSD binaries, for example,a distributed\n"
     36  1.9  thorpej "\tkernel. Recient additions allows the user to index into an array\n"
     37  1.9  thorpej "\tand assign a value. Binpatch has internal variables to allow\n"
     38  1.9  thorpej "\tyou to test it on itself under NetBSD.\n"
     39  1.9  thorpej "OPTIONS\n"
     40  1.9  thorpej "\t-a  patch variable by specifying address in hex\n"
     41  1.9  thorpej "\t-b  symbol or address to be patched is 1 byte\n"
     42  1.9  thorpej "\t-l  symbol or address to be patched is 4 bytes  (default)\n"
     43  1.9  thorpej "\t-o  offset to begin patching value relative to symbol or address\n"
     44  1.9  thorpej "\t-r  replace value, and print out previous value to stdout\n"
     45  1.9  thorpej "\t-s  patch variable by specifying symbol name. Use '[]'\n"
     46  1.9  thorpej "\t    to specify the 'index'. If '-b, -w or -l' not specified\n"
     47  1.9  thorpej "\t    then index value is used like an offset. Also can use '='\n"
     48  1.9  thorpej "\t    to assign value\n"
     49  1.9  thorpej "\t-w  symbol or address to be patched is 2 bytes\n"
     50  1.9  thorpej "EXAMPLES\n"
     51  1.9  thorpej "\tThis should print 100 (this is a nice reality check...)\n"
     52  1.9  thorpej "\t\tbinpatch -l -s _hz netbsd\n"
     53  1.9  thorpej "\tNow it gets more advanced, replace the value:\n"
     54  1.9  thorpej "\t\tbinpatch -l -s _sbic_debug -r 1 netbsd\n"
     55  1.9  thorpej "\tNow patch a variable at a given 'index' not offset,\n"
     56  1.9  thorpej "\tunder NetBSD you must use '', under AmigaDos CLI '' is optional.:\n"
     57  1.9  thorpej "\t\tbinpatch -w -s '_vieww[4]' -r 0 a.out\n"
     58  1.9  thorpej "\tsame as\n"
     59  1.9  thorpej "\t\tbinpatch -w -o 8 -s _vieww -r 0 a.out\n"
     60  1.9  thorpej "\tAnother example of using []\n"
     61  1.9  thorpej "\t\tbinpatch -s '_viewl[4]' -r 0 a.out\n"
     62  1.9  thorpej "\tsame as\n"
     63  1.9  thorpej "\t\tbinpatch -o 4 -s _viewl -r 0 a.out\n"
     64  1.9  thorpej "\tOne last example using '=' and []\n"
     65  1.9  thorpej "\t\tbinpatch -w -s '_vieww[4]=2' a.out\n"
     66  1.9  thorpej "\tSo if the kernel is not finding your drives, you could enable\n"
     67  1.9  thorpej "\tall available debugging options, helping to shed light on that problem.\n"
     68  1.9  thorpej "\t\tbinpatch -l -s _sbic_debug -r 1 netbsd	scsi-level\n"
     69  1.9  thorpej "\t\tbinpatch -l -s _sddebug -r 1 netbsd	sd-level (disk-driver)\n"
     70  1.9  thorpej "\t\tbinpatch -l -s _acdebug -r 1 netbsd	autoconfig-level\n"
     71  1.9  thorpej "SEE ALSO\n"
     72  1.9  thorpej "\tbinpatch.c binpatch(1)\n";
     73  1.6   chopps 
     74  1.1       mw extern char *optarg;
     75  1.1       mw extern int optind;
     76  1.1       mw 
     77  1.6   chopps volatile void error (char *);
     78  1.6   chopps static void Synopsis(char *program_name);
     79  1.6   chopps static void Usage(char *program_name);
     80  1.6   chopps static u_long FindAssign(char *symbol,u_long *rvalue);
     81  1.6   chopps static void FindOffset(char *symbol,u_long *index);
     82  1.1       mw 
     83  1.6   chopps /* The following variables are so binpatch can be tested on itself */
     84  1.1       mw int test = 1;
     85  1.1       mw int testbss;
     86  1.1       mw char foo = 23;
     87  1.6   chopps char  viewb[10] = {0,0,1,0,1,1,0,1,1,1};
     88  1.6   chopps short vieww[10] = {0,0,1,0,1,1,0,1,1,1};
     89  1.6   chopps long  viewl[10] = {0,0,1,0,1,1,0,1,1,1};
     90  1.6   chopps /* End of test binpatch variables */
     91  1.1       mw int
     92  1.6   chopps main(int argc, char *argv[])
     93  1.1       mw {
     94  1.1       mw   struct exec e;
     95  1.1       mw   int c;
     96  1.2       mw   u_long addr = 0, offset = 0;
     97  1.6   chopps   u_long index = 0;/* Related to offset */
     98  1.1       mw   u_long replace = 0, do_replace = 0;
     99  1.1       mw   char *symbol = 0;
    100  1.1       mw   char size = 4;  /* default to long */
    101  1.6   chopps   char size_opt = 0; /* Flag to say size option was set, used with index */
    102  1.1       mw   char *fname;
    103  1.6   chopps   char *pgname = argv[0]; /* Program name */
    104  1.1       mw   int fd;
    105  1.1       mw   int type, off;
    106  1.1       mw   u_long  lval;
    107  1.1       mw   u_short sval;
    108  1.1       mw   u_char  cval;
    109  1.8  aymeric 
    110  1.8  aymeric 
    111  1.7    lukem   while ((c = getopt (argc, argv, "H:a:bwlr:s:o:")) != -1)
    112  1.1       mw     switch (c)
    113  1.1       mw       {
    114  1.6   chopps       case 'H':
    115  1.6   chopps         Usage(argv[0]);
    116  1.6   chopps         break;
    117  1.1       mw       case 'a':
    118  1.1       mw 	if (addr || symbol)
    119  1.1       mw 	  error ("only one address/symbol allowed");
    120  1.1       mw 	if (! strncmp (optarg, "0x", 2))
    121  1.1       mw 	  sscanf (optarg, "%x", &addr);
    122  1.1       mw 	else
    123  1.1       mw 	  addr = atoi (optarg);
    124  1.1       mw 	if (! addr)
    125  1.1       mw 	  error ("invalid address");
    126  1.1       mw 	break;
    127  1.1       mw 
    128  1.1       mw       case 'b':
    129  1.1       mw 	size = 1;
    130  1.6   chopps         size_opt = 1;
    131  1.1       mw 	break;
    132  1.1       mw 
    133  1.1       mw       case 'w':
    134  1.1       mw 	size = 2;
    135  1.6   chopps         size_opt = 1;
    136  1.1       mw 	break;
    137  1.1       mw 
    138  1.1       mw       case 'l':
    139  1.1       mw 	size = 4;
    140  1.6   chopps         size_opt = 1;
    141  1.1       mw 	break;
    142  1.1       mw 
    143  1.1       mw       case 'r':
    144  1.1       mw 	do_replace = 1;
    145  1.1       mw 	if (! strncmp (optarg, "0x", 2))
    146  1.1       mw 	  sscanf (optarg, "%x", &replace);
    147  1.1       mw 	else
    148  1.1       mw 	  replace = atoi (optarg);
    149  1.1       mw 	break;
    150  1.1       mw 
    151  1.1       mw       case 's':
    152  1.1       mw 	if (addr || symbol)
    153  1.1       mw 	  error ("only one address/symbol allowed");
    154  1.1       mw 	symbol = optarg;
    155  1.1       mw 	break;
    156  1.2       mw 
    157  1.2       mw       case 'o':
    158  1.2       mw 	if (offset)
    159  1.2       mw 	  error ("only one offset allowed");
    160  1.2       mw 	if (! strncmp (optarg, "0x", 2))
    161  1.2       mw 	  sscanf (optarg, "%x", &offset);
    162  1.2       mw 	else
    163  1.2       mw           offset = atoi (optarg);
    164  1.2       mw         break;
    165  1.6   chopps       }/* while switch() */
    166  1.8  aymeric 
    167  1.6   chopps   if (argc > 1)
    168  1.6   chopps   {
    169  1.6   chopps     if (addr || symbol)
    170  1.6   chopps     {
    171  1.6   chopps       argv += optind;
    172  1.6   chopps       argc -= optind;
    173  1.6   chopps 
    174  1.6   chopps       if (argc < 1)
    175  1.6   chopps         error ("No file to patch.");
    176  1.1       mw 
    177  1.6   chopps       fname = argv[0];
    178  1.6   chopps       if ((fd = open (fname, 0)) < 0)
    179  1.6   chopps         error ("Can't open file");
    180  1.1       mw 
    181  1.6   chopps       if (read (fd, &e, sizeof (e)) != sizeof (e)
    182  1.6   chopps         || N_BADMAG (e))
    183  1.6   chopps         error ("Not a valid executable.");
    184  1.1       mw 
    185  1.6   chopps       /* fake mid, so the N_ macros work on the amiga.. */
    186  1.6   chopps       e.a_midmag |= 127 << 16;
    187  1.1       mw 
    188  1.6   chopps       if (symbol)
    189  1.6   chopps       {
    190  1.6   chopps         struct nlist nl[2];
    191  1.6   chopps         if (offset == 0)
    192  1.6   chopps 	{
    193  1.6   chopps             u_long new_do_replace = 0;
    194  1.6   chopps             new_do_replace = FindAssign(symbol,&replace);
    195  1.6   chopps             if (new_do_replace && do_replace)
    196  1.6   chopps               error("Cannot use both '=' and '-r' option!");
    197  1.6   chopps             FindOffset(symbol,&index);
    198  1.6   chopps             if (size_opt)
    199  1.6   chopps                offset = index*size; /* Treat like an index */
    200  1.6   chopps             else
    201  1.6   chopps                offset = index; /* Treat index like an offset */
    202  1.6   chopps 	    if (new_do_replace)
    203  1.6   chopps 	       do_replace = new_do_replace;
    204  1.6   chopps 	}
    205  1.6   chopps         nl[0].n_un.n_name = symbol;
    206  1.6   chopps         nl[1].n_un.n_name = 0;
    207  1.6   chopps         if (nlist (fname, nl) != 0)
    208  1.6   chopps 	{
    209  1.6   chopps           fprintf(stderr,"Symbol is %s ",symbol);
    210  1.6   chopps 	  error ("Symbol not found.");
    211  1.6   chopps         }
    212  1.6   chopps         addr = nl[0].n_value;
    213  1.6   chopps         type = nl[0].n_type & N_TYPE;
    214  1.6   chopps       }
    215  1.6   chopps       else
    216  1.6   chopps       {
    217  1.6   chopps         type = N_UNDF;
    218  1.6   chopps         if (addr >= N_TXTADDR(e) && addr < N_DATADDR(e))
    219  1.6   chopps 	  type = N_TEXT;
    220  1.6   chopps         else if (addr >= N_DATADDR(e) && addr < N_DATADDR(e) + e.a_data)
    221  1.6   chopps 	  type = N_DATA;
    222  1.6   chopps       }
    223  1.6   chopps       addr += offset;
    224  1.1       mw 
    225  1.6   chopps       /* if replace-mode, have to reopen the file for writing.
    226  1.8  aymeric          Can't do that from the beginning, or nlist() will not
    227  1.6   chopps          work (at least not under AmigaDOS) */
    228  1.6   chopps       if (do_replace)
    229  1.6   chopps       {
    230  1.6   chopps         close (fd);
    231  1.6   chopps         if ((fd = open (fname, 2)) == -1)
    232  1.6   chopps 	  error ("Can't reopen file for writing.");
    233  1.6   chopps       }
    234  1.1       mw 
    235  1.6   chopps       if (type != N_TEXT && type != N_DATA)
    236  1.6   chopps         error ("address/symbol is not in text or data section.");
    237  1.1       mw 
    238  1.6   chopps       if (type == N_TEXT)
    239  1.6   chopps         off = addr - N_TXTADDR(e) + N_TXTOFF(e);
    240  1.6   chopps       else
    241  1.6   chopps         off = addr - N_DATADDR(e) + N_DATOFF(e);
    242  1.1       mw 
    243  1.6   chopps       if (lseek (fd, off, 0) == -1)
    244  1.6   chopps         error ("lseek");
    245  1.1       mw 
    246  1.6   chopps       /* not beautiful, but works on big and little endian machines */
    247  1.6   chopps       switch (size)
    248  1.6   chopps         {
    249  1.6   chopps         case 1:
    250  1.6   chopps           if (read (fd, &cval, 1) != 1)
    251  1.6   chopps 	    error ("cread");
    252  1.6   chopps           lval = cval;
    253  1.6   chopps           break;
    254  1.6   chopps 
    255  1.6   chopps         case 2:
    256  1.6   chopps           if (read (fd, &sval, 2) != 2)
    257  1.6   chopps 	    error ("sread");
    258  1.6   chopps           lval = sval;
    259  1.6   chopps           break;
    260  1.6   chopps 
    261  1.6   chopps         case 4:
    262  1.6   chopps           if (read (fd, &lval, 4) != 4)
    263  1.6   chopps 	    error ("lread");
    264  1.6   chopps           break;
    265  1.6   chopps         }/* switch size */
    266  1.6   chopps 
    267  1.8  aymeric 
    268  1.6   chopps       if (symbol)
    269  1.6   chopps         printf ("%s(0x%x): %d (0x%x)\n", symbol, addr, lval, lval);
    270  1.6   chopps       else
    271  1.6   chopps         printf ("0x%x: %d (0x%x)\n", addr, lval, lval);
    272  1.1       mw 
    273  1.6   chopps       if (do_replace)
    274  1.6   chopps       {
    275  1.6   chopps         if (lseek (fd, off, 0) == -1)
    276  1.6   chopps 	  error ("write-lseek");
    277  1.6   chopps         switch (size)
    278  1.6   chopps 	  {
    279  1.6   chopps 	  case 1:
    280  1.6   chopps 	    cval = replace;
    281  1.6   chopps 	    if (cval != replace)
    282  1.6   chopps 	      error ("byte-value overflow.");
    283  1.6   chopps 	    if (write (fd, &cval, 1) != 1)
    284  1.6   chopps 	      error ("cwrite");
    285  1.6   chopps 	    break;
    286  1.6   chopps 
    287  1.6   chopps 	  case 2:
    288  1.6   chopps 	    sval = replace;
    289  1.6   chopps 	    if (sval != replace)
    290  1.6   chopps 	      error ("word-value overflow.");
    291  1.6   chopps 	    if (write (fd, &sval, 2) != 2)
    292  1.6   chopps 	      error ("swrite");
    293  1.6   chopps 	    break;
    294  1.6   chopps 
    295  1.6   chopps 	  case 4:
    296  1.6   chopps 	    if (write (fd, &replace, 4) != 4)
    297  1.6   chopps 	      error ("lwrite");
    298  1.6   chopps 	    break;
    299  1.6   chopps 	  }/* switch(size) */
    300  1.6   chopps       }/* if (do_replace) */
    301  1.1       mw 
    302  1.6   chopps       close (fd);
    303  1.6   chopps     }/* if(addr || symbol ) */
    304  1.6   chopps     else
    305  1.1       mw     {
    306  1.6   chopps       error("Must specify either address or symbol.");
    307  1.1       mw     }
    308  1.6   chopps   }/* if argc < 1 */
    309  1.6   chopps   else
    310  1.6   chopps   {
    311  1.6   chopps     Synopsis(pgname);
    312  1.6   chopps   }
    313  1.6   chopps   return(0);
    314  1.6   chopps }/* main () */
    315  1.1       mw 
    316  1.1       mw 
    317  1.1       mw 
    318  1.6   chopps volatile void error (char *str)
    319  1.6   chopps {
    320  1.6   chopps   fprintf (stderr, "%s\n", str);
    321  1.6   chopps   exit (1);
    322  1.1       mw }
    323  1.1       mw 
    324  1.6   chopps /* Give user very short help to avoid scrolling screen much */
    325  1.6   chopps static void Synopsis(char *pgname)
    326  1.6   chopps {
    327  1.6   chopps   fprintf(stdout,synusage,pgname,pgname,pgname,pgname,pgname);
    328  1.6   chopps }
    329  1.1       mw 
    330  1.1       mw 
    331  1.6   chopps static void Usage(char *pgname)
    332  1.1       mw {
    333  1.6   chopps   Synopsis(pgname);
    334  1.6   chopps   fprintf(stdout,desusage);
    335  1.6   chopps   exit(0);
    336  1.1       mw }
    337  1.6   chopps 
    338  1.6   chopps 
    339  1.6   chopps /* FindOffset() - Determine if there is an offset, -or- index
    340  1.6   chopps                  embedded in the symbol.
    341  1.6   chopps                  If there is, return it, and truncate symbol to
    342  1.6   chopps                  exclude the [...].
    343  1.6   chopps                  Example: If view is declared as short view[10],
    344  1.6   chopps                           and we want to index the 3rd. element.
    345  1.6   chopps                           which is offset = (3 -1)*sizeof(short) =4.
    346  1.6   chopps                  we would use view[4], which becomes view,4.
    347  1.6   chopps                  The was the code is implemented the [value] is
    348  1.6   chopps                  treated as a index if-and-only-if a '-b -w -l' option
    349  1.6   chopps                  was given. Otherwise it is treated like an offset.
    350  1.6   chopps                  See above documentation in for of help!
    351  1.8  aymeric */
    352  1.6   chopps static void FindOffset(char *symbol,u_long *index)
    353  1.6   chopps {
    354  1.6   chopps   char *sb=strchr(symbol,'['); /* Start of '[', now line must
    355  1.6   chopps                                  contain matching']' */
    356  1.6   chopps   char *eb=strchr(symbol,']'); /* End of ']' */
    357  1.6   chopps   short sz=strlen(symbol);    /* symbol size */
    358  1.6   chopps   if (sb)
    359  1.6   chopps   {
    360  1.6   chopps     if (eb && (eb > sb))
    361  1.6   chopps     {
    362  1.6   chopps       if ((eb - symbol) == (sz - 1))
    363  1.6   chopps       {
    364  1.6   chopps         char *sindex; /* Start of index */
    365  1.6   chopps         u_long newindex = 0;
    366  1.6   chopps         /* In the future we could get fancy and parse the
    367  1.6   chopps            sindex string for mathmatical expressions like:
    368  1.6   chopps            (3 - 1)*2 = 4 from above example,
    369  1.6   chopps            ugh forget I mentioned ot :-) !
    370  1.6   chopps         */
    371  1.6   chopps         sindex = sb + 1;
    372  1.6   chopps         *eb = '\0';
    373  1.6   chopps         newindex = (u_long)atoi(sindex);
    374  1.6   chopps         if (*index == 0)
    375  1.6   chopps         {
    376  1.6   chopps           *index = newindex;
    377  1.6   chopps           *sb = '\0'; /* Make _view[3] look like _view */
    378  1.6   chopps         }
    379  1.6   chopps         else
    380  1.6   chopps           fprintf(stderr,"Error index can only be specified once!\n");
    381  1.6   chopps       }
    382  1.6   chopps       else
    383  1.6   chopps       {
    384  1.6   chopps         fprintf(stderr,"Error: Garbage trailing ']'\n");
    385  1.8  aymeric       }
    386  1.6   chopps     }
    387  1.6   chopps     else
    388  1.6   chopps     {
    389  1.6   chopps        fprintf(stderr,"Error ']' in symbol before '[' !\n");
    390  1.6   chopps     }
    391  1.6   chopps   }/* if sb != 0 */
    392  1.6   chopps }/* FindOffset */
    393  1.6   chopps 
    394  1.6   chopps /* FindAssign : Scans symbol name for an '=number' strips it off
    395  1.6   chopps    of the symbol and proceeds.
    396  1.6   chopps */
    397  1.6   chopps static u_long FindAssign(char *symbol,u_long *rvalue)
    398  1.6   chopps {
    399  1.6   chopps   char *ce = rindex(symbol,'='); /* Assign symbol some number */
    400  1.6   chopps   char *cn = ce + 1; /* This should point at some number, no spaces allowed */
    401  1.6   chopps   u_long dr = 0; /* flag for do_replace */
    402  1.6   chopps   if (ce)
    403  1.6   chopps   {
    404  1.6   chopps     int nscan; /* number of variaables scanned in */
    405  1.6   chopps     /* get the number to assign to symbol and strip off = */
    406  1.6   chopps     for (cn=ce + 1;((*cn==' ')&&(*cn!='\0'));cn++)
    407  1.6   chopps     ;
    408  1.6   chopps     if (! strncmp (cn, "0x", 2))
    409  1.6   chopps 	nscan = sscanf (cn, "%x",rvalue);
    410  1.6   chopps     else
    411  1.6   chopps         nscan = sscanf(cn,"%d",rvalue);
    412  1.6   chopps     if (nscan != 1)
    413  1.6   chopps       error("Invalid value following '='");
    414  1.6   chopps     dr = 1;
    415  1.8  aymeric     *ce = '\0';/* Now were left with just symbol */
    416  1.6   chopps   }/* if (ce) */
    417  1.6   chopps   return(dr);
    418  1.6   chopps }/* FindAssign */
    419