binpatch.c revision 1.10 1 1.10 thorpej /* $NetBSD: binpatch.c,v 1.10 2002/12/10 17:14:05 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.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.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