diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2008-08-22 15:18:56 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2008-08-22 15:18:56 +0000 |
commit | f58dd4fe87fead2d644fc1341d7731fe34c75b13 (patch) | |
tree | 0e1c8bda49466845ec92f92ade36dd92d2239379 /usr.sbin/crunchgen/elf_hide.c | |
parent | c1a84c1c712d13ee22082743780139fe2a4855f5 (diff) |
Merge crunchgen & crunchhide (using name checking), and move to usr.sbin
next step is to not install it as two programs, but be even more clever
Diffstat (limited to 'usr.sbin/crunchgen/elf_hide.c')
-rw-r--r-- | usr.sbin/crunchgen/elf_hide.c | 474 |
1 files changed, 474 insertions, 0 deletions
diff --git a/usr.sbin/crunchgen/elf_hide.c b/usr.sbin/crunchgen/elf_hide.c new file mode 100644 index 00000000000..b52a7757b07 --- /dev/null +++ b/usr.sbin/crunchgen/elf_hide.c @@ -0,0 +1,474 @@ +/* $OpenBSD: elf_hide.c,v 1.1 2008/08/22 15:18:55 deraadt Exp $ */ + +/* + * Copyright (c) 1997 Dale Rahn. + * All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/exec.h> +#ifdef _NLIST_DO_ELF +#include <sys/exec_elf.h> + +void load_strtab(Elf_Ehdr * pehdr, char *pexe); +void dump_strtab(); +char *get_str(int indx); + +void load_symtab(Elf_Ehdr * pehdr, char *pexe); +void dump_symtab(); + +void load_shstr_tab(Elf_Ehdr * pehdr, char *pexe); +char *get_shstr(int indx); +void fprint_shstr(FILE * channel, int indx); + +void hide_sym(); +void reorder_syms(Elf_Ehdr * ehdr, Elf_Shdr * symsect, + Elf_Sym * symtab, int symtabsize, int symtabsecnum); +typedef long Symmap; +void renum_reloc_syms(Elf_Ehdr * ehdr, Symmap * symmap, + int symtabsecnum); + + +char *pexe; + +void +elf_hide(int pfile, char *p) +{ + Elf_Ehdr *pehdr; +#ifdef DEBUG + Elf_Shdr *pshdr; + Elf_Phdr *pphdr; + int i; +#endif + struct stat sb; + + pexe = p; + pehdr = (Elf_Ehdr *) pexe; + +#ifdef DEBUG + printf("elf header\n"); + printf("e_type %x\n", pehdr->e_type); + printf("e_machine %x\n", pehdr->e_machine); + printf("e_version %x\n", pehdr->e_version); + printf("e_entry %x\n", pehdr->e_entry); + printf("e_phoff %x\n", pehdr->e_phoff); + printf("e_shoff %x\n", pehdr->e_shoff); + printf("e_flags %x\n", pehdr->e_flags); + printf("e_ehsize %x\n", pehdr->e_ehsize); + printf("e_phentsize %x\n", pehdr->e_phentsize); + printf("e_phnum %x\n", pehdr->e_phnum); + printf("e_shentsize %x\n", pehdr->e_shentsize); + printf("e_shnum %x\n", pehdr->e_shnum); + printf("e_shstrndx %x\n", pehdr->e_shstrndx); +#endif + + load_shstr_tab(pehdr, pexe); +#ifdef DEBUG + for (i = 0; i < pehdr->e_shnum; i++) { + pshdr = (Elf_Phdr *) (pexe + pehdr->e_shoff + + (i * pehdr->e_shentsize)); + + printf("section header %d\n", i); + printf("sh_name %x ", pshdr->sh_name); + fprint_shstr(stdout, pshdr->sh_name); + printf("\n"); + printf("sh_type %x\n", pshdr->sh_type); + printf("sh_flags %x\n", pshdr->sh_flags); + printf("sh_addr %x\n", pshdr->sh_addr); + printf("sh_offset %x\n", pshdr->sh_offset); + printf("sh_size %x\n", pshdr->sh_size); + printf("sh_link %x\n", pshdr->sh_link); + printf("sh_info %x\n", pshdr->sh_info); + printf("sh_addralign %x\n", pshdr->sh_addralign); + printf("sh_entsize %x\n", pshdr->sh_entsize); + } +#endif /* DEBUG */ + +#ifdef DEBUG + for (i = 0; i < pehdr->e_phnum; i++) { + pshdr = (Elf_Phdr *) (pexe + pehdr->e_phoff + + (i * pehdr->e_phentsize)); + + printf("program header %d\n", i); + printf("p_type %x\n", pphdr->p_type); + printf("p_offset %x\n", pphdr->p_offset); + printf("p_vaddr %x\n", pphdr->p_vaddr); + printf("p_paddr %x\n", pphdr->p_paddr); + printf("p_filesz %x\n", pphdr->p_filesz); + printf("p_memsz %x\n", pphdr->p_memsz); + printf("p_flags %x\n", pphdr->p_flags); + printf("p_align %x\n", pphdr->p_align); + } +#endif /* DEBUG */ +#if 0 + for (i = 0; i < pehdr->e_shnum; i++) { + pshdr = (Elf_Phdr *) (pexe + pehdr->e_shoff + + (i * pehdr->e_shentsize)); + if (strcmp(".strtab", get_shstr(pshdr->sh_name)) == 0) + break; + } + fprint_shstr(stdout, pshdr->sh_name); + printf("\n"); +#endif + + load_strtab(pehdr, pexe); + load_symtab(pehdr, pexe); + + munmap(pexe, sb.st_size); + close(pfile); +} +char *shstrtab; + +void +load_shstr_tab(Elf_Ehdr * pehdr, char *pexe) +{ + Elf_Shdr *pshdr; + shstrtab = NULL; + if (pehdr->e_shstrndx == 0) + return; + pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff + + (pehdr->e_shstrndx * pehdr->e_shentsize)); + + shstrtab = (char *) (pexe + pshdr->sh_offset); +} + +void +fprint_shstr(FILE * channel, int indx) +{ + if (shstrtab != NULL) + fprintf(channel, "\"%s\"", &(shstrtab[indx])); +} + +char * +get_shstr(int indx) +{ + return &(shstrtab[indx]); +} + +void +load_symtab(Elf_Ehdr * pehdr, char *pexe) +{ + Elf_Sym *symtab; + Elf_Shdr *symsect; + int symtabsize; + Elf_Shdr *psymshdr; + Elf_Shdr *pshdr; +#ifdef DEBUG + char *shname; +#endif + int i; + + symtab = NULL; + for (i = 0; i < pehdr->e_shnum; i++) { + pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff + + (i * pehdr->e_shentsize)); + if (SHT_REL != pshdr->sh_type && SHT_RELA != pshdr->sh_type) + continue; + psymshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff + + (pshdr->sh_link * pehdr->e_shentsize)); +#ifdef DEBUG + fprint_shstr(stdout, pshdr->sh_name); + printf("\n"); +#endif + symtab = (Elf_Sym *) (pexe + psymshdr->sh_offset); + symsect = psymshdr; + symtabsize = psymshdr->sh_size; + +#ifdef DEBUG + dump_symtab(symsect, symtab, symtabsize); +#endif + hide_sym(pehdr, symsect, symtab, symtabsize, pshdr->sh_link); + } + +} + +void +dump_symtab(Elf_Shdr * symsect, Elf_Sym * symtab, int symtabsize) +{ + int i; + Elf_Sym *psymtab; + + for (i = 0; i < (symtabsize / sizeof(Elf_Sym)); i++) { + psymtab = &(symtab[i]); + if ((psymtab->st_info & 0xf0) == 0x10 && + (psymtab->st_shndx != SHN_UNDEF)) { + printf("symbol %d:\n", i); + printf("st_name %x \"%s\"\n", psymtab->st_name, + get_str(psymtab->st_name)); + printf("st_value %x\n", psymtab->st_value); + printf("st_size %x\n", psymtab->st_size); + printf("st_info %x\n", psymtab->st_info); + printf("st_other %x\n", psymtab->st_other); + printf("st_shndx %x\n", psymtab->st_shndx); + } + } +} + +char *strtab; +int strtabsize; +void +load_strtab(Elf_Ehdr * pehdr, char *pexe) +{ + Elf_Shdr *pshdr = NULL; + char *shname; + int i; + strtab = NULL; + for (i = 0; i < pehdr->e_shnum; i++) { + pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff + + (i * pehdr->e_shentsize)); + + shname = get_shstr(pshdr->sh_name); + if (strcmp(".strtab", shname) == 0) + break; + } +#ifdef DEBUG + fprint_shstr(stdout, pshdr->sh_name); + printf("\n"); +#endif + + strtab = (char *) (pexe + pshdr->sh_offset); + + strtabsize = pshdr->sh_size; + +#ifdef DEBUG + dump_strtab(); +#endif +} + +void +dump_strtab() +{ + int index; + char *pstr; + char *pnstr; + int i = 0; + index = 0; + pstr = strtab; + while (index < strtabsize) { + printf("string %x: \"%s\"\n", i, pstr); + pnstr = pstr + strlen(pstr) + 1; + index = pnstr - strtab; + pstr = pnstr; + i++; + } + +} + +void +fprint_str(FILE * channel, int indx) +{ + if (strtab != NULL) + fprintf(channel, "\"%s\"", &(strtab[indx])); +} + +char * +get_str(int indx) +{ + return &(strtab[indx]); +} + +int in_keep_list(char *symbol); + +void +hide_sym(Elf_Ehdr * ehdr, Elf_Shdr * symsect, + Elf_Sym * symtab, int symtabsize, int symtabsecnum) +{ + int i; + unsigned char info; + Elf_Sym *psymtab; + +#ifdef __mips__ + u_int32_t f = arc4random(); +#endif + + for (i = 0; i < (symtabsize / sizeof(Elf_Sym)); i++) { + psymtab = &(symtab[i]); + if ((psymtab->st_info & 0xf0) == 0x10 && + (psymtab->st_shndx != SHN_UNDEF)) { + if (in_keep_list(get_str(psymtab->st_name))) + continue; +#ifdef DEBUG + printf("symbol %d:\n", i); + printf("st_name %x \"%s\"\n", psymtab->st_name, + get_str(psymtab->st_name)); + printf("st_info %x\n", psymtab->st_info); +#endif +#ifndef __mips__ + info = psymtab->st_info; + info = info & 0xf; + psymtab->st_info = info; +#else + /* + * XXX This is a small ugly hack to be able to use + * XXX chrunchide with MIPS. + * XXX Because MIPS needs global symbols to stay + * XXX global (has to do with GOT), we mess around + * XXX with the symbol names instead. For most uses + * XXX this will be no problem, symbols are stripped + * XXX anyway. However, if many one character + * XXX symbols exist, names may clash. + */ + { + char *p; + u_int32_t n, z; + + z = f++; + p = get_str(psymtab->st_name); + n = strlen(p); + if (n > 4) + n = 4; + while (n--) { + p[n] = z; + z >>= 8; + while (p[n] == 0) + p[n] += arc4random(); + } + } + +#endif +#ifdef DEBUG + printf("st_info %x\n", psymtab->st_info); +#endif + } + } + reorder_syms(ehdr, symsect, symtab, symtabsize, symtabsecnum); +} + +void +reorder_syms(Elf_Ehdr * ehdr, Elf_Shdr * symsect, + Elf_Sym * symtab, int symtabsize, int symtabsecnum) +{ + int i; + int nsyms; + int cursym; + Elf_Sym *tmpsymtab; + Symmap *symmap; + + + nsyms = symtabsize / sizeof(Elf_Sym); + + tmpsymtab = (Elf_Sym *) calloc(1, symtabsize); + symmap = (Symmap *) calloc(nsyms, sizeof(Symmap)); + if (!tmpsymtab || !symmap) + errx(5, "calloc: %s", strerror(ENOMEM)); + + bcopy(symtab, tmpsymtab, symtabsize); + + cursym = 1; + for (i = 1; i < nsyms; i++) { + if ((tmpsymtab[i].st_info & 0xf0) == 0x00) { +#ifdef DEBUG + printf("copying l o%d n%d <%s>\n", i, cursym, + get_str(tmpsymtab[i].st_name)); +#endif + bcopy(&(tmpsymtab[i]), &(symtab[cursym]), + sizeof(Elf_Sym)); + symmap[i] = cursym; + cursym++; + } + } + symsect->sh_info = cursym; + for (i = 1; i < nsyms; i++) { + if ((tmpsymtab[i].st_info & 0xf0) != 0x00) { +#ifdef DEBUG + printf("copying nl o%d n%d <%s>\n", i, cursym, + get_str(tmpsymtab[i].st_name)); +#endif + bcopy(&(tmpsymtab[i]), &(symtab[cursym]), + sizeof(Elf_Sym)); + symmap[i] = cursym; + cursym++; + } + } + if (cursym != nsyms) { + printf("miscounted symbols somewhere c %d n %d \n", + cursym, nsyms); + exit(5); + } + renum_reloc_syms(ehdr, symmap, symtabsecnum); + free(tmpsymtab); + free(symmap); +} + +void +renum_reloc_syms(Elf_Ehdr * ehdr, Symmap * symmap, int symtabsecnum) +{ + Elf_Shdr *pshdr; + int i, j; + int num_reloc; + Elf_Rel *prel; + Elf_RelA *prela; + int symnum; + + for (i = 0; i < ehdr->e_shnum; i++) { + pshdr = (Elf_Shdr *) (pexe + ehdr->e_shoff + + (i * ehdr->e_shentsize)); + if ((pshdr->sh_type == SHT_RELA) && + pshdr->sh_link == symtabsecnum) { + +#ifdef DEBUG + printf("section %d has rela relocations in symtab\n", i); +#endif + prela = (Elf_RelA *) (pexe + pshdr->sh_offset); + num_reloc = pshdr->sh_size / sizeof(Elf_RelA); + for (j = 0; j < num_reloc; j++) { + symnum = ELF_R_SYM(prela[j].r_info); +#ifdef DEBUG + printf("sym num o %d n %d\n", symnum, + symmap[symnum]); +#endif + prela[j].r_info = ELF_R_INFO(symmap[symnum], + ELF_R_TYPE(prela[j].r_info)); + } + } + if ((pshdr->sh_type == SHT_REL) && + pshdr->sh_link == symtabsecnum) { +#ifdef DEBUG + printf("section %d has rel relocations in symtab\n", i); +#endif + prel = (Elf_Rel *) (pexe + pshdr->sh_offset); + num_reloc = pshdr->sh_size / sizeof(Elf_Rel); + for (j = 0; j < num_reloc; j++) { + symnum = ELF_R_SYM(prel[j].r_info); +#ifdef DEBUG + printf("sym num o %d n %d\n", symnum, + symmap[symnum]); +#endif + prel[j].r_info = ELF_R_INFO(symmap[symnum], + ELF_R_TYPE(prel[j].r_info)); + } + } + } + +} +#endif /* _NLIST_DO_ELF */ |