1 /* $OpenBSD: elf_hide.c,v 1.3 2008/11/24 17:23:26 drahn Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Dale Rahn. 5 * All rights reserved. 6 * 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/types.h> 30 #include <sys/mman.h> 31 #include <sys/stat.h> 32 #include <err.h> 33 #include <errno.h> 34 #include <fcntl.h> 35 #include <unistd.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <sys/exec.h> 40 #ifdef _NLIST_DO_ELF 41 #include <sys/exec_elf.h> 42 43 extern int elf_mangle; 44 45 void load_strtab(Elf_Ehdr * pehdr, char *pexe); 46 void dump_strtab(); 47 char *get_str(int indx); 48 49 void load_symtab(Elf_Ehdr * pehdr, char *pexe); 50 void dump_symtab(); 51 52 void load_shstr_tab(Elf_Ehdr * pehdr, char *pexe); 53 char *get_shstr(int indx); 54 void fprint_shstr(FILE * channel, int indx); 55 56 void hide_sym(); 57 void reorder_syms(Elf_Ehdr * ehdr, Elf_Shdr * symsect, 58 Elf_Sym * symtab, int symtabsize, int symtabsecnum); 59 typedef long Symmap; 60 void renum_reloc_syms(Elf_Ehdr * ehdr, Symmap * symmap, 61 int symtabsecnum); 62 63 64 char *pexe; 65 66 void 67 elf_hide(int pfile, char *p) 68 { 69 Elf_Ehdr *pehdr; 70 #ifdef DEBUG 71 Elf_Shdr *pshdr; 72 Elf_Phdr *pphdr; 73 int i; 74 #endif 75 struct stat sb; 76 77 pexe = p; 78 pehdr = (Elf_Ehdr *) pexe; 79 80 #ifdef DEBUG 81 printf("elf header\n"); 82 printf("e_type %x\n", pehdr->e_type); 83 printf("e_machine %x\n", pehdr->e_machine); 84 printf("e_version %x\n", pehdr->e_version); 85 printf("e_entry %x\n", pehdr->e_entry); 86 printf("e_phoff %x\n", pehdr->e_phoff); 87 printf("e_shoff %x\n", pehdr->e_shoff); 88 printf("e_flags %x\n", pehdr->e_flags); 89 printf("e_ehsize %x\n", pehdr->e_ehsize); 90 printf("e_phentsize %x\n", pehdr->e_phentsize); 91 printf("e_phnum %x\n", pehdr->e_phnum); 92 printf("e_shentsize %x\n", pehdr->e_shentsize); 93 printf("e_shnum %x\n", pehdr->e_shnum); 94 printf("e_shstrndx %x\n", pehdr->e_shstrndx); 95 #endif 96 97 load_shstr_tab(pehdr, pexe); 98 #ifdef DEBUG 99 for (i = 0; i < pehdr->e_shnum; i++) { 100 pshdr = (Elf_Phdr *) (pexe + pehdr->e_shoff + 101 (i * pehdr->e_shentsize)); 102 103 printf("section header %d\n", i); 104 printf("sh_name %x ", pshdr->sh_name); 105 fprint_shstr(stdout, pshdr->sh_name); 106 printf("\n"); 107 printf("sh_type %x\n", pshdr->sh_type); 108 printf("sh_flags %x\n", pshdr->sh_flags); 109 printf("sh_addr %x\n", pshdr->sh_addr); 110 printf("sh_offset %x\n", pshdr->sh_offset); 111 printf("sh_size %x\n", pshdr->sh_size); 112 printf("sh_link %x\n", pshdr->sh_link); 113 printf("sh_info %x\n", pshdr->sh_info); 114 printf("sh_addralign %x\n", pshdr->sh_addralign); 115 printf("sh_entsize %x\n", pshdr->sh_entsize); 116 } 117 #endif /* DEBUG */ 118 119 #ifdef DEBUG 120 for (i = 0; i < pehdr->e_phnum; i++) { 121 pshdr = (Elf_Phdr *) (pexe + pehdr->e_phoff + 122 (i * pehdr->e_phentsize)); 123 124 printf("program header %d\n", i); 125 printf("p_type %x\n", pphdr->p_type); 126 printf("p_offset %x\n", pphdr->p_offset); 127 printf("p_vaddr %x\n", pphdr->p_vaddr); 128 printf("p_paddr %x\n", pphdr->p_paddr); 129 printf("p_filesz %x\n", pphdr->p_filesz); 130 printf("p_memsz %x\n", pphdr->p_memsz); 131 printf("p_flags %x\n", pphdr->p_flags); 132 printf("p_align %x\n", pphdr->p_align); 133 } 134 #endif /* DEBUG */ 135 #if 0 136 for (i = 0; i < pehdr->e_shnum; i++) { 137 pshdr = (Elf_Phdr *) (pexe + pehdr->e_shoff + 138 (i * pehdr->e_shentsize)); 139 if (strcmp(".strtab", get_shstr(pshdr->sh_name)) == 0) 140 break; 141 } 142 fprint_shstr(stdout, pshdr->sh_name); 143 printf("\n"); 144 #endif 145 146 load_strtab(pehdr, pexe); 147 load_symtab(pehdr, pexe); 148 149 munmap(pexe, sb.st_size); 150 close(pfile); 151 } 152 char *shstrtab; 153 154 void 155 load_shstr_tab(Elf_Ehdr * pehdr, char *pexe) 156 { 157 Elf_Shdr *pshdr; 158 shstrtab = NULL; 159 if (pehdr->e_shstrndx == 0) 160 return; 161 pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff + 162 (pehdr->e_shstrndx * pehdr->e_shentsize)); 163 164 shstrtab = (char *) (pexe + pshdr->sh_offset); 165 } 166 167 void 168 fprint_shstr(FILE * channel, int indx) 169 { 170 if (shstrtab != NULL) 171 fprintf(channel, "\"%s\"", &(shstrtab[indx])); 172 } 173 174 char * 175 get_shstr(int indx) 176 { 177 return &(shstrtab[indx]); 178 } 179 180 void 181 load_symtab(Elf_Ehdr * pehdr, char *pexe) 182 { 183 Elf_Sym *symtab; 184 Elf_Shdr *symsect; 185 int symtabsize; 186 Elf_Shdr *psymshdr; 187 Elf_Shdr *pshdr; 188 #ifdef DEBUG 189 char *shname; 190 #endif 191 int i; 192 193 symtab = NULL; 194 for (i = 0; i < pehdr->e_shnum; i++) { 195 pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff + 196 (i * pehdr->e_shentsize)); 197 if (SHT_REL != pshdr->sh_type && SHT_RELA != pshdr->sh_type) 198 continue; 199 psymshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff + 200 (pshdr->sh_link * pehdr->e_shentsize)); 201 #ifdef DEBUG 202 fprint_shstr(stdout, pshdr->sh_name); 203 printf("\n"); 204 #endif 205 symtab = (Elf_Sym *) (pexe + psymshdr->sh_offset); 206 symsect = psymshdr; 207 symtabsize = psymshdr->sh_size; 208 209 #ifdef DEBUG 210 dump_symtab(symsect, symtab, symtabsize); 211 #endif 212 hide_sym(pehdr, symsect, symtab, symtabsize, pshdr->sh_link); 213 } 214 215 } 216 217 void 218 dump_symtab(Elf_Shdr * symsect, Elf_Sym * symtab, int symtabsize) 219 { 220 int i; 221 Elf_Sym *psymtab; 222 223 for (i = 0; i < (symtabsize / sizeof(Elf_Sym)); i++) { 224 psymtab = &(symtab[i]); 225 if ((psymtab->st_info & 0xf0) == 0x10 && 226 (psymtab->st_shndx != SHN_UNDEF)) { 227 printf("symbol %d:\n", i); 228 printf("st_name %x \"%s\"\n", psymtab->st_name, 229 get_str(psymtab->st_name)); 230 printf("st_value %llx\n", (unsigned long long)psymtab->st_value); 231 printf("st_size %llx\n", (unsigned long long)psymtab->st_size); 232 printf("st_info %x\n", psymtab->st_info); 233 printf("st_other %x\n", psymtab->st_other); 234 printf("st_shndx %x\n", psymtab->st_shndx); 235 } 236 } 237 } 238 239 char *strtab; 240 int strtabsize; 241 void 242 load_strtab(Elf_Ehdr * pehdr, char *pexe) 243 { 244 Elf_Shdr *pshdr = NULL; 245 char *shname; 246 int i; 247 strtab = NULL; 248 for (i = 0; i < pehdr->e_shnum; i++) { 249 pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff + 250 (i * pehdr->e_shentsize)); 251 252 shname = get_shstr(pshdr->sh_name); 253 if (strcmp(".strtab", shname) == 0) 254 break; 255 } 256 #ifdef DEBUG 257 fprint_shstr(stdout, pshdr->sh_name); 258 printf("\n"); 259 #endif 260 261 strtab = (char *) (pexe + pshdr->sh_offset); 262 263 strtabsize = pshdr->sh_size; 264 265 #ifdef DEBUG 266 dump_strtab(); 267 #endif 268 } 269 270 void 271 dump_strtab() 272 { 273 int index; 274 char *pstr; 275 char *pnstr; 276 int i = 0; 277 index = 0; 278 pstr = strtab; 279 while (index < strtabsize) { 280 printf("string %x: \"%s\"\n", i, pstr); 281 pnstr = pstr + strlen(pstr) + 1; 282 index = pnstr - strtab; 283 pstr = pnstr; 284 i++; 285 } 286 287 } 288 289 void 290 fprint_str(FILE * channel, int indx) 291 { 292 if (strtab != NULL) 293 fprintf(channel, "\"%s\"", &(strtab[indx])); 294 } 295 296 char * 297 get_str(int indx) 298 { 299 return &(strtab[indx]); 300 } 301 302 int in_keep_list(char *symbol); 303 304 void 305 hide_sym(Elf_Ehdr * ehdr, Elf_Shdr * symsect, 306 Elf_Sym * symtab, int symtabsize, int symtabsecnum) 307 { 308 int i; 309 unsigned char info; 310 Elf_Sym *psymtab; 311 312 for (i = 0; i < (symtabsize / sizeof(Elf_Sym)); i++) { 313 psymtab = &(symtab[i]); 314 if ((psymtab->st_info & 0xf0) == 0x10 && 315 (psymtab->st_shndx != SHN_UNDEF)) { 316 if (in_keep_list(get_str(psymtab->st_name))) 317 continue; 318 #ifdef DEBUG 319 printf("symbol %d:\n", i); 320 printf("st_name %x \"%s\"\n", psymtab->st_name, 321 get_str(psymtab->st_name)); 322 printf("st_info %x\n", psymtab->st_info); 323 #endif 324 if (!elf_mangle) { 325 info = psymtab->st_info; 326 info = info & 0xf; 327 psymtab->st_info = info; 328 } else { 329 /* 330 * XXX This is a small ugly hack to be able to 331 * XXX use chrunchide with MIPS. 332 * XXX Because MIPS needs global symbols to stay 333 * XXX global (has to do with GOT), we mess 334 * XXX around with the symbol names instead. 335 * XXX For most uses this will be no problem, 336 * XXX symbols are stripped anyway. 337 * XXX However, if many one character 338 * XXX symbols exist, names may clash. 339 */ 340 char *p; 341 u_int32_t n, z; 342 u_int32_t f; 343 f = arc4random(); 344 345 z = f++; 346 p = get_str(psymtab->st_name); 347 n = strlen(p); 348 if (n > 4) 349 n = 4; 350 while (n--) { 351 p[n] = z; 352 z >>= 8; 353 while (p[n] == 0) 354 p[n] += arc4random(); 355 } 356 } 357 #ifdef DEBUG 358 printf("st_info %x\n", psymtab->st_info); 359 #endif 360 } 361 } 362 reorder_syms(ehdr, symsect, symtab, symtabsize, symtabsecnum); 363 } 364 365 void 366 reorder_syms(Elf_Ehdr * ehdr, Elf_Shdr * symsect, 367 Elf_Sym * symtab, int symtabsize, int symtabsecnum) 368 { 369 int i; 370 int nsyms; 371 int cursym; 372 Elf_Sym *tmpsymtab; 373 Symmap *symmap; 374 375 376 nsyms = symtabsize / sizeof(Elf_Sym); 377 378 tmpsymtab = (Elf_Sym *) calloc(1, symtabsize); 379 symmap = (Symmap *) calloc(nsyms, sizeof(Symmap)); 380 if (!tmpsymtab || !symmap) 381 errx(5, "calloc: %s", strerror(ENOMEM)); 382 383 bcopy(symtab, tmpsymtab, symtabsize); 384 385 cursym = 1; 386 for (i = 1; i < nsyms; i++) { 387 if ((tmpsymtab[i].st_info & 0xf0) == 0x00) { 388 #ifdef DEBUG 389 printf("copying l o%d n%d <%s>\n", i, cursym, 390 get_str(tmpsymtab[i].st_name)); 391 #endif 392 bcopy(&(tmpsymtab[i]), &(symtab[cursym]), 393 sizeof(Elf_Sym)); 394 symmap[i] = cursym; 395 cursym++; 396 } 397 } 398 symsect->sh_info = cursym; 399 for (i = 1; i < nsyms; i++) { 400 if ((tmpsymtab[i].st_info & 0xf0) != 0x00) { 401 #ifdef DEBUG 402 printf("copying nl o%d n%d <%s>\n", i, cursym, 403 get_str(tmpsymtab[i].st_name)); 404 #endif 405 bcopy(&(tmpsymtab[i]), &(symtab[cursym]), 406 sizeof(Elf_Sym)); 407 symmap[i] = cursym; 408 cursym++; 409 } 410 } 411 if (cursym != nsyms) { 412 printf("miscounted symbols somewhere c %d n %d \n", 413 cursym, nsyms); 414 exit(5); 415 } 416 renum_reloc_syms(ehdr, symmap, symtabsecnum); 417 free(tmpsymtab); 418 free(symmap); 419 } 420 421 void 422 renum_reloc_syms(Elf_Ehdr * ehdr, Symmap * symmap, int symtabsecnum) 423 { 424 Elf_Shdr *pshdr; 425 int i, j; 426 int num_reloc; 427 Elf_Rel *prel; 428 Elf_RelA *prela; 429 int symnum; 430 431 for (i = 0; i < ehdr->e_shnum; i++) { 432 pshdr = (Elf_Shdr *) (pexe + ehdr->e_shoff + 433 (i * ehdr->e_shentsize)); 434 if ((pshdr->sh_type == SHT_RELA) && 435 pshdr->sh_link == symtabsecnum) { 436 437 #ifdef DEBUG 438 printf("section %d has rela relocations in symtab\n", i); 439 #endif 440 prela = (Elf_RelA *) (pexe + pshdr->sh_offset); 441 num_reloc = pshdr->sh_size / sizeof(Elf_RelA); 442 for (j = 0; j < num_reloc; j++) { 443 symnum = ELF_R_SYM(prela[j].r_info); 444 #ifdef DEBUG 445 printf("sym num o %d n %d\n", symnum, 446 symmap[symnum]); 447 #endif 448 prela[j].r_info = ELF_R_INFO(symmap[symnum], 449 ELF_R_TYPE(prela[j].r_info)); 450 } 451 } 452 if ((pshdr->sh_type == SHT_REL) && 453 pshdr->sh_link == symtabsecnum) { 454 #ifdef DEBUG 455 printf("section %d has rel relocations in symtab\n", i); 456 #endif 457 prel = (Elf_Rel *) (pexe + pshdr->sh_offset); 458 num_reloc = pshdr->sh_size / sizeof(Elf_Rel); 459 for (j = 0; j < num_reloc; j++) { 460 symnum = ELF_R_SYM(prel[j].r_info); 461 #ifdef DEBUG 462 printf("sym num o %d n %d\n", symnum, 463 symmap[symnum]); 464 #endif 465 prel[j].r_info = ELF_R_INFO(symmap[symnum], 466 ELF_R_TYPE(prel[j].r_info)); 467 } 468 } 469 } 470 471 } 472 #endif /* _NLIST_DO_ELF */ 473