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