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