Initial commit (from git)
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
# Makefile for sstrip
|
||||
|
||||
sstrip: sstrip.c
|
||||
gcc -ggdb -Wall -W -o sstrip sstrip.c
|
||||
|
||||
clean:
|
||||
rm -f sstrip
|
||||
@@ -0,0 +1,40 @@
|
||||
sstrip is a small utility that removes the contents at the end of an
|
||||
ELF file that are not part of the program's memory image.
|
||||
|
||||
Most ELF executables are built with both a program header table and a
|
||||
section header table. However, only the former is required in order
|
||||
for the OS to load, link and execute a program. sstrip attempts to
|
||||
extract the ELF header, the program header table, and its contents,
|
||||
leaving everything else in the bit bucket. It can only remove parts of
|
||||
the file that occur at the end, after the parts to be saved. However,
|
||||
this almost always includes the section header table, and occasionally
|
||||
a few random sections that are not used when running a program.
|
||||
|
||||
It should be noted that the GNU bfd library is (understandably)
|
||||
dependent on the section header table as an index to the file's
|
||||
contents. Thus, an executable file that has no section header table
|
||||
cannot be used with gdb, objdump, or any other program based upon the
|
||||
bfd library, at all. In fact, the program will not even recognize the
|
||||
file as a valid executable. (This limitation is noted in the source
|
||||
code comments for bfd, and is marked "FIXME", so this may change at
|
||||
some future date. However, I would imagine that it is a pretty
|
||||
low-priority item, as executables without a section header table are
|
||||
rare in the extreme.) This probably also explains why strip doesn't
|
||||
offer the option to do this.
|
||||
|
||||
Shared library files may also have their section header table removed.
|
||||
Such a library will still function; however, it will no longer be
|
||||
possible for a compiler to link a new program against it.
|
||||
|
||||
As an added bonus, sstrip also tries to removes trailing zero bytes
|
||||
from the end of the file. (This normally cannot be done with an
|
||||
executable that has a section header table.)
|
||||
|
||||
sstrip is a very simplistic program. It depends upon the common
|
||||
practice of putting the parts of the file that contribute to the
|
||||
memory image at the front, and the remaining material at the end. This
|
||||
permits it to discard the latter material without affecting file
|
||||
offsets and memory addresses in what remains. However, the ELF
|
||||
standard permits files to be organized in almost any order. So
|
||||
although this procedure usually works in practice, it is not meant to
|
||||
be taken too seriously.
|
||||
@@ -0,0 +1,70 @@
|
||||
This distribution is a collection of programs that are generally
|
||||
unrelated, except in that they all deal with the ELF file format.
|
||||
|
||||
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.)
|
||||
|
||||
Each program is independent. There is no shared code between them, and
|
||||
in fact they all take slightly different approaches to handling ELF
|
||||
files.
|
||||
|
||||
The table of contents:
|
||||
|
||||
sstrip/
|
||||
sstrip is a small utility that removes everything from an ELF file
|
||||
that is not part of the file's memory image.
|
||||
|
||||
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
|
||||
the file's contents.
|
||||
|
||||
elftoc/
|
||||
elftoc takes an ELF file and generates C code that defines a
|
||||
structure with the same memory image, using the structures and
|
||||
preprocessor symbols defined in <linux/elf.h>.
|
||||
|
||||
ebfc/
|
||||
ebfc is a compiler for a tiny programming language. The compiler can
|
||||
generate ELF executables, object files, and shared libraries.
|
||||
|
||||
tiny/
|
||||
This directory contains a collection of very small ELF executables.
|
||||
|
||||
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
|
||||
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 all free software; you can redistribute and/or
|
||||
modify them under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
These programs are distributed in the hope that they will be
|
||||
interesting, but without any warranty; without even the implied
|
||||
warranty of merchantability or fitness for a particular purpose.
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program, in the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA.
|
||||
|
||||
Bug reports and general feedback should be directed to the author at
|
||||
breadbox@muppetlabs.com.
|
||||
|
||||
Share and enjoy.
|
||||
|
||||
Brian Raiter
|
||||
breadbox@muppetlabs.com
|
||||
July, 1999
|
||||
@@ -0,0 +1,218 @@
|
||||
/* sstrip, version 1.0: Copyright (C) 1999 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>
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/* The memory-allocation macro.
|
||||
*/
|
||||
#define alloc(p, n) (((p) = realloc(p, n)) \
|
||||
|| (fputs("Out of memory.\n", stderr), \
|
||||
exit(EXIT_FAILURE), 0))
|
||||
|
||||
static char const *thefilename; /* the current file name */
|
||||
static FILE *thefile; /* the current file handle */
|
||||
|
||||
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.
|
||||
*/
|
||||
static int err(char const *errmsg)
|
||||
{
|
||||
if (errno)
|
||||
perror(thefilename);
|
||||
else
|
||||
fprintf(stderr, "%s: %s\n", thefilename, 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.
|
||||
*/
|
||||
static int readheaders(void)
|
||||
{
|
||||
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.");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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.");
|
||||
|
||||
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.
|
||||
*/
|
||||
static int getloadsize(void)
|
||||
{
|
||||
Elf32_Phdr *phdr;
|
||||
unsigned long 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);
|
||||
}
|
||||
|
||||
for (i = 0 ; i < elfhdr.e_phnum ; ++i)
|
||||
if (phdr->p_filesz > 0 && phdr->p_offset >= newsize)
|
||||
memset(phdr, 0, elfhdr.e_phentsize);
|
||||
|
||||
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.
|
||||
*/
|
||||
static int truncatezeros(void)
|
||||
{
|
||||
char contents[1024];
|
||||
unsigned long n;
|
||||
|
||||
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");
|
||||
while (n && !contents[--n])
|
||||
--newsize;
|
||||
} while (newsize && !n);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* modifyheaders() removes references to the section header table if
|
||||
* it was removed, and reduces program header table entries that
|
||||
* included truncated bytes at the end of the file.
|
||||
*/
|
||||
static int modifyheaders(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
static int savestripped(void)
|
||||
{
|
||||
rewind(thefile);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* main() loops over the cmdline arguments, leaving all the real work
|
||||
* to the other functions.
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char **arg;
|
||||
int ret = 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;
|
||||
}
|
||||
|
||||
for (arg = argv + 1 ; (thefilename = *arg) != NULL ; ++arg) {
|
||||
if (!(thefile = fopen(thefilename, "rb+"))) {
|
||||
err("unable to open.");
|
||||
++ret;
|
||||
continue;
|
||||
}
|
||||
if (!readheaders() || !getloadsize() || !truncatezeros()
|
||||
|| !modifyheaders() || !savestripped())
|
||||
++ret;
|
||||
fclose(thefile);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user