1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00

Upgraded to ELFkickers 2.0.

committer: mfx <mfx> 987374332 +0000
This commit is contained in:
Markus F.X.J. Oberhumer 2001-04-15 22:38:52 +00:00
parent 0e063b9759
commit e08d3858be
2 changed files with 232 additions and 157 deletions

View File

@ -5,8 +5,8 @@ The main purpose of these programs is to be illustrative and
educational -- to help fellow programmers understand the ELF file educational -- to help fellow programmers understand the ELF file
format and something of how it works under the Linux platform. For the format and something of how it works under the Linux platform. For the
most part, these programs have limited real-world utility. (Although I most part, these programs have limited real-world utility. (Although I
myself have found these programs quite useful while writing the myself have found some of these programs quite useful while writing
others.) the others.)
Each program is independent. There is no shared code between them, and Each program is independent. There is no shared code between them, and
in fact they all take slightly different approaches to handling ELF in fact they all take slightly different approaches to handling ELF
@ -18,6 +18,10 @@ sstrip/
sstrip is a small utility that removes everything from an ELF file sstrip is a small utility that removes everything from an ELF file
that is not part of the file's memory image. that is not part of the file's memory image.
rebind/
rebind is another small utility that alters the binding of selected
exported symbols in an ELF object file.
elfls/ elfls/
elfls is a utility that displays an ELF file's program and/or elfls is a utility that displays an ELF file's program and/or
section header tables, which serve as a kind of global roadmap to section header tables, which serve as a kind of global roadmap to
@ -38,12 +42,12 @@ tiny/
See the README in each directory for more details. See the README in each directory for more details.
The ELF standard is necessary reading if you wish to fully understand The ELF standard is necessary reading if you wish to fully understand
how these programs work. You can download a copy as a Postscript how all of the programs work. You can download a copy as a Postscript
document from ftp://tsx.mit.edu/pub/linux/packages/GCC/ELF.doc.tar.gz. document from ftp://tsx.mit.edu/pub/linux/packages/GCC/ELF.doc.tar.gz.
Alternately, you can obtain a flat-text transcription of this document Alternately, you can obtain a flat-text transcription of this document
from http://www.muppetlabs.com/~breadbox/software/ELF.txt. from http://www.muppetlabs.com/~breadbox/software/ELF.txt.
All these programs are Copyright (C) 1999 by Brian Raiter. These programs are Copyright (C) 1999-2001 by Brian Raiter.
These programs are all free software; you can redistribute and/or These programs are all free software; you can redistribute and/or
modify them under the terms of the GNU General Public License as modify them under the terms of the GNU General Public License as
@ -67,22 +71,3 @@ Share and enjoy.
Brian Raiter Brian Raiter
breadbox@muppetlabs.com breadbox@muppetlabs.com
July, 1999
________________
This is a minor update of the original release. Shortly after
installing a 2.2 Linux kernel, I discovered that changes to the system
header files, plus a new warning in gcc 2.95.2, caused several of the
programs to generate numerous compiler warnings and errors. The errors
were caused by system headers re-defining a macro (benignly), and were
suppressed by rearranging the inclusion of some header files. The
warnings were due to my taking advantage of the standard feature of
omitting trailing initializers in the definition of a structure, and
were suppressed by omitting the -W gcc option in the Makefiles,
leaving just -Wall. My apologies to any Linux 2.2 users who were
bitten by this. (Hopefully Linux 2.4 isn't in the process of breaking
this version as I write.)
August, 2000

View File

