Renamed src/stub/util/ to src/stub/tools/ .

This commit is contained in:
Markus F.X.J. Oberhumer
2006-06-15 17:56:57 +02:00
parent 0c9f3c638a
commit 2dfc0a58ab
6 changed files with 0 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
# Makefile for armpe_tester
MAKEFLAGS += -rR
SHELL = /bin/sh
# update path for our special stub build tools
ifneq ($(wildcard $(HOME)/local/bin/bin-upx),)
export PATH := $(HOME)/local/bin/bin-upx:$(PATH)
endif
all: armpe_tester wtest.exe
armpe_tester: armpe_tester.c
arm-9tdmi-linux-gnu-gcc -Wl,--section-start,.interp=0x1000 -g -Wall -W -o $@ $<
wtest.exe: armpe_tester.c
arm-wince-pe-gcc -Wl,--image-base,0x400000 -s -Wall -W -o $@ $<
mostlyclean clean distclean maintainer-clean:
rm -f *.d *.o *.obj
rm -f armpe_tester wtest.exe
.PHONY: all mostlyclean clean distclean maintainer-clean
+354
View File
@@ -0,0 +1,354 @@
/* armpe_tester.c -- ARM/PE loader/tester for arm linux
This file is part of the UPX executable compressor.
Copyright (C) 1996-2006 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2006 Laszlo Molnar
Copyright (C) 2000-2006 John F. Reiser
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
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.
This program is distributed in the hope that it will be useful,
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; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer Laszlo Molnar
<mfx@users.sourceforge.net> <ml1050@users.sourceforge.net>
John F. Reiser
<jreiser@users.sourceforge.net>
*/
// arm-9tdmi-linux-gnu-gcc -Wl,--section-start,.interp=0x1000
// arm-wince-pe-gcc -Wl,--image-base,0x400000
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#ifdef i386
# define UPX_MMAP_ADDRESS 0x20000000
#else
# define UPX_MMAP_ADDRESS 0x10000
#endif
#ifdef linux
# include <sys/mman.h>
#else
void *VirtualAlloc(void *address, unsigned size, unsigned type, unsigned protect);
# define MEM_COMMIT 0x1000
# define PAGE_EXECUTE_READWRITE 0x0040
#endif
typedef unsigned short LE16;
typedef unsigned long LE32;
#define __attribute_packed
struct ddirs_t
{
LE32 vaddr;
LE32 size;
}
__attribute_packed;
struct pe_header_t
{
// 0x0
char _[4];
LE16 cpu;
LE16 objects;
char __[12];
LE16 opthdrsize;
LE16 flags;
// optional header
char ___[4];
LE32 codesize;
// 0x20
LE32 datasize;
LE32 bsssize;
LE32 entry;
LE32 codebase;
// 0x30
LE32 database;
// nt specific fields
LE32 imagebase;
LE32 objectalign;
LE32 filealign;
// 0x40
char ____[16];
// 0x50
LE32 imagesize;
LE32 headersize;
LE32 chksum;
LE16 subsystem;
LE16 dllflags;
// 0x60
char _____[20];
// 0x74
LE32 ddirsentries;
struct ddirs_t ddirs[16];
}
__attribute_packed;
struct pe_section_t
{
char name[8];
LE32 vsize;
LE32 vaddr;
LE32 size;
LE32 rawdataptr;
char _[12];
LE32 flags;
}
__attribute_packed;
struct exe_header_t
{
LE16 mz;
LE16 m512;
LE16 p512;
char _[18];
LE16 relocoffs;
char __[34];
LE32 nexepos;
}
__attribute_packed;
enum {
PEDIR_EXPORT = 0,
PEDIR_IMPORT = 1,
PEDIR_RESOURCE = 2,
PEDIR_EXCEPTION = 3,
PEDIR_SEC = 4,
PEDIR_RELOC = 5,
PEDIR_DEBUG = 6,
PEDIR_COPYRIGHT = 7,
PEDIR_GLOBALPTR = 8,
PEDIR_TLS = 9,
PEDIR_LOADCONF = 10,
PEDIR_BOUNDIM = 11,
PEDIR_IAT = 12,
PEDIR_DELAYIMP = 13,
PEDIR_COMRT = 14
};
#define get_le32(p) (*(unsigned *) (p))
#define set_le32(p, v) (*(unsigned *) (p) = (v))
#define get_le16(p) (*(unsigned short *) (p))
static struct pe_header_t ih;
static struct pe_section_t isections[3];
static FILE *f;
static void *vaddr;
static FILE *out;
static int print(const char *format, ...)
{
va_list ap;
int ret;
va_start(ap, format);
ret = fprintf(out, format, ap);
fflush(out);
va_end(ap);
return ret;
}
static int load(const char *file)
{
struct exe_header_t h;
int ic;
unsigned pe_offset = 0;
if ((f = fopen(file, "rb")) == NULL)
return print("can not open file: %s\n", file);
for (ic = 0; ic < 20; ic++)
{
if (fseek(f, pe_offset, SEEK_SET)
|| fread(&h, sizeof(h), 1, f) != 1)
return print("read error at %u\n", pe_offset);
if (h.mz == 'M' + 'Z'*256) // dos exe
{
if (h.relocoffs >= 0x40) // new format exe
pe_offset += h.nexepos;
else
pe_offset += h.p512 * 512 + h.m512 - h.m512 ? 512 : 0;
}
else if (get_le32(&h) == 'P' + 'E'*256)
break;
else
return print("bad header at %u\n", pe_offset);
}
if (ic == 20)
return print("pe header not found\n");
if (fseek(f, pe_offset, SEEK_SET)
|| fread(&ih, sizeof(ih), 1, f) != 1)
return print("can not load pe header\n");
if (ih.cpu != 0x1c0 && ih.cpu != 0x1c2)
return print("unsupported processor type: %x\n", ih.cpu);
if (ih.objects != 3 || fread(isections, sizeof(isections), 1, f) != 1)
return print("error reading section descriptors\n");
return 0;
}
static int read(void)
{
unsigned ic;
#ifdef linux
vaddr = mmap((void *) UPX_MMAP_ADDRESS, ih.imagesize,
PROT_WRITE | PROT_READ | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (((int) vaddr) == -1)
return print("mmap() failed: %d\n", errno);
#else
if ((vaddr = VirtualAlloc(0, ih.imagesize,
MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == 0)
return print("VirtualAlloc() failed\n");
print("VirtualAlloc() ok %x\n", vaddr);
#endif
for (ic = 1; ic <= 2; ic++)
if (fseek(f, isections[ic].rawdataptr, SEEK_SET)
|| fread(vaddr + isections[ic].vaddr,
isections[ic].vsize, 1, f) != 1)
return print("error reading section %u\n", ic);
return 0;
}
static void dump(char n)
{
char buf[100];
#ifdef linux
snprintf(buf, sizeof(buf), "/tmp/a.dump%c", n);
#else
snprintf(buf, sizeof(buf), "/a.dump%c", n);
#endif
FILE *f2 = fopen(buf, "wb");
fwrite(vaddr + 0x1000, ih.imagesize - 0x1000, 1, f2);
fclose(f2);
}
static int loadlibraryw(unsigned short *name)
{
return name[0] + name[1] * 0x100 + name[2] * 0x10000;
}
static int getprocaddressa(unsigned h, const char *proc)
{
unsigned p = (unsigned) proc;
if (p < 0x10000)
{
print("getprocaddressa called %c%c%c, ordinal %u\n",
h, h >> 8, h >> 16, p);
return h + p * 0x10000;
}
print("getprocaddressa called %c%c%c, name %s\n",
h, h >> 8, h >> 16, proc);
return h + proc[0] * 0x10000 + proc[1] * 0x1000000;
}
static void cachesync(unsigned v)
{
print("cachesync called %u\n", v);
}
static int import(void)
{
if (ih.ddirs[PEDIR_IMPORT].vaddr == 0)
return print("no imports?\n");
void *imports = vaddr + ih.ddirs[PEDIR_IMPORT].vaddr;
void *coredll_imports = vaddr + get_le32(imports + 16);
set_le32(coredll_imports, (unsigned) loadlibraryw);
set_le32(coredll_imports + 4, (unsigned) getprocaddressa);
set_le32(coredll_imports + 8, (unsigned) cachesync);
return 0;
}
static int reloc(void)
{
if (ih.ddirs[PEDIR_RELOC].vaddr == 0)
return 0;
void *relocs = vaddr + ih.ddirs[PEDIR_RELOC].vaddr;
void *page = vaddr + get_le32(relocs);
unsigned size = get_le32(relocs + 4);
if (size != ih.ddirs[PEDIR_RELOC].size)
return print("only 1 page can be relocated\n");
unsigned num = (size - 8) / 2;
while (num--)
{
unsigned pos = get_le16(relocs + 8 + num * 2);
if (pos == 0)
continue;
if ((pos & 0xF000) != 0x3000)
return print("unknown relocation type: %x\n", pos);
void *r = page + (pos & 0xFFF);
set_le32(r, get_le32(r) - ih.imagebase + (unsigned) vaddr);
}
return 0;
}
static void dump2(int c)
{
print("dump2 %c\n", c);
dump(c);
}
static void call(void)
{
#ifndef i386
void (*entry)(void (*)(int), unsigned) = vaddr + ih.entry;
entry(dump2, 1);
dump('z');
#endif
}
static int main2(int argc, char **argv)
{
if (argc != 2)
return print("usage: %s arm_pe_file\n", argv[0]), 1;
if (load(argv[1]))
return 2;
if (read())
return 3;
dump('0');
if (import())
return 4;
dump('1');
if (reloc())
return 5;
dump('2');
call();
print("ok.\n");
return 0;
}
int main(int argc, char **argv)
{
out = stdout;
#ifndef linux
out = fopen("/wtest.log", "wt");
#endif
int ret = main2(argc, argv);
fclose(out);
return ret;
}
+21
View File
@@ -0,0 +1,21 @@
# Makefile for sstrip
SHELL = /bin/sh
##all: amd64-linux-sstrip
##all: i386-linux-sstrip
all: sstrip
sstrip: sstrip.c
gcc -O2 -g -Wall -W -o $@ $<
amd64-linux-sstrip: sstrip.c
gcc -m64 -O2 -g -Wall -W -o $@ $<
i386-linux-sstrip: sstrip.c
gcc -m32 -O2 -g -Wall -W -o $@ $<
mostlyclean clean distclean maintainer-clean:
rm -f *.d *.o *.obj
rm -f sstrip amd64-linux-sstrip i386-linux-sstrip
.PHONY: all mostlyclean clean distclean maintainer-clean
+40
View File
@@ -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. Of course, the ELF
standard permits files to be organized in almost any order, so if a
pathological linker decided to put its section headers at the top,
sstrip would be useless on such executables.
+73
View File
@@ -0,0 +1,73 @@
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 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
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.
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
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 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.
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
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
+473
View File
@@ -0,0 +1,473 @@
/* http://www.muppetlabs.com/~breadbox/software/elfkickers.html */
/* sstrip: Copyright (C) 1999-2001 by Brian Raiter, under the GNU
* General Public License. No warranty. See COPYING for details.
*
* Aug 23, 2004 Hacked by Manuel Novoa III <mjn3@codepoet.org> to
* handle targets of different endianness and/or elf class, making
* it more useful in a cross-devel environment.
*/
/* ============== original README ===================
*
* 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. Of course, the ELF
* standard permits files to be organized in almost any order, so if a
* pathological linker decided to put its section headers at the top,
* sstrip would be useless on such executables.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <elf.h>
#include <endian.h>
#include <byteswap.h>
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
/* The name of the program.
*/
static char const *progname;
/* The name of the current file.
*/
static char const *filename;
/* A simple error-handling function. FALSE is always returned for the
* convenience of the caller.
*/
static int err(char const *errmsg)
{
fprintf(stderr, "%s: %s: %s\n", progname, filename, errmsg);
return FALSE;
}
/* A flag to signal the need for endian reversal.
*/
static int do_reverse_endian;
/* Get a value from the elf header, compensating for endianness.
*/
#define EGET(X) \
(__extension__ ({ \
uint64_t __res; \
if (!do_reverse_endian) { \
__res = (X); \
} else if (sizeof(X) == 1) { \
__res = (X); \
} else if (sizeof(X) == 2) { \
__res = bswap_16((X)); \
} else if (sizeof(X) == 4) { \
__res = bswap_32((X)); \
} else if (sizeof(X) == 8) { \
__res = bswap_64((X)); \
} else { \
fprintf(stderr, "%s: %s: EGET failed for size %ld\n", \
progname, filename, (long) sizeof(X)); \
exit(EXIT_FAILURE); \
} \
__res; \
}))
/* Set a value 'Y' in the elf header to 'X', compensating for endianness.
*/
#define ESET(Y,X) \
do if (!do_reverse_endian) { \
Y = (X); \
} else if (sizeof(Y) == 1) { \
Y = (X); \
} else if (sizeof(Y) == 2) { \
Y = bswap_16((uint16_t)(X)); \
} else if (sizeof(Y) == 4) { \
Y = bswap_32((uint32_t)(X)); \
} else if (sizeof(Y) == 8) { \
Y = bswap_64((uint64_t)(X)); \
} else { \
fprintf(stderr, "%s: %s: ESET failed for size %ld\n", \
progname, filename, (long) sizeof(Y)); \
exit(EXIT_FAILURE); \
} while (0)
/* A macro for I/O errors: The given error message is used only when
* errno is not set.
*/
#define ferr(msg) (err(errno ? strerror(errno) : (msg)))
#define HEADER_FUNCTIONS(CLASS) \
\
/* 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 ## CLASS (int fd, Elf ## CLASS ## _Ehdr *ehdr) \
{ \
if (read(fd, ((char *)ehdr)+EI_NIDENT, sizeof(*ehdr) - EI_NIDENT) \
!= (ssize_t)sizeof(*ehdr) - EI_NIDENT) \
return ferr("missing or incomplete ELF header."); \
\
/* Verify the sizes of the ELF header and the program segment \
* header table entries. \
*/ \
if (EGET(ehdr->e_ehsize) != sizeof(Elf ## CLASS ## _Ehdr)) \
return err("unrecognized ELF header size."); \
if (EGET(ehdr->e_phentsize) != sizeof(Elf ## CLASS ## _Phdr)) \
return err("unrecognized program segment header size."); \
\
/* Finally, check the file type. \
*/ \
if (EGET(ehdr->e_type) != ET_EXEC && EGET(ehdr->e_type) != ET_DYN) \
return err("not an executable or shared-object library."); \
\
return TRUE; \
} \
\
/* readphdrtable() loads the program segment header table into memory. \
*/ \
static int readphdrtable ## CLASS (int fd, Elf ## CLASS ## _Ehdr const *ehdr, \
Elf ## CLASS ## _Phdr **phdrs) \
{ \
size_t size; \
\
if (!EGET(ehdr->e_phoff) || !EGET(ehdr->e_phnum) \
) return err("ELF file has no program header table."); \
\
size = EGET(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 ## CLASS (Elf ## CLASS ## _Ehdr const *ehdr, \
Elf ## CLASS ## _Phdr const *phdrs, \
unsigned long *newsize) \
{ \
Elf ## CLASS ## _Phdr const *phdr; \
unsigned long size, n; \
size_t i; \
\
/* Start by setting the size to include the ELF header and the \
* complete program segment header table. \
*/ \
size = EGET(ehdr->e_phoff) + EGET(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 < EGET(ehdr->e_phnum) ; ++i, ++phdr) { \
if (EGET(phdr->p_type) != PT_NULL) { \
n = EGET(phdr->p_offset) + EGET(phdr->p_filesz); \
if (n > size) \
size = n; \
} \
} \
\
*newsize = size; \
return TRUE; \
} \
\
/* modifyheaders() removes references to the section header table if \
* it was stripped, and reduces program header table entries that \
* included truncated bytes at the end of the file. \
*/ \
static int modifyheaders ## CLASS (Elf ## CLASS ## _Ehdr *ehdr, \
Elf ## CLASS ## _Phdr *phdrs, \
unsigned long newsize) \
{ \
Elf ## CLASS ## _Phdr *phdr; \
size_t i; \
\
/* If the section header table is gone, then remove all references \
* to it in the ELF header. \
*/ \
if (EGET(ehdr->e_shoff) >= newsize) { \
ESET(ehdr->e_shoff,0); \
ESET(ehdr->e_shnum,0); \
ESET(ehdr->e_shentsize,0); \
ESET(ehdr->e_shstrndx,0); \
} \
\
/* 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 < EGET(ehdr->e_phnum) ; ++i, ++phdr) { \
if (EGET(phdr->p_offset) >= newsize) { \
ESET(phdr->p_offset,newsize); \
ESET(phdr->p_filesz,0); \
} else if (EGET(phdr->p_offset) + EGET(phdr->p_filesz) > newsize) { \
newsize -= EGET(phdr->p_offset); \
ESET(phdr->p_filesz, newsize); \
} \
} \
\
return TRUE; \
} \
\
/* commitchanges() writes the new headers back to the original file \
* and sets the file to its new size. \
*/ \
static int commitchanges ## CLASS (int fd, Elf ## CLASS ## _Ehdr const *ehdr, \
Elf ## CLASS ## _Phdr *phdrs, \
unsigned long newsize) \
{ \
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 (write(fd, ehdr, sizeof *ehdr) != (ssize_t)sizeof *ehdr) \
return err("could not modify file"); \
\
/* Save the changes to the program segment header table, if any. \
*/ \
if (lseek(fd, EGET(ehdr->e_phoff), SEEK_SET) == (off_t)-1) { \
err("could not seek in file."); \
goto warning; \
} \
n = EGET(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 < EGET(ehdr->e_phoff) + n) \
newsize = EGET(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!"); \
}
/* First elements of Elf32_Ehdr and Elf64_Ehdr are common.
*/
static int readelfheaderident(int fd, Elf32_Ehdr *ehdr)
{
errno = 0;
if (read(fd, ehdr, EI_NIDENT) != EI_NIDENT)
return ferr("missing or incomplete ELF header.");
/* 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))
{
err("missing ELF signature.");
return -1;
}
/* Compare the file's class and endianness with the program's.
*/
#if __BYTE_ORDER == __LITTLE_ENDIAN
if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) {
do_reverse_endian = 0;
} else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
/* fprintf(stderr, "ELF file has different endianness.\n"); */
do_reverse_endian = 1;
}
#elif __BYTE_ORDER == __BIG_ENDIAN
if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) {
/* fprintf(stderr, "ELF file has different endianness.\n"); */
do_reverse_endian = 1;
} else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) {
do_reverse_endian = 0;
}
#else
#error unkown endianness
#endif
else {
err("Unsupported endianness");
return -1;
}
/* Check the target architecture.
*/
/* if (EGET(ehdr->e_machine) != ELF_ARCH) { */
/* /\* return err("ELF file created for different architecture."); *\/ */
/* fprintf(stderr, "ELF file created for different architecture.\n"); */
/* } */
return ehdr->e_ident[EI_CLASS];
}
HEADER_FUNCTIONS(32)
HEADER_FUNCTIONS(64)
/* truncatezeros() examines the bytes at the end of the file's
* size-to-be, and reduces the size to exclude any trailing zero
* bytes.
*/
static int truncatezeros(int fd, unsigned long *newsize)
{
unsigned char contents[1024];
unsigned long size, n;
size = *newsize;
do {
n = sizeof 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])
--size;
} while (size && !n);
/* Sanity check.
*/
if (!size)
return err("ELF file is completely blank!");
*newsize = size;
return TRUE;
}
/* main() loops over the cmdline arguments, leaving all the real work
* to the other functions.
*/
int main(int argc, char *argv[])
{
int fd;
union {
Elf32_Ehdr ehdr32;
Elf64_Ehdr ehdr64;
} e;
union {
Elf32_Phdr *phdrs32;
Elf64_Phdr *phdrs64;
} p;
unsigned long newsize;
char **arg;
int failures = 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-X Copyright (C) 2000,2001 Brian Raiter.\n"
"Cross-devel hacks Copyright (C) 2004 Manuel Novoa III.\n"
"This program is free software, licensed under the GNU\n"
"General Public License. There is absolutely no warranty.\n");
return EXIT_SUCCESS;
}
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;
}
switch (readelfheaderident(fd, &e.ehdr32)) {
case ELFCLASS32:
if (!(readelfheader32(fd, &e.ehdr32) &&
readphdrtable32(fd, &e.ehdr32, &p.phdrs32) &&
getmemorysize32(&e.ehdr32, p.phdrs32, &newsize) &&
truncatezeros(fd, &newsize) &&
modifyheaders32(&e.ehdr32, p.phdrs32, newsize) &&
commitchanges32(fd, &e.ehdr32, p.phdrs32, newsize)))
++failures;
break;
case ELFCLASS64:
if (!(readelfheader64(fd, &e.ehdr64) &&
readphdrtable64(fd, &e.ehdr64, &p.phdrs64) &&
getmemorysize64(&e.ehdr64, p.phdrs64, &newsize) &&
truncatezeros(fd, &newsize) &&
modifyheaders64(&e.ehdr64, p.phdrs64, newsize) &&
commitchanges64(fd, &e.ehdr64, p.phdrs64, newsize)))
++failures;
break;
default:
++failures;
break;
}
close(fd);
}
return failures ? EXIT_FAILURE : EXIT_SUCCESS;
}
/*
vi:ts=4:et:nowrap
*/