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 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 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