@ -1,191 +1,264 @@
/* sstrip, version 1.0: Copyright (C) 1999 by Brian Raiter, under the /* sstrip: Copyright (C) 1999-2001 by Brian Raiter, under the GNU
* GNU General Public License. No warranty. See COPYING for details. * General Public License. No warranty. See COPYING for details.
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdarg.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <linux/elf.h> #include <fcntl.h>
#include <elf.h>
#include <asm/elf.h>
#ifndef TRUE #ifndef TRUE
#define TRUE 1 #define TRUE 1
#define FALSE 0 #define FALSE 0
#endif #endif
/* The memory-allocation macro. #if ELF_CLASS == ELFCLASS32
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Phdr Elf32_Phdr
#else
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Phdr Elf64_Phdr
#endif
/* The name of the program.
*/ */
#define alloc(p, n) (((p) = realloc(p, n)) \ static char const *progname;
|| (fputs("Out of memory.\n", stderr), \
exit(EXIT_FAILURE), 0))
static char const *thefilename; /* the current file name */ /* The name of the current file.
static FILE *thefile; /* the current file handle */ */
static char const *filename;
static Elf32_Ehdr elfhdr; /* original ELF header */
static Elf32_Phdr *phdrs = NULL; /* original program header tbl */
static unsigned long phdrsize; /* size of program header tbl */
static unsigned long newsize; /* size of the new file */
/* An error-handling function. The given error message is used only /* A simple error-handling function. FALSE is always returned for the
* when errno is not set. * convenience of the caller.
*/ */
static int err(char const *errmsg) static int err(char const *errmsg)
{ {
if (errno) fprintf(stderr, "%s: %s: %s\n", progname, filename, errmsg);
perror(thefilename);
else
fprintf(stderr, "%s: %s\n", thefilename, errmsg);
return FALSE; return FALSE;
} }
/* readheaders() reads the ELF header and the program header table, /* A macro for I/O errors: The given error message is used only when
* and checks to make sure that this is in fact a file that we should * errno is not set.
* be munging.
*/ */
static int readheaders(void) #define ferr(msg) (err(errno ? strerror(errno) : (msg)))
/* readelfheader() reads the ELF header into our global variable, and
* checks to make sure that this is in fact a file that we should be
* munging.
*/
static int readelfheader(int fd, Elf_Ehdr *ehdr)
{ {
int bigend;
errno = 0; errno = 0;
if (fread(&elfhdr, sizeof elfhdr, 1, thefile) != 1) if (read(fd, ehdr, sizeof *ehdr) != sizeof *ehdr)
return err("not an ELF file."); return ferr("missing or incomplete ELF header.");
if (elfhdr.e_ident[EI_MAG0] != ELFMAG0
|| elfhdr.e_ident[EI_MAG1] != ELFMAG1
|| elfhdr.e_ident[EI_MAG2] != ELFMAG2
|| elfhdr.e_ident[EI_MAG3] != ELFMAG3)
return err("not an ELF file.");
bigend = TRUE; /* Check the ELF signature.
*(char*)&bigend = 0; */
if (elfhdr.e_ident[EI_DATA] != (bigend ? ELFDATA2MSB : ELFDATA2LSB)) { if (!(ehdr->e_ident[EI_MAG0] == ELFMAG0 &&
fprintf(stderr, "%s: not %s-endian.\n", ehdr->e_ident[EI_MAG1] == ELFMAG1 &&
thefilename, bigend ? "big" : "little"); ehdr->e_ident[EI_MAG2] == ELFMAG2 &&
return FALSE; ehdr->e_ident[EI_MAG3] == ELFMAG3))
} return err("missing ELF signature.");
if (elfhdr.e_ehsize != sizeof(Elf32_Ehdr)) {
fprintf(stderr, "%s: unrecognized ELF header size "
"(size = %u instead of %u).\n",
thefilename, elfhdr.e_ehsize, sizeof(Elf32_Ehdr));
return FALSE;
}
if (!elfhdr.e_phoff)
return err("no program header table.");
if (elfhdr.e_phentsize != sizeof(Elf32_Phdr)) {
fprintf(stderr, "%s: unrecognized program header size "
"(size = %u instead of %u).\n",
thefilename, elfhdr.e_phentsize, sizeof(Elf32_Ehdr));
return FALSE;
}
phdrsize = elfhdr.e_phnum * elfhdr.e_phentsize; /* Compare the file's class and endianness with the program's.
alloc(phdrs, phdrsize); */
errno = 0; if (ehdr->e_ident[EI_DATA] != ELF_DATA)
if (fread(phdrs, phdrsize, 1, thefile) != 1) return err("ELF file has different endianness.");
return err("invalid program header table."); if (ehdr->e_ident[EI_CLASS] != ELF_CLASS)
return err("ELF file has different word size.");
/* Check the target architecture.
*/
if (ehdr->e_machine != ELF_ARCH)
return err("ELF file created for different architecture.");
/* Verify the sizes of the ELF header and the program segment
* header table entries.
*/
if (ehdr->e_ehsize != sizeof(Elf_Ehdr))
return err("unrecognized ELF header size.");
if (ehdr->e_phentsize != sizeof(Elf_Phdr))
return err("unrecognized program segment header size.");
/* Finally, check the file type.
*/
if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
return err("not an executable or shared-object library.");
return TRUE; return TRUE;
} }
/* getloadsize() determines the offset of the last byte of the file /* readphdrtable() loads the program segment header table into memory.
* that is actually loaded into memory. Anything after this point can
* be safely discarded.
*/ */
static int getloadsize(void) static int readphdrtable(int fd, Elf_Ehdr const *ehdr, Elf_Phdr **phdrs)
{ {
Elf32_Phdr *phdr; size_t size;
unsigned long n;
int i;
newsize = elfhdr.e_phoff + phdrsize; if (!ehdr->e_phoff || !ehdr->e_phnum)
phdr = phdrs; return err("ELF file has no program header table.");
for (i = 0 ; i < elfhdr.e_phnum ; ++i) {
if (phdr->p_type == PT_NULL || phdr->p_type == PT_NOTE) size = ehdr->e_phnum * sizeof **phdrs;
continue; if (!(*phdrs = malloc(size)))
n = phdr->p_offset + phdr->p_filesz; return err("Out of memory!");
if (n > newsize)
newsize = n; errno = 0;
phdr = (Elf32_Phdr*)((char*)phdr + elfhdr.e_phentsize); if (read(fd, *phdrs, size) != (ssize_t)size)
return ferr("missing or incomplete program segment header table.");
return TRUE;
} }
for (i = 0 ; i < elfhdr.e_phnum ; ++i) /* getmemorysize() determines the offset of the last byte of the file
if (phdr->p_filesz > 0 && phdr->p_offset >= newsize) * that is referenced by an entry in the program segment header table.
memset(phdr, 0, elfhdr.e_phentsize); * (Anything in the file after that point is not used when the program
* is executing, and thus can be safely discarded.)
*/
static int getmemorysize(Elf_Ehdr const *ehdr, Elf_Phdr const *phdrs,
unsigned long *newsize)
{
Elf32_Phdr const *phdr;
unsigned long size, n;
int i;
/* Start by setting the size to include the ELF header and the
* complete program segment header table.
*/
size = ehdr->e_phoff + ehdr->e_phnum * sizeof *phdrs;
if (size < sizeof *ehdr)
size = sizeof *ehdr;
/* Then keep extending the size to include whatever data the
* program segment header table references.
*/
for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) {
if (phdr->p_type != PT_NULL) {
n = phdr->p_offset + phdr->p_filesz;
if (n > size)
size = n;
}
}
*newsize = size;
return TRUE; return TRUE;
} }
/* truncatezeros() examines the bytes at the end of the file's /* truncatezeros() examines the bytes at the end of the file's
* size-to-be, and reduces the size to exclude trailing zero bytes. * size-to-be, and reduces the size to exclude any trailing zero
* bytes.
*/ */
static int truncatezeros(void) static int truncatezeros(int fd, unsigned long *newsize)
{ {
char contents[1024]; unsigned char contents[1024];
unsigned long n; unsigned long size, n;
size = *newsize;
do { do {
n = sizeof contents; n = sizeof contents;
if (n > newsize) if (n > size)
n = newsize; n = size;
if (fseek(thefile, newsize - n, SEEK_SET) if (lseek(fd, size - n, SEEK_SET) == (off_t)-1)
|| fread(contents, n, 1, thefile) != 1) return ferr("cannot seek in file.");
return err("cannot read file contents"); if (read(fd, contents, n) != (ssize_t)n)
return ferr("cannot read file contents");
while (n && !contents[--n]) while (n && !contents[--n])
--newsize; --size;
} while (newsize && !n); } while (size && !n);
/* Sanity check.
*/
if (!size)
return err("ELF file is completely blank!");
*newsize = size;
return TRUE; return TRUE;
} }
/* modifyheaders() removes references to the section header table if /* modifyheaders() removes references to the section header table if
* it was removed, and reduces program header table entries that * it was stripped, and reduces program header table entries that
* included truncated bytes at the end of the file. * included truncated bytes at the end of the file.
*/ */
static int modifyheaders(void) static int modifyheaders(Elf_Ehdr *ehdr, Elf_Phdr *phdrs,
unsigned long newsize)
{ {
Elf32_Phdr *phdr; Elf32_Phdr *phdr;
int i; int i;
if (elfhdr.e_shoff >= newsize) { /* If the section header table is gone, then remove all references
elfhdr.e_shoff = 0; * to it in the ELF header.
elfhdr.e_shnum = 0; */
elfhdr.e_shentsize = 0; if (ehdr->e_shoff >= newsize) {
elfhdr.e_shstrndx = 0; ehdr->e_shoff = 0;
ehdr->e_shnum = 0;
ehdr->e_shentsize = 0;
ehdr->e_shstrndx = 0;
} }
phdr = phdrs; /* The program adjusts the file size of any segment that was
for (i = 0 ; i < elfhdr.e_phnum ; ++i) { * truncated. The case of a segment being completely stripped out
if (phdr->p_offset + phdr->p_filesz > newsize) { * is handled separately.
if (phdr->p_offset >= newsize) */
for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) {
if (phdr->p_offset >= newsize) {
phdr->p_offset = newsize;
phdr->p_filesz = 0; phdr->p_filesz = 0;
else } else if (phdr->p_offset + phdr->p_filesz > newsize) {
phdr->p_filesz = newsize - phdr->p_offset; phdr->p_filesz = newsize - phdr->p_offset;
} }
phdr = (Elf32_Phdr*)((char*)phdr + elfhdr.e_phentsize);
} }
return TRUE; return TRUE;
} }
/* savestripped() writes the new headers back to the original file /* commitchanges() writes the new headers back to the original file
* and sets the new file size. * and sets the file to its new size.
*/ */
static int savestripped(void) static int commitchanges(int fd, Elf_Ehdr const *ehdr, Elf_Phdr *phdrs,
unsigned long newsize)
{ {
rewind(thefile); size_t n;
/* Save the changes to the ELF header, if any.
*/
if (lseek(fd, 0, SEEK_SET))
return ferr("could not rewind file");
errno = 0; errno = 0;
if (fwrite(&elfhdr, sizeof elfhdr, 1, thefile) != 1 if (write(fd, ehdr, sizeof *ehdr) != sizeof *ehdr)
|| fwrite(phdrs, phdrsize, 1, thefile) != 1 return err("could not modify file");
|| ftruncate(fileno(thefile), newsize)) {
err("could not write contents"); /* Save the changes to the program segment header table, if any.
fprintf(stderr, "WARNING: %s may be corrupted!\n", thefilename); */
return FALSE; if (lseek(fd, ehdr->e_phoff, SEEK_SET) == (off_t)-1) {
err("could not seek in file.");
goto warning;
}
n = ehdr->e_phnum * sizeof *phdrs;
if (write(fd, phdrs, n) != (ssize_t)n) {
err("could not write to file");
goto warning;
}
/* Eleventh-hour sanity check: don't truncate before the end of
* the program segment header table.
*/
if (newsize < ehdr->e_phoff + n)
newsize = ehdr->e_phoff + n;
/* Chop off the end of the file.
*/
if (ftruncate(fd, newsize)) {
err("could not resize file");
goto warning;
} }
return TRUE; return TRUE;
warning:
return err("ELF file may have been corrupted!");
} }
/* main() loops over the cmdline arguments, leaving all the real work /* main() loops over the cmdline arguments, leaving all the real work
@ -193,31 +266,48 @@ static int savestripped(void)
*/ */
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int fd;
Elf_Ehdr ehdr;
Elf_Phdr *phdrs;
unsigned long newsize;
char **arg; char **arg;
int ret = 0; int failures = 0;
if (argc < 2 || !strcmp(argv[1], "-h")) { if (argc < 2 || argv[1][0] == '-') {
printf("sstrip, version 2.0: Copyright (C) 1999 Brian Raiter\n" printf("Usage: sstrip FILE...\n"
"Usage: sstrip FILE...\n"); "sstrip discards all nonessential bytes from an executable.\n\n"
return 0; "Version 2.0 Copyright (C) 2000,2001 Brian Raiter.\n"
"This program is free software, licensed under the GNU\n"
"General Public License. There is absolutely no warranty.\n");
return EXIT_SUCCESS;
} }
for (arg = argv + 1 ; (thefilename = *arg) != NULL ; ++arg) { progname = argv[0];
if (!(thefile = fopen(thefilename, "rb+"))) {
err("unable to open."); for (arg = argv + 1 ; *arg != NULL ; ++arg) {
++ret; filename = *arg;
fd = open(*arg, O_RDWR);
if (fd < 0) {
ferr("can't open");
++failures;
continue; continue;
} }
if (!readheaders() || !getloadsize() || !truncatezeros()
|| !modifyheaders() || !savestripped()) if (!(readelfheader(fd, &ehdr) &&
++ret; readphdrtable(fd, &ehdr, &phdrs) &&
fclose(thefile); getmemorysize(&ehdr, phdrs, &newsize) &&
truncatezeros(fd, &newsize) &&
modifyheaders(&ehdr, phdrs, newsize) &&
commitchanges(fd, &ehdr, phdrs, newsize)))
++failures;
close(fd);
} }
return ret; return failures ? EXIT_FAILURE : EXIT_SUCCESS;
} }
/* /*
vi:ts=8:et:nowrap vi:ts=8:et:nowrap
*/ */