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