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