2 * Copyright (c) 2007 S.Sam Arun Raj
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/types.h>
49 ELFTC_VCSID("$Id: strings.c 3446 2016-05-03 01:31:17Z emaste $");
67 ENCODING_16BIT_LITTLE,
72 #define PRINTABLE(c) \
73 ((c) >= 0 && (c) <= 255 && \
74 ((c) == '\t' || isprint((c)) || \
75 (encoding == ENCODING_8BIT && (c) > 127)))
77 static int encoding_size, entire_file, show_filename, show_loc;
78 static enum encoding_style encoding;
79 static enum radix_style radix;
80 static intmax_t min_len;
82 static struct option strings_longopts[] = {
83 { "all", no_argument, NULL, 'a'},
84 { "bytes", required_argument, NULL, 'n'},
85 { "encoding", required_argument, NULL, 'e'},
86 { "help", no_argument, NULL, 'h'},
87 { "print-file-name", no_argument, NULL, 'f'},
88 { "radix", required_argument, NULL, 't'},
89 { "version", no_argument, NULL, 'v'},
93 long getcharacter(void);
94 int handle_file(const char *);
95 int handle_elf(const char *, int);
96 int handle_binary(const char *, int);
97 int find_strings(const char *, off_t, off_t);
98 void show_version(void);
102 * strings(1) extracts text(contiguous printable characters)
103 * from elf and binary files.
106 main(int argc, char **argv)
113 if (elf_version(EV_CURRENT) == EV_NONE)
114 errx(EXIT_FAILURE, "ELF library initialization failed: %s",
117 while ((ch = getopt_long(argc, argv, "1234567890ae:fhn:ot:Vv",
118 strings_longopts, NULL)) != -1)
124 if (*optarg == 's') {
125 encoding = ENCODING_7BIT;
126 } else if (*optarg == 'S') {
127 encoding = ENCODING_8BIT;
128 } else if (*optarg == 'b') {
129 encoding = ENCODING_16BIT_BIG;
131 } else if (*optarg == 'B') {
132 encoding = ENCODING_32BIT_BIG;
134 } else if (*optarg == 'l') {
135 encoding = ENCODING_16BIT_LITTLE;
137 } else if (*optarg == 'L') {
138 encoding = ENCODING_32BIT_LITTLE;
148 min_len = strtoimax(optarg, (char**)NULL, 10);
150 errx(EX_USAGE, "option -n should specify a "
151 "positive decimal integer.");
160 radix = RADIX_DECIMAL;
161 else if (*optarg == 'o')
163 else if (*optarg == 'x')
198 rc = handle_file("{standard input}");
200 rc = handle_file(*argv);
207 handle_file(const char *name)
212 return (RETURN_NOINPUT);
213 if (strcmp("{standard input}", name) != 0) {
214 if (freopen(name, "rb", stdin) == NULL) {
215 warnx("'%s': %s", name, strerror(errno));
216 return (RETURN_NOINPUT);
219 return (find_strings(name, (off_t)0, (off_t)0));
224 return (RETURN_NOINPUT);
225 rt = handle_elf(name, fd);
230 * Files not understood by handle_elf, will be passed off here and will
231 * treated as a binary file. This would include text file, core dumps ...
234 handle_binary(const char *name, int fd)
238 memset(&buf, 0, sizeof(struct stat));
239 (void) lseek(fd, (off_t)0, SEEK_SET);
240 if (!fstat(fd, &buf))
241 return (find_strings(name, (off_t)0, buf.st_size));
242 return (RETURN_SOFTWARE);
246 * Will analyse a file to see if it ELF, other files including ar(1),
247 * core dumps are passed off and treated as flat binary files. Unlike
248 * GNU size in FreeBSD this routine will not treat ELF object from
249 * different archs as flat binary files(has to overridden using -a).
252 handle_elf(const char *name, int fd)
261 /* If entire file is chosen, treat it as a binary file */
263 return (handle_binary(name, fd));
265 (void) lseek(fd, (off_t)0, SEEK_SET);
266 elf = elf_begin(fd, ELF_C_READ, NULL);
267 if (elf_kind(elf) != ELF_K_ELF) {
269 return (handle_binary(name, fd));
272 if (gelf_getehdr(elf, &elfhdr) == NULL) {
274 warnx("%s: ELF file could not be processed", name);
275 return (RETURN_SOFTWARE);
278 if (elfhdr.e_shnum == 0 && elfhdr.e_type == ET_CORE) {
280 return (handle_binary(name, fd));
283 while ((scn = elf_nextscn(elf, scn)) != NULL) {
284 if (gelf_getshdr(scn, &shdr) == NULL)
286 if (shdr.sh_type != SHT_NOBITS &&
287 (shdr.sh_flags & SHF_ALLOC) != 0) {
288 rc = find_strings(name, shdr.sh_offset,
298 * Retrieves a character from input stream based on the encoding
309 for(i = 0; i < encoding_size; i++) {
321 case ENCODING_16BIT_BIG:
322 rt = (buf[0] << 8) | buf[1];
324 case ENCODING_16BIT_LITTLE:
325 rt = buf[0] | (buf[1] << 8);
327 case ENCODING_32BIT_BIG:
328 rt = ((long) buf[0] << 24) | ((long) buf[1] << 16) |
329 ((long) buf[2] << 8) | buf[3];
331 case ENCODING_32BIT_LITTLE:
332 rt = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) |
333 ((long) buf[3] << 24);
340 * Input stream stdin is read until the end of file is reached or until
341 * the section size is reached in case of ELF files. Contiguous
342 * characters of >= min_size(default 4) will be displayed.
345 find_strings(const char *name, off_t offset, off_t size)
347 off_t cur_off, start_off;
352 if ((obuf = (char*)calloc(1, min_len + 1)) == NULL) {
353 (void) fprintf(stderr, "Unable to allocate memory: %s\n",
355 return (RETURN_SOFTWARE);
358 (void) fseeko(stdin, offset, SEEK_SET);
362 if ((offset + size) && (cur_off >= offset + size))
365 memset(obuf, 0, min_len+1);
366 for(i = 0; i < min_len; i++) {
368 if (c == EOF && feof(stdin))
373 cur_off += encoding_size;
375 if (encoding == ENCODING_8BIT &&
379 cur_off += encoding_size;
382 cur_off += encoding_size;
387 if (i >= min_len && ((cur_off <= offset + size) ||
390 printf ("%s: ", name);
394 (void) printf("%7ju ",
395 (uintmax_t)start_off);
398 (void) printf("%7jx ",
399 (uintmax_t)start_off);
402 (void) printf("%7jo ",
403 (uintmax_t)start_off);
410 if ((offset + size) &&
411 (cur_off >= offset + size))
414 cur_off += encoding_size;
415 if (encoding == ENCODING_8BIT &&
420 if (!PRINTABLE(c) || c == EOF)
432 #define USAGE_MESSAGE "\
433 Usage: %s [options] [file...]\n\
434 Print contiguous sequences of printable characters.\n\n\
436 -a | --all Scan the entire file for strings.\n\
437 -e ENC | --encoding=ENC Select the character encoding to use.\n\
438 -f | --print-file-name Print the file name before each string.\n\
439 -h | --help Print a help message and exit.\n\
440 -n N | --bytes=N | -N Print sequences with 'N' or more characters.\n\
441 -o Print offsets in octal.\n\
442 -t R | --radix=R Print offsets using the radix named by 'R'.\n\
443 -v | --version Print a version identifier and exit.\n"
448 (void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
455 (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());