1 /* $NetBSD: binpatch.c,v 1.7 2016/09/22 17:08:16 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 2009 Izumi Tsutsui.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 /*
28  * Copyright (c) 1996 Christopher G. Demetriou
29  * All rights reserved.
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions
33  * are met:
34  * 1. Redistributions of source code must retain the above copyright
35  *    notice, this list of conditions and the following disclaimer.
36  * 2. Redistributions in binary form must reproduce the above copyright
37  *    notice, this list of conditions and the following disclaimer in the
38  *    documentation and/or other materials provided with the distribution.
39  * 3. The name of the author may not be used to endorse or promote products
40  *    derived from this software without specific prior written permission.
41  *
42  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
43  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
44  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
45  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
46  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
48  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
49  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
51  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52  *
53  * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
54  */
55 
56 #include <sys/cdefs.h>
57 #ifndef lint
58 __COPYRIGHT("@(#) Copyright (c) 1996\
59  Christopher G. Demetriou.  All rights reserved.");
60 #endif /* not lint */
61 
62 #ifndef lint
63 __RCSID("$NetBSD: binpatch.c,v 1.7 2016/09/22 17:08:16 christos Exp $");
64 #endif /* not lint */
65 
66 #include <sys/types.h>
67 #include <sys/mman.h>
68 #include <sys/stat.h>
69 #include <sys/inttypes.h>
70 
71 #include <err.h>
72 #include <fcntl.h>
73 #include <limits.h>
74 #include <nlist.h>
75 #include <stdio.h>
76 #include <stdlib.h>
77 #include <stdbool.h>
78 #include <unistd.h>
79 
80 #include "extern.h"
81 
82 static void         usage(void) __dead;
83 
84 bool replace, verbose;
85 u_long addr, offset;
86 char *symbol;
87 size_t size;
88 uint64_t val;
89 
90 static const struct {
91           const char *name;
92           int       (*check)(const char *, size_t);
93           int       (*findoff)(const char *, size_t, u_long, size_t *, u_long);
94 } exec_formats[] = {
95 #ifdef NLIST_AOUT
96           {         "a.out",  check_aout,         findoff_aout,       },
97 #endif
98 #ifdef NLIST_ECOFF
99           {         "ECOFF",  check_ecoff,        findoff_ecoff,      },
100 #endif
101 #ifdef NLIST_ELF32
102           {         "ELF32",  check_elf32,        findoff_elf32,      },
103 #endif
104 #ifdef NLIST_ELF64
105           {         "ELF64",  check_elf64,        findoff_elf64,      },
106 #endif
107 #ifdef NLIST_COFF
108           {         "COFF",             check_coff,         findoff_coff,       },
109 #endif
110 };
111 
112 
113 int
main(int argc,char * argv[])114 main(int argc, char *argv[])
115 {
116           const char *fname;
117           struct stat sb;
118           struct nlist nl[2];
119           char *mappedfile;
120           size_t valoff;
121           void *valp;
122           uint8_t uval8;
123           int8_t  sval8;
124           uint16_t uval16;
125           int16_t  sval16;
126           uint32_t uval32;
127           int32_t  sval32;
128           uint64_t uval64;
129           int64_t  sval64;
130           int ch, fd, rv, i, n;
131           u_long    text_start;                   /* Start of kernel text (a.out) */
132 
133           setprogname(argv[0]);
134           text_start = (unsigned long)~0;
135 
136           while ((ch = getopt(argc, argv, "bwldT:a:s:o:r:v")) != -1)
137                     switch (ch) {
138                     case 'b':
139                               size = sizeof(uint8_t);
140                               break;
141                     case 'w':
142                               size = sizeof(uint16_t);
143                               break;
144                     case 'l':
145                               size = sizeof(uint32_t);
146                               break;
147                     case 'd':
148                               size = sizeof(uint64_t);
149                               break;
150                     case 'a':
151                               if (addr != 0 || symbol != NULL)
152                                         errx(EXIT_FAILURE,
153                                             "only one address/symbol allowed");
154                               addr = strtoul(optarg, NULL, 0);
155                               break;
156                     case 's':
157                               if (addr != 0 || symbol != NULL)
158                                         errx(EXIT_FAILURE,
159                                             "only one address/symbol allowed");
160                               symbol = optarg;
161                               break;
162                     case 'o':
163                               if (offset != 0)
164                                         err(EXIT_FAILURE,
165                                             "only one offset allowed");
166                               offset = strtoul(optarg, NULL, 0);
167                               break;
168                     case 'r':
169                               replace = true;
170                               val = strtoull(optarg, NULL, 0);
171                               break;
172                     case 'v':
173                               verbose = true;
174                               break;
175                     case 'T':
176                               text_start = strtoul(optarg, NULL, 0);
177                               break;
178                     case '?':
179                     default:
180                               usage();
181           }
182           argc -= optind;
183           argv += optind;
184 
185           if (argc != 1)
186                     usage();
187 
188           if (addr == 0 && symbol == NULL) {
189                     warnx("no address or symbol specified");
190                     usage();
191           }
192 
193           if (size == 0)
194                     size = sizeof(uint32_t);      /* default to int */
195 
196           fname = argv[0];
197 
198           if ((fd = open(fname, replace ? O_RDWR : O_RDONLY, 0))  == -1)
199                     err(EXIT_FAILURE, "open %s", fname);
200 
201           if (symbol != NULL) {
202                     nl[0].n_name = symbol;
203                     nl[1].n_name = NULL;
204                     if ((rv = __fdnlist(fd, nl)) != 0)
205                               errx(EXIT_FAILURE, "could not find symbol %s in %s",
206                                   symbol, fname);
207                     addr = nl[0].n_value;
208                     if (verbose)
209                               fprintf(stderr, "got symbol address 0x%lx from %s\n",
210                                   addr, fname);
211           }
212 
213           addr += offset * size;
214 
215           if (fstat(fd, &sb) == -1)
216                     err(EXIT_FAILURE, "fstat %s", fname);
217           if (sb.st_size != (ssize_t)sb.st_size)
218                     errx(EXIT_FAILURE, "%s too big to map", fname);
219 
220           if ((mappedfile = mmap(NULL, sb.st_size,
221               replace ? PROT_READ | PROT_WRITE : PROT_READ,
222               MAP_FILE | MAP_SHARED, fd, 0)) == (char *)-1)
223                     err(EXIT_FAILURE, "mmap %s", fname);
224           if (verbose)
225                     fprintf(stderr, "mapped %s\n", fname);
226 
227           n = __arraycount(exec_formats);
228           for (i = 0; i < n; i++) {
229                     if ((*exec_formats[i].check)(mappedfile, sb.st_size) == 0)
230                               break;
231           }
232           if (i == n)
233                     errx(EXIT_FAILURE, "%s: unknown executable format", fname);
234 
235           if (verbose) {
236                     fprintf(stderr, "%s is an %s binary\n", fname,
237                         exec_formats[i].name);
238                     if (text_start != (u_long)~0)
239                               fprintf(stderr, "kernel text loads at 0x%lx\n",
240                                   text_start);
241           }
242 
243           if ((*exec_formats[i].findoff)(mappedfile, sb.st_size,
244               addr, &valoff, text_start) != 0)
245                     errx(EXIT_FAILURE, "couldn't find file offset for %s in %s",
246                         symbol != NULL ? nl[0].n_name : "address" , fname);
247 
248           valp = mappedfile + valoff;
249 
250           if (symbol)
251                     printf("%s(0x%lx): ", symbol, addr);
252           else
253                     printf("0x%lx: ", addr);
254 
255           switch (size) {
256           case sizeof(uint8_t):
257                     uval8 = *(uint8_t *)valp;
258                     sval8 = *(int8_t *)valp;
259                     printf("0x%02" PRIx8 " (%" PRIu8, uval8, uval8);
260                     if (sval8 < 0)
261                               printf("/%" PRId8, sval8);
262                     printf(")");
263                     break;
264           case sizeof(uint16_t):
265                     uval16 = *(uint16_t *)valp;
266                     sval16 = *(int16_t *)valp;
267                     printf("0x%04" PRIx16 " (%" PRIu16, uval16, uval16);
268                     if (sval16 < 0)
269                               printf("/%" PRId16, sval16);
270                     printf(")");
271                     break;
272           case sizeof(uint32_t):
273                     uval32 = *(uint32_t *)valp;
274                     sval32 = *(int32_t *)valp;
275                     printf("0x%08" PRIx32 " (%" PRIu32, uval32, uval32);
276                     if (sval32 < 0)
277                               printf("/%" PRId32, sval32);
278                     printf(")");
279                     break;
280           case sizeof(uint64_t):
281                     uval64 = *(uint64_t *)valp;
282                     sval64 = *(int64_t *)valp;
283                     printf("0x%016" PRIx64 " (%" PRIu64, uval64, uval64);
284                     if (sval64 < 0)
285                               printf("/%" PRId64, sval64);
286                     printf(")");
287                     break;
288           }
289           printf(", at offset %#lx in %s\n", (unsigned long)valoff, fname);
290 
291           if (!replace)
292                     goto done;
293 
294           printf("new value: ");
295 
296           switch (size) {
297           case sizeof(uint8_t):
298                     uval8 = (uint8_t)val;
299                     sval8 = (int8_t)val;
300                     printf("0x%02" PRIx8 " (%" PRIu8, uval8, uval8);
301                     if (sval8 < 0)
302                               printf("/%" PRId8, sval8);
303                     printf(")");
304                     *(uint8_t *)valp = uval8;
305                     break;
306           case sizeof(uint16_t):
307                     uval16 = (uint16_t)val;
308                     sval16 = (int16_t)val;
309                     printf("0x%04" PRIx16 " (%" PRIu16, uval16, uval16);
310                     if (sval16 < 0)
311                               printf("/%" PRId16, sval16);
312                     printf(")");
313                     *(uint16_t *)valp = uval16;
314                     break;
315           case sizeof(uint32_t):
316                     uval32 = (uint32_t)val;
317                     sval32 = (int32_t)val;
318                     printf("0x%08" PRIx32 " (%" PRIu32, uval32, uval32);
319                     if (sval32 < 0)
320                               printf("/%" PRId32, sval32);
321                     printf(")");
322                     *(uint32_t *)valp = uval32;
323                     break;
324           case sizeof(uint64_t):
325                     uval64 = (uint64_t)val;
326                     sval64 = (int64_t)val;
327                     printf("0x%016" PRIx64 " (%" PRIu64, uval64, uval64);
328                     if (sval64 < 0)
329                               printf("/%" PRId64, sval64);
330                     printf(")");
331                     *(uint64_t *)valp = uval64;
332                     break;
333           }
334           printf("\n");
335 
336  done:
337           munmap(mappedfile, sb.st_size);
338           close(fd);
339 
340           if (verbose)
341                     fprintf(stderr, "exiting\n");
342           exit(EXIT_SUCCESS);
343 }
344 
345 static void
usage(void)346 usage(void)
347 {
348 
349           fprintf(stderr,
350               "Usage: %s [-b|-w|-l|-d] [-a address | -s symbol] [-o offset]"
351               " [-r value] [-T text_start] [-v] binary\n", getprogname());
352           exit(EXIT_FAILURE);
353 }
354