int hide_aout(int inf, const char *filename) { struct stat infstat; struct relocation_info *relp; struct nlist *symp; int rc; /* * do some error checking. */ if(fstat(inf, &infstat) == -1) { perror(filename); return 1; } /* * Read the entire file into memory. XXX - Really, we only need to * read the header and from TRELOFF to the end of the file. */ if((aoutdata = (char *) malloc(infstat.st_size)) == NULL) { fprintf(stderr, "%s: too big to read into memory\n", filename); return 1; } if((rc = read(inf, aoutdata, infstat.st_size)) < infstat.st_size) { fprintf(stderr, "%s: read error: %s\n", filename, rc == -1? strerror(errno) : "short read"); return 1; } /* * Calculate offsets and sizes from the header. */ hdrp = (struct exec *) aoutdata; #ifdef __FreeBSD__ textrel = (struct relocation_info *) (aoutdata + N_RELOFF(*hdrp)); datarel = (struct relocation_info *) (aoutdata + N_RELOFF(*hdrp) + hdrp->a_trsize); #else textrel = (struct relocation_info *) (aoutdata + N_TRELOFF(*hdrp)); datarel = (struct relocation_info *) (aoutdata + N_DRELOFF(*hdrp)); #endif symbase = (struct nlist *) (aoutdata + N_SYMOFF(*hdrp)); strbase = (char *) (aoutdata + N_STROFF(*hdrp)); ntextrel = hdrp->a_trsize / sizeof(struct relocation_info); ndatarel = hdrp->a_drsize / sizeof(struct relocation_info); nsyms = hdrp->a_syms / sizeof(struct nlist); /* * Zap the type field of all globally-defined symbols. The linker will * subsequently ignore these entries. Don't zap any symbols in the * keep list. */ for(symp = symbase; symp < symbase + nsyms; symp++) { if(!IS_GLOBAL_DEFINED(symp)) /* keep undefined syms */ continue; /* keep (C) symbols which are on the keep list */ if(SYMSTR(symp)[0] == '_' && in_keep_list(SYMSTR(symp) + 1)) continue; symp->n_type = 0; } /* * Check whether the relocation entries reference any symbols that we * just zapped. I don't know whether ld can handle this case, but I * haven't encountered it yet. These checks are here so that the program * doesn't fail silently should such symbols be encountered. */ for(relp = textrel; relp < textrel + ntextrel; relp++) check_reloc(filename, relp); for(relp = datarel; relp < datarel + ndatarel; relp++) check_reloc(filename, relp); /* * Write the .o file back out to disk. XXX - Really, we only need to * write the symbol table entries back out. */ lseek(inf, 0, SEEK_SET); if((rc = write(inf, aoutdata, infstat.st_size)) < infstat.st_size) { fprintf(stderr, "%s: write error: %s\n", filename, rc == -1? strerror(errno) : "short write"); return 1; } return 0; }
static #endif void dump_file(const char *fname) { int fd; struct stat sb; caddr_t objbase; if (stat(fname, &sb) == -1) { warnx("cannot stat \"%s\"", fname); ++error_count; return; } if ((sb.st_mode & S_IFMT) != S_IFREG) { warnx("\"%s\" is not a regular file", fname); ++error_count; return; } if ((fd = open(fname, O_RDONLY, 0)) == -1) { warnx("cannot open \"%s\"", fname); ++error_count; return; } objbase = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); if (objbase == (caddr_t) -1) { warnx("cannot mmap \"%s\"", fname); ++error_count; close(fd); return; } close(fd); file_base = (const char *) objbase; /* Makes address arithmetic easier */ if (IS_ELF(*(const Elf32_Ehdr*) align_struct(file_base))) { warnx("%s: this is an ELF program; use objdump to examine", fname); ++error_count; munmap(objbase, sb.st_size); return; } ex = (const struct exec *) align_struct(file_base); printf("%s: a_midmag = 0x%lx\n", fname, (long)ex->a_midmag); printf(" magic = 0x%lx = 0%lo, netmagic = 0x%lx = 0%lo\n", (long)N_GETMAGIC(*ex), (long)N_GETMAGIC(*ex), (long)N_GETMAGIC_NET(*ex), (long)N_GETMAGIC_NET(*ex)); if (N_BADMAG(*ex)) { warnx("%s: bad magic number", fname); ++error_count; munmap(objbase, sb.st_size); return; } printf(" a_text = 0x%lx\n", (long)ex->a_text); printf(" a_data = 0x%lx\n", (long)ex->a_data); printf(" a_bss = 0x%lx\n", (long)ex->a_bss); printf(" a_syms = 0x%lx\n", (long)ex->a_syms); printf(" a_entry = 0x%lx\n", (long)ex->a_entry); printf(" a_trsize = 0x%lx\n", (long)ex->a_trsize); printf(" a_drsize = 0x%lx\n", (long)ex->a_drsize); text_base = file_base + N_TXTOFF(*ex); data_base = file_base + N_DATOFF(*ex); rel_base = (const struct relocation_info *) align_struct(file_base + N_RELOFF(*ex)); sym_base = (const struct nlist *) align_struct(file_base + N_SYMOFF(*ex)); str_base = file_base + N_STROFF(*ex); rel_count = (ex->a_trsize + ex->a_drsize) / sizeof rel_base[0]; assert(rel_count * sizeof rel_base[0] == ex->a_trsize + ex->a_drsize); sym_count = ex->a_syms / sizeof sym_base[0]; assert(sym_count * sizeof sym_base[0] == ex->a_syms); if (sym_count != 0) { sym_used = (unsigned char *) calloc(sym_count, sizeof(unsigned char)); assert(sym_used != NULL); } printf(" Entry = 0x%lx\n", (long)ex->a_entry); printf(" Text offset = %x, address = %lx\n", N_TXTOFF(*ex), (long)N_TXTADDR(*ex)); printf(" Data offset = %lx, address = %lx\n", (long)N_DATOFF(*ex), (long)N_DATADDR(*ex)); /* * In an executable program file, everything is relocated relative to * the assumed run-time load address, i.e., N_TXTADDR(*ex), i.e., 0x1000. * * In a shared library file, everything is relocated relative to the * start of the file, i.e., N_TXTOFF(*ex), i.e., 0. * * The way to tell the difference is by looking at ex->a_entry. If it * is >= 0x1000, then we have an executable program. Otherwise, we * have a shared library. * * When a program is executed, the entire file is mapped into memory, * including the a.out header and so forth. But it is not mapped at * address 0; rather it is mapped at address 0x1000. The first page * of the user's address space is left unmapped in order to catch null * pointer dereferences. * * In this program, when we map in an executable program, we have to * simulate the empty page by decrementing our assumed base address by * a pagesize. */ text_addr = text_base; data_addr = data_base; origin = 0; if (ex->a_entry >= PAGE_SIZE) { /* Executable, not a shared library */ /* * The fields in the object have already been relocated on the * assumption that the object will be loaded at N_TXTADDR(*ex). * We have to compensate for that. */ text_addr -= PAGE_SIZE; data_addr -= PAGE_SIZE; origin = PAGE_SIZE; printf(" Program, origin = %lx\n", origin); } else if (N_GETFLAG(*ex) & EX_DYNAMIC) printf(" Shared library, origin = %lx\n", origin); else printf(" Object file, origin = %lx\n", origin); if (N_GETFLAG(*ex) & EX_DYNAMIC) { dyn = (const struct _dynamic *) align_struct(data_base); printf(" Dynamic version = %d\n", dyn->d_version); sdt = (const struct section_dispatch_table *) align_struct(text_addr + (unsigned long) dyn->d_un.d_sdt); rtrel_base = (const struct relocation_info *) align_struct(text_addr + sdt->sdt_rel); rtrel_count = (sdt->sdt_hash - sdt->sdt_rel) / sizeof rtrel_base[0]; assert(rtrel_count * sizeof rtrel_base[0] == (size_t)(sdt->sdt_hash - sdt->sdt_rel)); rtsym_base = (const struct nzlist *) align_struct(text_addr + sdt->sdt_nzlist); rtsym_count = (sdt->sdt_strings - sdt->sdt_nzlist) / sizeof rtsym_base[0]; assert(rtsym_count * sizeof rtsym_base[0] == (size_t)(sdt->sdt_strings - sdt->sdt_nzlist)); if (rtsym_count != 0) { rtsym_used = (unsigned char *) calloc(rtsym_count, sizeof(unsigned char)); assert(rtsym_used != NULL); } rtstr_base = text_addr + sdt->sdt_strings; } dump_segs(); dump_sods(); dump_rels("Relocations", rel_base, rel_count, sym_name, sym_used); dump_syms(); dump_rels("Run-time relocations", rtrel_base, rtrel_count, rtsym_name, rtsym_used); dump_rtsyms(); if (rtsym_used != NULL) { free(rtsym_used); rtsym_used = NULL; } if (sym_used != NULL) { free(sym_used); sym_used = NULL; } munmap(objbase, sb.st_size); }