1 // Scalpel Copyright (C) 2005-11 by Golden G. Richard III and
2 // 2007-11 by Vico Marziale.
3 // Written by Golden G. Richard III and Vico Marziale.
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301, USA.
19 //
20 // Thanks to Kris Kendall, Jesse Kornblum, et al for their work
21 // on Foremost.  Foremost 0.69 was used as the starting point for
22 // Scalpel, in 2005.
23 
24 #include "scalpel.h"
25 
26 // get # of seconds between two specified times
27 #if defined(_WIN32)
elapsed(LARGE_INTEGER A,LARGE_INTEGER B)28 inline double elapsed(LARGE_INTEGER A, LARGE_INTEGER B) {
29   LARGE_INTEGER freq;
30   QueryPerformanceFrequency(&freq);
31   return fabs(((double)A.QuadPart - (double)B.QuadPart) /
32 	      (double)freq.QuadPart);
33 }
34 #else
elapsed(struct timeval A,struct timeval B)35 double elapsed(struct timeval A, struct timeval B) {
36   return fabs(A.tv_sec - B.tv_sec) + fabs(A.tv_usec - B.tv_usec) / 1000000;
37 }
38 #endif
39 
40 // determine if a string begins and ends with '/' characters
isRegularExpression(char * s)41 int isRegularExpression(char *s) {
42   return (s && s[0] && s[0] == '/' && s[strlen(s) - 1] == '/');
43 }
44 
45 
46 void
checkMemoryAllocation(struct scalpelState * state,void * ptr,int line,const char * file,const char * structure)47 checkMemoryAllocation(struct scalpelState *state, void *ptr, int line,
48 		      const char *file, const char *structure) {
49   if(ptr) {
50     return;
51   }
52   else {
53     fprintf(stderr, "** MEMORY ALLOCATION FAILURE **\n");
54     fprintf(stderr,
55 	    "ERROR: Memory exhausted at line %d in file %s. Scalpel was \n",
56 	    line, file);
57     fprintf(stderr,
58 	    "allocating memory for %s when this condition occurred.\n",
59 	    structure);
60 
61     fprintf(state->auditFile,
62 	    "ERROR: Memory exhausted at line %d in file %s. Scalpel was \n",
63 	    line, file);
64     fprintf(state->auditFile,
65 	    "allocating memory for %s when this condition occurred.\n",
66 	    structure);
67 
68     handleError(state, SCALPEL_GENERAL_ABORT);	// fatal
69   }
70 }
71 
72 
73 #ifndef __GLIBC__
setProgramName(char * s)74 void setProgramName(char *s) {
75   char *fn = (char *)malloc(sizeof(char) * PATH_MAX);
76   if(realpath(s, fn) == NULL) {
77     __scalpel__progname = strdup("scalpel");
78     return;
79   }
80 
81   __scalpel__progname = basename(fn);
82 }
83 
84 #endif /* ifndef __GLIBC__ */
85 
86 
87 // write entry to both the screen and the audit file (if possible)
scalpelLog(struct scalpelState * state,const char * format,...)88 void scalpelLog(struct scalpelState *state, const char *format, ...) {
89 
90   va_list argp;
91 
92   va_start(argp, format);
93   vfprintf(stderr, format, argp);
94   va_end(argp);
95 
96   va_start(argp, format);
97   if(state->auditFile) {
98     vfprintf(state->auditFile, format, argp);
99   }
100   va_end(argp);
101 }
102 
103 // determine if two characters match, with optional case
104 // insensitivity.  If a is the Scalpel wildcard character,
105 // then a and b will always match.
charactersMatch(char a,char b,int caseSensitive)106 int charactersMatch(char a, char b, int caseSensitive) {
107 
108   if(a == wildcard || a == b) {
109     return 1;
110   }
111   if(caseSensitive || (a < 'A' || a > 'z' || b < 'A' || b > 'z')) {
112     return 0;
113   }
114 
115   /* This line is equivalent to (abs(a-b)) == 'a' - 'A' */
116   return (abs(a - b) == 32);
117 }
118 
119 
120 // memwildcardcmp is a memcmp() clone, except that single
121 // character wildcards are supported.  The default wildcard character is '?',
122 // but this can be redefined in the configuration file.  A wildcard in s1 will
123 // match any single character in s2.
memwildcardcmp(const void * s1,const void * s2,size_t n,int caseSensitive)124 int memwildcardcmp(const void *s1, const void *s2, size_t n, int caseSensitive) {
125   if(n != 0) {
126     register const unsigned char *p1 = (const unsigned char *)s1,
127       *p2 = (const unsigned char *)s2;
128     do {
129       if(!charactersMatch(*p1++, *p2++, caseSensitive)) {
130 	return (*--p1 - *--p2);
131       }
132     }
133     while (--n != 0);
134   }
135   return 0;
136 }
137 
138 
139 // initialize Boyer-Moore "jump table" for search. Dependence
140 // on search type (e.g., FORWARD, REVERSE, etc.) from Foremost
141 // has been removed, because Scalpel always performs searches across
142 // a buffer in a forward direction.
143 void
init_bm_table(char * needle,size_t table[UCHAR_MAX+1],size_t len,int casesensitive)144 init_bm_table(char *needle, size_t table[UCHAR_MAX + 1],
145 	      size_t len, int casesensitive) {
146 
147   size_t i = 0, j = 0, currentindex = 0;
148 
149   for(i = 0; i <= UCHAR_MAX; i++) {
150     table[i] = len;
151   }
152 
153   for(i = 0; i < len; i++) {
154     currentindex = len - i - 1;	//Count from the back of string
155     //No skip entry can advance us past the last wildcard in the string
156     if(needle[i] == wildcard) {
157       for(j = 0; j <= UCHAR_MAX; j++) {
158 	table[j] = currentindex;
159       }
160     }
161     table[(unsigned char)needle[i]] = currentindex;
162     if(!casesensitive && needle[i] > 0) {
163       table[tolower(needle[i])] = currentindex;
164       table[toupper(needle[i])] = currentindex;
165     }
166   }
167 }
168 
169 #ifdef USE_SIMPLE_STRING_SEARCH
170 
171 // Perform a simple string search, supporting wildcards,
172 // case-insensitive searches, and specifiable start locations in the buffer.
173 // The parameter 'table' is ignored.
bm_needleinhaystack_skipnchars(char * needle,size_t needle_len,char * haystack,size_t haystack_len,size_t table[UCHAR_MAX+1],int casesensitive,int start_pos)174 char *bm_needleinhaystack_skipnchars(char *needle, size_t needle_len,
175 				     char *haystack, size_t haystack_len,
176 				     size_t table[UCHAR_MAX + 1],
177 				     int casesensitive, int start_pos) {
178 
179   register int i, j, go;
180 
181   if(needle_len == 0) {
182     return haystack;
183   }
184 
185   for(i = start_pos; i < haystack_len; i++) {
186     go = 1;
187     j = 0;
188     while (go) {
189       go = (i + j) < haystack_len && j < needle_len &&
190 	charactersMatch(needle[j], haystack[i + j], casesensitive);
191       j++;
192     }
193 
194     if(j > needle_len) {
195       return haystack + i;
196     }
197   }
198 
199   return NULL;
200 
201 }
202 
203 #endif
204 
205 
206 
207 #ifdef USE_FAST_STRING_SEARCH
208 
209 // Perform a modified Boyer-Moore string search, supporting wildcards,
210 // case-insensitive searches, and specifiable start locations in the buffer.
211 // Dependence on search type (e.g., FORWARD, REVERSe, etc.) from Foremost has
212 // been removed, because Scalpel always performs forward searching.
bm_needleinhaystack_skipnchars(char * needle,size_t needle_len,char * haystack,size_t haystack_len,size_t table[UCHAR_MAX+1],int casesensitive,int start_pos)213 char *bm_needleinhaystack_skipnchars(char *needle, size_t needle_len,
214 				     char *haystack, size_t haystack_len,
215 				     size_t table[UCHAR_MAX + 1],
216 				     int casesensitive, int start_pos) {
217 
218   register size_t shift = 0;
219   register size_t pos = start_pos;
220   char *here;
221 
222   if(needle_len == 0) {
223     return haystack;
224   }
225 
226   while (pos < haystack_len) {
227     while (pos < haystack_len
228 	   && (shift = table[(unsigned char)haystack[pos]]) > 0) {
229       pos += shift;
230     }
231     if(0 == shift) {
232       if(0 ==
233 	 memwildcardcmp(needle, here =
234 			(char *)&haystack[pos - needle_len + 1],
235 			needle_len, casesensitive)) {
236 	return (here);
237       }
238       else {
239 	pos++;
240       }
241     }
242   }
243   return NULL;
244 }
245 
246 #endif
247 
248 
bm_needleinhaystack(char * needle,size_t needle_len,char * haystack,size_t haystack_len,size_t table[UCHAR_MAX+1],int casesensitive)249 char *bm_needleinhaystack(char *needle, size_t needle_len,
250 			  char *haystack, size_t haystack_len,
251 			  size_t table[UCHAR_MAX + 1], int casesensitive) {
252 
253   return bm_needleinhaystack_skipnchars(needle,
254 					needle_len,
255 					haystack,
256 					haystack_len,
257 					table, casesensitive, needle_len - 1);
258 }
259 
260 
261 
262 // find longest header OR footer.  Headers or footers which are
263 // regular expressions are assigned LARGEST_REGEXP_OVERLAP lengths, to
264 // allow for regular expressions spanning SIZE_OF_BUFFER-sized chunks
265 // of the disk image.
findLongestNeedle(struct SearchSpecLine * SearchSpec)266 int findLongestNeedle(struct SearchSpecLine *SearchSpec) {
267   int longest = 0;
268   int i = 0;
269   int lenb, lene;
270   for(i = 0; SearchSpec[i].suffix != NULL; i++) {
271     lenb =
272       SearchSpec[i].beginisRE ? LARGEST_REGEXP_OVERLAP : SearchSpec[i].
273       beginlength;
274     lene =
275       SearchSpec[i].endisRE ? LARGEST_REGEXP_OVERLAP : SearchSpec[i].endlength;
276     if(lenb > longest) {
277       longest = lenb;
278     }
279     if(lene > longest) {
280       longest = lene;
281     }
282   }
283   return longest;
284 }
285 
286 
287 // do a regular expression search using the Tre regular expression
288 // library.  The needle is a previously compiled regular expression
289 // (via Tre regcomp()).  The caller must free the memory associated
290 // with the returned regmatch_t structure.
re_needleinhaystack(regex_t * needle,char * haystack,size_t haystack_len)291 regmatch_t *re_needleinhaystack(regex_t * needle, char *haystack,
292 				size_t haystack_len) {
293 
294   regmatch_t *match = (regmatch_t *) malloc(sizeof(regmatch_t));
295 
296 
297   // LMIII temp fix till working with g++
298   if(!regnexec(needle, haystack, (size_t) haystack_len, (size_t) 1, match, 0)) {
299     // match
300     return match;
301   }
302   else {
303     // no match
304     return NULL;
305   }
306 }
307 
308 
309 // decode strings with embedded escape sequences and return the total length of the
310 // translated string.
311 
translate(char * str)312 int translate(char *str) {
313   char next;
314   char *rd = str, *wr = str, *bad;
315   char temp[1 + 3 + 1];
316   char ch;
317 
318   if(!*rd) {			//If it's a null string just return
319     return 0;
320   }
321 
322   while (*rd) {
323     // Is it an escaped character?
324     if(*rd == '\\') {
325       rd++;
326       switch (*rd) {
327       case '\\':
328 	rd++;
329 	*(wr++) = '\\';
330 	break;
331       case 'a':
332 	rd++;
333 	*(wr++) = '\a';
334 	break;
335       case 's':
336 	rd++;
337 	*(wr++) = ' ';
338 	break;
339       case 'n':
340 	rd++;
341 	*(wr++) = '\n';
342 	break;
343       case 'r':
344 	rd++;
345 	*(wr++) = '\r';
346 	break;
347       case 't':
348 	rd++;
349 	*(wr++) = '\t';
350 	break;
351       case 'v':
352 	rd++;
353 	*(wr++) = '\v';
354 	break;
355 	// Hexadecimal/Octal values are treated in one place using strtoul()
356       case 'x':
357       case '0':
358       case '1':
359       case '2':
360       case '3':
361 	next = *(rd + 1);
362       if(next < 48 || (57 < next && next < 65) ||
363 	 (70 < next && next < 97) || next > 102)
364 	break;		//break if not a digit or a-f, A-F
365       next = *(rd + 2);
366       if(next < 48 || (57 < next && next < 65) ||
367 	 (70 < next && next < 97) || next > 102)
368 	break;		//break if not a digit or a-f, A-F
369 
370       temp[0] = '0';
371       bad = temp;
372       strncpy(temp + 1, rd, 3);
373       temp[4] = '\0';
374       ch = strtoul(temp, &bad, 0);
375       if(*bad == '\0') {
376 	*(wr++) = ch;
377 	rd += 3;
378       }			// else INVALID CHARACTER IN INPUT ('\\' followed by *rd)
379       break;
380       default:		// INVALID CHARACTER IN INPUT (*rd)
381 	*(wr++) = '\\';
382 	break;
383       }
384     }
385     // just copy un-escaped characters
386     else {
387       *(wr++) = *(rd++);
388     }
389   }
390   *wr = '\0';			// null termination
391   return wr - str;
392 }
393 
394 // skip leading whitespace
skipWhiteSpace(char * str)395 char *skipWhiteSpace(char *str) {
396   while (isspace(str[0])) {
397     str++;
398   }
399   return str;
400 }
401 
402 // describe Scalpel error conditions.  Some errors are fatal, while
403 // others are advisory.
handleError(struct scalpelState * state,int error)404 void handleError(struct scalpelState *state, int error) {
405 
406   switch (error) {
407 
408   case SCALPEL_ERROR_PTHREAD_FAILURE:
409     // fatal
410     scalpelLog(state,
411 	       "Scalpel was unable to create threads and will abort.\n");
412     closeAuditFile(state->auditFile);
413     exit(-1);
414     break;
415 
416   case SCALPEL_ERROR_FILE_OPEN:
417     // non-fatal
418     if (state->imagefile == 0 || *(state->imagefile) == '\0') {
419       scalpelLog(state, "Scalpel was unable to open the image file: <blank>....\n"
420 		 "Skipping...\n");
421     }
422     else {
423       scalpelLog(state, "Scalpel was unable to open the image file: %s...%s\n"
424 		 "Skipping...\n", state->imagefile, strerror(errno));
425     }
426     break;
427   case SCALPEL_ERROR_FILE_TOO_SMALL:
428     // non-fatal
429     scalpelLog(state,
430 	       "The image file %s is smaller than the longest header/footer and cannot be processed.\n"
431 	       "Skipping...\n", state->imagefile);
432     break;
433 
434   case SCALPEL_ERROR_FILE_READ:
435     // non-fatal
436     scalpelLog(state, "Scalpel was unable to read the image file: %s\n"
437 	       "Skipping...\n", state->imagefile);
438     break;
439 
440   case SCALPEL_ERROR_FATAL_READ:
441     // fatal
442     scalpelLog(state,
443 	       "Scalpel was unable to read a needed file and will abort.\n");
444     closeAuditFile(state->auditFile);
445     exit(-1);
446     break;
447 
448   case SCALPEL_ERROR_NONEMPTY_DIRECTORY:
449     // fatal
450     fprintf(stderr,
451 	    "Scalpel will write only to empty output directories to avoid\n");
452     fprintf(stderr, "mixing the output from multiple carving operations.\n");
453     fprintf(stderr,
454 	    "Please specify a different output directory or delete the specified\noutput directory.\n");
455     closeAuditFile(state->auditFile);
456     exit(-1);
457     break;
458 
459   case SCALPEL_ERROR_FILE_WRITE:
460     // fatal--unable to write files, which may mean that disk space is exhausted.
461     fprintf(stderr,
462 	    "Scalpel was unable to write output files and will abort.\n");
463     fprintf(stderr,
464 	    "This error generally indicates that disk space is exhausted.\n");
465     closeAuditFile(state->auditFile);
466     exit(-1);
467     break;
468 
469   case SCALPEL_ERROR_NO_SEARCH_SPEC:
470     // fatal, configuration file didn't specify anything to carve
471     scalpelLog(state,
472 	       "ERROR: The configuration file didn't specify any file types to carve.\n");
473     scalpelLog(state,
474 	       "(If you're using the default configuration file, you'll have to\n");
475     scalpelLog(state, "uncomment some of the file types.)\n");
476     closeAuditFile(state->auditFile);
477     exit(-1);
478     break;
479 
480   case SCALPEL_GENERAL_ABORT:
481     // fatal
482     scalpelLog(state, "Scalpel will abort.\n");
483     closeAuditFile(state->auditFile);
484     exit(-1);
485     break;
486 
487   default:
488     // fatal
489     closeAuditFile(state->auditFile);
490     exit(-1);
491   }
492 }
493 
494 
setttywidth(void)495 void setttywidth(void) {
496 #if defined (_WIN32)
497   CONSOLE_SCREEN_BUFFER_INFO csbi;
498   HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
499   if(!GetConsoleScreenBufferInfo(hConsole, &csbi)) {
500     ttywidth = 80;
501   }
502   else {
503     ttywidth = csbi.dwSize.X;
504   }
505 #else
506   //#if defined(__BSD)
507   //  ttywidth = 80;
508   //#else
509   struct winsize winsize;
510   if(ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1) {
511     ttywidth = winsize.ws_col;
512   }
513   else {
514     // 80 is a reasonable default
515     ttywidth = 80;
516   }
517   //#endif
518 #endif
519 }
520 
521 
skipInFile(struct scalpelState * state,FILE * infile)522 int skipInFile(struct scalpelState *state, FILE * infile) {
523 
524   int retries = 0;
525   while (TRUE) {
526     if((fseeko(infile, state->skip, SEEK_SET))) {
527 
528 #ifdef _WIN32
529       fprintf(stderr,
530 	      "ERROR: Couldn't skip %I64u bytes at the start of image file %s\n",
531 	      state->skip, state->imagefile);
532 #else
533       fprintf(stderr,
534 	      "ERROR: Couldn't skip %lld bytes at the start of image file %s\n",
535 	      state->skip, state->imagefile);
536 #endif
537 
538       if(retries++ > 3) {
539 	fprintf(stderr, "Sorry, maximum retries exceeded...\n");
540 	return FALSE;
541       }
542       else {
543 	fprintf(stderr, "Waiting to try again... \n");
544 	sleep(3);
545       }
546     }
547     else {
548 #ifdef _WIN32
549       fprintf(stderr, "Skipped the first %I64u bytes of %s...\n",
550 	      state->skip, state->imagefile);
551 #else
552       fprintf(stderr, "Skipped the first %lld bytes of %s...\n",
553 	      state->skip, state->imagefile);
554 #endif
555 
556 
557       return TRUE;
558     }
559   }
560 }
561