Lines 1-5
Link Here
|
|
|
1 |
/* http://www.muppetlabs.com/~breadbox/software/elfkickers.html */ |
2 |
|
1 |
/* sstrip: Copyright (C) 1999-2001 by Brian Raiter, under the GNU |
3 |
/* sstrip: Copyright (C) 1999-2001 by Brian Raiter, under the GNU |
2 |
* General Public License. No warranty. See COPYING for details. |
4 |
* General Public License. No warranty. See COPYING for details. |
|
|
5 |
* |
6 |
* Aug 23, 2004 Hacked by Manuel Novoa III <mjn3@codepoet.org> to |
7 |
* handle targets of different endianness and/or elf class, making |
8 |
* it more useful in a cross-devel environment. |
9 |
*/ |
10 |
|
11 |
/* ============== original README =================== |
12 |
* |
13 |
* sstrip is a small utility that removes the contents at the end of an |
14 |
* ELF file that are not part of the program's memory image. |
15 |
* |
16 |
* Most ELF executables are built with both a program header table and a |
17 |
* section header table. However, only the former is required in order |
18 |
* for the OS to load, link and execute a program. sstrip attempts to |
19 |
* extract the ELF header, the program header table, and its contents, |
20 |
* leaving everything else in the bit bucket. It can only remove parts of |
21 |
* the file that occur at the end, after the parts to be saved. However, |
22 |
* this almost always includes the section header table, and occasionally |
23 |
* a few random sections that are not used when running a program. |
24 |
* |
25 |
* It should be noted that the GNU bfd library is (understandably) |
26 |
* dependent on the section header table as an index to the file's |
27 |
* contents. Thus, an executable file that has no section header table |
28 |
* cannot be used with gdb, objdump, or any other program based upon the |
29 |
* bfd library, at all. In fact, the program will not even recognize the |
30 |
* file as a valid executable. (This limitation is noted in the source |
31 |
* code comments for bfd, and is marked "FIXME", so this may change at |
32 |
* some future date. However, I would imagine that it is a pretty |
33 |
* low-priority item, as executables without a section header table are |
34 |
* rare in the extreme.) This probably also explains why strip doesn't |
35 |
* offer the option to do this. |
36 |
* |
37 |
* Shared library files may also have their section header table removed. |
38 |
* Such a library will still function; however, it will no longer be |
39 |
* possible for a compiler to link a new program against it. |
40 |
* |
41 |
* As an added bonus, sstrip also tries to removes trailing zero bytes |
42 |
* from the end of the file. (This normally cannot be done with an |
43 |
* executable that has a section header table.) |
44 |
* |
45 |
* sstrip is a very simplistic program. It depends upon the common |
46 |
* practice of putting the parts of the file that contribute to the |
47 |
* memory image at the front, and the remaining material at the end. This |
48 |
* permits it to discard the latter material without affecting file |
49 |
* offsets and memory addresses in what remains. Of course, the ELF |
50 |
* standard permits files to be organized in almost any order, so if a |
51 |
* pathological linker decided to put its section headers at the top, |
52 |
* sstrip would be useless on such executables. |
3 |
*/ |
53 |
*/ |
4 |
|
54 |
|
5 |
#include <stdio.h> |
55 |
#include <stdio.h> |
Lines 9-36
Link Here
|
9 |
#include <unistd.h> |
59 |
#include <unistd.h> |
10 |
#include <fcntl.h> |
60 |
#include <fcntl.h> |
11 |
#include <elf.h> |
61 |
#include <elf.h> |
12 |
#include <asm/elf.h> |
62 |
#ifdef __FreeBSD__ |
|
|
63 |
/** |
64 |
* This seems to work on FreeBSD 5.3, should |
65 |
* work on all newer versions as well. I have |
66 |
* no idea if it will work on versions < 5.3 |
67 |
* |
68 |
* Joe Estock (guru) <jestock at nutextonline.com> |
69 |
*/ |
70 |
#include <sys/endian.h> |
71 |
#define bswap_64 __bswap64 |
72 |
#define bswap_32 __bswap32 |
73 |
#define bswap_16 __bswap16 |
74 |
#else |
75 |
#include <endian.h> |
76 |
#include <byteswap.h> |
77 |
#endif /* defined(__FreeBSD__) */ |
78 |
|
13 |
|
79 |
|
14 |
#ifndef TRUE |
80 |
#ifndef TRUE |
15 |
#define TRUE 1 |
81 |
#define TRUE 1 |
16 |
#define FALSE 0 |
82 |
#define FALSE 0 |
17 |
#endif |
83 |
#endif |
18 |
|
84 |
|
19 |
#if ELF_CLASS == ELFCLASS32 |
|
|
20 |
#define Elf_Ehdr Elf32_Ehdr |
21 |
#define Elf_Phdr Elf32_Phdr |
22 |
#else |
23 |
#define Elf_Ehdr Elf64_Ehdr |
24 |
#define Elf_Phdr Elf64_Phdr |
25 |
#endif |
26 |
|
27 |
/* The name of the program. |
85 |
/* The name of the program. |
28 |
*/ |
86 |
*/ |
29 |
static char const *progname; |
87 |
static char const *progname; |
30 |
|
88 |
|
31 |
/* The name of the current file. |
89 |
/* The name of the current file. |
32 |
*/ |
90 |
*/ |
33 |
static char const *filename; |
91 |
static char const *filename; |
34 |
|
92 |
|
35 |
|
93 |
|
36 |
/* A simple error-handling function. FALSE is always returned for the |
94 |
/* A simple error-handling function. FALSE is always returned for the |
Lines 38-264
Link Here
|
38 |
*/ |
96 |
*/ |
39 |
static int err(char const *errmsg) |
97 |
static int err(char const *errmsg) |
40 |
{ |
98 |
{ |
41 |
fprintf(stderr, "%s: %s: %s\n", progname, filename, errmsg); |
99 |
fprintf(stderr, "%s: %s: %s\n", progname, filename, errmsg); |
42 |
return FALSE; |
100 |
return FALSE; |
43 |
} |
101 |
} |
44 |
|
102 |
|
45 |
/* A macro for I/O errors: The given error message is used only when |
103 |
/* A flag to signal the need for endian reversal. |
46 |
* errno is not set. |
|
|
47 |
*/ |
104 |
*/ |
48 |
#define ferr(msg) (err(errno ? strerror(errno) : (msg))) |
105 |
static int do_reverse_endian; |
49 |
|
106 |
|
50 |
/* readelfheader() reads the ELF header into our global variable, and |
107 |
/* Get a value from the elf header, compensating for endianness. |
51 |
* checks to make sure that this is in fact a file that we should be |
|
|
52 |
* munging. |
53 |
*/ |
108 |
*/ |
54 |
static int readelfheader(int fd, Elf_Ehdr *ehdr) |
109 |
#define EGET(X) \ |
55 |
{ |
110 |
(__extension__ ({ \ |
56 |
errno = 0; |
111 |
uint64_t __res; \ |
57 |
if (read(fd, ehdr, sizeof *ehdr) != sizeof *ehdr) |
112 |
if (!do_reverse_endian) { \ |
58 |
return ferr("missing or incomplete ELF header."); |
113 |
__res = (X); \ |
59 |
|
114 |
} else if (sizeof(X) == 1) { \ |
60 |
/* Check the ELF signature. |
115 |
__res = (X); \ |
61 |
*/ |
116 |
} else if (sizeof(X) == 2) { \ |
62 |
if (!(ehdr->e_ident[EI_MAG0] == ELFMAG0 && |
117 |
__res = bswap_16((X)); \ |
63 |
ehdr->e_ident[EI_MAG1] == ELFMAG1 && |
118 |
} else if (sizeof(X) == 4) { \ |
64 |
ehdr->e_ident[EI_MAG2] == ELFMAG2 && |
119 |
__res = bswap_32((X)); \ |
65 |
ehdr->e_ident[EI_MAG3] == ELFMAG3)) |
120 |
} else if (sizeof(X) == 8) { \ |
66 |
return err("missing ELF signature."); |
121 |
__res = bswap_64((X)); \ |
67 |
|
122 |
} else { \ |
68 |
/* Compare the file's class and endianness with the program's. |
123 |
fprintf(stderr, "%s: %s: EGET failed for size %ld\n", \ |
69 |
*/ |
124 |
progname, filename, sizeof(X)); \ |
70 |
if (ehdr->e_ident[EI_DATA] != ELF_DATA) |
125 |
exit(EXIT_FAILURE); \ |
71 |
return err("ELF file has different endianness."); |
126 |
} \ |
72 |
if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) |
127 |
__res; \ |
73 |
return err("ELF file has different word size."); |
128 |
})) |
74 |
|
129 |
|
75 |
/* Check the target architecture. |
130 |
/* Set a value 'Y' in the elf header to 'X', compensating for endianness. |
76 |
*/ |
131 |
*/ |
77 |
if (ehdr->e_machine != ELF_ARCH) |
132 |
#define ESET(Y,X) \ |
78 |
return err("ELF file created for different architecture."); |
133 |
do if (!do_reverse_endian) { \ |
79 |
|
134 |
Y = (X); \ |
80 |
/* Verify the sizes of the ELF header and the program segment |
135 |
} else if (sizeof(Y) == 1) { \ |
81 |
* header table entries. |
136 |
Y = (X); \ |
82 |
*/ |
137 |
} else if (sizeof(Y) == 2) { \ |
83 |
if (ehdr->e_ehsize != sizeof(Elf_Ehdr)) |
138 |
Y = bswap_16((uint16_t)(X)); \ |
84 |
return err("unrecognized ELF header size."); |
139 |
} else if (sizeof(Y) == 4) { \ |
85 |
if (ehdr->e_phentsize != sizeof(Elf_Phdr)) |
140 |
Y = bswap_32((uint32_t)(X)); \ |
86 |
return err("unrecognized program segment header size."); |
141 |
} else if (sizeof(Y) == 8) { \ |
87 |
|
142 |
Y = bswap_64((uint64_t)(X)); \ |
88 |
/* Finally, check the file type. |
143 |
} else { \ |
89 |
*/ |
144 |
fprintf(stderr, "%s: %s: ESET failed for size %ld\n", \ |
90 |
if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) |
145 |
progname, filename, sizeof(Y)); \ |
91 |
return err("not an executable or shared-object library."); |
146 |
exit(EXIT_FAILURE); \ |
|
|
147 |
} while (0) |
92 |
|
148 |
|
93 |
return TRUE; |
|
|
94 |
} |
95 |
|
149 |
|
96 |
/* readphdrtable() loads the program segment header table into memory. |
150 |
/* A macro for I/O errors: The given error message is used only when |
|
|
151 |
* errno is not set. |
97 |
*/ |
152 |
*/ |
98 |
static int readphdrtable(int fd, Elf_Ehdr const *ehdr, Elf_Phdr **phdrs) |
153 |
#define ferr(msg) (err(errno ? strerror(errno) : (msg))) |
99 |
{ |
|
|
100 |
size_t size; |
101 |
|
102 |
if (!ehdr->e_phoff || !ehdr->e_phnum) |
103 |
return err("ELF file has no program header table."); |
104 |
|
154 |
|
105 |
size = ehdr->e_phnum * sizeof **phdrs; |
|
|
106 |
if (!(*phdrs = malloc(size))) |
107 |
return err("Out of memory!"); |
108 |
|
155 |
|
109 |
errno = 0; |
|
|
110 |
if (read(fd, *phdrs, size) != (ssize_t)size) |
111 |
return ferr("missing or incomplete program segment header table."); |
112 |
|
156 |
|
113 |
return TRUE; |
157 |
#define HEADER_FUNCTIONS(CLASS) \ |
|
|
158 |
\ |
159 |
/* readelfheader() reads the ELF header into our global variable, and \ |
160 |
* checks to make sure that this is in fact a file that we should be \ |
161 |
* munging. \ |
162 |
*/ \ |
163 |
static int readelfheader ## CLASS (int fd, Elf ## CLASS ## _Ehdr *ehdr) \ |
164 |
{ \ |
165 |
if (read(fd, ((char *)ehdr)+EI_NIDENT, sizeof(*ehdr) - EI_NIDENT) \ |
166 |
!= sizeof(*ehdr) - EI_NIDENT) \ |
167 |
return ferr("missing or incomplete ELF header."); \ |
168 |
\ |
169 |
/* Verify the sizes of the ELF header and the program segment \ |
170 |
* header table entries. \ |
171 |
*/ \ |
172 |
if (EGET(ehdr->e_ehsize) != sizeof(Elf ## CLASS ## _Ehdr)) \ |
173 |
return err("unrecognized ELF header size."); \ |
174 |
if (EGET(ehdr->e_phentsize) != sizeof(Elf ## CLASS ## _Phdr)) \ |
175 |
return err("unrecognized program segment header size."); \ |
176 |
\ |
177 |
/* Finally, check the file type. \ |
178 |
*/ \ |
179 |
if (EGET(ehdr->e_type) != ET_EXEC && EGET(ehdr->e_type) != ET_DYN) \ |
180 |
return err("not an executable or shared-object library."); \ |
181 |
\ |
182 |
return TRUE; \ |
183 |
} \ |
184 |
\ |
185 |
/* readphdrtable() loads the program segment header table into memory. \ |
186 |
*/ \ |
187 |
static int readphdrtable ## CLASS (int fd, Elf ## CLASS ## _Ehdr const *ehdr, \ |
188 |
Elf ## CLASS ## _Phdr **phdrs) \ |
189 |
{ \ |
190 |
size_t size; \ |
191 |
\ |
192 |
if (!EGET(ehdr->e_phoff) || !EGET(ehdr->e_phnum) \ |
193 |
) return err("ELF file has no program header table."); \ |
194 |
\ |
195 |
size = EGET(ehdr->e_phnum) * sizeof **phdrs; \ |
196 |
if (!(*phdrs = malloc(size))) \ |
197 |
return err("Out of memory!"); \ |
198 |
\ |
199 |
errno = 0; \ |
200 |
if (read(fd, *phdrs, size) != (ssize_t)size) \ |
201 |
return ferr("missing or incomplete program segment header table."); \ |
202 |
\ |
203 |
return TRUE; \ |
204 |
} \ |
205 |
\ |
206 |
/* getmemorysize() determines the offset of the last byte of the file \ |
207 |
* that is referenced by an entry in the program segment header table. \ |
208 |
* (Anything in the file after that point is not used when the program \ |
209 |
* is executing, and thus can be safely discarded.) \ |
210 |
*/ \ |
211 |
static int getmemorysize ## CLASS (Elf ## CLASS ## _Ehdr const *ehdr, \ |
212 |
Elf ## CLASS ## _Phdr const *phdrs, \ |
213 |
unsigned long *newsize) \ |
214 |
{ \ |
215 |
Elf ## CLASS ## _Phdr const *phdr; \ |
216 |
unsigned long size, n; \ |
217 |
int i; \ |
218 |
\ |
219 |
/* Start by setting the size to include the ELF header and the \ |
220 |
* complete program segment header table. \ |
221 |
*/ \ |
222 |
size = EGET(ehdr->e_phoff) + EGET(ehdr->e_phnum) * sizeof *phdrs; \ |
223 |
if (size < sizeof *ehdr) \ |
224 |
size = sizeof *ehdr; \ |
225 |
\ |
226 |
/* Then keep extending the size to include whatever data the \ |
227 |
* program segment header table references. \ |
228 |
*/ \ |
229 |
for (i = 0, phdr = phdrs ; i < EGET(ehdr->e_phnum) ; ++i, ++phdr) { \ |
230 |
if (EGET(phdr->p_type) != PT_NULL) { \ |
231 |
n = EGET(phdr->p_offset) + EGET(phdr->p_filesz); \ |
232 |
if (n > size) \ |
233 |
size = n; \ |
234 |
} \ |
235 |
} \ |
236 |
\ |
237 |
*newsize = size; \ |
238 |
return TRUE; \ |
239 |
} \ |
240 |
\ |
241 |
/* modifyheaders() removes references to the section header table if \ |
242 |
* it was stripped, and reduces program header table entries that \ |
243 |
* included truncated bytes at the end of the file. \ |
244 |
*/ \ |
245 |
static int modifyheaders ## CLASS (Elf ## CLASS ## _Ehdr *ehdr, \ |
246 |
Elf ## CLASS ## _Phdr *phdrs, \ |
247 |
unsigned long newsize) \ |
248 |
{ \ |
249 |
Elf ## CLASS ## _Phdr *phdr; \ |
250 |
int i; \ |
251 |
\ |
252 |
/* If the section header table is gone, then remove all references \ |
253 |
* to it in the ELF header. \ |
254 |
*/ \ |
255 |
if (EGET(ehdr->e_shoff) >= newsize) { \ |
256 |
ESET(ehdr->e_shoff,0); \ |
257 |
ESET(ehdr->e_shnum,0); \ |
258 |
ESET(ehdr->e_shentsize,0); \ |
259 |
ESET(ehdr->e_shstrndx,0); \ |
260 |
} \ |
261 |
\ |
262 |
/* The program adjusts the file size of any segment that was \ |
263 |
* truncated. The case of a segment being completely stripped out \ |
264 |
* is handled separately. \ |
265 |
*/ \ |
266 |
for (i = 0, phdr = phdrs ; i < EGET(ehdr->e_phnum) ; ++i, ++phdr) { \ |
267 |
if (EGET(phdr->p_offset) >= newsize) { \ |
268 |
ESET(phdr->p_offset,newsize); \ |
269 |
ESET(phdr->p_filesz,0); \ |
270 |
} else if (EGET(phdr->p_offset) + EGET(phdr->p_filesz) > newsize) { \ |
271 |
newsize -= EGET(phdr->p_offset); \ |
272 |
ESET(phdr->p_filesz, newsize); \ |
273 |
} \ |
274 |
} \ |
275 |
\ |
276 |
return TRUE; \ |
277 |
} \ |
278 |
\ |
279 |
/* commitchanges() writes the new headers back to the original file \ |
280 |
* and sets the file to its new size. \ |
281 |
*/ \ |
282 |
static int commitchanges ## CLASS (int fd, Elf ## CLASS ## _Ehdr const *ehdr, \ |
283 |
Elf ## CLASS ## _Phdr *phdrs, \ |
284 |
unsigned long newsize) \ |
285 |
{ \ |
286 |
size_t n; \ |
287 |
\ |
288 |
/* Save the changes to the ELF header, if any. \ |
289 |
*/ \ |
290 |
if (lseek(fd, 0, SEEK_SET)) \ |
291 |
return ferr("could not rewind file"); \ |
292 |
errno = 0; \ |
293 |
if (write(fd, ehdr, sizeof *ehdr) != sizeof *ehdr) \ |
294 |
return err("could not modify file"); \ |
295 |
\ |
296 |
/* Save the changes to the program segment header table, if any. \ |
297 |
*/ \ |
298 |
if (lseek(fd, EGET(ehdr->e_phoff), SEEK_SET) == (off_t)-1) { \ |
299 |
err("could not seek in file."); \ |
300 |
goto warning; \ |
301 |
} \ |
302 |
n = EGET(ehdr->e_phnum) * sizeof *phdrs; \ |
303 |
if (write(fd, phdrs, n) != (ssize_t)n) { \ |
304 |
err("could not write to file"); \ |
305 |
goto warning; \ |
306 |
} \ |
307 |
\ |
308 |
/* Eleventh-hour sanity check: don't truncate before the end of \ |
309 |
* the program segment header table. \ |
310 |
*/ \ |
311 |
if (newsize < EGET(ehdr->e_phoff) + n) \ |
312 |
newsize = EGET(ehdr->e_phoff) + n; \ |
313 |
\ |
314 |
/* Chop off the end of the file. \ |
315 |
*/ \ |
316 |
if (ftruncate(fd, newsize)) { \ |
317 |
err("could not resize file"); \ |
318 |
goto warning; \ |
319 |
} \ |
320 |
\ |
321 |
return TRUE; \ |
322 |
\ |
323 |
warning: \ |
324 |
return err("ELF file may have been corrupted!"); \ |
114 |
} |
325 |
} |
115 |
|
326 |
|
116 |
/* getmemorysize() determines the offset of the last byte of the file |
|
|
117 |
* that is referenced by an entry in the program segment header table. |
118 |
* (Anything in the file after that point is not used when the program |
119 |
* is executing, and thus can be safely discarded.) |
120 |
*/ |
121 |
static int getmemorysize(Elf_Ehdr const *ehdr, Elf_Phdr const *phdrs, |
122 |
unsigned long *newsize) |
123 |
{ |
124 |
Elf32_Phdr const *phdr; |
125 |
unsigned long size, n; |
126 |
int i; |
127 |
|
128 |
/* Start by setting the size to include the ELF header and the |
129 |
* complete program segment header table. |
130 |
*/ |
131 |
size = ehdr->e_phoff + ehdr->e_phnum * sizeof *phdrs; |
132 |
if (size < sizeof *ehdr) |
133 |
size = sizeof *ehdr; |
134 |
|
135 |
/* Then keep extending the size to include whatever data the |
136 |
* program segment header table references. |
137 |
*/ |
138 |
for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) { |
139 |
if (phdr->p_type != PT_NULL) { |
140 |
n = phdr->p_offset + phdr->p_filesz; |
141 |
if (n > size) |
142 |
size = n; |
143 |
} |
144 |
} |
145 |
|
146 |
*newsize = size; |
147 |
return TRUE; |
148 |
} |
149 |
|
327 |
|
150 |
/* truncatezeros() examines the bytes at the end of the file's |
328 |
/* First elements of Elf32_Ehdr and Elf64_Ehdr are common. |
151 |
* size-to-be, and reduces the size to exclude any trailing zero |
|
|
152 |
* bytes. |
153 |
*/ |
329 |
*/ |
154 |
static int truncatezeros(int fd, unsigned long *newsize) |
330 |
static int readelfheaderident(int fd, Elf32_Ehdr *ehdr) |
155 |
{ |
331 |
{ |
156 |
unsigned char contents[1024]; |
332 |
errno = 0; |
157 |
unsigned long size, n; |
333 |
if (read(fd, ehdr, EI_NIDENT) != EI_NIDENT) |
|
|
334 |
return ferr("missing or incomplete ELF header."); |
335 |
|
336 |
/* Check the ELF signature. |
337 |
*/ |
338 |
if (!(ehdr->e_ident[EI_MAG0] == ELFMAG0 && |
339 |
ehdr->e_ident[EI_MAG1] == ELFMAG1 && |
340 |
ehdr->e_ident[EI_MAG2] == ELFMAG2 && |
341 |
ehdr->e_ident[EI_MAG3] == ELFMAG3)) |
342 |
{ |
343 |
err("missing ELF signature."); |
344 |
return -1; |
345 |
} |
158 |
|
346 |
|
159 |
size = *newsize; |
347 |
/* Compare the file's class and endianness with the program's. |
160 |
do { |
348 |
*/ |
161 |
n = sizeof contents; |
349 |
#if __BYTE_ORDER == __LITTLE_ENDIAN |
162 |
if (n > size) |
350 |
if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) { |
163 |
n = size; |
351 |
do_reverse_endian = 0; |
164 |
if (lseek(fd, size - n, SEEK_SET) == (off_t)-1) |
352 |
} else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) { |
165 |
return ferr("cannot seek in file."); |
353 |
/* fprintf(stderr, "ELF file has different endianness.\n"); */ |
166 |
if (read(fd, contents, n) != (ssize_t)n) |
354 |
do_reverse_endian = 1; |
167 |
return ferr("cannot read file contents"); |
355 |
} |
168 |
while (n && !contents[--n]) |
356 |
#elif __BYTE_ORDER == __BIG_ENDIAN |
169 |
--size; |
357 |
if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) { |
170 |
} while (size && !n); |
358 |
/* fprintf(stderr, "ELF file has different endianness.\n"); */ |
171 |
|
359 |
do_reverse_endian = 1; |
172 |
/* Sanity check. |
360 |
} else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) { |
173 |
*/ |
361 |
do_reverse_endian = 0; |
174 |
if (!size) |
362 |
} |
175 |
return err("ELF file is completely blank!"); |
363 |
#else |
|
|
364 |
#error unkown endianness |
365 |
#endif |
366 |
else { |
367 |
err("Unsupported endianness"); |
368 |
return -1; |
369 |
} |
176 |
|
370 |
|
177 |
*newsize = size; |
371 |
/* Check the target architecture. |
178 |
return TRUE; |
372 |
*/ |
|
|
373 |
/* if (EGET(ehdr->e_machine) != ELF_ARCH) { */ |
374 |
/* /\* return err("ELF file created for different architecture."); *\/ */ |
375 |
/* fprintf(stderr, "ELF file created for different architecture.\n"); */ |
376 |
/* } */ |
377 |
return ehdr->e_ident[EI_CLASS]; |
179 |
} |
378 |
} |
180 |
|
379 |
|
181 |
/* modifyheaders() removes references to the section header table if |
|
|
182 |
* it was stripped, and reduces program header table entries that |
183 |
* included truncated bytes at the end of the file. |
184 |
*/ |
185 |
static int modifyheaders(Elf_Ehdr *ehdr, Elf_Phdr *phdrs, |
186 |
unsigned long newsize) |
187 |
{ |
188 |
Elf32_Phdr *phdr; |
189 |
int i; |
190 |
|
380 |
|
191 |
/* If the section header table is gone, then remove all references |
381 |
HEADER_FUNCTIONS(32) |
192 |
* to it in the ELF header. |
|
|
193 |
*/ |
194 |
if (ehdr->e_shoff >= newsize) { |
195 |
ehdr->e_shoff = 0; |
196 |
ehdr->e_shnum = 0; |
197 |
ehdr->e_shentsize = 0; |
198 |
ehdr->e_shstrndx = 0; |
199 |
} |
200 |
|
201 |
/* The program adjusts the file size of any segment that was |
202 |
* truncated. The case of a segment being completely stripped out |
203 |
* is handled separately. |
204 |
*/ |
205 |
for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) { |
206 |
if (phdr->p_offset >= newsize) { |
207 |
phdr->p_offset = newsize; |
208 |
phdr->p_filesz = 0; |
209 |
} else if (phdr->p_offset + phdr->p_filesz > newsize) { |
210 |
phdr->p_filesz = newsize - phdr->p_offset; |
211 |
} |
212 |
} |
213 |
|
382 |
|
214 |
return TRUE; |
383 |
HEADER_FUNCTIONS(64) |
215 |
} |
|
|
216 |
|
384 |
|
217 |
/* commitchanges() writes the new headers back to the original file |
385 |
/* truncatezeros() examines the bytes at the end of the file's |
218 |
* and sets the file to its new size. |
386 |
* size-to-be, and reduces the size to exclude any trailing zero |
|
|
387 |
* bytes. |
219 |
*/ |
388 |
*/ |
220 |
static int commitchanges(int fd, Elf_Ehdr const *ehdr, Elf_Phdr *phdrs, |
389 |
static int truncatezeros(int fd, unsigned long *newsize) |
221 |
unsigned long newsize) |
|
|
222 |
{ |
390 |
{ |
223 |
size_t n; |
391 |
unsigned char contents[1024]; |
224 |
|
392 |
unsigned long size, n; |
225 |
/* Save the changes to the ELF header, if any. |
|
|
226 |
*/ |
227 |
if (lseek(fd, 0, SEEK_SET)) |
228 |
return ferr("could not rewind file"); |
229 |
errno = 0; |
230 |
if (write(fd, ehdr, sizeof *ehdr) != sizeof *ehdr) |
231 |
return err("could not modify file"); |
232 |
|
233 |
/* Save the changes to the program segment header table, if any. |
234 |
*/ |
235 |
if (lseek(fd, ehdr->e_phoff, SEEK_SET) == (off_t)-1) { |
236 |
err("could not seek in file."); |
237 |
goto warning; |
238 |
} |
239 |
n = ehdr->e_phnum * sizeof *phdrs; |
240 |
if (write(fd, phdrs, n) != (ssize_t)n) { |
241 |
err("could not write to file"); |
242 |
goto warning; |
243 |
} |
244 |
|
245 |
/* Eleventh-hour sanity check: don't truncate before the end of |
246 |
* the program segment header table. |
247 |
*/ |
248 |
if (newsize < ehdr->e_phoff + n) |
249 |
newsize = ehdr->e_phoff + n; |
250 |
|
251 |
/* Chop off the end of the file. |
252 |
*/ |
253 |
if (ftruncate(fd, newsize)) { |
254 |
err("could not resize file"); |
255 |
goto warning; |
256 |
} |
257 |
|
393 |
|
258 |
return TRUE; |
394 |
size = *newsize; |
|
|
395 |
do { |
396 |
n = sizeof contents; |
397 |
if (n > size) |
398 |
n = size; |
399 |
if (lseek(fd, size - n, SEEK_SET) == (off_t)-1) |
400 |
return ferr("cannot seek in file."); |
401 |
if (read(fd, contents, n) != (ssize_t)n) |
402 |
return ferr("cannot read file contents"); |
403 |
while (n && !contents[--n]) |
404 |
--size; |
405 |
} while (size && !n); |
406 |
|
407 |
/* Sanity check. |
408 |
*/ |
409 |
if (!size) |
410 |
return err("ELF file is completely blank!"); |
259 |
|
411 |
|
260 |
warning: |
412 |
*newsize = size; |
261 |
return err("ELF file may have been corrupted!"); |
413 |
return TRUE; |
262 |
} |
414 |
} |
263 |
|
415 |
|
264 |
/* main() loops over the cmdline arguments, leaving all the real work |
416 |
/* main() loops over the cmdline arguments, leaving all the real work |
Lines 266-309
Link Here
|
266 |
*/ |
418 |
*/ |
267 |
int main(int argc, char *argv[]) |
419 |
int main(int argc, char *argv[]) |
268 |
{ |
420 |
{ |
269 |
int fd; |
421 |
int fd; |
270 |
Elf_Ehdr ehdr; |
422 |
union { |
271 |
Elf_Phdr *phdrs; |
423 |
Elf32_Ehdr ehdr32; |
272 |
unsigned long newsize; |
424 |
Elf64_Ehdr ehdr64; |
273 |
char **arg; |
425 |
} e; |
274 |
int failures = 0; |
426 |
union { |
275 |
|
427 |
Elf32_Phdr *phdrs32; |
276 |
if (argc < 2 || argv[1][0] == '-') { |
428 |
Elf64_Phdr *phdrs64; |
277 |
printf("Usage: sstrip FILE...\n" |
429 |
} p; |
278 |
"sstrip discards all nonessential bytes from an executable.\n\n" |
430 |
unsigned long newsize; |
279 |
"Version 2.0 Copyright (C) 2000,2001 Brian Raiter.\n" |
431 |
char **arg; |
280 |
"This program is free software, licensed under the GNU\n" |
432 |
int failures = 0; |
281 |
"General Public License. There is absolutely no warranty.\n"); |
433 |
|
282 |
return EXIT_SUCCESS; |
434 |
if (argc < 2 || argv[1][0] == '-') { |
283 |
} |
435 |
printf("Usage: sstrip FILE...\n" |
284 |
|
436 |
"sstrip discards all nonessential bytes from an executable.\n\n" |
285 |
progname = argv[0]; |
437 |
"Version 2.0-X Copyright (C) 2000,2001 Brian Raiter.\n" |
286 |
|
438 |
"Cross-devel hacks Copyright (C) 2004 Manuel Novoa III.\n" |
287 |
for (arg = argv + 1 ; *arg != NULL ; ++arg) { |
439 |
"This program is free software, licensed under the GNU\n" |
288 |
filename = *arg; |
440 |
"General Public License. There is absolutely no warranty.\n"); |
289 |
|
441 |
return EXIT_SUCCESS; |
290 |
fd = open(*arg, O_RDWR); |
|
|
291 |
if (fd < 0) { |
292 |
ferr("can't open"); |
293 |
++failures; |
294 |
continue; |
295 |
} |
442 |
} |
296 |
|
443 |
|
297 |
if (!(readelfheader(fd, &ehdr) && |
444 |
progname = argv[0]; |
298 |
readphdrtable(fd, &ehdr, &phdrs) && |
|
|
299 |
getmemorysize(&ehdr, phdrs, &newsize) && |
300 |
truncatezeros(fd, &newsize) && |
301 |
modifyheaders(&ehdr, phdrs, newsize) && |
302 |
commitchanges(fd, &ehdr, phdrs, newsize))) |
303 |
++failures; |
304 |
|
445 |
|
305 |
close(fd); |
446 |
for (arg = argv + 1 ; *arg != NULL ; ++arg) { |
306 |
} |
447 |
filename = *arg; |
|
|
448 |
|
449 |
fd = open(*arg, O_RDWR); |
450 |
if (fd < 0) { |
451 |
ferr("can't open"); |
452 |
++failures; |
453 |
continue; |
454 |
} |
455 |
|
456 |
switch (readelfheaderident(fd, &e.ehdr32)) { |
457 |
case ELFCLASS32: |
458 |
if (!(readelfheader32(fd, &e.ehdr32) && |
459 |
readphdrtable32(fd, &e.ehdr32, &p.phdrs32) && |
460 |
getmemorysize32(&e.ehdr32, p.phdrs32, &newsize) && |
461 |
truncatezeros(fd, &newsize) && |
462 |
modifyheaders32(&e.ehdr32, p.phdrs32, newsize) && |
463 |
commitchanges32(fd, &e.ehdr32, p.phdrs32, newsize))) |
464 |
++failures; |
465 |
break; |
466 |
case ELFCLASS64: |
467 |
if (!(readelfheader64(fd, &e.ehdr64) && |
468 |
readphdrtable64(fd, &e.ehdr64, &p.phdrs64) && |
469 |
getmemorysize64(&e.ehdr64, p.phdrs64, &newsize) && |
470 |
truncatezeros(fd, &newsize) && |
471 |
modifyheaders64(&e.ehdr64, p.phdrs64, newsize) && |
472 |
commitchanges64(fd, &e.ehdr64, p.phdrs64, newsize))) |
473 |
++failures; |
474 |
break; |
475 |
default: |
476 |
++failures; |
477 |
break; |
478 |
} |
479 |
close(fd); |
480 |
} |
307 |
|
481 |
|
308 |
return failures ? EXIT_FAILURE : EXIT_SUCCESS; |
482 |
return failures ? EXIT_FAILURE : EXIT_SUCCESS; |
309 |
} |
483 |
} |