source: trunk/src/sstrip.c@ 20

Last change on this file since 20 was 1, checked in by katerina, 19 years ago

Initial import

File size: 8.5 KB
Line 
1/* sstrip, version 2.0: Copyright (C) 1999-2001 by Brian Raiter, under the
2 * GNU General Public License. No warranty. See LICENSE for details.
3 */
4
5/* #include "config_xor.h" */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <errno.h>
11#include <unistd.h>
12#include <fcntl.h>
13
14#if !defined(__ia64) && !defined(__ia64__) && !defined(__itanium__) && \
15 !defined(__alpha) && !defined(__alpha__) && \
16 (defined(__linux__) || defined(__FreeBSD__)) && \
17 (defined(__i386__) || defined(__i386) || defined(i386))
18
19/* || defined(__sun) || defined(__sun__) || defined(sun) */
20
21#if defined(__linux__)
22#include <linux/elf.h>
23#else
24#include <elf.h>
25#endif
26
27#ifndef TRUE
28#define TRUE 1
29#define FALSE 0
30#endif
31
32#if ELF_CLASS == ELFCLASS32
33#define Elf_Ehdr Elf32_Ehdr
34#define Elf_Phdr Elf32_Phdr
35#else
36#define Elf_Ehdr Elf64_Ehdr
37#define Elf_Phdr Elf64_Phdr
38#endif
39
40/* The name of the program.
41 */
42static char const *progname;
43
44/* The name of the current file.
45 */
46static char const *filename;
47
48
49/* A simple error-handling function. FALSE is always returned for the
50 * convenience of the caller.
51 */
52static int err(char const *errmsg)
53{
54 fprintf(stderr, "%s: %s: %s\n", progname, filename, errmsg);
55 return FALSE;
56}
57
58/* A macro for I/O errors: The given error message is used only when
59 * errno is not set.
60 */
61#define ferr(msg) (err(errno ? strerror(errno) : (msg)))
62
63/* readelfheader() reads the ELF header into our global variable, and
64 * checks to make sure that this is in fact a file that we should be
65 * munging.
66 */
67static int readelfheader(int fd, Elf_Ehdr *ehdr)
68{
69 errno = 0;
70 if (read(fd, ehdr, sizeof *ehdr) != sizeof *ehdr)
71 return ferr("missing or incomplete ELF header.");
72
73 /* Check the ELF signature.
74 */
75 if (!(ehdr->e_ident[EI_MAG0] == ELFMAG0 &&
76 ehdr->e_ident[EI_MAG1] == ELFMAG1 &&
77 ehdr->e_ident[EI_MAG2] == ELFMAG2 &&
78 ehdr->e_ident[EI_MAG3] == ELFMAG3))
79 return err("missing ELF signature.");
80
81 /* Compare the file's class and endianness with the program's.
82 */
83 if (ehdr->e_ident[EI_DATA] != ELF_DATA)
84 return err("ELF file has different endianness.");
85 if (ehdr->e_ident[EI_CLASS] != ELF_CLASS)
86 return err("ELF file has different word size.");
87
88 /* Check the target architecture.
89 */
90 if (ehdr->e_machine != ELF_ARCH)
91 return err("ELF file created for different architecture.");
92
93 /* Verify the sizes of the ELF header and the program segment
94 * header table entries.
95 */
96 if (ehdr->e_ehsize != sizeof(Elf_Ehdr))
97 return err("unrecognized ELF header size.");
98 if (ehdr->e_phentsize != sizeof(Elf_Phdr))
99 return err("unrecognized program segment header size.");
100
101 /* Finally, check the file type.
102 */
103 if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
104 return err("not an executable or shared-object library.");
105
106 return TRUE;
107}
108
109/* readphdrtable() loads the program segment header table into memory.
110 */
111static int readphdrtable(int fd, Elf_Ehdr const *ehdr, Elf_Phdr **phdrs)
112{
113 size_t size;
114
115 if (!ehdr->e_phoff || !ehdr->e_phnum)
116 return err("ELF file has no program header table.");
117
118 size = ehdr->e_phnum * sizeof **phdrs;
119 if (!(*phdrs = malloc(size)))
120 return err("Out of memory!");
121
122 errno = 0;
123 if (read(fd, *phdrs, size) != (ssize_t)size)
124 return ferr("missing or incomplete program segment header table.");
125
126 return TRUE;
127}
128
129/* getmemorysize() determines the offset of the last byte of the file
130 * that is referenced by an entry in the program segment header table.
131 * (Anything in the file after that point is not used when the program
132 * is executing, and thus can be safely discarded.)
133 */
134static int getmemorysize(Elf_Ehdr const *ehdr, Elf_Phdr const *phdrs,
135 unsigned long *newsize)
136{
137 Elf_Phdr const *phdr;
138 unsigned long size, n;
139 int i;
140
141 /* Start by setting the size to include the ELF header and the
142 * complete program segment header table.
143 */
144 size = ehdr->e_phoff + ehdr->e_phnum * sizeof *phdrs;
145 if (size < sizeof *ehdr)
146 size = sizeof *ehdr;
147
148 /* Then keep extending the size to include whatever data the
149 * program segment header table references.
150 */
151 for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) {
152 if (phdr->p_type != PT_NULL) {
153 n = phdr->p_offset + phdr->p_filesz;
154 if (n > size)
155 size = n;
156 }
157 }
158
159 *newsize = size;
160 return TRUE;
161}
162
163/* truncatezeros() examines the bytes at the end of the file's
164 * size-to-be, and reduces the size to exclude any trailing zero
165 * bytes.
166 */
167static int truncatezeros(int fd, unsigned long *newsize)
168{
169 unsigned char contents[1024];
170 unsigned long size, n;
171
172 size = *newsize;
173 do {
174 n = sizeof contents;
175 if (n > size)
176 n = size;
177 if (lseek(fd, size - n, SEEK_SET) == (off_t)-1)
178 return ferr("cannot seek in file.");
179 if (read(fd, contents, n) != (ssize_t)n)
180 return ferr("cannot read file contents");
181 while (n && !contents[--n])
182 --size;
183 } while (size && !n);
184
185 /* Sanity check.
186 */
187 if (!size)
188 return err("ELF file is completely blank!");
189
190 *newsize = size;
191 return TRUE;
192}
193
194/* modifyheaders() removes references to the section header table if
195 * it was stripped, and reduces program header table entries that
196 * included truncated bytes at the end of the file.
197 */
198static int modifyheaders(Elf_Ehdr *ehdr, Elf_Phdr *phdrs,
199 unsigned long newsize)
200{
201 Elf_Phdr *phdr;
202 int i;
203
204 /* If the section header table is gone, then remove all references
205 * to it in the ELF header.
206 */
207 if (ehdr->e_shoff >= newsize) {
208 ehdr->e_shoff = 0;
209 ehdr->e_shnum = 0;
210 ehdr->e_shentsize = 0;
211 ehdr->e_shstrndx = 0;
212 }
213
214 /* The program adjusts the file size of any segment that was
215 * truncated. The case of a segment being completely stripped out
216 * is handled separately.
217 */
218 for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) {
219 if (phdr->p_offset >= newsize) {
220 phdr->p_offset = newsize;
221 phdr->p_filesz = 0;
222 } else if (phdr->p_offset + phdr->p_filesz > newsize) {
223 phdr->p_filesz = newsize - phdr->p_offset;
224 }
225 }
226
227 return TRUE;
228}
229
230/* commitchanges() writes the new headers back to the original file
231 * and sets the file to its new size.
232 */
233static int commitchanges(int fd, Elf_Ehdr const *ehdr, Elf_Phdr *phdrs,
234 unsigned long newsize)
235{
236 size_t n;
237
238 /* Save the changes to the ELF header, if any.
239 */
240 if (lseek(fd, 0, SEEK_SET))
241 return ferr("could not rewind file");
242 errno = 0;
243 if (write(fd, ehdr, sizeof *ehdr) != sizeof *ehdr)
244 return err("could not modify file");
245
246 /* Save the changes to the program segment header table, if any.
247 */
248 if (lseek(fd, ehdr->e_phoff, SEEK_SET) == (off_t)-1) {
249 err("could not seek in file.");
250 goto warning;
251 }
252 n = ehdr->e_phnum * sizeof *phdrs;
253 if (write(fd, phdrs, n) != (ssize_t)n) {
254 err("could not write to file");
255 goto warning;
256 }
257
258 /* Eleventh-hour sanity check: don't truncate before the end of
259 * the program segment header table.
260 */
261 if (newsize < ehdr->e_phoff + n)
262 newsize = ehdr->e_phoff + n;
263
264 /* Chop off the end of the file.
265 */
266 if (ftruncate(fd, newsize)) {
267 err("could not resize file");
268 goto warning;
269 }
270
271 return TRUE;
272
273 warning:
274 return err("ELF file may have been corrupted!");
275}
276
277/* main() loops over the cmdline arguments, leaving all the real work
278 * to the other functions.
279 */
280int main(int argc, char *argv[])
281{
282 int fd;
283 Elf_Ehdr ehdr;
284 Elf_Phdr *phdrs = NULL;
285 unsigned long newsize;
286 char **arg;
287 int failures = 0;
288
289 if (argc < 2 || argv[1][0] == '-') {
290 printf("Usage: sstrip FILE...\n"
291 "sstrip discards all nonessential bytes from an executable.\n\n"
292 "Version 2.0 Copyright (C) 2000,2001 Brian Raiter.\n"
293 "This program is free software, licensed under the GNU\n"
294 "General Public License. There is absolutely no warranty.\n");
295 return EXIT_SUCCESS;
296 }
297
298 progname = argv[0];
299
300 for (arg = argv + 1 ; *arg != NULL ; ++arg) {
301 filename = *arg;
302
303 fd = open(*arg, O_RDWR);
304 if (fd < 0) {
305 ferr("can't open");
306 ++failures;
307 continue;
308 }
309
310 if (!(readelfheader(fd, &ehdr) &&
311 readphdrtable(fd, &ehdr, &phdrs) &&
312 getmemorysize(&ehdr, phdrs, &newsize) &&
313 truncatezeros(fd, &newsize) &&
314 modifyheaders(&ehdr, phdrs, newsize) &&
315 commitchanges(fd, &ehdr, phdrs, newsize)))
316 ++failures;
317
318 close(fd);
319 }
320
321 return failures ? EXIT_FAILURE : EXIT_SUCCESS;
322}
323
324#else
325
326int main()
327{
328 return (EXIT_SUCCESS);
329}
330
331#endif
Note: See TracBrowser for help on using the repository browser.