📄 unexelf.c
字号:
2 0x60874 0x80a9874 0 0x80 0 7 0 */#include <sys/types.h>#include <stdio.h>#include <sys/stat.h>#include <memory.h>#include <string.h>#include <errno.h>#include <unistd.h>#include <fcntl.h>#include <elf.h>#include <sys/mman.h>#ifndef emacs#define fatal(a, b, c) fprintf(stderr, a, b, c), exit(1)#elseextern void fatal(char *, ...);#endif/* Get the address of a particular section or program header entry, * accounting for the size of the entries. */#define OLD_SECTION_H(n) \ (*(Elf32_Shdr *) ((byte *) old_section_h + old_file_h->e_shentsize * (n)))#define NEW_SECTION_H(n) \ (*(Elf32_Shdr *) ((byte *) new_section_h + new_file_h->e_shentsize * (n)))#define OLD_PROGRAM_H(n) \ (*(Elf32_Phdr *) ((byte *) old_program_h + old_file_h->e_phentsize * (n)))#define NEW_PROGRAM_H(n) \ (*(Elf32_Phdr *) ((byte *) new_program_h + new_file_h->e_phentsize * (n)))typedef unsigned char byte;/* **************************************************************** * unexec * * driving logic. * * In ELF, this works by replacing the old .bss section with a new * .data section, and inserting an empty .bss immediately afterwards. * */voidunexec (new_name, old_name, data_start, bss_start, entry_address) char *new_name, *old_name; unsigned data_start, bss_start, entry_address;{ extern unsigned int bss_end; int new_file, old_file, new_file_size; /* Pointers to the base of the image of the two files. */ caddr_t old_base, new_base; /* Pointers to the file, program and section headers for the old and new * files. */ Elf32_Ehdr *old_file_h, *new_file_h; Elf32_Phdr *old_program_h, *new_program_h; Elf32_Shdr *old_section_h, *new_section_h; /* Point to the section name table in the old file */ char *old_section_names; Elf32_Addr old_bss_addr, new_bss_addr; Elf32_Word old_bss_size, new_data2_size; Elf32_Off new_data2_offset; Elf32_Addr new_data2_addr; int n, old_bss_index, old_data_index, new_data2_index; struct stat stat_buf; /* Open the old file & map it into the address space. */ old_file = open (old_name, O_RDONLY); if (old_file < 0) fatal ("Can't open %s for reading: errno %d\n", old_name, errno); if (fstat (old_file, &stat_buf) == -1) fatal ("Can't fstat(%s): errno %d\n", old_name, errno); old_base = mmap (0, stat_buf.st_size, PROT_READ, MAP_SHARED, old_file, 0); if (old_base == (caddr_t) -1) fatal ("Can't mmap(%s): errno %d\n", old_name, errno);#ifdef DEBUG fprintf (stderr, "mmap(%s, %x) -> %x\n", old_name, stat_buf.st_size, old_base);#endif /* Get pointers to headers & section names */ old_file_h = (Elf32_Ehdr *) old_base; old_program_h = (Elf32_Phdr *) ((byte *) old_base + old_file_h->e_phoff); old_section_h = (Elf32_Shdr *) ((byte *) old_base + old_file_h->e_shoff); old_section_names = (char *) old_base + OLD_SECTION_H(old_file_h->e_shstrndx).sh_offset; /* Find the old .bss section. Figure out parameters of the new * data2 and bss sections. */ for (old_bss_index = 1; old_bss_index < old_file_h->e_shnum; old_bss_index++) {#ifdef DEBUG fprintf (stderr, "Looking for .bss - found %s\n", old_section_names + OLD_SECTION_H(old_bss_index).sh_name);#endif if (!strcmp (old_section_names + OLD_SECTION_H(old_bss_index).sh_name, ".bss")) break; } if (old_bss_index == old_file_h->e_shnum) fatal ("Can't find .bss in %s.\n", old_name, 0); old_bss_addr = OLD_SECTION_H(old_bss_index).sh_addr; old_bss_size = OLD_SECTION_H(old_bss_index).sh_size;#if defined(emacs) || !defined(DEBUG) bss_end = (unsigned int) sbrk (0); new_bss_addr = (Elf32_Addr) bss_end;#else new_bss_addr = old_bss_addr + old_bss_size + 0x1234;#endif new_data2_addr = old_bss_addr; new_data2_size = new_bss_addr - old_bss_addr; new_data2_offset = OLD_SECTION_H(old_bss_index).sh_offset;#ifdef DEBUG fprintf (stderr, "old_bss_index %d\n", old_bss_index); fprintf (stderr, "old_bss_addr %x\n", old_bss_addr); fprintf (stderr, "old_bss_size %x\n", old_bss_size); fprintf (stderr, "new_bss_addr %x\n", new_bss_addr); fprintf (stderr, "new_data2_addr %x\n", new_data2_addr); fprintf (stderr, "new_data2_size %x\n", new_data2_size); fprintf (stderr, "new_data2_offset %x\n", new_data2_offset);#endif if ((unsigned) new_bss_addr < (unsigned) old_bss_addr + old_bss_size) fatal (".bss shrank when undumping???\n", 0, 0); /* Set the output file to the right size and mmap(2) it. Set * pointers to various interesting objects. stat_buf still has * old_file data. */ new_file = open (new_name, O_RDWR | O_CREAT, 0666); if (new_file < 0) fatal ("Can't creat(%s): errno %d\n", new_name, errno); new_file_size = stat_buf.st_size + old_file_h->e_shentsize + new_data2_size; if (ftruncate (new_file, new_file_size)) fatal ("Can't ftruncate(%s): errno %d\n", new_name, errno); new_base = mmap (0, new_file_size, PROT_READ | PROT_WRITE, MAP_SHARED, new_file, 0); if (new_base == (caddr_t) -1) fatal ("Can't mmap(%s): errno %d\n", new_name, errno); new_file_h = (Elf32_Ehdr *) new_base; new_program_h = (Elf32_Phdr *) ((byte *) new_base + old_file_h->e_phoff); new_section_h = (Elf32_Shdr *) ((byte *) new_base + old_file_h->e_shoff + new_data2_size); /* Make our new file, program and section headers as copies of the * originals. */ memcpy (new_file_h, old_file_h, old_file_h->e_ehsize); memcpy (new_program_h, old_program_h, old_file_h->e_phnum * old_file_h->e_phentsize); memcpy (new_section_h, old_section_h, old_file_h->e_shnum * old_file_h->e_shentsize); /* Fix up file header. We'll add one section. Section header is * further away now. */ new_file_h->e_shoff += new_data2_size; new_file_h->e_shnum += 1;#ifdef DEBUG fprintf (stderr, "Old section offset %x\n", old_file_h->e_shoff); fprintf (stderr, "Old section count %d\n", old_file_h->e_shnum); fprintf (stderr, "New section offset %x\n", new_file_h->e_shoff); fprintf (stderr, "New section count %d\n", new_file_h->e_shnum);#endif /* Fix up a new program header. Extend the writable data segment so * that the bss area is covered too. Find that segment by looking * for a segment that ends just before the .bss area. Make sure * that no segments are above the new .data2. Put a loop at the end * to adjust the offset and address of any segment that is above * data2, just in case we decide to allow this later. */ for (n = new_file_h->e_phnum - 1; n >= 0; n--) { if (NEW_PROGRAM_H(n).p_vaddr + NEW_PROGRAM_H(n).p_filesz > old_bss_addr) fatal ("Program segment above .bss in %s\n", old_name, 0); if (NEW_PROGRAM_H(n).p_type == PT_LOAD && (NEW_PROGRAM_H(n).p_vaddr + NEW_PROGRAM_H(n).p_filesz == old_bss_addr)) break; } if (n < 0) fatal ("Couldn't find segment next to .bss in %s\n", old_name, 0); NEW_PROGRAM_H(n).p_filesz += new_data2_size; NEW_PROGRAM_H(n).p_memsz = NEW_PROGRAM_H(n).p_filesz;#if 0 /* Maybe allow section after data2 - does this ever happen? */ for (n = new_file_h->e_phnum - 1; n >= 0; n--) { if (NEW_PROGRAM_H(n).p_vaddr && NEW_PROGRAM_H(n).p_vaddr >= new_data2_addr) NEW_PROGRAM_H(n).p_vaddr += new_data2_size - old_bss_size; if (NEW_PROGRAM_H(n).p_offset >= new_data2_offset) NEW_PROGRAM_H(n).p_offset += new_data2_size; }#endif /* Fix up section headers based on new .data2 section. Any section * whose offset or virtual address is after the new .data2 section * gets its value adjusted. .bss size becomes zero and new address * is set. data2 section header gets added by copying the existing * .data header and modifying the offset, address and size. */ for (n = 1; n < new_file_h->e_shnum; n++) { if (NEW_SECTION_H(n).sh_offset >= new_data2_offset) NEW_SECTION_H(n).sh_offset += new_data2_size; if (NEW_SECTION_H(n).sh_addr && NEW_SECTION_H(n).sh_addr >= new_data2_addr) NEW_SECTION_H(n).sh_addr += new_data2_size - old_bss_size; } new_data2_index = old_file_h->e_shnum; for (old_data_index = 1; old_data_index < old_file_h->e_shnum; old_data_index++) if (!strcmp (old_section_names + OLD_SECTION_H(old_data_index).sh_name, ".data")) break; if (old_data_index == old_file_h->e_shnum) fatal ("Can't find .data in %s.\n", old_name, 0); memcpy (&NEW_SECTION_H(new_data2_index), &OLD_SECTION_H(old_data_index), new_file_h->e_shentsize); NEW_SECTION_H(new_data2_index).sh_addr = new_data2_addr; NEW_SECTION_H(new_data2_index).sh_offset = new_data2_offset; NEW_SECTION_H(new_data2_index).sh_size = new_data2_size; NEW_SECTION_H(old_bss_index).sh_size = 0; NEW_SECTION_H(old_bss_index).sh_addr = new_data2_addr + new_data2_size; /* Write out the sections. .data and .data1 (and data2, called * ".data" in the strings table) get copied from the current process * instead of the old file. */ for (n = new_file_h->e_shnum - 1; n; n--) { caddr_t src; if (NEW_SECTION_H(n).sh_type == SHT_NULL || NEW_SECTION_H(n).sh_type == SHT_NOBITS) continue; if (!strcmp (old_section_names + NEW_SECTION_H(n).sh_name, ".data") || !strcmp ((old_section_names + NEW_SECTION_H(n).sh_name), ".data1")) src = (caddr_t) NEW_SECTION_H(n).sh_addr; else src = old_base + OLD_SECTION_H(n).sh_offset; memcpy (NEW_SECTION_H(n).sh_offset + new_base, src, NEW_SECTION_H(n).sh_size); } /* Close the files and make the new file executable */ if (close (old_file)) fatal ("Can't close(%s): errno %d\n", old_name, errno); if (close (new_file)) fatal ("Can't close(%s): errno %d\n", new_name, errno); if (stat (new_name, &stat_buf) == -1) fatal ("Can't stat(%s): errno %d\n", new_name, errno); n = umask (777); umask (n); stat_buf.st_mode |= 0111 & ~n; if (chmod (new_name, stat_buf.st_mode) == -1) fatal ("Can't chmod(%s): errno %d\n", new_name, errno);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -