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
format and something of how it works under the Linux platform. For the
most part, these programs have limited real-world utility. (Although I
myself have found these programs quite useful while writing the
others.)
myself have found some of these programs quite useful while writing
the others.)
Each program is independent. There is no shared code between them, and
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
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 is a utility that displays an ELF file's program and/or
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.
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.
Alternately, you can obtain a flat-text transcription of this document
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
modify them under the terms of the GNU General Public License as
@ -67,22 +71,3 @@ Share and enjoy.
Brian Raiter
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
* GNU General Public License. No warranty. See COPYING for details.
/* sstrip: Copyright (C) 1999-2001 by Brian Raiter, under the GNU
* General Public License. No warranty. See COPYING for details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <linux/elf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <elf.h>
#include <asm/elf.h>
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#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)) \
|| (fputs("Out of memory.\n", stderr), \
exit(EXIT_FAILURE), 0))
static char const *progname;
static char const *thefilename; /* the current file name */
static FILE *thefile; /* the current file handle */
/* The name of the current file.
*/
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
* when errno is not set.
/* A simple error-handling function. FALSE is always returned for the
* convenience of the caller.
*/
static int err(char const *errmsg)
{
if (errno)
perror(thefilename);
else
fprintf(stderr, "%s: %s\n", thefilename, errmsg);
fprintf(stderr, "%s: %s: %s\n", progname, filename, errmsg);
return FALSE;
}
/* readheaders() reads the ELF header and the program header table,
* and checks to make sure that this is in fact a file that we should
* be munging.
/* A macro for I/O errors: The given error message is used only when
* errno is not set.
*/
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;
if (fread(&elfhdr, sizeof elfhdr, 1, thefile) != 1)
return err("not an ELF file.");
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.");
if (read(fd, ehdr, sizeof *ehdr) != sizeof *ehdr)
return ferr("missing or incomplete ELF header.");
bigend = TRUE;
*(char*)&bigend = 0;
if (elfhdr.e_ident[EI_DATA] != (bigend ? ELFDATA2MSB : ELFDATA2LSB)) {
fprintf(stderr, "%s: not %s-endian.\n",
thefilename, bigend ? "big" : "little");
return FALSE;
}
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;
}
/* Check the ELF signature.
*/
if (!(ehdr->e_ident[EI_MAG0] == ELFMAG0 &&
ehdr->e_ident[EI_MAG1] == ELFMAG1 &&
ehdr->e_ident[EI_MAG2] == ELFMAG2 &&
ehdr->e_ident[EI_MAG3] == ELFMAG3))
return err("missing ELF signature.");
phdrsize = elfhdr.e_phnum * elfhdr.e_phentsize;
alloc(phdrs, phdrsize);
errno = 0;
if (fread(phdrs, phdrsize, 1, thefile) != 1)
return err("invalid program header table.");
/* Compare the file's class and endianness with the program's.
*/
if (ehdr->e_ident[EI_DATA] != ELF_DATA)
return err("ELF file has different endianness.");
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;
}
/* getloadsize() determines the offset of the last byte of the file
* that is actually loaded into memory. Anything after this point can
* be safely discarded.
/* readphdrtable() loads the program segment header table into memory.
*/
static int getloadsize(void)
static int readphdrtable(int fd, Elf_Ehdr const *ehdr, Elf_Phdr **phdrs)
{
Elf32_Phdr *phdr;
unsigned long n;
size_t size;
if (!ehdr->e_phoff || !ehdr->e_phnum)
return err("ELF file has no program header table.");
size = ehdr->e_phnum * sizeof **phdrs;
if (!(*phdrs = malloc(size)))
return err("Out of memory!");
errno = 0;
if (read(fd, *phdrs, size) != (ssize_t)size)
return ferr("missing or incomplete program segment header table.");
return TRUE;
}
/* getmemorysize() determines the offset of the last byte of the file
* that is referenced by an entry in the program segment header table.
* (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;
newsize = elfhdr.e_phoff + phdrsize;
phdr = phdrs;
for (i = 0 ; i < elfhdr.e_phnum ; ++i) {
if (phdr->p_type == PT_NULL || phdr->p_type == PT_NOTE)
continue;
n = phdr->p_offset + phdr->p_filesz;
if (n > newsize)
newsize = n;
phdr = (Elf32_Phdr*)((char*)phdr + elfhdr.e_phentsize);
/* 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;
}
}
for (i = 0 ; i < elfhdr.e_phnum ; ++i)
if (phdr->p_filesz > 0 && phdr->p_offset >= newsize)
memset(phdr, 0, elfhdr.e_phentsize);
*newsize = size;
return TRUE;
}
/* 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 long n;
unsigned char contents[1024];
unsigned long size, n;
size = *newsize;
do {
n = sizeof contents;
if (n > newsize)
n = newsize;
if (fseek(thefile, newsize - n, SEEK_SET)
|| fread(contents, n, 1, thefile) != 1)
return err("cannot read file contents");
if (n > size)
n = size;
if (lseek(fd, size - n, SEEK_SET) == (off_t)-1)
return ferr("cannot seek in file.");
if (read(fd, contents, n) != (ssize_t)n)
return ferr("cannot read file contents");
while (n && !contents[--n])
--newsize;
} while (newsize && !n);
--size;
} while (size && !n);
/* Sanity check.
*/
if (!size)
return err("ELF file is completely blank!");
*newsize = size;
return TRUE;
}
/* 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.
*/
static int modifyheaders(void)
static int modifyheaders(Elf_Ehdr *ehdr, Elf_Phdr *phdrs,
unsigned long newsize)
{
Elf32_Phdr *phdr;
int i;
if (elfhdr.e_shoff >= newsize) {
elfhdr.e_shoff = 0;
elfhdr.e_shnum = 0;
elfhdr.e_shentsize = 0;
elfhdr.e_shstrndx = 0;
/* If the section header table is gone, then remove all references
* to it in the ELF header.
*/
if (ehdr->e_shoff >= newsize) {
ehdr->e_shoff = 0;
ehdr->e_shnum = 0;
ehdr->e_shentsize = 0;
ehdr->e_shstrndx = 0;
}
phdr = phdrs;
for (i = 0 ; i < elfhdr.e_phnum ; ++i) {
if (phdr->p_offset + phdr->p_filesz > newsize) {
if (phdr->p_offset >= newsize)
phdr->p_filesz = 0;
else
phdr->p_filesz = newsize - phdr->p_offset;
/* The program adjusts the file size of any segment that was
* truncated. The case of a segment being completely stripped out
* is handled separately.
*/
for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) {
if (phdr->p_offset >= newsize) {
phdr->p_offset = newsize;
phdr->p_filesz = 0;
} else if (phdr->p_offset + phdr->p_filesz > newsize) {
phdr->p_filesz = newsize - phdr->p_offset;
}
phdr = (Elf32_Phdr*)((char*)phdr + elfhdr.e_phentsize);
}
return TRUE;
}
/* savestripped() writes the new headers back to the original file
* and sets the new file size.
/* commitchanges() writes the new headers back to the original file
* 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;
if (fwrite(&elfhdr, sizeof elfhdr, 1, thefile) != 1
|| fwrite(phdrs, phdrsize, 1, thefile) != 1
|| ftruncate(fileno(thefile), newsize)) {
err("could not write contents");
fprintf(stderr, "WARNING: %s may be corrupted!\n", thefilename);
return FALSE;
if (write(fd, ehdr, sizeof *ehdr) != sizeof *ehdr)
return err("could not modify file");
/* Save the changes to the program segment header table, if any.
*/
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;
warning:
return err("ELF file may have been corrupted!");
}
/* 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 fd;
Elf_Ehdr ehdr;
Elf_Phdr *phdrs;
unsigned long newsize;
char **arg;
int ret = 0;
int failures = 0;
if (argc < 2 || !strcmp(argv[1], "-h")) {
printf("sstrip, version 2.0: Copyright (C) 1999 Brian Raiter\n"
"Usage: sstrip FILE...\n");
return 0;
if (argc < 2 || argv[1][0] == '-') {
printf("Usage: sstrip FILE...\n"
"sstrip discards all nonessential bytes from an executable.\n\n"
"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) {
if (!(thefile = fopen(thefilename, "rb+"))) {
err("unable to open.");
++ret;
progname = argv[0];
for (arg = argv + 1 ; *arg != NULL ; ++arg) {
filename = *arg;
fd = open(*arg, O_RDWR);
if (fd < 0) {
ferr("can't open");
++failures;
continue;
}
if (!readheaders() || !getloadsize() || !truncatezeros()
|| !modifyheaders() || !savestripped())
++ret;
fclose(thefile);
if (!(readelfheader(fd, &ehdr) &&
readphdrtable(fd, &ehdr, &phdrs) &&
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
*/