scalpel-1.60/ 40777 0 0 0 10536373031 11236 5ustar usergroupscalpel-1.60/base_name.c100666 0 0 4303 10445550521 13411 0ustar usergroup/* basename.c -- return the last element in a path Copyright (C) 1990, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, 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; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if HAVE_CONFIG_H # include #endif #include #include "dirname.h" /* In general, we can't use the builtin `basename' function if available, since it has different meanings in different environments. In some environments the builtin `basename' modifies its argument. Return the address of the last file name component of NAME. If NAME has no file name components because it is all slashes, return NAME if it is empty, the address of its last slash otherwise. */ char * base_name (char const *name) { char const *base = name + FILESYSTEM_PREFIX_LEN (name); char const *p; for (p = base; *p; p++) { if (ISSLASH (*p)) { /* Treat multiple adjacent slashes like a single slash. */ do p++; while (ISSLASH (*p)); /* If the file name ends in slash, use the trailing slash as the basename if no non-slashes have been found. */ if (! *p) { if (ISSLASH (*base)) base = p - 1; break; } /* *P is a non-slash preceded by a slash. */ base = p; } } return (char *) base; } /* Return the length of of the basename NAME. Typically NAME is the value returned by base_name. Act like strlen (NAME), except omit redundant trailing slashes. */ size_t base_len (char const *name) { size_t len; for (len = strlen (name); 1 < len && ISSLASH (name[len - 1]); len--) continue; return len; } scalpel-1.60/base_name.h100666 0 0 44 10515267060 13355 0ustar usergroupchar *base_name (char const *name); scalpel-1.60/changelog100666 0 0 13740 10536323446 13237 0ustar usergroup1.4: First public beta release. 1.5: Added "-b" option for complete carving compability with foremost 0.69. 1.51: Fixed a problem with Scalpel not carving all files near the end of some large images. The locations of the files was detected, but an optimization to minimize reads on pass 2 caused the files not to be written (and not to be noted in the Scalpel log). Also, more work to bring the Win32 version into compliance. :( Fixed problem with Win32 version reporting "Couldn't measure size of image file" for large images--required ftello64()/fseeko64() under mingw. 40+GB images have now been carved successfully under Win32. Fixed format of offset in log file for large offsets under Win32; the printf() implementation in mingw under Windows doesn't support "%llu" for unsigned long long integers--needs "%I64u". Blech. 1.52 Foremost 0.69 didn't discover overlapping headers/footers. If you want this behavior, use "-r" on the command line. Scalpel's default behavior is now to discover all headers/footers, even if they overlap. Different Quicktime needles (from the 'file' command's magic file) are now used in the configuration file, because the default Foremost needles didn't seem to match valid Quicktime files. The needles are still weak, in that they cause a bunch of false positives. The configuration file now uses more reasonable (in my opinion) maximum carve sizes. By default, all file types are still commented out. 1.53 Verbose mode implemented. "-v" outputs copious (too much?) information about what Scalpel is doing as files are carved. Mac OS X is now supported, including the use of raw block devices (e.g., /dev/disk0) as carve targets. Use "make bsd" for an OS X compilation. 1.54 Maximum size for carved files is now 18 exabytes. Minor changes to Makefile. Fixed minor formatting problem in audit log. Scalpel man page created. Eliminated duplicate error messages when targets could not be opened. Thanks to John Vigo for additional MAC OS X testing on this release. 1.60 Changes in this release include: o Some of the headers and footers in the default 'scalpel.conf' file have been improved. In particular, the GIF89 footer was made less restrictive; GIF89 files were encountered in the wild for which the legacy Foremost footer was too restrictive. o REVERSE carving semantics now fixed as "helpers.c" functions continue to evolve from their Foremost roots; this is mostly useful for PDF carving and when some carved files appear to be truncated--e.g., many times GIF files will contain the footer string internally and with FORWARD carving, will be truncated. REVERSE carving can help, but at the expense of occasionally carving overly large files. o Removed obsolete option "-f". o Maximum number of files that can be carved per file type is now 18,446,744,073,709,551,616. This is also the maximum number of files of all combined types that can be carved in a single run. This is unlikely to be a problematic upper bound in the near term. o The "-q" command line option is now available to force block-aligned carving; only files with headers that begin on block boundaries are carved. The block size for this mode is user-specified. o The "-r" option was not accepted in recent releases due to an omission in Scalpel's command line argument parsing. This option isn't generally used except for compatibility testing with Foremost 0.69 (it actually forces Scalpel to mimic some buggy Foremost behavior) and should be considered deprecated. In a future release of Scalpel, it will be removed. o Scalpel now organizes carved files into subdirectories by type (and for each type, additional subdirectories are created with a maximum of MAX_FILES_PER_SUBDIRECTORY [default: 5000] files each). This will allow you to more comfortably explore the set of carved files using the Windows or Linux file explorers without having them choke on large subdirectories. The files are organized within the Scalpel output directory into subdirectories with the following naming convention: suffix-rule#-counter suffix-rule#-counter ... suffix-rule#-counter where 'suffix' matches the suffix specified in the Scalpel configuration file (e.g, "jpg"), 'rule#' is the index of the corresponding rule in the configuration file (with the first uncommented rule being 0), and 'counter' being incremented after every MAX_FILES_PER_SUBDIRECTORY files corresponding to a rule are carved. You can turn off this default organization by using the "-O" command line flag (then Scalpel acts as in previous releases and dumps all carved files into a single output directory). o The "-p" performs a "preview" carve, creating an audit file indicating which files would be carved, but without performing carving operations. This substantially increases execution speed and also supports "in-line" carving, when used in conjunction with our custom FUSE filesystem. o A memory corruption error when Scalpel had large numbers of files open (typically, when a large number of file types were specified in the configuration file) was corrected. Thanks to both Doug Koster and Peter Theobald for pointing out this error. o In this release some unused functions were removed from the Scalpel source. o A bug which arose for case-insensitive header/footer specifications in the legacy Foremost Boyer-Moore string search initialization was corrected. Thanks to Doug Koster for pointing out this bug. o Fixed (slightly) garbled invocation string in audit file; this resulted from an unitialized string in legacy Foremost code. o The "-d", "-m", "-t", and "-u" options are experimental and are part of evolving support for interaction between Scalpel and external tools, with the goal being better support for recovery of fragmented files. Please contact the author --> golden@digitalforensicssolutions.com <-- for more information if these options appear useful to you. More information will be provided when the necessary external tools are released. scalpel-1.60/dig.c100666 0 0 171052 10536322077 12314 0ustar usergroup// Scalpel Copyright (C) 2005-6 by Golden G. Richard III. // Written by Golden G. Richard III. // // This program is free software; you can redistribute it and/or // modify it 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; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301, USA. // Scalpel is a complete rewrite of the foremost 0.69 file carver to // increase speed and support execution on machines with minimal // resources (e.g., < 256MB RAM). // // Thanks to Kris Kendall, Jesse Kornblum, et al for their work on // foremost. #include "scalpel.h" /////////// GLOBALS //////////// static char readbuffer[SIZE_OF_BUFFER]; // read buffer--process image // files in SIZE_OF_BUFFER-sized // chunks // prototypes for private dig.c functions static int writeHeaderFooterDatabase(struct scalpelState *state); static int setupCoverageMaps(struct scalpelState *state, unsigned long long filesize); static int auditUpdateCoverageBlockmap(struct scalpelState *state, struct CarveInfo *carve); static int updateCoverageBlockmap(struct scalpelState *state, unsigned long long block); static void generateFragments(struct scalpelState *state, Queue *fragments, struct CarveInfo *carve); static unsigned long long positionUseCoverageBlockmap(struct scalpelState *state, unsigned long long position); static void destroyCoverageMaps(struct scalpelState *state); static int fseeko_use_coverage_map(struct scalpelState *state, FILE *fp, off64_t offset); static off64_t ftello_use_coverage_map(struct scalpelState *state, FILE *fp); static size_t fread_use_coverage_map(struct scalpelState *state, void *ptr, size_t size, size_t nmemb, FILE *stream); static void printhex(char *s, int len); static void clean_up(struct scalpelState* state, int signum); static int displayPosition(int *units, unsigned long long pos, unsigned long long size, char *fn); static void setupAuditFile(struct scalpelState* state); static int bm_digBuffer(struct scalpelState *state, FILE *infile, unsigned long long lengthofbuf, unsigned long long offset); //static void adjustForEmbedding(struct SearchSpecLine *currentneedle, // unsigned long long headerindex, unsigned long long *prevstopindex); // output hex notation for chars in 's' static void printhex(char *s, int len) { int i; for (i=0; i < len; i++) { printf("\\x%.2x", (unsigned char)s[i]); } } static void clean_up(struct scalpelState* state, int signum) { scalpelLog (state,"Cleaning up...\n"); scalpelLog (state, "\nCaught signal: %s. Program is terminating early\n", (char*) strsignal(signum)); if (closeFile(state->auditFile)) { scalpelLog(state,"Error closing %s/audit.txt -- %s", state->outputdirectory, (char*) strerror(ferror(state->auditFile))); } exit(1); } // display progress bar static int displayPosition(int *units, unsigned long long pos, unsigned long long size, char *fn) { double percentDone = (((double)pos)/(double)(size) * 100); double position = (double) pos; int count; int barlength,i,len; double elapsed; long remaining; char buf[MAX_STRING_LENGTH]; char line[MAX_STRING_LENGTH]; #ifdef __WIN32 static LARGE_INTEGER start; LARGE_INTEGER now; static LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); #else static struct timeval start; struct timeval now, td; #endif // get current time and remember start time when first chunk of // an image file is read if (pos <= SIZE_OF_BUFFER) { gettimeofday(&start, (struct timezone *)0); } gettimeofday(&now, (struct timezone *)0); // First, reduce the position to the right units for (count = 0; count < *units; count++) { position = position / 1024; } // Now check if we've hit the next type of units while (position > 1023) { position = position / 1024; (*units)++; } switch (*units) { case UNITS_BYTES: sprintf(buf,"bytes"); break; case UNITS_KILOB: sprintf(buf,"KB"); break; case UNITS_MEGAB: sprintf(buf,"MB"); break; case UNITS_GIGAB: sprintf(buf,"GB"); break; case UNITS_TERAB: sprintf(buf,"TB"); break; case UNITS_PETAB: sprintf(buf,"PB"); break; case UNITS_EXAB: sprintf(buf,"EB"); break; default: fprintf (stdout, "Unable to compute progress.\n"); return SCALPEL_OK; } len = 0; len += snprintf(line+len,sizeof(line)-len,"\r%s: %5.1f%% ",fn, percentDone); barlength = ttywidth - strlen(fn) - strlen(buf) - 32; if (barlength > 0) { i = barlength * (int) percentDone / 100; len += snprintf(line+len, sizeof(line)-len, "|%.*s%*s|", i, "****************************************************************************************************************************************************************", barlength-i, ""); } len += snprintf(line+len,sizeof(line)-len," %6.1f %s",position,buf); #ifdef __WIN32 elapsed = ((double)now.QuadPart - (double)start.QuadPart)/((double)freq.QuadPart); //printf("elapsed: %f\n",elapsed); #else timersub(&now, &start, &td); elapsed = td.tv_sec + (td.tv_usec / 1000000.0); #endif remaining = (100-percentDone)/percentDone*elapsed; //printf("Ratio remaining: %f\n",(100-percentDone)/percentDone); //printf("Elapsed time: %f\n",elapsed); if(remaining >= 100*(60*60)){ //60*60 is seconds per hour len +=snprintf(line+len, sizeof(line)-len," --:--ETA"); }else{ i = remaining / (60*60); if(i) len += snprintf(line+len,sizeof(line)-len," %2d:",i); else len += snprintf(line+len,sizeof(line)-len," "); i = remaining%(60*60); len += snprintf(line+len,sizeof(line)-len,"%02d:%02d ETA",i/60, i%60); } fprintf(stdout,"%s",line); fflush(stdout); return SCALPEL_OK; } // create initial entries in audit for each image file processed static void setupAuditFile(struct scalpelState* state) { char imageFile[MAX_STRING_LENGTH]; realpath(state->imagefile,imageFile); scalpelLog(state,"\nOpening target \"%s\"\n\n", imageFile); #ifdef __WIN32 if (state->skip) { fprintf(state->auditFile,"Skipped the first %I64u bytes of %s...\n", state->skip, state->imagefile); if (state->modeVerbose) { fprintf(stdout,"Skipped the first %I64u bytes of %s...\n", state->skip, state->imagefile); } } #else if (state->skip) { fprintf(state->auditFile,"Skipped the first %llu bytes of %s...\n", state->skip, state->imagefile); if (state->modeVerbose) { fprintf(stdout,"Skipped the first %llu bytes of %s...\n", state->skip, state->imagefile); } } #endif fprintf(state->auditFile,"The following files were carved:\n"); fprintf(state->auditFile, "File\t\t Start\t\t\tChop\t\tLength\t\tExtracted From\n"); } // add entries to header/footer database during search of current // buffer. static int bm_digBuffer(struct scalpelState *state, FILE *infile, unsigned long long lengthofbuf, unsigned long long offset) { unsigned long long startLocation = 0; int needlenum; char *foundat; struct SearchSpecLine *currentneedle; // for each file type, find all headers and some (or all) footers for (needlenum=0; state->SearchSpec[needlenum].suffix != NULL; needlenum++) { currentneedle = &(state->SearchSpec[needlenum]); // header search first foundat = readbuffer; while (foundat) { // signal check if (signal_caught == SIGTERM || signal_caught == SIGINT){ clean_up(state,signal_caught); } foundat = bm_needleinhaystack(currentneedle->begin, currentneedle->beginlength, foundat, (int)(lengthofbuf-(foundat-readbuffer)), currentneedle->begin_bm_table, currentneedle->casesensitive); startLocation = offset + (foundat-readbuffer); if (foundat > 0) { // GGRIII: found a header--record location in header offsets // database... if (state->modeVerbose) { #ifdef __WIN32 fprintf(stdout, "A %s header was found at : %I64u\n", currentneedle->suffix, positionUseCoverageBlockmap(state, startLocation)); #else fprintf(stdout, "A %s header was found at : %llu\n", currentneedle->suffix, positionUseCoverageBlockmap(state, startLocation)); #endif } currentneedle->offsets.numheaders++; if (currentneedle->offsets.headerstorage <= currentneedle->offsets.numheaders) { // need more memory for header offset storage--add an // additional 100 elements currentneedle->offsets.headers = realloc(currentneedle->offsets.headers, sizeof(unsigned long long) * (currentneedle->offsets.numheaders + 100)); checkMemoryAllocation(state, currentneedle->offsets.headers, __LINE__, __FILE__, "header array"); currentneedle->offsets.headerstorage = currentneedle->offsets.numheaders + 100; if (state->modeVerbose) { #ifdef __WIN32 fprintf(stdout, "Memory reallocation performed, total header storage = %I64u\n", currentneedle->offsets.headerstorage); #else fprintf(stdout, "Memory reallocation performed, total header storage = %llu\n", currentneedle->offsets.headerstorage); #endif } } currentneedle->offsets.headers[currentneedle->offsets.numheaders-1] = startLocation; } if (foundat) { // move past match position. Foremost 0.69 didn't find overlapping // headers/footers. If you need that behavior, specify "-r" on the // command line. Scalpel's default behavior is to find overlapping // headers/footers. if (state->noSearchOverlap) { foundat = foundat + currentneedle->beginlength; } else { foundat++; } } } // now footer search, if: // // there's a footer for this file type and // at least one header for that type has been previously seen and // at least one header is viable--that is, it was found in the current // buffer, or it's less than the max carve distance behind the current // file offset // // OR // // a header/footer database is being created. In this case, ALL headers and // footers must be discovered. if ( // regular case--want to search for only "viable" (in the sense that they are // useful for carving unfragmented files) footers, to save time (currentneedle->offsets.numheaders > 0 && currentneedle->endlength && (currentneedle->offsets.headers[currentneedle->offsets.numheaders-1] > offset || (offset - currentneedle->offsets.headers[currentneedle->offsets.numheaders-1] < currentneedle->length))) || // generating header/footer database, need to find all footers (currentneedle->endlength && state->generateHeaderFooterDatabase)) { foundat = readbuffer; while (foundat) { // signal check if (signal_caught == SIGTERM || signal_caught == SIGINT){ clean_up(state,signal_caught); } // GGRIII: look for footer foundat = bm_needleinhaystack(currentneedle->end, currentneedle->endlength, foundat, (int)(lengthofbuf-(foundat-readbuffer)), currentneedle->end_bm_table, currentneedle->casesensitive); if (foundat > 0) { // GGRIII: found a footer--record location in footer offsets // database... startLocation = offset + (foundat-readbuffer); if (state->modeVerbose) { #ifdef __WIN32 fprintf(stdout, "A %s footer was found at : %I64u\n", currentneedle->suffix, positionUseCoverageBlockmap(state, startLocation)); #else fprintf(stdout, "A %s footer was found at : %llu\n", currentneedle->suffix, positionUseCoverageBlockmap(state, startLocation)); #endif } currentneedle->offsets.numfooters++; if (currentneedle->offsets.footerstorage <= currentneedle->offsets.numfooters) { // need more memory for footer offset storage--add an // additional 100 elements currentneedle->offsets.footers = realloc(currentneedle->offsets.footers, sizeof(unsigned long long) * (currentneedle->offsets.numfooters + 100)); checkMemoryAllocation(state, currentneedle->offsets.footers, __LINE__, __FILE__, "footer array"); currentneedle->offsets.footerstorage = currentneedle->offsets.numfooters + 100; if (state->modeVerbose) { #ifdef __WIN32 fprintf(stdout, "Memory reallocation performed, total footer storage = %I64u\n", currentneedle->offsets.footerstorage); #else fprintf(stdout, "Memory reallocation performed, total footer storage = %llu\n", currentneedle->offsets.footerstorage); #endif } } currentneedle->offsets.footers[currentneedle->offsets.numfooters-1] = startLocation; // move past match position. Foremost 0.69 didn't find overlapping // headers/footers. If you need that behavior, specify "-r" on the // command line. Scalpel's default behavior is to find overlapping // headers/footers. if (state->noSearchOverlap) { foundat = foundat + currentneedle->endlength; } else { foundat++; } } } } } return SCALPEL_OK; } // GGRIII: Scalpel's approach dictates that this function dig an image // file, building the header/footer offset database. The task of // extracting files from the image has been moved to carveImageFile(), // which operates in a second pass over the image. Digging for // header/footer values proceeds in SIZE_OF_BUFFER sized chunks of the // image file. This buffer is now global and named "readbuffer". int digImageFile(struct scalpelState* state) { FILE *infile; unsigned long long filesize = 0, bytesread = 0, fileposition = 0, filebegin = 0, beginreadpos = 0; long err=0; int status, displayUnits = UNITS_BYTES; int success=0; int longestneedle; setupAuditFile(state); if (state->SearchSpec[0].suffix == NULL) { return SCALPEL_ERROR_NO_SEARCH_SPEC; } // GGRIII: Scalpel eliminates the large buffer in foremost 0.69 whose // size was governed by the variable maxchar [which has been // removed]. This allows scalpel to run with a memory footprint // less than 1/10 of the size of foremost, for typical // "foremost.conf" values. Still need to know the longest needle, // so edge conditions on the buffer can be dealt with. longestneedle = findLongestNeedle(state->SearchSpec); // open current image file if ((infile = fopen(state->imagefile,"rb")) == NULL) { fprintf(stderr, "ERROR: Couldn't open input file: %s -- %s\n", (*(state->imagefile)=='\0')?"":state->imagefile, strerror(errno)); return SCALPEL_ERROR_FILE_OPEN; } #ifdef __WIN32 // set binary mode for Win32 setmode(fileno(infile),O_BINARY); #endif #ifdef __LINUX fcntl(fileno(infile),F_SETFL, O_LARGEFILE); #endif // skip initial portion of input file, if that cmd line option // was set if(state->skip > 0){ if (!skipInFile(state,infile)) { return SCALPEL_ERROR_FILE_READ; } // ***GGRIII: want to update coverage bitmap when skip is specified???? // ***GGRIII: want to update coverage bitmap when skip is specified???? } filebegin = ftello(infile); if ((filesize = measureOpenFile(infile, state)) == -1) { fprintf (stderr, "ERROR: Couldn't measure size of image file %s\n", state->imagefile); return SCALPEL_ERROR_FILE_READ; } #ifdef __WIN32 if (state->modeVerbose) { fprintf (stdout, "Total file size is %I64u bytes\n", filesize); } #else if (state->modeVerbose) { fprintf (stdout, "Total file size is %llu bytes\n", filesize); } #endif // allocate and initialize coverage bitmap and blockmap, if appropriate if ((err = setupCoverageMaps(state, filesize)) != SCALPEL_OK) { return err; } // GGRIII: process SIZE_OF_BUFFER-sized chunks of the current image // file and look for both headers and footers, recording their // offsets for use in the 2nd scalpel phase, when file data will // be extracted. fprintf(stdout, "Image file pass 1/2.\n"); success=1; while ((bytesread = fread_use_coverage_map(state, readbuffer, 1, SIZE_OF_BUFFER, infile)) > longestneedle-1 || success==0) { if (state->modeVerbose) { #ifdef __WIN32 fprintf(stdout, "Read %I64u bytes from image file.\n", bytesread); #else fprintf(stdout, "Read %llu bytes from image file.\n", bytesread); #endif } if ((err = ferror(infile))) { return SCALPEL_ERROR_FILE_READ; } success=1; // progress report needs a fileposition that doesn't depend on coverage map fileposition = ftello(infile); displayPosition(&displayUnits,fileposition-filebegin, filesize,state->imagefile); // if carving is dependent on coverage map, need adjusted fileposition fileposition = ftello_use_coverage_map(state, infile); beginreadpos = fileposition - bytesread; //signal check if (signal_caught == SIGTERM || signal_caught == SIGINT) clean_up(state,signal_caught); // process current buffer if ((status = bm_digBuffer(state,infile, bytesread,beginreadpos)) != SCALPEL_OK) { // GGRIII: error, just return status return status; } // move file position back a bit so headers and footers that fall // across SIZE_OF_BUFFER boundaries in the image file aren't // missed fseeko_use_coverage_map(state, infile, -1 * (longestneedle-1)); } closeFile(infile); return SCALPEL_OK; } // GGRIII: carveImageFile() uses the header/footer offsets database // created by digImageFile() to build a list of files to carve. These // files are then carved during a single, sequential pass over the // image file. The global 'readbuffer' is used as a buffer in this // function. int carveImageFile(struct scalpelState* state) { FILE *infile; struct SearchSpecLine *currentneedle; struct CarveInfo *carveinfo; char fn[MAX_STRING_LENGTH]; // temp buffer for output filename char orgdir[MAX_STRING_LENGTH]; // buffer for name of organizing subdirectory unsigned long long start, stop; // temp begin/end bytes for file to carve unsigned long long prevstopindex; // tracks index of first 'reasonable' // footer int needlenum; unsigned long long filesize = 0, bytesread = 0, fileposition = 0, filebegin = 0; long err=0; int displayUnits = UNITS_BYTES; int success=0; unsigned long long i,j; int halt; char chopped; // file chopped because it exceeds // max carve size for type? int CURRENTFILESOPEN=0; // number of files open (during carve) // index of header and footer within image file, in SIZE_OF_BUFFER // blocks unsigned long long headerblockindex, footerblockindex; struct Queue *carvelists; // one entry for each SIZE_OF_BUFFER bytes of // input file // open image file and get size so carvelists can be allocated if ((infile = fopen(state->imagefile,"rb")) == NULL) { fprintf(stderr, "ERROR: Couldn't open input file: %s -- %s\n", (*(state->imagefile)=='\0')?"":state->imagefile, strerror(errno)); return SCALPEL_ERROR_FILE_OPEN; } #ifdef __WIN32 // explicit binary option for Win32 setmode(fileno(infile),O_BINARY); #endif #ifdef __LINUX fcntl(fileno(infile),F_SETFL, O_LARGEFILE); #endif // If skip was activated, then there's no way headers/footers were // found there, so skip during the carve operations, too if (state->skip > 0){ if (!skipInFile(state,infile)) { return SCALPEL_ERROR_FILE_READ; } } filebegin = ftello(infile); if ((filesize = measureOpenFile(infile, state)) == -1) { fprintf (stderr, "ERROR: Couldn't measure size of image file %s\n", state->imagefile); return SCALPEL_ERROR_FILE_READ; } // allocate memory for carvelists--we alloc a queue for each // SIZE_OF_BUFFER bytes in advance because it's simpler and an empty // queue doesn't consume much memory, anyway. carvelists = malloc(sizeof(Queue) * (2 + ( filesize / SIZE_OF_BUFFER))); checkMemoryAllocation(state, carvelists, __LINE__, __FILE__, "carvelists"); // queue associated with each buffer of data holds pointers to // CarveInfo structures. fprintf(stdout, "Allocating work queues...\n"); for (i=0; i < 2 + (filesize / SIZE_OF_BUFFER); i++) { init_queue(&carvelists[i], sizeof(struct CarveInfo *), TRUE, 0); } fprintf(stdout, "Work queues allocation complete. Building carve lists...\n"); // build carvelists before 2nd pass over image file for (needlenum=0; state->SearchSpec[needlenum].suffix != NULL; needlenum++) { currentneedle = &(state->SearchSpec[needlenum]); // handle each discovered header independently prevstopindex = 0; for (i=0; i < currentneedle->offsets.numheaders; i++) { start = currentneedle->offsets.headers[i]; // block aligned test for "-q" if (state->blockAlignedOnly && start % state->alignedblocksize != 0) { continue; } stop=0; chopped=0; // case 1: no footer defined for this file type if (! currentneedle->endlength) { // this is the unfortunate case--if file type doesn't have a footer, // all we can done is carve a block between header position and // maximum carve size. stop = start + currentneedle->length - 1; // these are always considered chopped, because we don't really // know the actual size chopped=1; } else if (currentneedle->searchtype == SEARCHTYPE_FORWARD || currentneedle->searchtype == SEARCHTYPE_FORWARD_NEXT) { // footer defined: use FORWARD or FORWARD_NEXT semantics. // Stop at first occurrence of footer, but for FORWARD, // include the header in the carved file; for FORWARD_NEXT, // don't include footer in carved file. For FORWARD_NEXT, if // no footer is found, then the maximum carve size for this // file type will be used and carving will proceed. For // FORWARD, if no footer is found then no carving will be // performed unless -b was specified on the command line. halt=0; // if (state->ignoreEmbedded) { // adjustForEmbedding(currentneedle, i, &prevstopindex); // } for (j=prevstopindex; j < currentneedle->offsets.numfooters && ! halt; j++) { if (currentneedle->offsets.footers[j] <= start) { prevstopindex=j; } else { halt=1; stop = currentneedle->offsets.footers[j]; if (currentneedle->searchtype == SEARCHTYPE_FORWARD) { // include footer in carved file stop += currentneedle->endlength - 1; } else { // FORWARD_NEXT--don't include footer in carved file stop--; } // sanity check on size of potential file to carve--different // actions depending on FORWARD or FORWARD_NEXT semantics if (stop - start + 1 > currentneedle->length) { if (currentneedle->searchtype == SEARCHTYPE_FORWARD) { // if the user specified -b, then foremost 0.69 // compatibility is desired: carve this file even // though the footer wasn't found and indicate // the file was chopped, in the log. Otherwise, // carve nothing and move on. if (state->carveWithMissingFooters) { stop = start + currentneedle->length - 1; chopped=1; } else { stop=0; } } else { // footer found for FORWARD_NEXT, but distance exceeds // max carve size for this file type, so use max carve // size as stop stop = start + currentneedle->length - 1; chopped=1; } } } } if (! halt && (currentneedle->searchtype == SEARCHTYPE_FORWARD_NEXT || (currentneedle->searchtype == SEARCHTYPE_FORWARD && state->carveWithMissingFooters))) { // no footer found for SEARCHTYPE_FORWARD_NEXT, or no footer // found for SEARCHTYPE_FORWARD and user specified -b, so just use // max carve size for this file type as stop stop = start + currentneedle->length - 1; } } else { // footer defined: use REVERSE semantics: want matching footer // as far away from header as possible, within maximum carving // size for this file type. Don't bother to look at footers // that can't possibly match a header and remember this info // in prevstopindex, as the next headers will be even deeper // into the image file. Footer is included in carved file for // this type of carve. halt=0; for (j=prevstopindex; j < currentneedle->offsets.numfooters && ! halt; j++) { if (currentneedle->offsets.footers[j] <= start) { prevstopindex=j; } else if (currentneedle->offsets.footers[j] - start <= currentneedle->length) { stop = currentneedle->offsets.footers[j] + currentneedle->endlength - 1; } else { halt=1; } } } // if stop <> 0, then we have enough information to set up a // file carving operation if (stop) { // don't carve past end of image file... stop = stop > filesize ? filesize : stop; // find indices (in SIZE_OF_BUFFER units) of header and // footer, so the carveinfo can be placed into the right // queues. The priority of each element in a queue allows the // appropriate thing to be done (e.g., STARTSTOPCARVE, // STARTCARVE, STOPCARVE, CONTINUECARVE). headerblockindex = start / SIZE_OF_BUFFER; footerblockindex = stop / SIZE_OF_BUFFER; // set up a struct CarveInfo for inclusion into the // appropriate carvelists // generate unique filename for file to carve if (state->organizeSubdirectories) { snprintf(orgdir, MAX_STRING_LENGTH, "%s/%s-%d-%1lu", state->outputdirectory, currentneedle->suffix, needlenum, currentneedle->organizeDirNum); if (! state->previewMode) { #ifdef __WIN32 mkdir(orgdir); #else mkdir(orgdir, 0777); #endif } } else { snprintf(orgdir, MAX_STRING_LENGTH, "%s", state->outputdirectory); } if (state->modeNoSuffix || currentneedle->suffix[0] == SCALPEL_NOEXTENSION) { #ifdef __WIN32 snprintf(fn,MAX_STRING_LENGTH,"%s/%08I64u", orgdir, state->fileswritten); #else snprintf(fn,MAX_STRING_LENGTH,"%s/%08llu", orgdir, state->fileswritten); #endif } else { #ifdef __WIN32 snprintf(fn,MAX_STRING_LENGTH,"%s/%08I64u.%s", orgdir, state->fileswritten, currentneedle->suffix); #else snprintf(fn,MAX_STRING_LENGTH,"%s/%08llu.%s", orgdir, state->fileswritten, currentneedle->suffix); #endif } state->fileswritten++; currentneedle->numfilestocarve++; if (currentneedle->numfilestocarve % state->organizeMaxFilesPerSub == 0) { currentneedle->organizeDirNum++; } carveinfo = malloc(sizeof(struct CarveInfo)); checkMemoryAllocation(state, carveinfo, __LINE__, __FILE__, "carveinfo"); // remember filename carveinfo->filename=malloc(strlen(fn)+1); checkMemoryAllocation(state, carveinfo->filename, __LINE__, __FILE__, "carveinfo"); strcpy(carveinfo->filename, fn); carveinfo->start = start; carveinfo->stop = stop; carveinfo->chopped = chopped; // fp will be allocated when the first byte of the file is // in the current buffer and cleaned up when we encounter the // last byte of the file. carveinfo->fp = 0; if (headerblockindex == footerblockindex) { // header and footer will both appear in the same buffer add_to_queue(&carvelists[headerblockindex], &carveinfo, STARTSTOPCARVE); } else { // header/footer will appear in different buffers, add carveinfo to // stop and start lists... add_to_queue(&carvelists[headerblockindex], &carveinfo, STARTCARVE); add_to_queue(&carvelists[footerblockindex], &carveinfo, STOPCARVE); // .. and to all lists in between (these will result in a full // SIZE_OF_BUFFER bytes being carved into the file). for (j=headerblockindex+1; j < footerblockindex; j++) { add_to_queue(&carvelists[j], &carveinfo, CONTINUECARVE); } } } } } fprintf(stdout, "Carve lists built. Workload:\n"); for (needlenum=0; state->SearchSpec[needlenum].suffix != NULL; needlenum++) { currentneedle = &(state->SearchSpec[needlenum]); fprintf(stdout, "%s with header \"", currentneedle->suffix); printhex(currentneedle->begin, currentneedle->beginlength); fprintf(stdout,"\" and footer \""); if (currentneedle->end == 0) { fprintf(stdout,"NONE"); } else { printhex(currentneedle->end, currentneedle->endlength); } #ifdef __WIN32 fprintf(stdout,"\" --> %I64u files\n", currentneedle->numfilestocarve); #else fprintf(stdout,"\" --> %llu files\n", currentneedle->numfilestocarve); #endif } if (state->previewMode) { fprintf(stdout, "** PREVIEW MODE: GENERATING AUDIT LOG ONLY **\n"); fprintf(stdout, "** NO CARVED FILES WILL BE WRITTEN **\n"); } fprintf(stdout, "Carving files from image.\n"); fprintf(stdout, "Image file pass 2/2.\n"); // now read image file in SIZE_OF_BUFFER-sized windows, writing // carved files to output directory success=1; while (success) { unsigned long long biglseek=0L; // goal: skip reading buffers for which there is no work to do by using one big // seek fileposition = ftello_use_coverage_map(state, infile); while (queue_length(&carvelists[fileposition / SIZE_OF_BUFFER]) == 0 && success) { biglseek += SIZE_OF_BUFFER; fileposition += SIZE_OF_BUFFER; success = fileposition <= filesize; } if (success && biglseek) { fseeko_use_coverage_map(state, infile, biglseek); } if (! success) { // not an error--just means we've exhausted the image file--show // progress report then quit carving displayPosition(&displayUnits,filesize, filesize,state->imagefile); continue; } if (! state->previewMode) { bytesread = fread_use_coverage_map(state,readbuffer,1,SIZE_OF_BUFFER, infile); // Check for read errors if ((err = ferror(infile))) { return SCALPEL_ERROR_FILE_READ; } else if (bytesread == 0) { // no error, but image file exhausted success=0; continue; } } else { // in preview mode, seeks are used in the 2nd pass instead of // reads. This isn't optimal, but it's fast enough and avoids // complicating the file carving code further. fileposition = ftello_use_coverage_map(state, infile); fseeko_use_coverage_map(state, infile, SIZE_OF_BUFFER); bytesread = ftello_use_coverage_map(state, infile) - fileposition; // Check for errors if ((err = ferror(infile))) { return SCALPEL_ERROR_FILE_READ; } else if (bytesread == 0) { // no error, but image file exhausted success=0; continue; } } success=1; // progress report needs real file position fileposition = ftello(infile); displayPosition(&displayUnits,fileposition-filebegin, filesize,state->imagefile); // if using coverage map for carving, need adjusted file position fileposition = ftello_use_coverage_map(state, infile); // signal check if (signal_caught == SIGTERM || signal_caught == SIGINT) { clean_up(state,signal_caught); } // deal with work for this SIZE_OF_BUFFER-sized block by // examining the associated queue rewind_queue(&carvelists[(fileposition-bytesread) / SIZE_OF_BUFFER]); while (! end_of_queue(&carvelists[(fileposition-bytesread) / SIZE_OF_BUFFER])) { struct CarveInfo *carve; int operation; unsigned long long bytestowrite=0, byteswritten=0, offset=0; peek_at_current(&carvelists[(fileposition-bytesread) / SIZE_OF_BUFFER], &carve); operation = current_priority(&carvelists[(fileposition-bytesread)/SIZE_OF_BUFFER]); // open file, if beginning of carve operation or file had to be closed // previously due to resource limitations if (operation == STARTSTOPCARVE || operation == STARTCARVE || carve->fp == 0) { if (! state->previewMode && state->modeVerbose) { fprintf(stdout, "OPENING %s\n", carve->filename); } carve->fp=(FILE *)1; if (! state->previewMode) { carve->fp = fopen(carve->filename,"ab"); } if (! carve->fp) { fprintf (stderr, "Error opening file: %s -- %s\n", carve->filename, strerror(errno)); fprintf (state->auditFile, "Error opening file: %s -- %s\n", carve->filename, strerror(errno)); return SCALPEL_ERROR_FILE_WRITE; } else { CURRENTFILESOPEN++; } } // write some portion of current readbuffer switch (operation) { case CONTINUECARVE: offset=0; bytestowrite=SIZE_OF_BUFFER; break; case STARTSTOPCARVE: offset=carve->start - (fileposition-bytesread); bytestowrite = carve->stop - carve->start + 1; break; case STARTCARVE: offset = carve->start - (fileposition-bytesread); bytestowrite = (carve->stop - carve->start + 1) > (SIZE_OF_BUFFER - offset) ? (SIZE_OF_BUFFER - offset) : (carve->stop - carve->start + 1); break; case STOPCARVE: offset = 0; bytestowrite=carve->stop - (fileposition-bytesread) + 1; break; } if (! state->previewMode) { if ((byteswritten = fwrite(readbuffer + offset, sizeof(char), bytestowrite, carve->fp)) != bytestowrite) { fprintf(stderr,"Error writing to file: %s -- %s\n", carve->filename, strerror(ferror(carve->fp))); fprintf(state->auditFile,"Error writing to file: %s -- %s\n", carve->filename, strerror(ferror(carve->fp))); return SCALPEL_ERROR_FILE_WRITE; } } // close file, if necessary. Always do it on STARTSTOPCARVE and // STOPCARVE, but also do it if we have a large number of files // open, otherwise we'll run out of available file handles. Updating the // coverage blockmap and auditing is done here, when a file being carved // is closed for the last time. if (operation == STARTSTOPCARVE || operation == STOPCARVE || CURRENTFILESOPEN > MAX_FILES_TO_OPEN) { err=0; if (! state->previewMode) { if (state->modeVerbose) { fprintf(stdout, "CLOSING %s\n", carve->filename); } err = fclose(carve->fp); } if (err) { fprintf(stderr, "Error closing file: %s -- %s\n\n", carve->filename,strerror(ferror(carve->fp))); fprintf(state->auditFile, "Error closing file: %s -- %s\n\n", carve->filename,strerror(ferror(carve->fp))); return SCALPEL_ERROR_FILE_WRITE; } else { CURRENTFILESOPEN--; carve->fp=0; // release filename buffer if it won't be needed again. Don't release it // if the file was closed only because a large number of files are currently // open! if (operation == STARTSTOPCARVE || operation == STOPCARVE) { auditUpdateCoverageBlockmap(state, carve); free(carve->filename); } } } next_element(&carvelists[(fileposition-bytesread) / SIZE_OF_BUFFER]); } } closeFile(infile); // write header/footer database, if necessary, before // cleanup for current image file. if (state->generateHeaderFooterDatabase) { if ((err = writeHeaderFooterDatabase(state)) != SCALPEL_OK) { return err; } } // tear down coverage maps, if necessary destroyCoverageMaps(state); printf("Processing of image file complete. Cleaning up...\n"); // tear down header/footer databases for (needlenum=0; state->SearchSpec[needlenum].suffix != NULL; needlenum++) { currentneedle = &(state->SearchSpec[needlenum]); if (currentneedle->offsets.headers) { free(currentneedle->offsets.headers); } if (currentneedle->offsets.footers) { free(currentneedle->offsets.footers); } currentneedle->offsets.headers=0; currentneedle->offsets.footers=0; currentneedle->offsets.numheaders=0; currentneedle->offsets.numfooters=0; currentneedle->offsets.headerstorage=0; currentneedle->offsets.footerstorage=0; } // tear down work queues--no memory deallocation for each queue // entry required, because memory associated with fp and the // filename was freed after the carved file was closed. // destroy queues for (i=0; i < 2 + (filesize / SIZE_OF_BUFFER); i++) { destroy_queue(&carvelists[i]); } // destroy array of queues free(carvelists); printf("Done."); return SCALPEL_OK; } // write header/footer database for current image file into the // Scalpel output directory. No information is written into the // database for file types without a suffix. The filename used // is the current image filename with ".hfd" appended. The // format of the database file is straightforward: // // suffix_#1 (string) // number_of_headers (unsigned long long) // header_pos_#1 (unsigned long long) // header_pos_#2 (unsigned long long) // ... // number_of_footers (unsigned long long) // footer_pos_#1 (unsigned long long) // footer_pos_#2 (unsigned long long) // ... // suffix_#2 (string) // number_of_headers (unsigned long long) // header_pos_#1 (unsigned long long) // header_pos_#2 (unsigned long long) // ... // number_of_footers (unsigned long long) // footer_pos_#1 (unsigned long long) // footer_pos_#2 (unsigned long long) // ... // ... // // If state->useCoverageBlockmap, then translation is required to // produce real disk image addresses for the generated header/footer // database file, because the Scalpel carving engine isn't aware of // gaps created by blocks that are covered by previously carved files. static int writeHeaderFooterDatabase(struct scalpelState *state) { FILE *dbfile; char fn[MAX_STRING_LENGTH]; // filename for header/footer database int needlenum; struct SearchSpecLine *currentneedle; int i; // generate unique name for header/footer database snprintf(fn,MAX_STRING_LENGTH,"%s/%s.hfd", state->outputdirectory, base_name(state->imagefile)); if ((dbfile = fopen(fn,"w")) == NULL) { fprintf(stderr,"Error writing to header/footer database file: %s\n", fn); fprintf(state->auditFile, "Error writing to header/footer database file: %s\n", fn); return SCALPEL_ERROR_FILE_WRITE; } #ifdef __WIN32 // set binary mode for Win32 setmode(fileno(dbfile),O_BINARY); #endif #ifdef __LINUX fcntl(fileno(dbfile),F_SETFL, O_LARGEFILE); #endif for (needlenum=0; state->SearchSpec[needlenum].suffix != NULL; needlenum++) { currentneedle = &(state->SearchSpec[needlenum]); if (currentneedle->suffix[0] != SCALPEL_NOEXTENSION) { // output current suffix if (fprintf(dbfile, "%s\n", currentneedle->suffix) <= 0) { fprintf(stderr,"Error writing to header/footer database file: %s\n", fn); fprintf(state->auditFile, "Error writing to header/footer database file: %s\n", fn); return SCALPEL_ERROR_FILE_WRITE; } // # of headers #ifdef __WIN32 if (fprintf(dbfile, "%I64u\n", currentneedle->offsets.numheaders) <= 0) { #else if (fprintf(dbfile, "%llu\n", currentneedle->offsets.numheaders) <= 0) { #endif fprintf(stderr,"Error writing to header/footer database file: %s\n", fn); fprintf(state->auditFile, "Error writing to header/footer database file: %s\n", fn); return SCALPEL_ERROR_FILE_WRITE; } // all header positions for current suffix for (i=0; i < currentneedle->offsets.numheaders; i++) { #ifdef __WIN32 if (fprintf(dbfile, "%I64u\n", positionUseCoverageBlockmap(state, currentneedle->offsets.headers[i])) <= 0) { #else if (fprintf(dbfile, "%llu\n", positionUseCoverageBlockmap(state, currentneedle->offsets.headers[i])) <= 0) { #endif fprintf(stderr,"Error writing to header/footer database file: %s\n", fn); fprintf(state->auditFile, "Error writing to header/footer database file: %s\n", fn); return SCALPEL_ERROR_FILE_WRITE; } } // # of footers #ifdef __WIN32 if (fprintf(dbfile, "%I64u\n", currentneedle->offsets.numfooters) <= 0) { #else if (fprintf(dbfile, "%llu\n", currentneedle->offsets.numfooters) <= 0) { #endif fprintf(stderr,"Error writing to header/footer database file: %s\n", fn); fprintf(state->auditFile, "Error writing to header/footer database file: %s\n", fn); return SCALPEL_ERROR_FILE_WRITE; } // all footer positions for current suffix for (i=0; i < currentneedle->offsets.numfooters; i++) { #ifdef __WIN32 if (fprintf(dbfile, "%I64u\n", positionUseCoverageBlockmap(state, currentneedle->offsets.footers[i])) <= 0) { #else if (fprintf(dbfile, "%llu\n", positionUseCoverageBlockmap(state, currentneedle->offsets.footers[i])) <= 0) { #endif fprintf(stderr,"Error writing to header/footer database file: %s\n", fn); fprintf(state->auditFile, "Error writing to header/footer database file: %s\n", fn); return SCALPEL_ERROR_FILE_WRITE; } } } } fclose(dbfile); return SCALPEL_OK; } // The coverage blockmap illustrates which blocks (of a // user-specified size) have been "covered" by a carved file. // The filename used for the coverage bitmap is the current // image filename with ".map" appended, generated in a // user-specified directory. If the coverage blockmap is to be // modified, check to see if it exists. If it does, then open // it and set the file handle in the Scalpel state. If it // doesn't, create a zeroed copy and set the file handle in the // Scalpel state. If the coverage blockmap is guiding carving, // then create the coverage bitmap and initialize it using the // coverage blockmap file. The difference between the coverage // blockmap (on disk) and the coverage bitmap (in memory) is // that the blockmap counts carved files that cover a block. // The coverage bitmap only indicates if ANY carved file covers // a block. 'filesize' is the size of the image file being // examined. static int setupCoverageMaps(struct scalpelState *state, unsigned long long filesize) { char fn[MAX_STRING_LENGTH]; // filename for coverage blockmap unsigned long long i, k; int empty; unsigned int blocksize, entry; state->coveragebitmap=0; state->coverageblockmap=0; if (state->modeVerbose && (state->useCoverageBlockmap || state->updateCoverageBlockmap)) { fprintf(stdout, "Setting up coverage maps.\n"); } if (state->updateCoverageBlockmap || state->useCoverageBlockmap) { // generate pathname for coverage blockmap snprintf(fn,MAX_STRING_LENGTH,"%s/%s.map", state->coveragedirectory, base_name(state->imagefile)); if (state->modeVerbose) { fprintf(stdout, "Coverage blockmap is \"%s\".\n", fn); } empty = ((state->coverageblockmap = fopen(fn,"rb")) == NULL); if (state->modeVerbose) { fprintf(stdout, "Coverage blockmap file is %s.\n", (empty?"EMPTY":"NOT EMPTY")); } if (! empty) { #ifdef __WIN32 // set binary mode for Win32 setmode(fileno(state->coverageblockmap),O_BINARY); #endif #ifdef __LINUX fcntl(fileno(state->coverageblockmap),F_SETFL, O_LARGEFILE); #endif if (state->modeVerbose) { fprintf(stdout, "Reading blocksize from Coverage blockmap file.\n"); } // read block size and make sure it matches user-specified block size if (fread(&blocksize, sizeof(unsigned int), 1, state->coverageblockmap) != 1) { fprintf(stderr,"Error reading coverage blockmap blocksize in\ncoverage blockmap file: %s\n", fn); fprintf(state->auditFile, "Error reading coverage blockmap blocksize in\ncoverage blockmap file: %s\n", fn); return SCALPEL_ERROR_FATAL_READ; } if (state->useCoverageBlockmap && ! state->updateCoverageBlockmap) { // just use blocksize in blockmap coverage file state->coverageblocksize = blocksize; if (state->modeVerbose) { fprintf(stdout, "Blocksize for coverage blockmap is %u.\n", state->coverageblocksize); } } else if (blocksize != state->coverageblocksize) { fprintf(stderr,"User-specified blocksize does not match blocksize in\ncoverage blockmap file: %s\n", fn); fprintf(state->auditFile, "User-specified blocksize does not match blocksize in\ncoverage blockmap file: %s\n", fn); return SCALPEL_GENERAL_ABORT; } state->coveragenumblocks=ceil((double)filesize / (double)state->coverageblocksize); if (state->modeVerbose) { #ifdef __WIN32 fprintf(stdout, "# of blocks in coverage blockmap is %I64u.\n", state->coveragenumblocks); #else fprintf(stdout, "# of blocks in coverage blockmap is %llu.\n", state->coveragenumblocks); #endif } if (state->useCoverageBlockmap) { if (state->modeVerbose) { fprintf(stdout, "Allocating and clearing coverage bitmap.\n"); } // for bitmap, 8 bits per unsigned char, with each bit representing one // block state->coveragebitmap = malloc((state->coveragenumblocks / 8) * sizeof(unsigned char)); checkMemoryAllocation(state, state->coveragebitmap, __LINE__, __FILE__, "coveragebitmap"); // zap coverage bitmap for (k=0; k < state->coveragenumblocks / 8; k++) { state->coveragebitmap[k]=0; } fprintf(stdout, "Reading existing coverage blockmap...this may take a while.\n"); for (i=0; i < state->coveragenumblocks; i++) { fseeko(state->coverageblockmap, (i + 1) * sizeof(unsigned int), SEEK_SET); if (fread(&entry, sizeof(unsigned int), 1, state->coverageblockmap) != 1) { fprintf(stderr,"Error reading coverage blockmap entry (blockmap truncated?): %s\n", fn); fprintf(state->auditFile, "Error reading coverage blockmap entry (blockmap truncated?): %s\n", fn); return SCALPEL_ERROR_FATAL_READ; } if (entry) { state->coveragebitmap[i / 8] |= 1 << (i % 8); } } } } else if (empty && state->useCoverageBlockmap) { fprintf(stderr,"-u option requires that the blockmap file %s exist.\n", fn); fprintf(state->auditFile, "-u option requires that the blockmap file %s exist.\n", fn); return SCALPEL_GENERAL_ABORT; } else { state->coveragenumblocks=ceil((double)filesize / (double)state->coverageblocksize); if (state->modeVerbose) { #ifdef __WIN32 fprintf(stdout, "# of blocks in coverage blockmap is %I64u.\n", state->coveragenumblocks); #else fprintf(stdout, "# of blocks in coverage blockmap is %llu.\n", state->coveragenumblocks); #endif } } // change mode to read/write for future updates if coverage blockmap will be updated if (state->updateCoverageBlockmap) { if (state->modeVerbose) { fprintf(stdout, "Changing mode of coverage blockmap file to R/W.\n"); } if (! empty) { fclose(state->coverageblockmap); } if ((state->coverageblockmap = fopen(fn,(empty?"w+b":"r+b"))) == NULL) { fprintf(stderr,"Error writing to coverage blockmap file: %s\n", fn); fprintf(state->auditFile, "Error writing to coverage blockmap file: %s\n", fn); return SCALPEL_ERROR_FILE_WRITE; } #ifdef __WIN32 // set binary mode for Win32 setmode(fileno(state->coverageblockmap),O_BINARY); #endif #ifdef __LINUX fcntl(fileno(state->coverageblockmap),F_SETFL, O_LARGEFILE); #endif if (empty) { // create entries in empty coverage blockmap file fprintf(stdout, "Writing empty coverage blockmap...this may take a while.\n"); entry=0; if (fwrite(&(state->coverageblocksize), sizeof(unsigned int), 1, state->coverageblockmap) != 1) { fprintf(stderr,"Error writing initial entry in coverage blockmap file!\n"); fprintf(state->auditFile, "Error writing initial entry in coverage blockmap file!\n"); return SCALPEL_ERROR_FILE_WRITE; } for (k=0; k < state->coveragenumblocks; k++) { if (fwrite(&entry, sizeof(unsigned int), 1, state->coverageblockmap) != 1) { fprintf(stderr,"Error writing to coverage blockmap file!\n"); fprintf(state->auditFile, "Error writing to coverage blockmap file!\n"); return SCALPEL_ERROR_FILE_WRITE; } } } } } if (state->modeVerbose && (state->useCoverageBlockmap || state->updateCoverageBlockmap)) { printf("Finished setting up coverage maps.\n"); } return SCALPEL_OK; } // map carve->start ... carve->stop into a queue of 'fragments' that // define a carved file in the disk image. static void generateFragments(struct scalpelState *state, Queue *fragments, CarveInfo *carve) { unsigned long long curblock, neededbytes=carve->stop - carve->start + 1, bytestoskip, morebytes, totalbytes=0, curpos; Fragment frag; init_queue(fragments, sizeof(struct Fragment), TRUE, 0); if (! state->useCoverageBlockmap) { // no translation necessary frag.start = carve->start; frag.stop = carve->stop; add_to_queue(fragments, &frag, 0); return; } else { curpos = positionUseCoverageBlockmap(state, carve->start); curblock= curpos / state->coverageblocksize; while (totalbytes < neededbytes && curblock < state->coveragenumblocks) { morebytes=0; bytestoskip=0; // skip covered blocks while (curblock < state->coveragenumblocks && (state->coveragebitmap[curblock / 8] & (1 << (curblock % 8)))) { bytestoskip += state->coverageblocksize - curpos % state->coverageblocksize; curblock++; } curpos += bytestoskip; // accumulate uncovered blocks in fragment while (curblock < state->coveragenumblocks && ((state->coveragebitmap[curblock / 8] & (1 << (curblock % 8))) == 0) && totalbytes + morebytes < neededbytes) { morebytes += state->coverageblocksize - curpos % state->coverageblocksize; curblock++; } // cap size if (totalbytes + morebytes > neededbytes) { morebytes = neededbytes - totalbytes; } frag.start=curpos; curpos += morebytes; frag.stop=curpos-1; totalbytes += morebytes; add_to_queue(fragments, &frag, 0); } } } // If the coverage blockmap is used to guide carving, then use the // coverage blockmap to map a logical index in the disk image (i.e., // the index skips covered blocks) to an actual disk image index. If // the coverage blockmap isn't being used, just returns the second // argument. // // ***This function assumes that the 'position' does NOT lie // within a covered block! *** static unsigned long long positionUseCoverageBlockmap(struct scalpelState *state, unsigned long long position) { unsigned long long totalbytes=0, neededbytes=position, morebytes, curblock=0, curpos=0, bytestoskip; if (! state->useCoverageBlockmap) { return position; } else { while (totalbytes < neededbytes && curblock < state->coveragenumblocks) { morebytes=0; bytestoskip=0; // skip covered blocks while (curblock < state->coveragenumblocks && (state->coveragebitmap[curblock / 8] & (1 << (curblock % 8)))) { bytestoskip += state->coverageblocksize - curpos % state->coverageblocksize; curblock++; } curpos += bytestoskip; // accumulate uncovered blocks while (curblock < state->coveragenumblocks && ((state->coveragebitmap[curblock / 8] & (1 << (curblock % 8))) == 0) && totalbytes + morebytes < neededbytes) { morebytes += state->coverageblocksize - curpos % state->coverageblocksize; curblock++; } // cap size if (totalbytes + morebytes > neededbytes) { morebytes = neededbytes - totalbytes; } curpos += morebytes; totalbytes += morebytes; } return curpos; } } // update the coverage blockmap for a carved file (if appropriate) and write entries into // the audit log describing the carved file. If the file is fragmented, then multiple // lines are written to indicate where the fragments occur. static int auditUpdateCoverageBlockmap(struct scalpelState *state, struct CarveInfo *carve) { struct Queue fragments; Fragment *frag; int k, err; // If the coverage blockmap used to guide carving, then carve->start and // carve->stop may not correspond to addresses in the disk image--the coverage blockmap // processing layer in Scalpel may have skipped "in use" blocks. Transform carve->start // and carve->stop into a list of fragments that contain real disk image offsets. generateFragments(state, &fragments, carve); rewind_queue(&fragments); while (! end_of_queue(&fragments)) { frag = (Fragment *)pointer_to_current(&fragments); fprintf(state->auditFile,"%s", base_name(carve->filename)); #ifdef __WIN32 fprintf(state->auditFile,"%13I64u\t\t", frag->start); #else fprintf(state->auditFile,"%13llu\t\t", frag->start); #endif fprintf(state->auditFile,"%3s", carve->chopped ? "YES " : "NO "); #ifdef __WIN32 fprintf(state->auditFile,"%13I64u\t\t", frag->stop - frag->start + 1); #else fprintf(state->auditFile,"%13llu\t\t", frag->stop - frag->start + 1); #endif fprintf(state->auditFile,"%s\n", base_name(state->imagefile)); // update coverage blockmap, if appropriate if (state->updateCoverageBlockmap) { for (k=frag->start / state->coverageblocksize; k <= frag->stop / state->coverageblocksize; k++) { if ((err = updateCoverageBlockmap(state, k)) != SCALPEL_OK) { destroy_queue(&fragments); return err; } } } next_element(&fragments); } destroy_queue(&fragments); return SCALPEL_OK; } static int updateCoverageBlockmap(struct scalpelState *state, unsigned long long block) { unsigned int entry; if (state->updateCoverageBlockmap) { // first entry in file is block size, so seek one unsigned int further fseeko(state->coverageblockmap, (block+1) * sizeof(unsigned int), SEEK_SET); if (fread(&entry, sizeof(unsigned int), 1, state->coverageblockmap) != 1) { fprintf(stderr,"Error reading coverage blockmap entry!\n"); fprintf(state->auditFile, "Error reading coverage blockmap entry!\n"); return SCALPEL_ERROR_FATAL_READ; } entry++; // first entry in file is block size, so seek one unsigned int further fseeko(state->coverageblockmap, (block+1) * sizeof(unsigned int), SEEK_SET); if (fwrite(&entry, sizeof(unsigned int), 1, state->coverageblockmap) != 1) { fprintf(stderr,"Error writing to coverage blockmap file!\n"); fprintf(state->auditFile, "Error writing to coverage blockmap file!\n"); return SCALPEL_ERROR_FILE_WRITE; } } return SCALPEL_OK; } static void destroyCoverageMaps(struct scalpelState *state) { // free memory associated with coverage bitmap, close coverage blockmap file if (state->coveragebitmap) { free(state->coveragebitmap); } if (state->useCoverageBlockmap || state->updateCoverageBlockmap) { fclose(state->coverageblockmap); } } // simple wrapper for fseeko with SEEK_CUR semantics that uses the // coverage bitmap to skip over covered blocks, IF the coverage // blockmap is being used. The offset is adjusted so that covered // blocks are silently skipped when seeking if the coverage blockmap // is used, otherwise an fseeko() with an umodified offset is // performed. static int fseeko_use_coverage_map(struct scalpelState *state, FILE *fp, off64_t offset) { off64_t currentpos; unsigned long long curblock, bytestoskip, bytestokeep, totalbytes=0; int sign; if (state->useCoverageBlockmap) { currentpos=ftello(fp); sign = (offset > 0 ? 1 : -1); curblock= currentpos / state->coverageblocksize; while (totalbytes < (offset > 0 ? offset : offset * -1) && curblock < state->coveragenumblocks && curblock >= 0) { bytestoskip=0; // covered blocks increase offset while (curblock < state->coveragenumblocks && curblock >= 0 && (state->coveragebitmap[curblock / 8] & (1 << (curblock % 8)))) { bytestoskip += (state->coverageblocksize - currentpos % state->coverageblocksize); curblock += sign; } offset += (bytestoskip * sign); currentpos += (bytestoskip * sign); bytestokeep=0; // uncovered blocks don't increase offset while (curblock < state->coveragenumblocks && curblock >= 0 && ((state->coveragebitmap[curblock / 8] & (1 << (curblock % 8))) == 0) && totalbytes < (offset > 0 ? offset : offset * -1)) { bytestokeep += (state->coverageblocksize - currentpos % state->coverageblocksize); curblock += sign; } totalbytes += bytestokeep; currentpos += (bytestokeep * sign); } } return fseeko(fp, offset, SEEK_CUR); } // simple wrapper for ftello() that uses the coverage bitmap to // report the current file position *minus* the contribution of // marked blocks, IF the coverage blockmap is being used. If a // coverage blockmap isn't in use, just performs a standard ftello() // call. // // GGRIII: *** This could use optimization, e.g., use of a pre-computed // table to avoid walking the coverage bitmap on each call. static off64_t ftello_use_coverage_map(struct scalpelState *state, FILE *fp) { off64_t currentpos, decrease=0; unsigned long long endblock, k; currentpos=ftello(fp); if (state->useCoverageBlockmap) { endblock = currentpos / state->coverageblocksize; // covered blocks don't contribute to current file position for (k=0; k <= endblock; k++) { if (state->coveragebitmap[k / 8] & (1 << (k % 8))) { decrease += state->coverageblocksize; } } if (state->coveragebitmap[endblock / 8] & (1 << (endblock % 8))) { decrease += (state->coverageblocksize - currentpos % state->coverageblocksize); } if (state->modeVerbose && state->useCoverageBlockmap) { #ifdef __WIN32 fprintf(stdout, "Coverage map decreased current file position by %I64u bytes.\n", (unsigned long long)decrease); #else fprintf(stdout, "Coverage map decreased current file position by %llu bytes.\n", (unsigned long long)decrease); #endif } } return currentpos - decrease; } // simple wrapper for fread() that uses the coverage bitmap--the read silently // skips blocks that are marked covered (corresponding bit in coverage // bitmap is 1) static size_t fread_use_coverage_map(struct scalpelState *state, void *ptr, size_t size, size_t nmemb, FILE *stream) { unsigned long long curblock, neededbytes=nmemb * size, bytestoskip, bytestoread, bytesread, totalbytesread=0, curpos; int shortread; if (state->useCoverageBlockmap) { if (state->modeVerbose) { #ifdef __WIN32 fprintf(stdout, "Issuing coverage map-based READ, wants %I64u bytes.\n", neededbytes); #else fprintf(stdout, "Issuing coverage map-based READ, wants %llu bytes.\n", neededbytes); #endif } curpos = ftello(stream); curblock= curpos / state->coverageblocksize; shortread=0; while (totalbytesread < neededbytes && curblock < state->coveragenumblocks && ! shortread) { bytestoread=0; bytestoskip=0; // skip covered blocks while (curblock < state->coveragenumblocks && (state->coveragebitmap[curblock / 8] & (1 << (curblock % 8)))) { bytestoskip += (state->coverageblocksize - curpos % state->coverageblocksize); curblock++; } curpos += bytestoskip; if (state->modeVerbose) { #ifdef __WIN32 fprintf(stdout, "fread using coverage map to skip %I64u bytes.\n", bytestoskip); #else fprintf(stdout, "fread using coverage map to skip %llu bytes.\n", bytestoskip); #endif } fseeko(stream, (off64_t)bytestoskip, SEEK_CUR); // accumulate uncovered blocks for read while (curblock < state->coveragenumblocks && ((state->coveragebitmap[curblock / 8] & (1 << (curblock % 8))) == 0) && totalbytesread + bytestoread <= neededbytes) { bytestoread += (state->coverageblocksize - curpos % state->coverageblocksize); curblock++; } // cap read size if (totalbytesread + bytestoread > neededbytes) { bytestoread = neededbytes - totalbytesread; } if (state->modeVerbose) { #ifdef __WIN32 fprintf(stdout, "fread using coverage map found %I64u consecutive bytes.\n", bytestoread); #else fprintf(stdout, "fread using coverage map found %llu consecutive bytes.\n", bytestoread); #endif } if ((bytesread=fread((char *)ptr+totalbytesread, 1, (size_t)bytestoread, stream)) < bytestoread) { shortread=1; } totalbytesread += bytesread; curpos += bytestoread; if (state->modeVerbose) { #ifdef __WIN32 fprintf(stdout, "fread using coverage map read %I64u bytes.\n", bytesread); #else fprintf(stdout, "fread using coverage map read %llu bytes.\n", bytesread); #endif } } if (state->modeVerbose) { fprintf(stdout, "Coverage map-based READ complete.\n"); } // conform with fread() semantics by returnign # of items read return totalbytesread / size; } else { return fread(ptr, size, nmemb, stream); } } scalpel-1.60/dirname.h100666 0 0 2712 10445550455 13133 0ustar usergroup/* Copyright (C) 1998, 2001 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, 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; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #ifndef DIRNAME_H_ # define DIRNAME_H_ 1 # ifndef PARAMS # if defined PROTOTYPES || (defined __STDC__ && __STDC__) # define PARAMS(Args) Args # else # define PARAMS(Args) () # endif # endif # ifndef DIRECTORY_SEPARATOR # define DIRECTORY_SEPARATOR '/' # endif # ifndef ISSLASH # define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR) # endif # ifndef FILESYSTEM_PREFIX_LEN # define FILESYSTEM_PREFIX_LEN(Filename) 0 # endif char *base_name PARAMS ((char const *path)); char *dir_name PARAMS ((char const *path)); size_t base_len PARAMS ((char const *path)); size_t dir_len PARAMS ((char const *path)); int strip_trailing_slashes PARAMS ((char *path)); #endif /* not DIRNAME_H_ */ scalpel-1.60/files.c100666 0 0 13774 10501706011 12623 0ustar usergroup// Scalpel Copyright (C) 2005-6 by Golden G. Richard III. // Written by Golden G. Richard III. // // This program is free software; you can redistribute it and/or // modify it 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; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301, USA. // Scalpel is a complete rewrite of the foremost 0.69 file carver to // increase speed and support execution on machines with minimal // resources (e.g., < 256MB RAM). // // Thanks to Kris Kendall, Jesse Kornblum, et al for their work on // foremost. #include "scalpel.h" // Returns TRUE if the directory exists and is empty. // If the directory does not exist, an attempt is made to // create it. On error, returns FALSE int outputDirectoryOK(char *dir) { DIR *temp; struct dirent *entry; int i; mode_t newDirectoryMode; if ((temp = opendir(dir)) == NULL) { // If the directory doesn't exist (ENOENT), we will create it if (errno == ENOENT) { // The directory mode values come from the chmod(2) man page #ifdef __MINGW32__ newDirectoryMode = 0; if(mkdir(dir)){ #else newDirectoryMode = (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH); if (mkdir(dir,newDirectoryMode)) { #endif fprintf (stderr,"An error occured while trying to create %s - %s\n", dir,strerror(errno)); return FALSE; } // try to open directory if ((temp = opendir(dir)) == NULL) { fprintf (stderr,"An error occured while trying to open %s - %s\n", dir,strerror(errno)); return FALSE; } } else { fprintf (stderr,"An error occured while trying to open %s - %s\n", dir,strerror(errno)); return FALSE; } } // verify directory is empty--there should be only two entries, // "." and ".." i=0; while((entry = readdir(temp))) { if (i>1) { fprintf(stderr, NONEMPTYDIR_ERROR_MSG); return FALSE; } i++; } closedir(temp); return TRUE; } // open audit file int openAuditFile(struct scalpelState* state){ time_t now = time(NULL); char* timestring = ctime(&now); char fn[MAX_STRING_LENGTH]; if (!outputDirectoryOK(state->outputdirectory)) { return SCALPEL_ERROR_FILE_OPEN; } snprintf(fn,MAX_STRING_LENGTH,"%s/audit.txt", state->outputdirectory); if (!(state->auditFile = fopen(fn,"w"))) { fprintf(stderr,"Couldn't open %s -- %s\n",fn,strerror(errno)); return SCALPEL_ERROR_FILE_OPEN; } fprintf (state->auditFile, "\nScalpel version %s audit file\n" "Started at %sCommand line:\n%s\n\n" "Output directory: %s\n" "Configuration file: %s\n", SCALPEL_VERSION, timestring, state->invocation, state->outputdirectory,state->conffile); return SCALPEL_OK; } int closeFile(FILE* f) { time_t now = time(NULL); char* timestring = ctime(&now); fprintf (f, "\n\nCompleted at %s", timestring); if (fclose(f)) { return SCALPEL_ERROR_FILE_CLOSE; } return SCALPEL_OK; } // helper function for measureOpenFile(), based on e2fsprogs utility // function valid_offset() static int valid_offset(int fd, off64_t offset) { char ch; if (lseek(fd, offset, SEEK_SET) < 0) { return 0; } if (read(fd, &ch, 1) < 1) { return 0; } return 1; } // Return the remaining size, in bytes, of an open file stream. On // error, return -1. Handling raw device files is substantially more // complicated than image files. For Linux, an ioctl() is used. For // other operating systems, a "binary search" technique similar to // that in e2fsprogs getsize.c is used. unsigned long long measureOpenFile(FILE *f, struct scalpelState* state) { unsigned long long total = 0, original = ftello(f); int descriptor = 0; struct stat *info; unsigned long long numsectors = 0; if ((fseeko(f,0,SEEK_END))) { if (state->modeVerbose) { fprintf(stdout, "fseeko() call failed on image file.\n"); fprintf(stdout, "Diagnosis: %s\n", strerror(errno)); } return -1; } total = ftello(f); // for block devices (e.g., raw disk devices), calculating size by // seeking the end of the opened stream doesn't work. For Linux, we use // an ioctl() call. For others (e.g., OS X), we use binary search. // is it a block device? descriptor = fileno(f); info = (struct stat*)malloc(sizeof(struct stat)); fstat(descriptor,info); if (S_ISBLK(info->st_mode)) { #if defined (__LINUX) if (ioctl(descriptor, BLKGETSIZE, &numsectors) < 0) { if (state->modeVerbose) { fprintf(stdout, "Using ioctl() call to measure block device size.\n"); } #if defined(__DEBUG) perror("BLKGETSIZE failed"); #endif } #else // non-Linux, use binary search { unsigned long long low, high, mid; fprintf(stdout, "Using binary search to measure block device size.\n"); low = 0; for (high = 512; valid_offset(descriptor, high); high *= 2) { low = high; } while (low < high - 1) { mid = (low + high) / 2; if (valid_offset(descriptor, mid)) { low = mid; } else { high = mid; } } numsectors = (low + 1) >> 9; } #endif // assume device has 512 byte sectors total = numsectors * 512; free(info); } // restore file position if ((fseeko(f,original,SEEK_SET))) { if (state->modeVerbose) { fprintf(stdout, "fseeko() call to restore file position failed on image file.\n"); } return -1; } return (total - original); } scalpel-1.60/gpl.txt100666 0 0 43103 10470507451 12701 0ustar usergroup GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it 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; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. scalpel-1.60/helpers.c100666 0 0 25272 10536334272 13175 0ustar usergroup// Scalpel Copyright (C) 2005-6 by Golden G. Richard III. // Written by Golden G. Richard III. // // This program is free software; you can redistribute it and/or // modify it 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; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301, USA. // Scalpel is a complete rewrite of the foremost 0.69 file carver to // increase speed and support execution on machines with minimal // resources (e.g., < 256MB RAM). // // Thanks to Kris Kendall, Jesse Kornblum, et al for their work on // foremost. #include "scalpel.h" void checkMemoryAllocation(struct scalpelState *state, void *ptr, int line, char *file, char *structure) { if (ptr) { return; } else { fprintf(stderr, "** MEMORY ALLOCATION FAILURE **\n"); fprintf (stderr, "ERROR: Memory exhausted at line %d in file %s. Scalpel was \n", line, file); fprintf(stderr, "allocating memory for %s when this condition occurred.\n", structure); fprintf (state->auditFile, "ERROR: Memory exhausted at line %d in file %s. Scalpel was \n", line, file); fprintf(state->auditFile, "allocating memory for %s when this condition occurred.\n", structure); handleError(state, SCALPEL_GENERAL_ABORT); // fatal } } #ifndef __GLIBC__ void setProgramName(char *s) { char *fn = (char *)malloc(sizeof(char) * PATH_MAX); if (realpath(s,fn) == NULL) { __progname = strdup("scalpel"); return; } __progname = basename(fn); } #endif /* ifndef __GLIBC__ */ // write entry to both the screen and the audit file void scalpelLog(struct scalpelState *state, char *format, ...) { va_list argp; va_start(argp,format); vfprintf (stderr,format,argp); vfprintf (state->auditFile,format,argp); va_end(argp); } // determine if two characters match, with optional case // insensitivity. If a is the Scalpel wildcard character, // then a and b will always match. int charactersMatch(char a, char b, int caseSensitive) { if (a == wildcard || a == b) { return 1; } if (caseSensitive || (a < 'A' || a > 'z' || b < 'A' || b > 'z')) { return 0; } /* This line is equivalent to (abs(a-b)) == 'a' - 'A' */ return (abs(a-b) == 32); } // memwildcardcmp is a memcmp() clone, except that single // character wildcards are supported. The default wildcard character is '?', // but this can be redefined in the configuration file. A wildcard in s1 will // match any single character in s2. int memwildcardcmp(const void *s1, const void *s2, size_t n,int caseSensitive){ if (n != 0) { register const unsigned char *p1 = s1, *p2 = s2; do { if (!charactersMatch(*p1++, *p2++, caseSensitive)) { return (*--p1 - *--p2); } } while (--n !=0); } return 0; } // initialize Boyer-Moore "jump table" for search. Dependence // on search type (e.g., FORWARD, REVERSE, etc.) from Foremost // has been removed, because Scalpel always performs searches across // a buffer in a forward direction. void init_bm_table(char *needle, size_t table[UCHAR_MAX + 1], size_t len, int casesensitive) { size_t i=0,j=0,currentindex=0; for (i = 0; i <= UCHAR_MAX; i++) { table[i] = len; } for (i = 0; i < len; i++) { currentindex = len-i-1; //Count from the back of string //No skip entry can advance us past the last wildcard in the string if (needle[i] == wildcard) { for (j=0; j<=UCHAR_MAX; j++) { table[j] = currentindex; } } table[(unsigned char)needle[i]] = currentindex; if (! casesensitive && needle[i] > 0) { table[tolower(needle[i])] = currentindex; table[toupper(needle[i])] = currentindex; } } } // Perform a modified Boyer-Moore string search, supporting wildcards, // case-insensitive searches, and specifiable start locations in the buffer. // Dependence on search type (e.g., FORWARD, REVERSe, etc.) from Foremost has // been removed, because Scalpel always performs forward searching. char *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) { register size_t shift=0; register size_t pos = start_pos; char *here; if(needle_len == 0) { return haystack; } while (pos < haystack_len){ while( pos < haystack_len && (shift = table[(unsigned char)haystack[pos]]) > 0) { pos += shift; } if (0 == shift) { if (0 == memwildcardcmp(needle,here = (char *)&haystack[pos-needle_len+1], needle_len, casesensitive)) { return(here); } else { pos++; } } } return NULL; } char *bm_needleinhaystack(char *needle, size_t needle_len, char *haystack, size_t haystack_len, size_t table[UCHAR_MAX + 1], int casesensitive) { return bm_needleinhaystack_skipnchars(needle, needle_len, haystack, haystack_len, table, casesensitive, needle_len - 1); } // find longest header OR footer int findLongestNeedle(struct SearchSpecLine *SearchSpec) { int longest = 0; int i=0; for(i=0; SearchSpec[i].suffix != NULL; i++) { if (SearchSpec[i].beginlength > longest) { longest = SearchSpec[i].beginlength; } if (SearchSpec[i].endlength > longest) { longest = SearchSpec[i].endlength; } } return longest; } // decode strings with embedded escape sequences and return the total length of the // translated string. int translate(char *str) { char next; char *rd=str,*wr=str,*bad; char temp[1+3+1]; char ch; if(!*rd) { //If it's a null string just return return 0; } while (*rd) { // Is it an escaped character? if (*rd=='\\') { rd++; switch(*rd) { case '\\': rd++;*(wr++)='\\'; break; case 'a': rd++;*(wr++)='\a'; break; case 's': rd++;*(wr++)=' '; break; case 'n': rd++;*(wr++)='\n'; break; case 'r': rd++;*(wr++)='\r'; break; case 't': rd++;*(wr++)='\t'; break; case 'v': rd++;*(wr++)='\v'; break; // Hexadecimal/Octal values are treated in one place using strtoul() case 'x': case '0': case '1': case '2': case '3': next = *(rd+1); if (next < 48 || (57 < next && next < 65) || (70 < next && next < 97) || next > 102) break; //break if not a digit or a-f, A-F next = *(rd+2); if (next < 48 || (57 < next && next < 65) || (70 < next && next < 97) || next > 102) break; //break if not a digit or a-f, A-F temp[0]='0'; bad=temp; strncpy(temp+1,rd,3); temp[4] = '\0'; ch=strtoul(temp,&bad,0); if (*bad=='\0') { *(wr++)=ch; rd+=3; } // else INVALID CHARACTER IN INPUT ('\\' followed by *rd) break; default: // INVALID CHARACTER IN INPUT (*rd) *(wr++)='\\'; break; } } // just copy un-escaped characters else { *(wr++)=*(rd++); } } *wr = '\0'; // null termination return wr-str; } // skip leading whitespace char *skipWhiteSpace(char* str) { while (isspace(str[0])) { str++; } return str; } // describe Scalpel error conditions. Some errors are fatal, while // others are advisory. void handleError(struct scalpelState *state, int error) { switch(error) { case SCALPEL_ERROR_FILE_OPEN: // non-fatal scalpelLog(state,"Scalpel was unable to open the image file: %s\n" "Skipping...\n\n", state->imagefile); break; case SCALPEL_ERROR_FILE_READ: // non-fatal scalpelLog(state,"Scalpel was unable to read the image file: %s\n" "Skipping...\n\n", state->imagefile); break; case SCALPEL_ERROR_FATAL_READ: // fatal scalpelLog(state,"Scalpel was unable to read a needed file and will abort.\n"); closeFile(state->auditFile); exit (-1); break; case SCALPEL_ERROR_FILE_WRITE: // fatal--unable to write files, which may mean that disk space is exhausted. fprintf(stderr, "Scalpel was unable to write output files and will abort.\n"); fprintf(stderr, "This error generally indicates that disk space is exhausted.\n"); closeFile(state->auditFile); exit (-1); case SCALPEL_ERROR_NO_SEARCH_SPEC: // fatal, configuration file didn't specify anything to carve scalpelLog(state, "ERROR: The configuration file didn't specify any file types to carve.\n"); scalpelLog(state, "(If you're using the default configuration file, you'll have to\n"); scalpelLog(state, "uncomment some of the file types.)\n"); closeFile(state->auditFile); exit (-1); case SCALPEL_GENERAL_ABORT: // fatal scalpelLog(state,"Scalpel will abort.\n"); closeFile(state->auditFile); exit (-1); break; default: // fatal scalpelLog(state, "Scalpel has encountered an error it doesn't know" "how to handle.\nError code: %d\n", error); closeFile(state->auditFile); exit (-1); } } void setttywidth(){ #if defined (__WIN32) CONSOLE_SCREEN_BUFFER_INFO csbi; HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); if(! GetConsoleScreenBufferInfo(hConsole, &csbi)){ ttywidth = 80; }else{ ttywidth = csbi.dwSize.X; } #else //#if defined(__BSD) // ttywidth = 80; //#else struct winsize winsize; if(ioctl(fileno(stdout),TIOCGWINSZ, &winsize) != -1) { ttywidth = winsize.ws_col; } else { // 80 is a reasonable default ttywidth = 80; } //#endif #endif } int skipInFile(struct scalpelState *state, FILE *infile) { int retries = 0; while(TRUE) { if ((fseeko(infile,state->skip,SEEK_SET))) { #ifdef __WIN32 fprintf(stderr, "ERROR: Couldn't skip %I64u bytes at the start of image file %s\n", state->skip,state->imagefile); #else fprintf(stderr, "ERROR: Couldn't skip %lld bytes at the start of image file %s\n", state->skip,state->imagefile); #endif if (retries++ > 3) { fprintf(stderr,"Sorry, maximum retries exceeded...\n"); return FALSE; } else { fprintf (stderr,"Waiting to try again... \n"); sleep(3); } } else { #ifdef __WIN32 fprintf(stderr,"Skipped the first %I64u bytes of %s...\n",state->skip, state->imagefile); #else fprintf(stderr,"Skipped the first %lld bytes of %s...\n",state->skip, state->imagefile); #endif return TRUE; } } } scalpel-1.60/Makefile100666 0 0 1531 10536331035 12771 0ustar usergroupCC = gcc CC_OPTS = -Wall -O2 GOAL = scalpel CC += $(CC_OPTS) .c.o: $(CC) -c $< HEADER_FILES = scalpel.h prioque.h dirname.h SRC = helpers.c files.c scalpel.c dig.c prioque.c base_name.c OBJS = helpers.o scalpel.o files.o dig.o prioque.o base_name.o all: linux linux: CC += -D__LINUX linux: $(GOAL) bsd: CC += -D__OPENBSD bsd: $(GOAL) win32: CC += -D__WIN32 -Ic:\PThreads\include win32: $(SRC) $(HEADER_FILES) $(CC) -o $(GOAL).exe $(SRC) -liberty -Lc:\PThreads\lib -lpthreadGC1 $(GOAL): $(OBJS) $(CC) -o $(GOAL) $(OBJS) -lm scalpel.o: scalpel.c $(HEADER_FILES) Makefile dig.o: dig.c $(HEADER_FILES) Makefile helpers.o: helpers.c $(HEADER_FILES) Makefile files.o: files.c $(HEADER_FILES) Makefile prioque.o: prioque.c prioque.h Makefile nice: rm -f *~ rm -rf scalpel-output clean: nice rm -f $(OBJS) $(GOAL) $(GOAL).exe core *.core scalpel-1.60/prioque.c100666 0 0 34744 10250423441 13211 0ustar usergroup// // implementation of "prioque.h" priority queue functions */ // (c) 198x/1998/2001 (minor updates) by Golden G. Richard III, Ph.D. */ // // Major update October 2004. See prioque.h for details. // #include #include #include #include "prioque.h" // global lock on entire package pthread_mutex_t global_lock=PTHREAD_MUTEX_INITIALIZER; // for init purposes pthread_mutex_t initial_mutex=PTHREAD_MUTEX_INITIALIZER; // function prototypes for internal functions void nolock_next_element(Queue *q); void nolock_rewind_queue(Queue *q); int nolock_element_in_queue(Queue *q, void *element); void nolock_destroy_queue(Queue *q); void local_nolock_next_element(Context *ctx); void local_nolock_rewind_queue(Context *ctx); void init_queue(Queue *q, int elementsize, int duplicates, int (*compare)(void *e1, void *e2)) { q->queuelength = 0; q->elementsize = elementsize; q->queue = 0; q->duplicates = duplicates; q->compare = compare; nolock_rewind_queue(q); q->lock=initial_mutex; } void destroy_queue(Queue *q) { // lock entire queue pthread_mutex_lock(&(q->lock)); nolock_destroy_queue(q); // release lock on queue pthread_mutex_unlock(&(q->lock)); } void nolock_destroy_queue(Queue *q) { Queue_element temp; if (q != 0) { while (q->queue != 0) { free(q->queue->info); temp = q->queue; q->queue = q->queue->next; free(temp); (q->queuelength)--; } } nolock_rewind_queue(q); } int element_in_queue(Queue *q, void *element) { int found; // lock entire queue pthread_mutex_lock(&(q->lock)); found = nolock_element_in_queue(q, element); // release lock on queue pthread_mutex_unlock(&(q->lock)); return found; } int nolock_element_in_queue(Queue *q, void *element) { int found=0; if (q->queue != 0) { nolock_rewind_queue(q); while (! end_of_queue(q) && ! found) { if (q->compare(element, q->current->info) == 0) { found=1; } else { nolock_next_element(q); } } } if (! found) { nolock_rewind_queue(q); } return found; } void nolock_add_to_queue(Queue *q, void *element, int priority) { Queue_element new_element, ptr, prev=0; if (! q->queue || (q->queue && (q->duplicates || ! nolock_element_in_queue(q, element)))) { new_element = (Queue_element)malloc(sizeof(struct _Queue_element)); if (new_element == 0) { fprintf(stderr,"Malloc failed in function add_to_queue()\n"); exit(1); } new_element->info = (void *)malloc(q->elementsize); if (new_element->info == 0) { fprintf(stderr,"Malloc failed in function add_to_queue()\n"); exit(1); } memcpy(new_element->info, element, q->elementsize); new_element->priority = priority; (q->queuelength)++; if (q->queue == 0) { new_element->next = 0; q->queue = new_element; } else if ((q->queue)->priority >= priority) { new_element->next = q->queue; q->queue = new_element; } else { ptr = q->queue; while (ptr != 0 && priority >= ptr->priority) { prev = ptr; ptr = ptr->next; } new_element->next = prev->next; prev->next = new_element; } nolock_rewind_queue(q); } } void add_to_queue(Queue *q, void *element, int priority) { // lock entire queue pthread_mutex_lock(&(q->lock)); nolock_add_to_queue(q, element, priority); // release lock on queue pthread_mutex_unlock(&(q->lock)); } int empty_queue(Queue *q) { return q->queue == 0; } void remove_from_front(Queue *q, void *element) { Queue_element temp; // lock entire queue pthread_mutex_lock(&(q->lock)); #if defined(CONSISTENCY_CHECKING) if (q->queue == 0) { fprintf(stderr,"NULL pointer in function remove_from_front()\n"); exit(1); } else #endif { memcpy(element, q->queue->info, q->elementsize); free(q->queue->info); temp = q->queue; q->queue = q->queue->next; free(temp); (q->queuelength)--; } nolock_rewind_queue(q); // release lock on queue pthread_mutex_unlock(&(q->lock)); } void peek_at_current(Queue *q, void *element) { // lock entire queue pthread_mutex_lock(&(q->lock)); #if defined(CONSISTENCY_CHECKING) if (q->queue == 0 || q->current == 0) { fprintf(stderr,"NULL pointer in function peek_at_current()\n"); exit(1); } else #endif { memcpy(element, (q->current)->info, q->elementsize); // release lock on queue pthread_mutex_unlock(&(q->lock)); } } void *pointer_to_current(Queue *q) { void *data; // lock entire queue pthread_mutex_lock(&(q->lock)); #if defined(CONSISTENCY_CHECKING) if (q->queue == 0 || q->current == 0) { fprintf(stderr,"NULL pointer in function pointer_to_current()\n"); exit(1); } else #endif { data = (q->current)->info; // release lock on queue pthread_mutex_unlock(&(q->lock)); return data; } } int current_priority(Queue *q) { int priority; // lock entire queue pthread_mutex_lock(&(q->lock)); #if defined(CONSISTENCY_CHECKING) if (q->queue == 0 || q->current == 0) { fprintf(stderr,"NULL pointer in function peek_at_current()\n"); exit(1); } else #endif { priority = (q->current)->priority; // release lock on queue pthread_mutex_unlock(&(q->lock)); return priority; } } void update_current(Queue *q, void *element) { // lock entire queue pthread_mutex_lock(&(q->lock)); #if defined(CONSISTENCY_CHECKING) if (q->queue == 0 || q->current == 0) { fprintf(stderr,"NULL pointer in function update_current()\n"); exit(1); } else #endif { memcpy(q->current->info, element, q->elementsize); } // release lock on queue pthread_mutex_unlock(&(q->lock)); } void delete_current(Queue *q) { Queue_element temp; // lock entire queue pthread_mutex_lock(&(q->lock)); #if defined(CONSISTENCY_CHECKING) if (q->queue == 0 || q->current == 0) { fprintf(stderr,"NULL pointer in function delete_current()\n"); exit(1); } else #endif { free(q->current->info); temp = q->current; if (q->previous == 0) { /* deletion at beginning */ q->queue = q->queue->next; q->current = q->queue; } else { /* internal deletion */ q->previous->next = q->current->next; q->current = q->previous->next; } free(temp); (q->queuelength)--; } // release lock on queue pthread_mutex_unlock(&(q->lock)); } int end_of_queue(Queue *q) { return (q->current == 0); } void next_element(Queue *q) { // lock entire queue pthread_mutex_lock(&(q->lock)); nolock_next_element(q); // release lock on queue pthread_mutex_unlock(&(q->lock)); } void nolock_next_element(Queue *q) { #if defined(CONSISTENCY_CHECKING) if (q->queue == 0) { fprintf(stderr,"NULL pointer in function next_element()\n"); exit(1); } else if (q->current == 0) { fprintf(stderr,"Advance past end in NULL pointer in function next_element()\n"); exit(1); } else #endif { q->previous = q->current; q->current = q->current->next; } } void rewind_queue(Queue *q) { // lock entire queue pthread_mutex_lock(&(q->lock)); nolock_rewind_queue(q); // release lock on queue pthread_mutex_unlock(&(q->lock)); } void nolock_rewind_queue(Queue *q) { q->current = q->queue; q->previous = 0; } int queue_length(Queue *q) { return q->queuelength; } void copy_queue(Queue *q1, Queue *q2) { Queue_element temp, new_element, endq1; // to avoid deadlock, this function acquires a global package // lock! pthread_mutex_lock(&global_lock); // lock entire queues q1, q2 pthread_mutex_lock(&(q1->lock)); pthread_mutex_lock(&(q2->lock)); /* free elements in q1 before copy */ nolock_destroy_queue(q1); /* now make q1 a clone of q2 */ q1->queuelength = 0; q1->elementsize = q2->elementsize; q1->queue = 0; q1->duplicates = q2->duplicates; q1->compare = q2->compare; temp = q2->queue; endq1 = q1->queue; while (temp != 0) { new_element = (Queue_element)malloc(sizeof(struct _Queue_element)); if (new_element == 0) { fprintf(stderr,"Malloc failed in function copy_queue()\n"); exit(1); } new_element->info = (void *)malloc(q1->elementsize); if (new_element->info == 0) { fprintf(stderr,"Malloc failed in function copy_queue()\n"); exit(1); } memcpy(new_element->info, temp->info, q1->elementsize); new_element->priority = temp->priority; new_element->next = 0; (q1->queuelength)++; if (endq1 == 0) { q1->queue = new_element; } else { endq1->next = new_element; } endq1 = new_element; temp = temp->next; } nolock_rewind_queue(q1); // release locks on q1, q2 pthread_mutex_unlock(&(q2->lock)); pthread_mutex_unlock(&(q1->lock)); // release global package lock pthread_mutex_unlock(&global_lock); } int equal_queues(Queue *q1, Queue *q2) { Queue_element temp1, temp2; int same = TRUE; // to avoid deadlock, this function acquires a global package // lock! pthread_mutex_lock(&global_lock); // lock entire queues q1, q2 pthread_mutex_lock(&(q1->lock)); pthread_mutex_lock(&(q2->lock)); if (q1->queuelength != q2->queuelength || q1->elementsize != q2->elementsize) { same = FALSE; } else { temp1 = q1->queue; temp2 = q2->queue; while (same && temp1 != 0) { same = (! memcmp(temp1->info, temp2->info, q1->elementsize) && temp1->priority == temp2->priority); temp1=temp1->next; temp2=temp2->next; } } // release locks on q1, q2 pthread_mutex_unlock(&(q2->lock)); pthread_mutex_unlock(&(q1->lock)); // release global package lock pthread_mutex_unlock(&global_lock); return same; } void merge_queues(Queue *q1, Queue *q2) { Queue_element temp; // to avoid deadlock, this function acquires a global package // lock! pthread_mutex_lock(&global_lock); // lock entire queues q1, q2 pthread_mutex_lock(&(q1->lock)); pthread_mutex_lock(&(q2->lock)); temp = q2->queue; while (temp != 0) { nolock_add_to_queue(q1, temp->info, temp->priority); temp=temp->next; } nolock_rewind_queue(q1); // release locks on q1, q2 pthread_mutex_unlock(&(q2->lock)); pthread_mutex_unlock(&(q1->lock)); // release global package lock pthread_mutex_unlock(&global_lock); } void local_peek_at_current(Context *ctx, void *element) { // lock entire queue pthread_mutex_lock(&(ctx->queue->lock)); #if defined(CONSISTENCY_CHECKING) if (ctx->queue == 0 || ctx->current == 0) { fprintf(stderr,"NULL pointer in function peek_at_current()\n"); exit(1); } else #endif { memcpy(element, (ctx->current)->info, ctx->queue->elementsize); // release lock on queue pthread_mutex_unlock(&(ctx->queue->lock)); } } void *local_pointer_to_current(Context *ctx) { void *data; // lock entire queue pthread_mutex_lock(&(ctx->queue->lock)); #if defined(CONSISTENCY_CHECKING) if (ctx->queue == 0 || ctx->current == 0) { fprintf(stderr,"NULL pointer in function pointer_to_current()\n"); exit(1); } else #endif { data = (ctx->current)->info; // release lock on queue pthread_mutex_unlock(&(ctx->queue->lock)); return data; } } int local_current_priority(Context *ctx) { int priority; // lock entire queue pthread_mutex_lock(&(ctx->queue->lock)); #if defined(CONSISTENCY_CHECKING) if (ctx->queue == 0 || ctx->current == 0) { fprintf(stderr,"NULL pointer in function peek_at_current()\n"); exit(1); } else #endif { priority = (ctx->current)->priority; // release lock on queue pthread_mutex_unlock(&(ctx->queue->lock)); return priority; } } void local_update_current(Context *ctx, void *element) { // lock entire queue pthread_mutex_lock(&(ctx->queue->lock)); #if defined(CONSISTENCY_CHECKING) if (ctx->queue == 0 || ctx->current == 0) { fprintf(stderr,"NULL pointer in function update_current()\n"); exit(1); } else #endif { memcpy(ctx->current->info, element, ctx->queue->elementsize); } // release lock on queue pthread_mutex_unlock(&(ctx->queue->lock)); } void local_delete_current(Context *ctx) { Queue_element temp; // lock entire queue pthread_mutex_lock(&(ctx->queue->lock)); #if defined(CONSISTENCY_CHECKING) if (ctx->queue == 0 || ctx->current == 0) { fprintf(stderr,"NULL pointer in function delete_current()\n"); exit(1); } else #endif { free(ctx->current->info); temp = ctx->current; if (ctx->previous == 0) { /* deletion at beginning */ ctx->queue->queue = ctx->queue->queue->next; ctx->current = ctx->queue->queue; } else { /* internal deletion */ ctx->previous->next = ctx->current->next; ctx->current = ctx->current->next; } free(temp); (ctx->queue->queuelength)--; } // release lock on queue pthread_mutex_unlock(&(ctx->queue->lock)); } int local_end_of_queue(Context *ctx) { return (ctx->current == 0); } void local_next_element(Context *ctx) { // lock entire queue pthread_mutex_lock(&(ctx->queue->lock)); local_nolock_next_element(ctx); // release lock on queue pthread_mutex_unlock(&(ctx->queue->lock)); } void local_nolock_next_element(Context *ctx) { #if defined(CONSISTENCY_CHECKING) if (ctx->queue == 0) { fprintf(stderr,"NULL pointer in function next_element()\n"); exit(1); } else if (ctx->current == 0) { fprintf(stderr,"Advance past end in NULL pointer in function next_element()\n"); exit(1); } else #endif { ctx->previous = ctx->current; ctx->current = ctx->current->next; } } void local_rewind_queue(Context *ctx) { // lock entire queue pthread_mutex_lock(&(ctx->queue->lock)); local_nolock_rewind_queue(ctx); // release lock on queue pthread_mutex_unlock(&(ctx->queue->lock)); } void local_nolock_rewind_queue(Context *ctx) { ctx->current = ctx->queue->queue; ctx->previous = 0; } void local_init_context(Queue *q, Context *ctx) { ctx->queue = q; ctx->current = q->queue; ctx->previous=0; } scalpel-1.60/prioque.h100666 0 0 21026 10240664716 13216 0ustar usergroup// // priority queue header file "prioque.h" */ // (c) 198x/1998/2001/2004 (minor updates) by Golden G. Richard III, Ph.D. */ // // // Major update October 2004: The package is now thread-safe. The // package now depends on the pthreads library (for access to // semaphores). All functions now take one or more pointers to a // queue or context, so existing applications will need to be // modified slightly. // Additionally, new functions are now provided for walking the queue // "locally"--that is, more than one thread can maintain a position in // the queue using a local Context. The old 'rewind_queue()', // 'pointer_to_current()', etc. are maintained for a single position // during a global walk. // // Finally, a long-standing memory leak was corrected. // #include #define TRUE 1 #define FALSE 0 #define CONSISTENCY_CHECKING #if ! defined(QUEUE_TYPE_DEFINED) #define QUEUE_TYPE_DEFINED /* type of one element in a queue */ typedef struct _Queue_element { void *info; int priority; struct _Queue_element *next; } *Queue_element; /* basic queue type */ typedef struct Queue { Queue_element queue; /* linked list of elements */ Queue_element current; /* current position for sequential access functions */ Queue_element previous; /* one step back from current */ int queuelength; /* # of elements in queue */ int elementsize; /* 'sizeof()' one element */ int duplicates; /* are duplicates allowed? */ int (*compare)(void *e1, void *e2); /* element comparision function */ pthread_mutex_t lock; } Queue; typedef struct Context { Queue_element current; /* current position for local seq access functions */ Queue_element previous; /* one step back from current */ Queue *queue; /* queue associated with this context */ } Context; /********/ /* NOTE: init_queue() must be called for a new queue before any other "prioque.c" functions are called. */ /********/ /* function prototypes and descriptions for visible "prioque.c" functions */ //////////////////////////// // SECTION 1 //////////////////////////// /* initializes a new queue 'q' to have elements of size 'elementsize'. If 'duplicates' is true, then duplicate elements in the queue are allowed, otherwise duplicates are silently deleted. The element-comparing function 'compare' is required only if duplicates==FALSE or either equal_queues() or element_in_queue() are used (otherwise, a null function is acceptable). 'compare' should be a standard qsort()-style element comparison function: returns 0 if elements match, otherwise a non-0 result (<, > cases are not used). NOTE:Only the 'compare' function is used for duplicate detection--priority is not considered (i.e., attempting to add a "duplicate" element that has a different priority than the existing element will have no effect!) */ void init_queue(Queue *q, int elementsize, int duplicates, int (*compare)(void *e1, void *e2)); /* destroys all elements in 'q' */ void destroy_queue(Queue *q); /* adds 'element' to the 'q' with position based on 'priority'. Elements with lower-numbered priorities are placed closer to the front of the queue, with strict 'to the rear' placement for items with equal priority [that is, given two items with equal priority, the one most recently added will appear closer to the rear of the queue]. */ void add_to_queue(Queue *q, void *element, int priority); /* removes the element at the front of the 'q' and places it in 'element'. */ void remove_from_front(Queue *q, void *element); /* returns TRUE if the 'element' exists in the 'q', otherwise false. The 'compare' function is used for matching. As a side-effect, the current position in the queue is set to matching element, so 'update_current()' can be used to update the value of the 'element'. If the element is not found, the current position is set to the first element in the queue. */ int element_in_queue(Queue *q, void *element); /* returns TRUE if 'q' is empty, FALSE otherwise */ int empty_queue(Queue *q); /* returns the number of elements in the 'q'. */ int queue_length(Queue *q); /* makes a copy of 'q2' into 'q1'. 'q2' is not modified. */ void copy_queue(Queue *q1, Queue *q2); /* determines if 'q1' and 'q2' are equivalent. Uses the 'compare' function of the first queue, which should match the 'compare' for the second! Returns TRUE if the queues are equal, otherwise returns FALSE. */ int equal_queues(Queue *q1, Queue *q2); /* merge 'q2' into 'q1'. 'q2' is not modified. */ void merge_queues(Queue *q1, Queue *q2); //////////////////////////// // SECTION 2 //////////////////////////// /* the following are functions used to "walk" the queue (globally) like a linked list, examining or deleting elements along the way. Current position is rewound to the beginning by functions above (in SECTION 1), except for 'empty_queue()' and 'queue_length()', which do not modify the global current position. */ /********************/ /********************/ /* move to the first element in the 'q' */ void rewind_queue(Queue *q); /* move to the next element in the 'q' */ void next_element(Queue *q); /* allows update of current element. The priority should not be changed by this function! */ void update_current(Queue *q, void *element); /* retrieve the element stored at the current position in the 'q' */ void peek_at_current(Queue *q, void *element); /* return a pointer to the data portion of the current element */ void *pointer_to_current(Queue *q); /* return priority of current element in the 'q' */ int current_priority(Queue *q); /* delete the element stored at the current position */ void delete_current(Queue *q); /* has the current position in 'q' moved beyond the last valid element? Returns TRUE if so, FALSE otherwise. */ int end_of_queue(Queue *q); //////////////////////////// // SECTION 3 //////////////////////////// // Functions in this section provide the ability to walk the queue // with a locally maintained position. They do not affect the global // queue position for functions in SECTION 2. // /* create a new local context for queue 'q'. The first element in 'q' becomes the current element in the newly created context. */ void local_init_context(Queue *q, Context *ctx); /* move to the first element in the 'q', maintaining a local position */ void local_rewind_queue(Context *ctx); /* move to the next element in the 'q', maintaining a local position */ void local_next_element(Context *ctx); /* allows update of current element, relative to current local position. The priority should not be changed by this function! */ void local_update_current(Context *ctx, void *element); /* retrieve the element stored at the current local position in the 'q' */ void local_peek_at_current(Context *ctx, void *element); /* return a pointer to the data portion of the element at the current local position */ void *local_pointer_to_current(Context *ctx); /* return priority of element at current local position in the 'q' */ int local_current_priority(Context *ctx); /* delete the element stored at the current local position */ void local_delete_current(Context *ctx); /* has the current local position in 'q' moved beyond the last valid element? Returns TRUE if so, FALSE otherwise. */ int local_end_of_queue(Context *ctx); #endif /*** QUICK REFERENCE *** // SECTION 1 void init_queue(Queue *q, int elementsize, int duplicates, int (*compare)(void *e1, void *e2)); void destroy_queue(Queue *q); void add_to_queue(Queue *q, void *element, int priority); void remove_from_front(Queue *q, void *element); int element_in_queue(Queue *q, void *element); int empty_queue(Queue *q); int queue_length(Queue *q); void copy_queue(Queue *q1, Queue *q2); int equal_queues(Queue q1, Queue *q2); void merge_queues(Queue *q1, Queue *q2); // SECTION 2 void rewind_queue(Queue *q); void next_element(Queue *q); void update_current(Queue *q, void *element); void peek_at_current(Queue *q, void *element); void *pointer_to_current(Queue *q); int current_priority(Queue *q); void delete_current(Queue *q); int end_of_queue(Queue *q); // SECTION 3 void local_init_context(Queue, *q, Context *ctx); void local_rewind_queue(Context *ctx); void local_next_element(Context *ctx); void local_update_current(Context *ctx, void *element); void local_peek_at_current(Context *ctx, void *element); void local_*pointer_to_current(Context *ctx); int local_current_priority(Context *ctx); void local_delete_current(Context *ctx); int local_end_of_queue(Context *ctx); *** QUICK REFERENCE ***/ scalpel-1.60/pthreadGC1.dll100666 0 0 161615 10213244662 14023 0ustar usergroupMZ@ !L!This program cannot be run in DOS mode. $PELI-B" 8^pi 8\.textD]^``.datapb@.bssp.edatad.idata8t@.rsrc\|@.relocUuu ]t\t$UT$U$M t,u iu1ۉ؋]u] Y덴&uGɐt&$tYitiUvUuP…tM؉]]Ð 'USQ1ۋEtu؋]]à RoOv'UEU tt t 1 ]Ð'UEM tt w1 ]É'UWVS u Åtve[^_]Í& x0WU tM S4s4us8t W1PPjCÅt tl jN jeu{@VVjWaNUWVS u Åtve[^_]Í& x0WU tM S8K4s8ut W1PPjs{@@PjjWT*ttH0 S1HuL hiWIpi CCtX=pipiupi hi+I Me[^_]ÍS PUjjR)tLH0 Wq*cKPPjQ ƅ[ URC*ľ(Åtc@tNtH@CC jjjjn?CtUe[^_]à S1=܍v1뷿 ΐt&(ɉ'UWVS1ۃ u }EWHÅu&UztZ WWÅt}>e[^_]ËM QR@> u Uԃ EP<ËBtHB밃 h`i\= >v h`iQ= 냻琍t&US 1jj<…t@M؉]]û vUSP1ۋEtu؋]]à R<v'UEU tt t 1 ]Ð'UEM tt w1 ]É'U1UM tt wJ]Ð'U1҉EM tt t @]ú&UWVS uE3Suo $pitUt3vt<t$PPjCP;ZYu $piEEe[^_]Ðt&3u뿋u1ɉƉס$piEuCs {WVKQS Rt{t E${sFso $pit/tPPjSR:ZYtEUt6uʋEi 1h`i: tTtFt-t" h`i{:] PPhLpiVrPPhHpiPPj䍶UWVS u Cuf $pitLu 1e[^_]Åt,tM RRQSR2u֋ $pi֍3uϋu1ɉƉס$piEuCs {vWVKQS RAt{t $RsFsD $pit$tU PPRCP1tuՋEs 1h`i8 tStEt,t! h`i8؃ SShLpiVWWhHpiPPj䍴&UVS1Uw?CuX$pit>t-x e[^]à KQ8 u䍶׾Љ3u뽍&+RPSRK Qt̃{t#$piC t낋3uvKIKtjUWV1S }w{=$pi1ɺt`u%Su e[^_]CC S{tiRPKQC Ptދ{G{뱉럍v 1h`i7 tStEt,t! h`i6 f=PPhLpiWPPhHpiPPj䍴&'U]7&U]W&UU]BÐt&UVSUtq5R C4?B)4B t+P4ÅPPVC

VW6 _Z j@6 HCvRK@PPjQ4t&'US1ۍURURQ5$6Zt,1ɸUtAuMtEE]Ð KERNEL32.DLLInterlockedCompareExchangeQUSEREX.DLLQueueUserAPCEx_InitQueueUserAPCExUSpiMPUQRQ pi4$55Z_1ɸUtAuI$pi h5i 5 i$5iP5Z(piY pi pi h6i4 0i ,piuK0i,pi]iu*0i0it pi pi؋]à P4 ȋ0iPPh6iRe4ZYtЅu 0i,pi]iQP4 0iQQh/6iP$4,piXZK i(piYiQ4  i$pipiPPjh pi&uPPjhpitU hi3h`i3hi3hi3hi3hi3pi QueueUserAPCEx_Finit&UWVSpiu e[^_]à  piR tx$tN0iu it P2 SShx8iP2ZYtЃ =0iW2 Xp TPޅ {0WKC<$_TXXPRP"XZ󥋽TPWQdEuK u]V$\u piPPj Q42^_ PD1 ك P61 말U]ÍUWVSpiu e[^_]à  piRNt݃x$u׋Xp TPޅ {0W)C<$_TXPRWX"XPZ󥋍TQPBEuK u]V$\u piSSjR1XZ! P"0 ك P0 U piM]!9%ÍUVS1ۃhi,/pi Ut"u VMËQUtt hi. %eH[^ ]ÉUWVS1ۃ }U ttte[^_]þ QQjjK.Åt@ @@RRjPƅuVSPUPjRzƅu1KPPjQDƅu C⭬x UR S S1I-JUWV1S uEEtt{⭬t e[^_]à Su SURDžu`S~5 uV$EEuEuE딋K9K à }CWDžt S` SL KQMUXR$E$E,j hi, >t hi, 8'US 1jj.,…tM؉]]Ð 'USP1ۋEtu؋]]à R_+v'UEU tt t 1 ]Ð'UEM tt w1 ]É'UWVS utt{⭬t e[^_]à SruS BS t]e[^_] sVADžu$K C )K CVDžt S넍& 1hi* t/u hi* t ؃<'QQjVɍ&UWVS uU Utt{⭬t e[^_]PPURS)uK AK t]e[^_]PPuVsVDžt=L't S뛋SBSK C )K CVdDžtă 1hi) t/u hi) t ؃+PPjVUWVS,utt{⭬t e[^_]à SBu SUR,DžCuvC~K )K CC ~Y؉CU؍sPSh^iRPPEPVDžuSx Q0uC usFs= St& 1hia( t/u hiQ( t ؃SSjVNɍ&UWVS,utt{⭬t e[^_]ËU PPRSuE WSWUPRDžsuyC~K )K CC ~\؉C}؍sPSh^iW]M PUQRVDžuSx QuC uC@C4 S 1hi& t/u hi& t ؃PPjVɍvUWVS Ett1t{⭬t e[^_]ËCuK {Wzƅu܋SBSt W…u빃 SRՃ HKCQ$t&UWVS utt{⭬t e[^_]à S2uS BS t]e[^_]= sVDžu$K C )K CV Džt S넍& 1hiQ% t/u hiA% t ؃<'QQjV>ɍ&UWVS utt{⭬t e[^_]à S"u sVDžueCuNC~K )K CS ~8 V Džt S됃 SDžuCڃ SZă 1hi$ t/u hi $ t ؃SSjV ɉU1҉Ett8tuU %HЃ0]ÉU1҉EM tt8tutv1]É'U1҉WVS ]u tt8tut >j9} e[^_]à jf9 1Q܍t&U1ɉSE] tt:tut 1Q[]øU1ɉSE] tt:tuwZ1[]Í&'U1ɉSE] tt:tut 1Q[]øUWVSU]u }UjVSuw 0te[^_]ËEu M]Ee[^_] UWVSuUV]U#9} e[^_]à V9~\}W M(QM>ƅtPPW}WR"ZYu ]SыMY,S w UWVSE ]j}PSuvUtM[,1e[^_]øvUPP}w ]썶UPP}w ]썶USS]u$U u 1]]Ít&[(!9tQSjh!Zu/!T 뿍t&USS]u 1]]6!9tQSjh4!Zu3!T 뺍Ujc 1]Í'UWV1S1ۃ U t,uM11e[^_]Ít&[t&PPj jƅt\UWWxjWtt Vjh?jjl Fu׃ Wwĉ _UWVS uEtu+te[^_]à uV|1 ǃWEqÅuMxo WXEXS uU눃 WÅtjh?jj}Gu1ZMGGt& W,v'UWVS Ut, {W]ƅuJ x- Wt0e[^_]Í&1 ʍvUWVS,UE2tL~ WEt'uԉ0e[^_]Í& KW2x ]ԅu1эMWVhdiQpF[PvEԉ$t&'UWVS<]U E ҉MtYJ  ȍ<C4UWV1S }tu e[^_]ÃtT;t< $pit(3Htt˃ S3׃ SR̃ hi ?t hi 捴&'UWVS ]t=t7t\5$pit&t<t 1t t e[^_]ÍJMe[^_]t&à 1hi t&u hi ueQQjS`҉'USEt=t7t2$pit: ƒt)Jt[]ÃuSU[]1 ŐUVS]t63t0t`$pitEƒt.1Jte[^]ÉuVUe[^]*ڍv뺃 1hi t&u hi u3aPPjS ҉'USPPjE MPQu {$tC$]]ø&UWVSME hiˉPTu tCu(DžD hi De[^_]à Pd =tŃ{$@ hi DžDtTPQWRPXDžD$u SRKDtWWVCPY[PG ~0WF<$XTZPQWrPZXY׹"󥋵TVS-Eu6 u]V$\ P" P DžDDžDvUWV1S} jjÅt@+@tt C{Ue[^_]à S1I܍t& щ'UWVS ut/F tVuC R~ u Ve1[^_]Í& NQt҃ NMQu^ t Sgtu ]Sv {C CStS uKt뵃 S$D UWVS ]; piщ…ҸtS1tKtCst?pBpDECA@>>>>()HXPR0QSPTS@;@68 ;9:PpJ0JJ`J0KPL`PPKPPOO0NMQMД4OkǕ7MgÖߖ6E\qٗ '6GVdqИݘ&9Ldzƙ1NhК8Ndӛ $:NcuÜ!@_~ŝܝ%/;HQZcu  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrpthreadGC1.dllpthreadCancelableTimedWaitpthreadCancelableWaitpthread_attr_destroypthread_attr_getdetachstatepthread_attr_getinheritschedpthread_attr_getschedparampthread_attr_getschedpolicypthread_attr_getscopepthread_attr_getstackaddrpthread_attr_getstacksizepthread_attr_initpthread_attr_setdetachstatepthread_attr_setinheritschedpthread_attr_setschedparampthread_attr_setschedpolicypthread_attr_setscopepthread_attr_setstackaddrpthread_attr_setstacksizepthread_barrier_destroypthread_barrier_initpthread_barrier_waitpthread_barrierattr_destroypthread_barrierattr_getpsharedpthread_barrierattr_initpthread_barrierattr_setpsharedpthread_cancelpthread_cond_broadcastpthread_cond_destroypthread_cond_initpthread_cond_signalpthread_cond_timedwaitpthread_cond_waitpthread_condattr_destroypthread_condattr_getpsharedpthread_condattr_initpthread_condattr_setpsharedpthread_createpthread_delay_nppthread_detachpthread_equalpthread_exitpthread_getconcurrencypthread_getschedparampthread_getspecificpthread_getw32threadhandle_nppthread_joinpthread_key_createpthread_key_deletepthread_killpthread_mutex_destroypthread_mutex_initpthread_mutex_lockpthread_mutex_timedlockpthread_mutex_trylockpthread_mutex_unlockpthread_mutexattr_destroypthread_mutexattr_getkind_nppthread_mutexattr_getpsharedpthread_mutexattr_gettypepthread_mutexattr_initpthread_mutexattr_setkind_nppthread_mutexattr_setpsharedpthread_mutexattr_settypepthread_num_processors_nppthread_oncepthread_rwlock_destroypthread_rwlock_initpthread_rwlock_rdlockpthread_rwlock_timedrdlockpthread_rwlock_timedwrlockpthread_rwlock_tryrdlockpthread_rwlock_trywrlockpthread_rwlock_unlockpthread_rwlock_wrlockpthread_rwlockattr_destroypthread_rwlockattr_getpsharedpthread_rwlockattr_initpthread_rwlockattr_setpsharedpthread_selfpthread_setcancelstatepthread_setcanceltypepthread_setconcurrencypthread_setschedparampthread_setspecificpthread_spin_destroypthread_spin_initpthread_spin_lockpthread_spin_trylockpthread_spin_unlockpthread_testcancelpthread_timechange_handler_nppthread_win32_process_attach_nppthread_win32_process_detach_nppthread_win32_test_features_nppthread_win32_thread_attach_nppthread_win32_thread_detach_npptw32_get_exception_services_codeptw32_pop_cleanupptw32_push_cleanupsched_get_priority_maxsched_get_priority_minsched_getschedulersched_setschedulersched_yieldsem_closesem_destroysem_getvaluesem_initsem_opensem_postsem_post_multiplesem_timedwaitsem_trywaitsem_unlinksem_waitTԦP@,<HTdt̢آ $8Pdṭ0HXh|̤ 0LdtĥХإHTdt̢آ $8Pdṭ0HXh|̤ 0LdtĥХإAddAtomACloseHandle3CreateEventAICreateSemaphoreAWDeleteCriticalSectioncDuplicateHandlefEnterCriticalSectionFindAtomAFreeLibraryGetAtomNameAGetCurrentProcessGetCurrentProcessIdGetCurrentThreadGetCurrentThreadIdGetExitCodeThreadGetLastErrorCGetProcAddressDGetProcessAffinityMaskoGetThreadContextqGetThreadPriorityInitializeCriticalSectionInterlockedDecrementInterlockedExchangeInterlockedIncrementLeaveCriticalSectionLoadLibraryAOpenProcess1ReleaseSemaphore6ResetEvent7ResumeThreadlSetEventxSetLastErrorSetThreadContextSetThreadPrioritySleepSuspendThreadTlsAllocTlsFreeTlsGetValueTlsSetValueWaitForMultipleObjectsWaitForSingleObject$__dllonexitr_beginthreadex_endthreadex_errno_ftimeq_setjmpabort callocexitfflush(freeZlongjmp[mallocWSAGetLastErrorWSASetLastErrorKERNEL32.dllmsvcrt.dll((WSOCK32.DLLI-BI-B0I-B HX4VS_VERSION_INFO?dStringFileInfo@040904b0h$DescriptionPOSIX Threads for Windows32 Library: ProductVersion1, 3, 0, 06 FileVersion1, 3, 0, 04 InternalNamepthreadGC< OriginalFilenamepthreadGCn'CompanyNameOpen Source Software community project~-LegalCopyrightCopyright (C) Project contributors 1998-2004"LicenceLGPLd*Infohttp://sources.redhat.com/pthreads-win32/d&CommentGNU C build -- longjmp thread exitingDVarFileInfo$Translation X:0}0000011%1J1U1111111112 22!2+252C2^2y229n;^<=:>@>t>?:??? l 1*1D1J1T1\1223333A333.666b7788*8S8X8s8x8888Q999::::::?;Z;_;u;=6=>>0???0 040H0000T11111*222v33334I6f66666666667777"7,767?7Z7a7|77777777777788/898C8M8W8a8l88888899:(::#;K;V;;==??@$001262 3z33&5F5[6{6=?PX222-3333i444s55589:g:z::::::::::<;=^=~=>3>O>c>~>>?>?`;0002b5r5555555556$6/6A6T6_6j666666777(7-787G7M7z7777777774898A88888888999999::":2:B:R:b:r:::::::::;;";2;B;R;b;r;;;;;;;;;<<"<2 ] P? g ? z `@  @  @  A  0A  PB  C  C  PD  E  `E . 0G B G V H k I  I  J  0J  `J  K  K  L " L 7 M R PM n M z N  pN  N  O  pO  O  O 2 P F R ] `S t T  @T  T    8    L  * I .textS.dataP.bss  .text`U.dataP.bss@.idata$7$.idata$5<.idata$4@.idata$6.textpU.dataP.bss@.idata$7(.idata$5@.idata$4D.idata$6.filegfakehname@fthunk<.textU.dataP.bss@.idata$2(.idata$58.idata$4<.filegfake.textU.dataP.bss@.idata$4H.idata$5D.idata$7, .fileggccmain.caP_p.0TnU U ___mainV .textU.dataP.bss@.filegpseudo-reloc.cV .textV(.data`.bss@.file{g.textV.data`.bss@VV @ pP&x2V NpW jX PY .textV%.datap.bss@ .textY.data.bss`.textY.data.bss`.idata$7.idata$5.idata$4.idata$6d.textY.data.bss`.idata$7.idata$5$.idata$4(.idata$6.textY.data.bss`.idata$7 .idata$5(.idata$4,.idata$6.textY.data.bss`.idata$7.idata$5 .idata$4.idata$6.textY.data.bss`.idata$7.idata$50.idata$44.idata$6.textZ.data.bss`.idata$7.idata$5.idata$4.idata$6.textZ.data.bss`.idata$7.idata$5.idata$4.idata$6t.text Z.data.bss`.idata$7.idata$5,.idata$40.idata$6.text0Z.data.bss`.idata$7.idata$5 .idata$4$.idata$6.text@Z.data.bss`.idata$7.idata$5.idata$4 .idata$6.textPZ.data.bss`.idata$7.idata$5.idata$4 .idata$6.text`Z.data.bss`.idata$7.idata$5.idata$4.idata$6.textpZ.data.bss`.idata$7.idata$5.idata$4.idata$6.filegfakehnamefthunk.textZ.data.bss`.idata$2.idata$5.idata$4.filegfake.textZ.data.bss`.idata$48.idata$54.idata$7 .textZ.data.bss`.idata$7D.idata$5h.idata$4l.idata$6.textZ.data.bss`.idata$7.idata$5.idata$4.idata$60.textZ.data.bss`.idata$7<.idata$5`.idata$4d.idata$6.textZ.data.bss`.idata$7.idata$5.idata$4.idata$6L.textZ.data.bss`.idata$7.idata$5.idata$4.idata$6.textZ.data.bss`.idata$7.idata$5.idata$4.idata$6.textZ.data.bss`.idata$7.idata$5.idata$4.idata$6|.textZ.data.bss`.idata$7.idata$5.idata$4.idata$6.text[.data.bss`.idata$7.idata$5.idata$4.idata$6.text[.data.bss`.idata$7.idata$5.idata$4.idata$6.text [.data.bss`.idata$70.idata$5T.idata$4X.idata$6T.text0[.data.bss`.idata$7x.idata$5.idata$4.idata$6.text@[.data.bss`.idata$7.idata$5.idata$4.idata$6.textP[.data.bss`.idata$7`.idata$5.idata$4.idata$68.text`[.data.bss`.idata$7T.idata$5x.idata$4|.idata$6.textp[.data.bss`.idata$7\.idata$5.idata$4.idata$6$.text[.data.bss`.idata$7@.idata$5d.idata$4h.idata$6.text[.data.bss`.idata$74.idata$5X.idata$4\.idata$6d.text[.data.bss`.idata$7.idata$5.idata$4.idata$6.text[.data.bss`.idata$7p.idata$5.idata$4.idata$6.text[.data.bss`.idata$7.idata$5.idata$4.idata$6H.text[.data.bss`.idata$7l.idata$5.idata$4.idata$6t.text[.data.bss`.idata$7L.idata$5p.idata$4t.idata$6.text[.data.bss`.idata$7|.idata$5.idata$4.idata$6.text\.data.bss`.idata$7.idata$5.idata$4.idata$6 .text\.data.bss`.idata$7.idata$5.idata$4.idata$6.text \.data.bss`.idata$7X.idata$5|.idata$4.idata$6 .text0\.data.bss`.idata$7.idata$5.idata$4.idata$6X.text@\.data.bss`.idata$7h.idata$5.idata$4.idata$6d.textP\.data.bss`.idata$78.idata$5\.idata$4`.idata$6t.text`\.data.bss`.idata$7.idata$5.idata$4.idata$6h.textp\.data.bss`.idata$7d.idata$5.idata$4.idata$6P.text\.data.bss`.idata$7.idata$5.idata$4.idata$6.text\.data.bss`.idata$7.idata$5.idata$4.idata$6.text\.data.bss`.idata$7.idata$5.idata$4.idata$6.text\.data.bss`.idata$7.idata$5.idata$4.idata$6.text\.data.bss`.idata$7t.idata$5.idata$4.idata$6.text\.data.bss`.idata$7.idata$5.idata$4.idata$6.text\.data.bss`.idata$7.idata$5.idata$4.idata$60.text\.data.bss`.idata$7H.idata$5l.idata$4p.idata$6.text].data.bss`.idata$7,.idata$5P.idata$4T.idata$6H.text].data.bss`.idata$7P.idata$5t.idata$4x.idata$6.filegfakehnameTfthunkP.text ].data.bss`.idata$2.idata$5L.idata$4P.filegfake.text ].data.bss`.idata$4.idata$5.idata$7 .filegcrtstuff.c ] .text ] .data.bss`.ctors4].rsrc0[\[T%4[C<]_freeY R`n [0_longjmp Z 7lJ__errnoY mZ ]@\8@\HP\] r[Z?XVnxpU [__ftimeZ , [/[?PZ __setjmp`Z `__dll__ri [pZ\0\DbxPZ endp[00]\_fflushY etextD]p(#@<Y i0]|t_calloc@Z p\$Z \.AWj0\ [__end__Y _mallocY /<]=VZn`\`U\P[d)$70\G_abortpZ U@q`[[(@[_end->PPeZ\Z( _exit0Z <V\e`Z\]\_Sleep@4[4,C,Xsh_DllMainCRTStartup@12_first_atexit_next_atexit___dll_exit___do_sjlj_init_ptw32_threadStart@4_ptw32_tkAssocCreate_ptw32_semwait_ptw32_get_exception_services_code_pthread_attr_init_pthread_attr_destroy_pthread_attr_getdetachstate_pthread_attr_setdetachstate_pthread_attr_getstackaddr_pthread_attr_setstackaddr_pthread_attr_getstacksize_pthread_attr_setstacksize_pthread_attr_getscope_pthread_attr_setscope_pthread_barrier_init_pthread_barrier_destroy_pthread_barrier_wait_pthread_barrierattr_init_pthread_barrierattr_destroy_pthread_barrierattr_getpshared_pthread_barrierattr_setpshared_pthread_setcancelstate_pthread_setcanceltype_pthread_testcancel_pthread_cancel_ptw32_pop_cleanup_ptw32_push_cleanup_pthread_condattr_init_pthread_condattr_destroy_pthread_condattr_getpshared_pthread_condattr_setpshared_pthread_cond_init_pthread_cond_destroy_pthread_cond_wait_pthread_cond_timedwait_pthread_cond_signal_pthread_cond_broadcast_pthread_create_pthread_exit_pthread_kill_pthread_once_pthread_self_pthread_equal_pthread_setconcurrency_pthread_getconcurrency_pthreadCancelableWait_pthreadCancelableTimedWait_ptw32_recursive_mutexattr_s_ptw32_errorcheck_mutexattr_s_ptw32_recursive_mutexattr_ptw32_errorcheck_mutexattr_pthread_mutex_init_pthread_mutex_destroy_pthread_mutexattr_init_pthread_mutexattr_destroy_pthread_mutexattr_getpshared_pthread_mutexattr_setpshared_pthread_mutexattr_settype_pthread_mutexattr_gettype_pthread_mutex_lock_pthread_mutex_timedlock_pthread_mutex_unlock_pthread_mutex_trylock_pthread_mutexattr_setkind_np_pthread_mutexattr_getkind_np_pthread_getw32threadhandle_np_pthread_delay_np_pthread_num_processors_np_pthread_win32_process_attach_np_ptw32_h_kernel32_ptw32_h_quserex_pthread_win32_process_detach_np_pthread_win32_thread_attach_np_pthread_win32_thread_detach_np_pthread_win32_test_features_np_pthread_timechange_handler_np_pthread_rwlock_init_pthread_rwlock_destroy_pthread_rwlockattr_init_pthread_rwlockattr_destroy_pthread_rwlockattr_getpshared_pthread_rwlockattr_setpshared_pthread_rwlock_rdlock_pthread_rwlock_timedrdlock_pthread_rwlock_wrlock_pthread_rwlock_timedwrlock_pthread_rwlock_unlock_pthread_rwlock_tryrdlock_pthread_rwlock_trywrlock_pthread_attr_setschedpolicy_pthread_attr_getschedpolicy_pthread_attr_setschedparam_pthread_attr_getschedparam_pthread_attr_setinheritsched_pthread_attr_getinheritsched_pthread_setschedparam_pthread_getschedparam_sched_get_priority_max_sched_get_priority_min_sched_setscheduler_sched_getscheduler_sched_yield_sem_init_sem_destroy_sem_trywait_sem_wait_sem_timedwait_sem_post_sem_post_multiple_sem_getvalue_sem_open_sem_close_sem_unlink_pthread_spin_init_pthread_spin_destroy_pthread_spin_lock_pthread_spin_unlock_pthread_spin_trylock_pthread_detach_pthread_join_pthread_key_create_pthread_key_delete_pthread_setspecific_pthread_getspecific_ptw32_InterlockedCompareExchange@12_ptw32_InterlockedExchange@8_ptw32_is_attr_ptw32_processInitialize_ptw32_threadDestroy_ptw32_tkAssocDestroy_ptw32_throw_ptw32_getprocessors_ptw32_RegisterCancelation_ptw32_cond_check_need_init_DllMain@12_ptw32_mutex_check_need_init_ptw32_rwlock_check_need_init_ptw32_rwlock_cancelwrwait_ptw32_spinlock_check_need_init_ptw32_cancel_self_ptw32_cancel_callback@4_ptw32_cond_timedwait_ptw32_cond_unblock_ptw32_cancelable_wait_ptw32_timed_eventwait_ptw32_sem_wait_cleanup_ptw32_sem_timedwait_cleanup_ptw32_cond_wait_cleanup_ptw32_threadReusePop_ptw32_setthreadpriority_ptw32_new_ptw32_pop_cleanup_all_ptw32_threadReusePush_ptw32_callUserDestroyRoutines_ptw32_processTerminate_initialized___do_global_dtors___do_global_ctors__pei386_runtime_relocatorpseudo-reloc-list.c_w32_atom_suffix___w32_sharedptr_default_unexpected_dw2_object_mutex.0_dw2_once.1_sjl_fc_key.2_sjl_once.3___w32_eh_shared_initialize___w32_sharedptr_initialize___w32_sharedptr_set___w32_sharedptr_get___sjlj_init_ctor_GetThreadPriority@4___RUNTIME_PSEUDO_RELOC_LIST___SetLastError@4__imp__GetThreadContext@8_SetEvent@4__imp__CloseHandle@4__data_start___FreeLibrary@4___DTOR_LIST___ptw32_mutex_test_init_lock__imp__GetLastError@0___w32_sharedptr_terminate__imp__TlsSetValue@8_GetProcessAffinityMask@12__imp___ftime_ptw32_once_control__imp__TlsGetValue@4__libmsvcrt_a_iname__imp__InterlockedExchange@8__imp__FindAtomA@4__imp__InitializeCriticalSection@4_DeleteCriticalSection@4__imp__abort_ptw32_cond_list_head__size_of_stack_commit____size_of_stack_reserve____major_subsystem_version___AddAtomA@4__imp__WSASetLastError@4__imp__CreateSemaphoreA@16_GetLastError@0_CreateSemaphoreA@16_ptw32_selfThreadKey_DuplicateHandle@28__imp__WaitForMultipleObjects@16__imp__InterlockedDecrement@4__imp__GetExitCodeThread@8__imp__OpenProcess@12_InterlockedDecrement@4__bss_start_____RUNTIME_PSEUDO_RELOC_LIST_END____imp__CreateEventA@16__size_of_heap_commit____imp__SetThreadPriority@8__imp__GetCurrentProcess@0_WSASetLastError@4__imp___errno__imp__GetProcAddress@8_GetProcAddress@8_ptw32_register_cancelation_CreateEventA@16_ptw32_concurrency_ResumeThread@4__imp__TlsFree@4__beginthreadex_ptw32_cleanupKey__minor_os_version____head_libmsvcrt_a__image_base____imp__exit__section_alignment___LoadLibraryA@4__imp__FreeLibrary@4_SuspendThread@4__imp___endthreadex_WaitForMultipleObjects@16_SetThreadContext@8__RUNTIME_PSEUDO_RELOC_LIST____imp___beginthreadex__endthreadex_GetCurrentThread@0__data_end_____w32_sharedptr__CTOR_LIST____imp__ResumeThread@4_TlsAlloc@0__bss_end____imp__ReleaseSemaphore@12__head_libwsock32_a__imp__WaitForSingleObject@8__imp__WSAGetLastError@0_ptw32_features__imp__SetLastError@4__imp__SuspendThread@4___CTOR_LIST____imp__GetCurrentProcessId@0__imp__GetAtomNameA@12_GetExitCodeThread@8_ptw32_smp_system_WaitForSingleObject@8_GetCurrentProcessId@0__imp____dllonexit_ptw32_cond_list_tail__file_alignment____imp__SetThreadContext@8__imp__LeaveCriticalSection@4__imp__malloc_SetThreadPriority@8__major_os_version___CloseHandle@4__imp__GetThreadPriority@4___dllonexit__imp__InterlockedIncrement@4__DTOR_LIST___ptw32_thread_reuse_lock_EnterCriticalSection@4_ReleaseSemaphore@12_WSAGetLastError@0_GetThreadContext@8_ptw32_cond_list_lock_GetCurrentThreadId@0__size_of_heap_reserve____imp__SetEvent@4__subsystem____imp__DuplicateHandle@28__imp__fflush_OpenProcess@12__imp__calloc___w32_sharedptr_unexpected_ptw32_processInitialized__imp__GetProcessAffinityMask@12_GetCurrentProcess@0_InitializeCriticalSection@4__imp__free_InterlockedExchange@8__major_image_version____imp__ResetEvent@4__loader_flags____imp__AddAtomA@4__head_libkernel32_a_ptw32_spinlock_test_init_lock__minor_subsystem_version____minor_image_version____imp__Sleep@4_InterlockedIncrement@4_TlsSetValue@8_ResetEvent@4_ptw32_interlocked_compare_exchange__imp__GetCurrentThreadId@0__imp__GetCurrentThread@0_TlsGetValue@4__imp__DeleteCriticalSection@4_LeaveCriticalSection@4_FindAtomA@4__imp__LoadLibraryA@4__imp___setjmp_GetAtomNameA@12__imp__TlsAlloc@0_TlsFree@4__RUNTIME_PSEUDO_RELOC_LIST_END____libkernel32_a_iname__imp__longjmp__libwsock32_a_iname_ptw32_cond_test_init_lock_ptw32_threadReuseBottom_ptw32_rwlock_test_init_lock_ptw32_threadReuseTop__imp__EnterCriticalSection@4scalpel-1.60/README100666 0 0 3210 10536325227 12213 0ustar usergroupScalpel is a complete rewrite of the Foremost 0.69 file carver. This version of Scalpel reads Foremost 0.69 configuration files--see the default configuration file, scalpel.conf, for more details. Important note: The default configuration file has all supported file patterns commented out--you must edit this before before running Scalpel. More details on execution options can be found in the Scalpel man page, "scalpel.1". Currently supported operating systems: Linux, Windows, Mac OS X. If you decide to compile Scalpel on win32, you'll need to install pthreads-win32 and hack the Makefile to reflect where you've installed the pthreads include and lib directories. If you want to run Scalpel on win32 w/o these hassles, just use the win32 executable that's provided in the distribution. COMPILE INSTRUCTIONS: Linux: make Win32: make win32 [or mingw32-make win32] Mac OS X: make bsd and enjoy. If you want to install the binary and man page in a more permanent place, just copy "scalpel" and "scalpel.1" to appropriate locations, e.g., on Linux, "/usr/local/bin" and "/usr/local/man/man1", respectively. On Windows, you'll also need to copy "pthreadGC1.dll" into the same directory as "scalpel.exe". LIMITATIONS: Carving Windows physical and logical device files (e.g., \\.\physicaldrive0 or \\.\c:) isn't currently supported, but will be supported in a future release. SUGGESTIONS: Bug reports, comments, complaints, and feature requests should be directed to the author at golden@digitalforensicssolutions.com. The latest version of Scalpel is always available at http://www.digitalforensicssolutions.com/Scalpel. Cheers, --Golden scalpel-1.60/scalpel.1100666 0 0 12054 10536335527 13072 0ustar usergroup.TH SCALPEL "1" "v1.60 - December 2006" "Digital Forensics Solutions" "Digital Forensics Solutions" .SH NAME scalpel \- Recover files using a header/footer database .SH SYNOPSIS .B scalpel [\fB-b\fR] [\fB-c\fR ] [\fB-d\fR] [\fB-h\fR] [\fB-i\fR ] [\fB-m\fR ] [\fB-n\fR] [\fB-o\fR

] [\fB-O\fR] [\fB-p\fR] [\fB-r\fR] [\fB-s\fR ] [\fB-t\fR] [\fB-u\fR] [\fB-V\fR] [\fB-v\fR] [\fIFILES\fR]... .SH DESCRIPTION .PP Recover files from a disk image or raw block device based on headers and footers specified by the user. .TP \fB\-b\fR Carve files even if defined footers aren't discovered within maximum carve size for file type [foremost 0.69 compat mode] .TP \fB-c\fR \fIfile\fR Chooses which configuration file to use. If this option is omitted, then "scalpel.conf" in the current directory is used. The format for the configuration file is described in the default configuration file "scalpel.conf". See the \fICONFIGURATION FILE\fR section below for more information. .TP \fB\-d\fR Generate header/footer database; will bypass certain optimizations and discover all footers, so performance suffers. Doesn't affect the set of files carved. **EXPERIMENTAL** .TP \fB\-m\fR Generate/update carve coverage blockmap file. The first 32bit unsigned int in the file identifies the block size. Thereafter each 32bit unsigned int entry in the blockmap file corresponds to one block in the image file. Each entry counts how many carved files contain this block. Requires more memory and disk. **EXPERIMENTAL** .TP \fB\-h\fR Show a help screen and exit. .TP \fB\-i\fR \fIfile\fR \fIfile\fR is used as a list of input files to examine. Each line in the specified file should contain a single filename. .TP \fB-o\fR \fIdirectory\fR Recovered files are written to the directory \fIdirectory\fR. Scalpel requires that this directory be either empty or not exist. The directory will be created if necessary. .TP \fB\-O\fR Don't organize carved files by type. Default is to organize carved files into subdirectories to make previewing of large numbers of carved files easier. .TP \fB\-p\fR Perform image file preview; audit log indicates which files would have been carved, but no files are actually carved. .TP \fB\-q\fR \fIclustersize\fR Carve only when header is cluster-aligned. .TP \fB\-r\fR Find only first of overlapping headers/footers [foremost 0.69 compat mode] .TP \fB-s\fR \fInumber\fR Skips \fInumber\fR bytes in each input file before beginning the search for file headers and footers. .TP \fB\-t\fR Set directory for coverage blockmap. **EXPERIMENTAL** .TP \fB\-u\fR Use carve coverage blockmap when carving. Carve only sections of the image whose entries in the blockmap are 0. These areas are treated as contiguous regions. **EXPERIMENTAL** .TP \fB\-V\fR Show copyright information and exit. .TP \fB\-v\fR Enables verbose mode. This causes copious amounts of debugging information to be output. .PP .SH CONFIGURATION FILE The configuration file is used to control the types of files Scalpel will attempt to carve. A sample configuration file, "scalpel.conf", is included with this distribution. For each file type, the configuration file describes the file's extension, whether the header and footer are case sensitive, the maximum file size, and the header and footer for the file. The footer field is optional, but the header, size, case sensitivity, and extension fields are required. Important note: The default configuration file has all supported file patterns commented out--you must edit this before before running Scalpel. Any line in the configuration file that begins with a pound sign is considered a comment and ignored. Headers and footers are decoded before use. To specify a value in hexadecimal use \\x[0-f][0-f], and for octal use \\[1-9][1-9][1-9]. Spaces can be represented by \\s. Example: "\\x4F\\123\\I\\sCCI" decodes to "OSI CCI". To match any single character (aka a wildcard) use a '?'. If you need to search for the '?' character, you will need to change the 'wildcard' line *and* every occurrence of the old wildcard character in the configuration file, including those appearing in hex and octal values. '?' is equal to \\x3f and \\063. .SH AUTHORS Written by Golden G. Richard III. The first version of Scalpel was based on foremost 0.69, which was written by Special Agent Kris Kendall and Special Agent Jesse Kornblum of the United States Air Force Office of Special Investigations. .SH BUGS AND LIMITATIONS It is currently not possible to carve physical block devices directly using the Windows version of Scalpel. This is a limitation that will be removed in a future release of Scalpel. .SH "REPORTING BUGS" When submitting a bug report, please include a description of the problem, how you found it, and your contact information. .PP Send bug reports to: .br golden@digitalforensicssolutions.com .PP .SH COPYRIGHT .PP This is free software. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" More information on Scalpel appears in the README file, distributed with the Scalpel source code. .PP scalpel-1.60/scalpel.c100666 0 0 47264 10536335537 13170 0ustar usergroup// Scalpel Copyright (C) 2005-6 by Golden G. Richard III. // Written by Golden G. Richard III. // // This program is free software; you can redistribute it and/or // modify it 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; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301, USA. // Scalpel is a complete rewrite of the foremost 0.69 file carver to // increase speed and support execution on machines with minimal // resources (e.g., < 256MB RAM). // // Thanks to Kris Kendall, Jesse Kornblum, et al for their work on // foremost. Additional thanks to Vassil Roussev and Vico Marziale, of the // Department of Computer Science at the University of New Orleans, for // ongoing support of Scalpel. // // Scalpel currently uses the SAME configuration file format as // foremost 0.69. This may change in the future, because of some // planned new features. // #include "scalpel.h" void usage() { printf("Carves files from a disk image based on file headers and footers.\n"); printf("\nUsage: scalpel [-b] [-c ] [-d] [-h|V] [-i ]\n"); printf(" [-m blocksize] [-n] [-o ] [-O num] [-q clustersize]\n"); printf(" [-r] [-s num] [-t ] [-u] [-v]\n"); printf(" [] ...\n\n"); printf("-b Carve files even if defined footers aren't discovered within\n"); printf(" maximum carve size for file type [foremost 0.69 compat mode].\n"); printf("-c Choose configuration file.\n"); printf("-d Generate header/footer database; will bypass certain optimizations\n"); printf(" and discover all footers, so performance suffers. Doesn't affect\n"); printf(" the set of files carved. **EXPERIMENTAL**\n"); printf("-h Print this help message and exit.\n"); printf("-i Read names of disk images from specified file.\n"); printf("-m Generate/update carve coverage blockmap file. The first 32bit\n"); printf(" unsigned int in the file identifies the block size. Thereafter\n"); printf(" each 32bit unsigned int entry in the blockmap file corresponds\n"); printf(" to one block in the image file. Each entry counts how many\n"); printf(" carved files contain this block. Requires more memory and\n"); printf(" disk. **EXPERIMENTAL**\n"); printf("-n Don't add extensions to extracted files.\n"); printf("-o Set output directory for carved files.\n"); printf("-O Don't organize carved files by type. Default is to organize carved files\n"); printf(" into subdirectories.\n"); printf("-p Perform image file preview; audit log indicates which files\n"); printf(" would have been carved, but no files are actually carved.\n"); printf("-q Carve only when header is cluster-aligned.\n"); printf("-r Find only first of overlapping headers/footers [foremost 0.69 compat mode].\n"); printf("-s Skip n bytes in each disk image before carving.\n"); printf("-t Set directory for coverage blockmap. **EXPERIMENTAL**\n"); printf("-u Use carve coverage blockmap when carving. Carve only sections\n"); printf(" of the image whose entries in the blockmap are 0. These areas\n"); printf(" are treated as contiguous regions. **EXPERIMENTAL**\n"); printf("-V Print copyright information and exit.\n"); printf("-v Verbose mode.\n"); } // signal handler, sets global variable 'signal_caught' which is // checked periodically during carve operations. Allows clean // shutdown. void catch_alarm (int signum) { signal_caught = signum; signal(signum,catch_alarm); #ifdef __DEBUG fprintf(stderr,"\nCaught signal: %s.\n",(char*) strsignal(signum)); #endif fprintf (stderr, "\nKill signal detected. Cleaning up...\n"); } int extractSearchSpecData(struct SearchSpecLine *s,char **tokenarray) { // process one line from config file: // token[0] = suffix // token[1] = case sensitive? // token[2] = maximum carve size // token[3] = begintag // token[4] = endtag // token[5] = search type (optional) s->suffix = malloc(MAX_SUFFIX_LENGTH*sizeof(char)); s->begin = malloc(MAX_STRING_LENGTH*sizeof(char)); s->end = malloc(MAX_STRING_LENGTH*sizeof(char)); if (!strncasecmp(tokenarray[0], SCALPEL_NOEXTENSION_SUFFIX, strlen(SCALPEL_NOEXTENSION_SUFFIX))) { s->suffix[0] = SCALPEL_NOEXTENSION; s->suffix[1] = 0; } else { memcpy(s->suffix,tokenarray[0],MAX_SUFFIX_LENGTH); } // case sensitivity check s->casesensitive = (!strncasecmp(tokenarray[1],"y",1) || !strncasecmp(tokenarray[1],"yes",3)); //#ifdef __WIN32 // s->length = _atoi64(tokenarray[2]); //#else // s->length = atoull(tokenarray[2]); //#endif s->length = strtoull(tokenarray[2], 0, 10); // determine search type for this needle s->searchtype = SEARCHTYPE_FORWARD; if (!strncasecmp(tokenarray[5],"REVERSE",strlen("REVERSE"))) { s->searchtype = SEARCHTYPE_REVERSE; } else if (!strncasecmp(tokenarray[5],"NEXT",strlen("NEXT"))) { s->searchtype = SEARCHTYPE_FORWARD_NEXT; } // FORWARD is the default, but OK if the user defines it explicitly else if (!strncasecmp(tokenarray[5],"FORWARD",strlen("FORWARD"))) { s->searchtype = SEARCHTYPE_FORWARD; } s->beginlength = translate(tokenarray[3]); memcpy(s->begin,tokenarray[3],s->beginlength); s->endlength = translate(tokenarray[4]); memcpy(s->end,tokenarray[4],s->endlength); init_bm_table(s->begin,s->begin_bm_table,s->beginlength, s->casesensitive); init_bm_table(s->end,s->end_bm_table,s->endlength, s->casesensitive); return SCALPEL_OK; } int processSearchSpecLine(struct scalpelState *state, char *buffer, int lineNumber) { char *buf = buffer; char *token; char **tokenarray = (char **) malloc(6*sizeof(char[MAX_STRING_LENGTH+1])); int i = 0, err=0, len = strlen(buffer); // murder CTRL-M (0x0d) characters if (buffer[len-2] == 0x0d && buffer[len-1] == 0x0a) { buffer[len-2] = buffer[len-1]; buffer[len-1] = buffer[len]; } buf = (char*) skipWhiteSpace(buf); token = strtok(buf," \t\n"); // lines beginning with # are comments if(token == NULL || token[0] == '#'){ return SCALPEL_OK; } // allow wildcard to be changed if (!strncasecmp(token,"wildcard",9)) { if ((token = strtok(NULL," \t\n")) != NULL) { translate(token); } else { fprintf (stdout,"Warning: Empty wildcard in configuration file line %d. Ignoring.\n", lineNumber); return SCALPEL_OK; } if (strlen(token) > 1) { fprintf(stderr,"Warning: Wildcard can only be one character," " but you specified %d characters.\n" " Using the first character, \"%c\", as the wildcard.\n", (int)strlen(token),token[0]); } wildcard = token[0]; return SCALPEL_OK; } while (token && (i < NUM_SEARCH_SPEC_ELEMENTS)){ tokenarray[i] = token; i++; token = strtok(NULL," \t\n"); } switch(NUM_SEARCH_SPEC_ELEMENTS-i){ case 2: tokenarray[NUM_SEARCH_SPEC_ELEMENTS-1] = ""; tokenarray[NUM_SEARCH_SPEC_ELEMENTS-2] = ""; break; case 1: tokenarray[NUM_SEARCH_SPEC_ELEMENTS-1] = ""; break; case 0: break; default: fprintf(stderr, "\nERROR: In line %d of the configuration file, expected %d tokens,\n" " but instead found only %d.\n", lineNumber,NUM_SEARCH_SPEC_ELEMENTS,i); return SCALPEL_ERROR_NO_SEARCH_SPEC; break; } if ((err = extractSearchSpecData(&(state->SearchSpec[state->specLines]), tokenarray))) { switch(err) { default: fprintf(stderr, "\nERROR: Unknown error on line %d of the configuration file.\n" ,lineNumber); } } state->specLines++; return SCALPEL_OK; } // process configuration file int readSearchSpecFile(struct scalpelState *state) { int lineNumber=0, status; FILE *f; char *buffer = malloc((NUM_SEARCH_SPEC_ELEMENTS * MAX_STRING_LENGTH + 1) * sizeof(char)); f = fopen(state->conffile,"r"); if (f == NULL) { fprintf (stderr, "ERROR: Couldn't open configuration file: %s -- %s\n", state->conffile,strerror(errno)); free(buffer); return SCALPEL_ERROR_FILE_OPEN; } while (fgets(buffer,NUM_SEARCH_SPEC_ELEMENTS * MAX_STRING_LENGTH, f)) { lineNumber++; if (state->specLines > MAX_FILE_TYPES) { fprintf(stderr,"Your conf file contains too many file types.\n"); fprintf(stderr,"This version was compiled with MAX_FILE_TYPES == %d.\n", MAX_FILE_TYPES); fprintf(stderr,"Increase MAX_FILE_TYPES, recompile, and try again.\n"); free(buffer); return SCALPEL_ERROR_TOO_MANY_TYPES; } if ((status = processSearchSpecLine(state,buffer,lineNumber)) != SCALPEL_OK) { free(buffer); return status; } } // add an empty object to the end of the list as a marker state->SearchSpec[state->specLines].suffix = NULL; state->SearchSpec[state->specLines].casesensitive = 0; state->SearchSpec[state->specLines].length = 0; state->SearchSpec[state->specLines].begin = NULL; state->SearchSpec[state->specLines].beginlength = 0; state->SearchSpec[state->specLines].end = NULL; state->SearchSpec[state->specLines].endlength = 0; // GGRIII: offsets field is uninitialized--it doesn't // matter, since we won't use this entry. fclose(f); free(buffer); return SCALPEL_OK; } // Register the signal-handler that will write to the audit file and // close it if we catch a SIGINT or SIGTERM void registerSignalHandlers() { if (signal (SIGINT, catch_alarm) == SIG_IGN) { signal (SIGINT, SIG_IGN); } if (signal (SIGTERM, catch_alarm) == SIG_IGN) { signal (SIGTERM, SIG_IGN); } #ifndef __WIN32 // *****GGRIII: is this problematic? // From foremost 0.69: /* Note: I haven't found a way to get notified of console resize events in Win32. Right now the statusbar will be too long or too short if the user decides to resize their console window while foremost runs.. */ signal(SIGWINCH, setttywidth); #endif } // initialize state variable and copy command line arguments void initializeState(char **argv, struct scalpelState *state) { char** argvcopy = argv; int sss; int i; // Allocate memory for the state state->imagefile = (char*) malloc(MAX_STRING_LENGTH * sizeof(char)); state->inputFileList = (char*) malloc(MAX_STRING_LENGTH * sizeof(char)); state->conffile = (char*) malloc(MAX_STRING_LENGTH * sizeof(char)); state->outputdirectory = (char*) malloc(MAX_STRING_LENGTH * sizeof(char)); state->invocation = (char*) malloc(MAX_STRING_LENGTH * sizeof(char)); // GGRIII: memory allocation made more sane, because we're storing // more information in Scalpel than foremost had to, for each file // type. sss = (MAX_FILE_TYPES+1)*sizeof(struct SearchSpecLine); state->SearchSpec = (struct SearchSpecLine*) malloc(sss); state->specLines = 0; // GGRIII: initialize header/footer offset data, carved file count, // et al. The header/footer database is re-initialized in "dig.c" // after each image file is processed (numfilestocarve and // organizeDirNum are not). Storage for the header/footer offsets // will be reallocated as needed. for (i=0; i < MAX_FILE_TYPES; i++) { state->SearchSpec[i].offsets.headers=0; state->SearchSpec[i].offsets.footers=0; state->SearchSpec[i].offsets.numheaders=0; state->SearchSpec[i].offsets.numfooters=0; state->SearchSpec[i].offsets.headerstorage=0; state->SearchSpec[i].offsets.footerstorage=0; state->SearchSpec[i].numfilestocarve=0; state->SearchSpec[i].organizeDirNum=0; } state->fileswritten = 0; state->skip = 0; state->organizeMaxFilesPerSub=MAX_FILES_PER_SUBDIRECTORY; state->modeVerbose = FALSE; state->modeNoSuffix = FALSE; state->useInputFileList = FALSE; state->carveWithMissingFooters=FALSE; state->noSearchOverlap=FALSE; state->generateHeaderFooterDatabase=FALSE; state->updateCoverageBlockmap=FALSE; state->useCoverageBlockmap=FALSE; state->blockAlignedOnly=FALSE; state->organizeSubdirectories=TRUE; state->previewMode=FALSE; state->ignoreEmbedded=FALSE; state->auditFile = NULL; // default values for output directory, config file, wildcard character, // coverage blockmap directory strncpy(state->outputdirectory,SCALPEL_DEFAULT_OUTPUT_DIR, strlen(SCALPEL_DEFAULT_OUTPUT_DIR)); strncpy(state->conffile,SCALPEL_DEFAULT_CONFIG_FILE, MAX_STRING_LENGTH); state->coveragedirectory = state->outputdirectory; wildcard = SCALPEL_DEFAULT_WILDCARD; signal_caught = 0; state->invocation[0]=0; // copy the invocation string into the state do { strncat(state->invocation, *argvcopy, MAX_STRING_LENGTH-strlen(state->invocation)); strncat(state->invocation, " ", MAX_STRING_LENGTH-strlen(state->invocation)); ++argvcopy; } while (*argvcopy); registerSignalHandlers(); } // parse command line arguments void processCommandLineArgs(int argc, char **argv, struct scalpelState *state) { char i; while ((i = getopt(argc, argv, "bhvVundpq:rt:c:o:s:i:m:O")) != -1) { switch (i) { case 'V': fprintf (stdout,SCALPEL_COPYRIGHT_STRING); exit(1); case 'h': usage(); exit(1); case 's': state->skip = strtoull(optarg,NULL,10); fprintf (stdout,"Skipping the first %lld bytes of each image file.\n", state->skip); break; case 'c': strncpy(state->conffile,optarg,MAX_STRING_LENGTH); break; case 'd': state->generateHeaderFooterDatabase=TRUE; break; // -e support is currently a work-in-progress and will be enabled in a future release // case 'e': // state->ignoreEmbedded=TRUE; // break; case 'm': state->updateCoverageBlockmap=TRUE; state->coverageblocksize=strtoul(optarg,NULL,10); if (state->coverageblocksize <= 0) { fprintf(stderr, "\nERROR: Invalid blocksize for -m command line option.\n"); exit(1); } break; case 'o': strncpy(state->outputdirectory,optarg,MAX_STRING_LENGTH); break; case 't': state->coveragedirectory = (char *) malloc(MAX_STRING_LENGTH * sizeof(char)); strncpy(state->coveragedirectory,optarg,MAX_STRING_LENGTH); break; case 'O': state->organizeSubdirectories=FALSE; break; case 'p': state->previewMode=TRUE; break; case 'b': state->carveWithMissingFooters=TRUE; break; case 'i': state->useInputFileList = TRUE; state->inputFileList = optarg; break; case 'n': state->modeNoSuffix = TRUE; fprintf (stdout,"Extracting files without filename extensions.\n"); break; case 'q': state->blockAlignedOnly=TRUE; state->alignedblocksize=strtoul(optarg,NULL,10); if (state->alignedblocksize <= 0) { fprintf(stderr, "\nERROR: Invalid blocksize for -q command line option.\n"); exit(1); } break; case 'r': state->noSearchOverlap=TRUE; break; case 'u': state->useCoverageBlockmap=TRUE; break; case 'v': state->modeVerbose=TRUE; break; default: exit(1); } } } // full pathnames for all files used void convertFileNames(struct scalpelState *state) { char fn[MAX_STRING_LENGTH]; realpath(state->outputdirectory,fn); strncpy(state->outputdirectory,fn,MAX_STRING_LENGTH); realpath(state->conffile,fn); strncpy(state->conffile,fn,MAX_STRING_LENGTH); } // GGRIII: for each file, build header/footer offset database first, // then carve files based on this database. Need to clear the // header/footer offset database after processing of each file. void digAllFiles(int argc, char **argv, struct scalpelState *state) { int i = 0, j = 0; FILE* listoffiles = NULL; if (state->useInputFileList) { fprintf(stdout, "Batch mode: reading list of images from %s.", state->inputFileList); listoffiles = fopen(state->inputFileList,"r"); if (listoffiles == NULL) { fprintf(stderr, "Couldn't open file: %s -- %s\n", (*(state->inputFileList)=='\0')?"":state->inputFileList, strerror(errno)); closeFile(state->auditFile); exit(-1); } j=0; do { j++; if (fgets(state->imagefile,MAX_STRING_LENGTH,listoffiles) == NULL) { fprintf(stderr, "Error reading line %d of %s. Skipping line.\n", j,state->inputFileList); continue; } if(state->imagefile[strlen(state->imagefile)-1] == '\n'){ state->imagefile[strlen(state->imagefile)-1] = '\x00'; } // GGRIII: this function now *only* builds the header/footer // database. Carving is handled afterward, in carveImageFile(). if ((i = digImageFile(state))) { handleError(state,i); } else { // GGRIII: "digging" is now complete and header/footer database // has been built. The function carveImageFile() performs // extraction of files based on this database. if ((i = carveImageFile(state))) { handleError(state,i); } } } while (!feof(listoffiles)); closeFile(listoffiles); } else { do { state->imagefile = *argv; // GGRIII: this function now *only* builds the header/footer // database. Carving is handled afterward, in carveImageFile(). if ((i = digImageFile(state))) { handleError(state,i); } else { // GGRIII: "digging" is now complete and header/footer database // has been built. The function carveImageFile() performs extraction // of files based on this database. if ((i = carveImageFile(state))) { handleError(state,i); } } ++argv; } while (*argv); } } int main(int argc, char **argv) { time_t starttime=time(0); struct scalpelState state; if (ldiv(SIZE_OF_BUFFER,SCALPEL_BLOCK_SIZE).rem != 0) { fprintf (stderr, SCALPEL_SIZEOFBUFFER_PANIC_STRING); exit (-1); } #ifndef __GLIBC__ setProgramName(argv[0]); #endif fprintf (stdout,SCALPEL_BANNER_STRING); initializeState(argv,&state); processCommandLineArgs(argc,argv,&state); convertFileNames(&state); if (state.modeVerbose) { fprintf (stdout,"Output directory: \"%s\"\n", state.outputdirectory); fprintf (stdout,"Configuration file: \"%s\"\n", state.conffile); fprintf (stdout,"Coverage maps directory: \"%s\"\n", state.coveragedirectory); } // read configuration file if (readSearchSpecFile(&state)) { // error in configuration file, msg has already been output exit(-1); } setttywidth(); argv += optind; if (*argv != NULL || state.useInputFileList) { // prepare audit file and make sure output directory is empty. if(openAuditFile(&state)){ fprintf(stderr, "Aborting.\n\n"); exit(-1); } digAllFiles(argc,argv,&state); closeFile(state.auditFile); } else { usage(); fprintf(stdout,"\nERROR: No image files specified.\n\n"); } #ifdef __WIN32 fprintf (stdout,"\nScalpel is done, files carved = %I64u, elapsed = %ld seconds.\n", state.fileswritten, (int)time(0) - starttime); #else fprintf (stdout,"\nScalpel is done, files carved = %llu, elapsed = %ld seconds.\n", state.fileswritten, (int)time(0) - starttime); #endif return 0; } scalpel-1.60/scalpel.conf100666 0 0 20720 10423530403 13637 0ustar usergroup# Scalpel configuration file # This configuration file controls the # types and sizes of files that are carved by Scalpel. Currently, # Scalpel can read Foremost 0.69 configuration files, but Scalpel # configuration files may not be backwards-compatible with Foremost. # In particular, maximum file carve size under Foremost 0.69 is 4GB, # while in the current version of Scalpel, it's 16EB (16 exabytes). # For each file type, the configuration file # describes the file's extension, whether the header and footer are # case sensitive, the maximum file size, and the header and footer for # the file. The footer field is optional, but header, size, case # sensitivity, and extension are required. Any line that begins with a # '#' is considered a comment and ignored. Thus, to skip a file type # just put a '#' at the beginning of that line # Headers and footers are decoded before use. To specify a value in # hexadecimal use \x[0-f][0-f] and for octal use \[0-3][0-7][0-7]. # Spaces can be represented by \s. Example: "\x4F\123\I\sCCI" decodes # to "OSI CCI". # To match any single character (aka a wildcard) use # a '?'. If you need to search for the '?' character, you will need to # change the 'wildcard' line *and* every occurrence of the old # wildcard character in the configuration file. ' # # Note: ?' is equal to 0x3f and \063. # # If you want files carved without filename extensions, # use "NONE" in the extension column. # The REVERSE keyword after a footer causes a search # backwards starting from [size] bytes beyond the location of the header # This is useful for files like PDFs that may contain multiple copies of # the footer throughout the file. When using the REVERSE keyword you will # extract bytes from the header to the LAST occurence of the footer (and # including the footer in the carved file). # # The NEXT keyword after a footer results in file carves that # include the header and all data BEFORE the first occurence of the # footer (the footer is not included in the carved file). If no # occurrence of the footer is discovered within maximum carve size bytes # from the header, then a block of the disk image including the header # and with length equal to the maximum carve size is carved. Use NEXT # when there is no definitive footer for a file type, but you know which # data should NOT be included in a carved file--e.g., the beginning of # a subsequent file of the same type. # # FORWARD_NEXT is the default carve type and this keyword may be # included after the footer, but is not required. For FORWARD_NEXT # carves, a block of data including the header and the first footer # (within the maximum carve size) are carved. If no footer appears # after the header within the maximum carve size, then no carving is # performed UNLESS the -b command line option is supplied. In this case, # a block of max carve size bytes, including the header, is carved and a # notation is made in the Scalpel log that the file was chopped. # To redefine the wildcard character, change the setting below and all # occurences in the formost.conf file. # #wildcard ? # case size header footer #extension sensitive # #--------------------------------------------------------------------- # EXAMPLE WITH NO SUFFIX #--------------------------------------------------------------------- # # Here is an example of how to use the no extension option. Any files # beginning with the string "FOREMOST" are carved and no file extensions # are used. No footer is defined and the max carve size is 1000 bytes. # # NONE y 1000 FOREMOST # #--------------------------------------------------------------------- # GRAPHICS FILES #--------------------------------------------------------------------- # # # AOL ART files # art y 150000 \x4a\x47\x04\x0e \xcf\xc7\xcb # art y 150000 \x4a\x47\x03\x0e \xd0\xcb\x00\x00 # # GIF and JPG files (very common) # gif y 5000000 \x47\x49\x46\x38\x37\x61 \x00\x3b # gif y 5000000 \x47\x49\x46\x38\x39\x61 \x00\x3b # jpg y 200000000 \xff\xd8\xff\xe0\x00\x10 \xff\xd9 # # # PNG # png y 20000000 \x50\x4e\x47? \xff\xfc\xfd\xfe # # # BMP (used by MSWindows, use only if you have reason to think there are # BMP files worth digging for. This often kicks back a lot of false # positives # # bmp y 100000 BM??\x00\x00\x00 # # TIFF # tif y 200000000 \x49\x49\x2a\x00 # TIFF # tif y 200000000 \x4D\x4D\x00\x2A # #--------------------------------------------------------------------- # ANIMATION FILES #--------------------------------------------------------------------- # # AVI (Windows animation and DiVX/MPEG-4 movies) # avi y 50000000 RIFF????AVI # # Apple Quicktime # These needles are based on the file command's magic. I don't # recommend uncommenting the 4th and 5th Quicktime needles unless # you're sure you need to, because they generate HUGE numbers of # false positives. # # mov y 10000000 ????moov # mov y 10000000 ????mdat # mov y 10000000 ????widev # mov y 10000000 ????skip # mov y 10000000 ????free # mov y 10000000 ????idsc # mov y 10000000 ????pckg # # MPEG Video # mpg y 50000000 \x00\x00\x01\xba \x00\x00\x01\xb9 # mpg y 50000000 \x00\x00\x01\xb3 \x00\x00\x01\xb7 # # Macromedia Flash # fws y 4000000 FWS # #--------------------------------------------------------------------- # MICROSOFT OFFICE #--------------------------------------------------------------------- # # Word documents # # # doc y 10000000 \xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1\x00\x00 \xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1\x00\x00 NEXT # doc y 10000000 \xd0\xcf\x11\xe0\xa1\xb1 # # Outlook files # pst y 500000000 \x21\x42\x4e\xa5\x6f\xb5\xa6 # ost y 500000000 \x21\x42\x44\x4e # # Outlook Express # dbx y 10000000 \xcf\xad\x12\xfe\xc5\xfd\x74\x6f # idx y 10000000 \x4a\x4d\x46\x39 # mbx y 10000000 \x4a\x4d\x46\x36 # #--------------------------------------------------------------------- # WORDPERFECT #--------------------------------------------------------------------- # # wpc y 1000000 ?WPC # #--------------------------------------------------------------------- # HTML #--------------------------------------------------------------------- # # htm n 50000 # #--------------------------------------------------------------------- # ADOBE PDF #--------------------------------------------------------------------- # # pdf y 5000000 %PDF %EOF\x0d REVERSE # pdf y 5000000 %PDF %EOF\x0a REVERSE # #--------------------------------------------------------------------- # AOL (AMERICA ONLINE) #--------------------------------------------------------------------- # # AOL Mailbox # mail y 500000 \x41\x4f\x4c\x56\x4d # # # #--------------------------------------------------------------------- # PGP (PRETTY GOOD PRIVACY) #--------------------------------------------------------------------- # # PGP Disk Files # pgd y 500000 \x50\x47\x50\x64\x4d\x41\x49\x4e\x60\x01 # # Public Key Ring # pgp y 100000 \x99\x00 # Security Ring # pgp y 100000 \x95\x01 # pgp y 100000 \x95\x00 # Encrypted Data or ASCII armored keys # pgp y 100000 \xa6\x00 # (there should be a trailer for this...) # txt y 100000 -----BEGIN\040PGP # # #--------------------------------------------------------------------- # RPM (Linux package format) #--------------------------------------------------------------------- # rpm y 1000000 \xed\xab # # #--------------------------------------------------------------------- # SOUND FILES #--------------------------------------------------------------------- # # wav y 200000 RIFF????WAVE # # Real Audio Files # ra y 1000000 \x2e\x72\x61\xfd # ra y 1000000 .RMF # #--------------------------------------------------------------------- # WINDOWS REGISTRY FILES #--------------------------------------------------------------------- # # Windows NT registry # dat y 4000000 regf # Windows 95 registry # dat y 4000000 CREG # # #--------------------------------------------------------------------- # MISCELLANEOUS #--------------------------------------------------------------------- # # zip y 10000000 PK\x03\x04 \x3c\xac # # java y 1000000 \xca\xfe\xba\xbe # #--------------------------------------------------------------------- # ScanSoft PaperPort "Max" files #--------------------------------------------------------------------- # max y 1000000 \x56\x69\x47\x46\x6b\x1a\x00\x00\x00\x00 \x00\x00\x05\x80\x00\x00 #--------------------------------------------------------------------- # PINs Password Manager program #--------------------------------------------------------------------- # pins y 8000 \x50\x49\x4e\x53\x20\x34\x2e\x32\x30\x0d scalpel-1.60/scalpel.exe100777 0 0 246465 10536370174 13552 0ustar usergroupMZ@ !L!This program cannot be run in DOS mode. $PEL|yE 8 @ ( .textԤ``.data`@.rdata0*,@@.bss.idata @U]U1ۉu1=wC=r[$1D$蔠tlt*$л؋u]]=t=t؋u]]v=u$ 1t$7t4t$ $\$t腉$ L$b US$]$@ڢ2EAU\$ @D$T$L$ $A豟tX0@Ht D$HK0 $fHt\$ HQP$@+0@^L$AT$A$ ž$ D$HB$HUv'U$(&U$(&U h]t&U P]ᐐU]闉US$øD$E$D$Þu$@`[]É$0v`[]Ðt&UuHu ]@]\$t$$V\$Et$@($@]u]ÍUSM] : 8 Шu;Uu9,A<9€@ Шu$z)Й1)1҃ t&[][1҉]Ít&UWVS }t2]u v'FMCL$T$$UtOuރ 1҉[^_]FS [)‰^_]Í&'UWVS 1ۋ} ECv19soN?4Mu+U~ $4U$ќ4CN;]s+U:u14@=vU떃 [^_]Ít&Uuu }}]] tR;]sI;Ut;]rut&ED$ U ؉T$)Ѝtt$E$tC1]u}]Ív]u}]ÐUU BD$ET$D$ED$ED$ ED$E$5ÍvUMS1ۋt51 D 9~Ë 9~Áh u܉[]Í&U1WVS'U(]E]uuEE }}t ]u}]áH$t@@D$ D$D$ԗt$ @|$D$H@$CED$@D$H@$#t$ @|$L$C($E@T$D$C($]u]E }]U8$.U؉T$$,u PEأÍ&'UWVS1ۋu} rD$F0V4D$@T$ D$H@$@CHL$$P@@D$ D$z$莙1D$ F0V4<$D$T$OjD$V4F0T$ l@D$T$H@$誖e[^_]áH$@@D$ #D$D$e1[^_]ÐUVS]$mtj1ۉ4$}t$4$lCu4$诎[^]Ív$@HT$@D$ D$V1[^]X8t2N$4D$ H@\$L$H@$裕뻉$t"$\$x@D$ \$$苊 U<WVS$]葕$mNjC$tvC4$D$ @D$D$ 4$@D$oC(tBC@D$CD$C,|$ #@$D$|$t$蓔1ҁ<[^_]$D$ (@D$Ht$@$T뼍'US]$芔EE$lD$@@$D$$/[Ѓ] U1҉SÉT$E$D$1҅x$D$ED$ԇ1҅ƒ[]Ðt&UEWVSLD$E$EEu EUE؉U11һ\$ L$T$U$觇ED$U$譓tqEӉ΋x$$EԉD$<$ UB%=0tA1|$ U܋E؉T$D$U$(W؉+EU܃L[^_]ËUM$T@H D$ 2D$D$ܑEEEEEUĉEȉUEUċEUĉ$T$BuЍ&'EUă;UrOw;EvH]ȉu]u$t$tTűEUĉ]ȃ;Us']ȋűUԃ  $諑]ueE @ uHL[^_]ËE p t$@H=\$L$ D$ 蕐$@H D$ $D$D$it$ZD$@D$H $͐]U$@n$D@b$@V$@J$@>$@@2$@&$@$@$0@$x@$@$@ސ$@Ґ$H@Ɛ$@躐$@讐$@袐$N@薐$l@芐$@~$@r$@f$0@Z$p@N$@B$@6$0@*$d@$@$@$(@$d@$@U"@EL$$p1$@H&T$@D$ D$GÐt&UW@VS]$u 蠎$蒎C$胎T$|$$薏3@1@FL$T$$d6{ 1D$1D$F$xCFS @ L$T$$  F $CKV D$ $T$hF$VD$ $T$>CD$ CD$CD$C$CD$ D$ D$$1[^_]Ë1 B@AFL$T$$.F@L$T$$ F@L$T$$ڍF@L$T$$赍1UWV1S] $`V$l| ?E $$@T$3 8#$ D$@D$&&'@FD$$׌1҃…uԸ)t$@|$ Et$D$H@$x[^_]$@D$V$$L'1[^_]Í| D DGY@|$UZiB h؉$uUB GY@GY@ɋE\@L$D$H@$蕊ƅtT$D$ @D$H@$f0(@UD$HT$ $AUWV1Sj@$`E\$UB$蟊]t&|$`D$M $Ȋt mL]D$MAQt$D$@T$\$ D$4$6O$9C{tith4$@HL$\$ D$ N}G11p$@H D$ D$D$MX@h\L$hD$HT$ $NUBtu<D$@D$H $MWG$@H D$ D$D$)M+PEM $@H|$t$ D$ L\$HL$$@ D$ L\11E]É։$D$1D$ t$?,$\\;lrw;hv1\x$@H D$ .D$D$K$L@H D$ &D$D$KD$P@D$H@$ Ld\ ҅\#U$0AD$L$Ed`1dC md ` $]CduFDN}_luOhtUB@$KK$t@KMA11w@111҉(1h<1hP1T101@1ɉ418HL}Gt4<(x$J@p$sJc1P1TD$1D$ hl$T$G<Éփ1w;Pv/P,$XPT;TsNj,$I$@HK11҉[^_]Ë}D$hlD$$T$ T$ $,]Cd@$I D$C4$D$ @D$D$dI|$4$ID$G$N=EH11tpp<8D$@t$ $H8@<\$D$T$ $lH<11819[(TT$$ED$@T$ L$$H3F<89wr9rTPT$ @D$T$$G5T11P19_t&@TT$$ED$@T$ D$ $eG FTP9wr9r]KthphtF<$6G1_uFD$GE!$1D$֋EE`)`ddG sd `\D$$Fu ]D$hlt$|$ + $$L$5 p։à Ш; +`d1ɉL$ |$$t$7,Љ$1ɉ|$L$ $t$7,ЉKu8Mu Q CSDH9 E]D ШtSUu$J  @$D DAq$$ 1111D$$n$pH Ш4$|$E= 111ECt$D$ D$0A$B111 l@@ $CD$ D$@D$H@$B@@ $ECD$ D$@D$MA($B1[^_]1s{1+@L$$BCSQB$BD$ D$@D$H@$BB$qBD$ D$@D$UB('YAqQ )111D$ D$D$ $U ]ClU1FV FVD$|$$_ 4$4$ <$ $MQ($T$ASD$@T$ D$uF($@@u@D$@D$UB($j@AQ +QD$@T$ D$uF($4@$*D$@D$F($@~hN<1WL$t$ $T$2ǐAQ MI<$T$L$1ɉL$ 19=r93][huG뱉1ɃL$ \$t$UB@$3MA@D$ D$D$$@H 1\$t$D$ MA@${3]C@4$D$ D$D$W>HL$@H|$)@D$ )D$!>C(t$D$ \$$@>$$> $ 4$O4$뽋"@\$D$H $&>]1AQ $T$EU][HM؋yF48$!أ8EtŰEM؋Q}؋G E3j@5ut(U x-tMċE6@ @tH} z-8D$D$ U D$@D$H@$@@8C@1xluEEE@;UDM B@4xEĀ84\@_Eĉ$L UċMУ8UB @9:D:@U}ĉ<$ )@t3Xjt$ U D$@D$H@$5@?@;U@} B@4 1M؃y@;U} B@]؉}G@95@}<:t:"8@D$ T$D$H@$M DD$ @L$D$H@$=8}iU D$ D$6@D$H@$ 8@Mnt$ T@M |$D$@t&t$ p@U L$D$H@$(5@M9:$?]؉}E t$ M D$p@D$H@$ @8$}أ8?:@t.U @D$ D$@D$H@$i8$k@أ8?}@D$ |$D$H@$<5@u_8$أ8?f18WUM D@D$ T$D$H@$}ػ@D$ U \$D$H@$q&'U111҉D$EL$T$ D$E D$E$OÐUWVS u==@@t.1ۍ9|PӃ qut& t [^_]á44$tكlj1@@ңA Au [^_]Í44$1`ljw=1@@;t&' Qut{<{+ Ut9}HX卶US]tMx;|1[]átu\$@D$$[]Ðt&묉'US]tMx;|1[]átu\$@D$$[]Ðt&{묉'UWVS 1ۋUtHtI59}*=t&tD$E$tC9|19!à [^_]밐t&U]]uu tht9w)t$@\$H@$]u]É2@t$L$D$ H@$]u]x두%% U0@Q@0@r]ÐU]ÐU@@t&  @@QA@@uÍ&US@t)t'@Ku$`@w[[]Ë Ĵ@1 @Ĵ@u뽍US u6@ t%tt&@Ku$`@w[[]Ë Ĵ@1 @Ĵ@uU]HUBSdT$U1ۉT$$ uFJx|*Au Jy;%(%,% %%$%X%%%t%%%%%%D%%%L%%x%\%p%%%0%%%%%%%%%%`%%l%%%%|%%%%%%d%%4%%8%@%<%%%%%%%%%%%%U]]@?@д@scalpelF@F@F@F@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@8@@@@@@@@@2@@@@@@@@@@@@@@@@@@@@@@@@@(@@@@@@@@@ @@@@@@F@Scalpel has encountered an error it doesn't knowhow to handle. Error code: %d Scalpel was unable to open the image file: %s Skipping... Scalpel will abort. Scalpel was unable to read the image file: %s Skipping... Scalpel was unable to read a needed file and will abort. ERROR: The configuration file didn't specify any file types to carve. (If you're using the default configuration file, you'll have to uncomment some of the file types.) Scalpel was unable to write output files and will abort. This error generally indicates that disk space is exhausted. ** MEMORY ALLOCATION FAILURE ** ERROR: Memory exhausted at line %d in file %s. Scalpel was allocating memory for %s when this condition occurred. ERROR: Couldn't skip %I64u bytes at the start of image file %s Waiting to try again... Skipped the first %I64u bytes of %s... Sorry, maximum retries exceeded... ERROR: You have attempted to use a non-empty output directory. In order to maintain forensic soundness, this is not allowed. An error occured while trying to open %s - %s An error occured while trying to create %s - %s %s/audit.txtw Scalpel version %s audit file Started at %sCommand line: %s Output directory: %s Configuration file: %s 1.60Couldn't open %s -- %s Completed at %sUsing binary search to measure block device size. fseeko() call to restore file position failed on image file. fseeko() call failed on image file. Diagnosis: %s Carves files from a disk image based on file headers and footers. Usage: scalpel [-b] [-c ] [-d] [-h|V] [-i ] [-m blocksize] [-n] [-o ] [-O num] [-q clustersize] [-r] [-s num] [-t ] [-u] [-v] [] ... -b Carve files even if defined footers aren't discovered within maximum carve size for file type [foremost 0.69 compat mode].-c Choose configuration file.-d Generate header/footer database; will bypass certain optimizations and discover all footers, so performance suffers. Doesn't affect the set of files carved. **EXPERIMENTAL**-h Print this help message and exit.-i Read names of disk images from specified file.-m Generate/update carve coverage blockmap file. The first 32bit unsigned int in the file identifies the block size. Thereafter each 32bit unsigned int entry in the blockmap file corresponds to one block in the image file. Each entry counts how many carved files contain this block. Requires more memory and disk. **EXPERIMENTAL**-n Don't add extensions to extracted files.-o Set output directory for carved files.-O Don't organize carved files by type. Default is to organize carved files into subdirectories.-p Perform image file preview; audit log indicates which files would have been carved, but no files are actually carved.-q Carve only when header is cluster-aligned.-r Find only first of overlapping headers/footers [foremost 0.69 compat mode].-s Skip n bytes in each disk image before carving.-t Set directory for coverage blockmap. **EXPERIMENTAL**-u Use carve coverage blockmap when carving. Carve only sections of the image whose entries in the blockmap are 0. These areas are treated as contiguous regions. **EXPERIMENTAL**-V Print copyright information and exit.-v Verbose mode. Kill signal detected. Cleaning up... NONEyREVERSEyesNEXTFORWARD wildcard ERROR: In line %d of the configuration file, expected %d tokens, but instead found only %d. ERROR: Unknown error on line %d of the configuration file. Warning: Wildcard can only be one character, but you specified %d characters. Using the first character, "%c", as the wildcard. Warning: Empty wildcard in configuration file line %d. Ignoring. rYour conf file contains too many file types. This version was compiled with MAX_FILE_TYPES == %d. Increase MAX_FILE_TYPES, recompile, and try again. ERROR: Couldn't open configuration file: %s -- %s scalpel.conf bhvVundpq:rt:c:o:s:i:m:OSkipping the first %lld bytes of each image file. ERROR: Invalid blocksize for -q command line option. Extracting files without filename extensions. ERROR: Invalid blocksize for -m command line option. Scalpel is (c) 2005-6 by Golden G. Richard III. This program is based on Foremost 0.69, by Kris Kendall and Jesse Kornblum..@T,@T,@T,@T,@T,@T,@f.@T,@T,@T,@T,@T,@T,@T,@T,@T,@T,@T,@Z.@@.@4.@T,@T,@T,@O,@ .@T,@T,@T,@-@-@m-@]-@,@,@,@r,@i,@`,@Batch mode: reading list of images from %s.Error reading line %d of %s. Skipping line. Couldn't open file: %s -- %s 1.60Scalpel version %s Written by Golden G. Richard III, based on Foremost 0.69. Scalpel is done, files carved = %I64u, elapsed = %ld seconds. ERROR: No image files specified. Output directory: "%s" Configuration file: "%s" Coverage maps directory: "%s" PANIC: SIZE_OF_BUFFER has been incorrectly configured. Aborting. \x%.2xCleaning up... Caught signal: %s. Program is terminating early Error closing %s/audit.txt -- %sUnable to compute progress. %s: %5.1f%% ****************************************************************************************************************************************************************|%.*s%*s| %6.1f %s %2d:%02d:%02d ETA --:--ETA_B:D5@8@o8@8@8@8@8@Coverage map decreased current file position by %I64u bytes. fread using coverage map read %I64u bytes. Issuing coverage map-based READ, wants %I64u bytes. fread using coverage map to skip %I64u bytes. Coverage map-based READ complete. fread using coverage map found %I64u consecutive bytes. Opening target "%s" The following files were carved: File Start Chop Length Extracted From Skipped the first %I64u bytes of %s... rbSetting up coverage maps. %s/%s.mapEMPTYNOT EMPTYCoverage blockmap file is %s. w+bError writing to coverage blockmap file: %s Image file pass 1/2. header arraydig.cfooter arrayA %s header was found at : %I64u Memory reallocation performed, total header storage = %I64u Read %I64u bytes from image file. Total file size is %I64u bytes Coverage blockmap is "%s". Error reading coverage blockmap blocksize in coverage blockmap file: %s Finished setting up coverage maps.Reading blocksize from Coverage blockmap file. Changing mode of coverage blockmap file to R/W. A %s footer was found at : %I64u Memory reallocation performed, total footer storage = %I64u ERROR: Couldn't measure size of image file %s -u option requires that the blockmap file %s exist. Writing empty coverage blockmap...this may take a while. Error writing initial entry in coverage blockmap file! # of blocks in coverage blockmap is %I64u. Blocksize for coverage blockmap is %u. Allocating and clearing coverage bitmap. coveragebitmapReading existing coverage blockmap...this may take a while. r+bUser-specified blocksize does not match blocksize in coverage blockmap file: %s ERROR: Couldn't open input file: %s -- %s Error reading coverage blockmap entry (blockmap truncated?): %s Error writing to coverage blockmap file! _carvelistsAllocating work queues... Work queues allocation complete. Building carve lists... %s/%s-%d-%1lu%s/%08I64ucarveinfo%s%s/%08I64u.%sCarve lists built. Workload: NONE" --> %I64u files %s with header "" and footer "Carving files from image. Image file pass 2/2. ** PREVIEW MODE: GENERATING AUDIT LOG ONLY ** ** NO CARVED FILES WILL BE WRITTEN ** Processing of image file complete. Cleaning up...Done.w%s/%s.hfd%s %I64u Error writing to file: %s -- %s abError opening file: %s -- %s %13I64u YES NO %3sOPENING %s CLOSING %s Error reading coverage blockmap entry! Error writing to header/footer database file: %s Error closing file: %s -- %s NULL pointer in function next_element() Advance past end in NULL pointer in function next_element() Malloc failed in function add_to_queue() NULL pointer in function remove_from_front() NULL pointer in function peek_at_current() NULL pointer in function pointer_to_current() NULL pointer in function update_current() NULL pointer in function delete_current() Malloc failed in function copy_queue() POSIXLY_CORRECT--%s: option `%c%s' doesn't allow an argument %s: unrecognized option `%c%s' %s: illegal option -- %c %s: unrecognized option `--%s' %s: option `%s' requires an argument %s: option `%s' is ambiguous %s: invalid option -- %c %s: option requires an argument -- %c %s: option `-W %s' is ambiguous %s: option `--%s' doesn't allow an argument %s: option `-W %s' doesn't allow an argument SIGINTInterruptSIGILLIllegal instructionSIGABRTAbortedSIGFPEArithmetic exceptionSIGSEGVSegmentation faultSIGTERMTerminated @'@1@8@L@T@\@c@ x@@@@Signal %d%s: unknown signal %s: %s   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~  !"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\]^_`abcdefghijklmnopqrstuvwxyz{|}~CBBBBQ00000000000000000000000000000000-LIBGCCW32-EH-2-SJLJ-GTHR-MINGW32w32_sharedptr->size == sizeof(W32_EH_SHARED)%s:%u: failed assertion `%s' ../../gcc/gcc/config/i386/w32-shared-ptr.cGetAtomNameA (atom, s, sizeof(s)) != 0/OhT|p 0<Ll(0<HXhx ,8DPXdlt| $08DP\ht  0<Ll(0<HXhx ,8DPXdlt| $08DP\ht AddAtomAExitProcessFindAtomAGetAtomNameAGetConsoleScreenBufferInfo2GetFileAttributesACGetLastErrorGetStdHandleSQueryPerformanceCounterTQueryPerformanceFrequencySetUnhandledExceptionFilterSleep!_fstat4_lseek8_mkdirA_readG_setmodeT_strdup'__getmainargs0__mb_cur_max<__p__environ>__p__fmodeP__set_app_typey_cexit_errno_filelengthi64_findclose_findfirst_findnext_fullpath_iob_isctype^_onexitg_pctype_setmode_snprintf_strnicmpabortatexit"ceil'ctime*exit-fclose0fflush2fgetpos3fgets8fopen9fprintf;fputs>fread?freeDfsetposGfwriteKgetenvlldivrmallocxmemcpyzmemsetprintfputsreallocsignalsprintfstrcmpstrcpystrerrorstrlenstrncatstrncmpstrncpystrtokstrtoultimetolowertouppervfprintf3pthread_mutex_lock6pthread_mutex_unlockKERNEL32.dllmsvcrt.dll((((((((((((((((((((((((((((((((((((((((((((((((((((((((((msvcrt.dll<<pthreadGC1.dll  @ _atexit` __onexitp .text|&.bss' .file#ghelpers.c7 G S@ d t   P   @        .textC.data.bss.rdataI.file3gfiles.c#@  6P  E`  P  ^ .text@ =.data.bss.rdata<.fileIgscalpel.c_usage o |   p `    @ _main  .textb .data.bss.rdata$(.file`gdig.cP# (# start.0freq.1 20$ C) `* yp, 0 3 0F .textP#F.data.bss .rdata0 .filegprioque.ci j k k l $@m 1`m Dn Un i o {o 0p p  q `q pq r s Pt t pu 6u Lv b@w vw @x x  x `w pj Pj  j $i :`i .text`i9.data.bss0.rdata .filegbase_name.cOx Zx .textxe.data.bss0dy .texty].data.bss0npy xy hxz 8XH_getopt0 .textpy .data .bss0X.rdatap"$p #- buf.18  buf.0C M _psignalp .textp/.data .bss.rdata $ .text.data .bss.rdata@%.text.data .bss.idata$7|.idata$5.idata$4.idata$6.text.data .bss.idata$7.idata$5 .idata$4.idata$6 .filegfakehnamefthunk.text .data .bss.idata$2<.idata$5.idata$4.filegfake.text .data .bss.idata$4.idata$5.idata$7.text .data .bss.text .data0.bss.text .data0.bss Y  .text (.data@.bss _fpresetP tP .textP.data@.bss ~ p.0@`  ___main .text`.data@.bss .textp.dataP.bss0@)p  @PP&X1  .textp,.dataP.bss@ .rdata@)probefdone}.text`-.data`.bss`M .text.data`.bss`Xp .textpU.data`.bss`bБ .textБ.data`.bss`lГ .textГ#.data`.bss`w .textX.data`.bss`.rdata *.text`.data`.bss`` .text`G.data`.bss`.text.data`.bss`.idata$7x.idata$5 .idata$4.idata$6<.text.data`.bss`.idata$7d.idata$5.idata$4.idata$6.textЕ.data`.bss`.idata$7p.idata$5.idata$4.idata$6(.text.data`.bss`.idata$7h.idata$5.idata$4.idata$6.text.data`.bss`.idata$7l.idata$5.idata$4.idata$6.text.data`.bss`.idata$7t.idata$5.idata$4.idata$60hnamefthunk.text.data`.bss`.idata$2.idata$5.idata$4.text.data`.bss`.idata$4.idata$5.idata$7|  .text.data`.bss`_opendir _readdir 0  _telldir _seekdir0 .text3#.data`.bss`  .text.data`.bss`.text.data`.bss`.idata$7.idata$5H.idata$4.idata$6.text.data`.bss`.idata$7.idata$5(.idata$4.idata$6.text.data`.bss`.idata$7.idata$5h.idata$4.idata$6X.text.data`.bss`.idata$7.idata$5P.idata$4.idata$6.text.data`.bss`.idata$7.idata$5,.idata$4.idata$6.text.data`.bss`.idata$7.idata$5 .idata$4.idata$6h.textР.data`.bss`.idata$74.idata$5.idata$4l.idata$6D.text.data`.bss`.idata$7.idata$5$.idata$4.idata$6x.text.data`.bss`.idata$7.idata$5X.idata$4.idata$6,.text.data`.bss`.idata$7.idata$5.idata$4.idata$6H.text.data`.bss`.idata$7.idata$5T.idata$4.idata$6 .text.data`.bss`.idata$7.idata$5.idata$4.idata$6X.text.data`.bss`.idata$7.idata$5.idata$4H.idata$6.text .data`.bss`.idata$7.idata$5t.idata$4.idata$6t.text0.data`.bss`.idata$7\.idata$5.idata$4.idata$6.text@.data`.bss`.idata$7T.idata$5.idata$4.idata$6.textP.data`.bss`.idata$7h.idata$5.idata$4.idata$6.text`.data`.bss`.idata$7d.idata$5.idata$4.idata$6.textp.data`.bss`.idata$7l.idata$5.idata$4.idata$6.text.data`.bss`.idata$7.idata$5D.idata$4.idata$6.text.data`.bss`.idata$7.idata$5.idata$4T.idata$6.text.data`.bss`.idata$7.idata$5.idata$44.idata$6.text.data`.bss`.idata$7.idata$5L.idata$4.idata$6.text.data`.bss`.idata$7.idata$5.idata$4@.idata$6.textС.data`.bss`.idata$7.idata$5x.idata$4 .idata$6|.text.data`.bss`.idata$7.idata$5\.idata$4.idata$68.text.data`.bss`.idata$7.idata$5p.idata$4.idata$6l.text.data`.bss`.idata$7`.idata$5.idata$4.idata$6.text.data`.bss`.idata$7D.idata$5.idata$4|.idata$6t.text .data`.bss`.idata$7.idata$50.idata$4.idata$6.text0.data`.bss`.idata$7.idata$5.idata$4(.idata$6.text@.data`.bss`.idata$7.idata$5.idata$40.idata$6.textP.data`.bss`.idata$7 .idata$5.idata$4X.idata$6 .text`.data`.bss`.idata$7,.idata$5.idata$4d.idata$60.textp.data`.bss`.idata$7.idata$5.idata$4P.idata$6.text.data`.bss`.idata$7L.idata$5.idata$4.idata$6.text.data`.bss`.idata$7.idata$5.idata$4,.idata$6.text.data`.bss`.idata$7X.idata$5.idata$4.idata$6.text.data`.bss`.idata$7H.idata$5.idata$4.idata$6.text.data`.bss`.idata$7.idata$5`.idata$4.idata$6D.textТ.data`.bss`.idata$7.idata$5.idata$48.idata$6.text.data`.bss`.idata$7.idata$5l.idata$4.idata$6d.text.data`.bss`.idata$7.idata$5.idata$4<.idata$6.text.data`.bss`.idata$7@.idata$5.idata$4x.idata$6h.text.data`.bss`.idata$70.idata$5.idata$4h.idata$68.text .data`.bss`.idata$7.idata$5|.idata$4$.idata$6.text0.data`.bss`.idata$7(.idata$5.idata$4`.idata$6$.text@.data`.bss`.idata$7P.idata$5.idata$4.idata$6.textP.data`.bss`.idata$7.idata$5.idata$4L.idata$6.text`.data`.bss`.idata$7<.idata$5.idata$4t.idata$6\.textp.data`.bss`.idata$78.idata$5.idata$4p.idata$6P.text.data`.bss`.idata$7.idata$5d.idata$4 .idata$6P.text.data`.bss`.idata$7 .idata$5.idata$4D.idata$6.text.data`.bss`.idata$7.idata$54.idata$4.idata$6.text.data`.bss`.idata$7$.idata$5.idata$4\.idata$6.text.data`.bss`.idata$7.idata$58.idata$4.idata$6.textУ.data`.bss`.idata$7.idata$5@.idata$4.idata$6.text.data`.bss`.idata$7.idata$5<.idata$4.idata$6hnamefthunk.text.data`.bss`.idata$2(.idata$5.idata$4.text.data`.bss`.idata$4.idata$5.idata$7p .text.data`.bss`.idata$7L.idata$5.idata$4.idata$6.text.data`.bss`.idata$7(.idata$5.idata$4l.idata$6 .text.data`.bss`.idata$7@.idata$5.idata$4.idata$6.text .data`.bss`.idata$74.idata$5.idata$4x.idata$6L.text0.data`.bss`.idata$7P.idata$5.idata$4.idata$6.text@.data`.bss`.idata$7H.idata$5.idata$4.idata$6.textP.data`.bss`.idata$7D.idata$5.idata$4.idata$6.text`.data`.bss`.idata$70.idata$5.idata$4t.idata$6<.textp.data`.bss`.idata$7,.idata$5.idata$4p.idata$60.text.data`.bss`.idata$7$.idata$5.idata$4h.idata$6.text.data`.bss`.idata$78.idata$5.idata$4|.idata$6l.text.data`.bss`.idata$7<.idata$5.idata$4.idata$6hnamehfthunk.text.data`.bss`.idata$2.idata$5.idata$4d.text.data`.bss`.idata$4.idata$5.idata$7T .text __cexit `0* &D7_sprintfp KPfXv̤_free p_strcmp` _opterrP   _mkdir ( 7 pK _fgetpos0 __errno  ^ dk @| 0_ceil        ` + ? c _puts` s  T  H_strncat    |_fstat    L+ : _toupperP H 0*k  0_fputsТ     \   @&__dll__ @%  _fwrite  * h_strncpy@ 8 [ (n }   @ l   t   _memcpyP _optarg4  0*_memset _optopt7 $__argcI e t <    `  _tolower`     _fflush   _ldivp _fprintf __alloca`_lseek "_strdup 4__argvA_fread Pf<}_fopen@ _setmode _time __fmode0@ _ctime  _realloc (6EZ fup_getenvP 8 __end___signalР _malloc ̤_fcloseС _strcpy _optindx   $=O]k_strtok x| _abort   `+_strncmp@ @P\   _strtoul0 ,_fgets )E]l_strlen |(4_readЕ _exit  p_fsetpos @'_printf0 `У 0*T_Sleep@40'p 1?_mainCRTStartup_WinMainCRTStartup___do_sjlj_init_setProgramName_scalpelLog_charactersMatch_memwildcardcmp_init_bm_table_bm_needleinhaystack_skipnchars_bm_needleinhaystack_findLongestNeedle_translate_skipWhiteSpace_checkMemoryAllocation_setttywidth_skipInFile_handleError_outputDirectoryOK_openAuditFile_closeFile_valid_offset_measureOpenFile_catch_alarm_extractSearchSpecData_processSearchSpecLine_readSearchSpecFile_registerSignalHandlers_initializeState_processCommandLineArgs_convertFileNames_digAllFiles_printhex_clean_up_displayPosition_positionUseCoverageBlockmap_ftello_use_coverage_map_fread_use_coverage_map_fseeko_use_coverage_map_digImageFile_readbuffer_carveImageFile_init_queue_destroy_queue_element_in_queue_nolock_add_to_queue_add_to_queue_empty_queue_remove_from_front_peek_at_current_pointer_to_current_current_priority_update_current_delete_current_next_element_rewind_queue_queue_length_copy_queue_equal_queues_merge_queues_local_peek_at_current_local_pointer_to_current_local_current_priority_local_update_current_local_delete_current_local_end_of_queue_local_next_element_local_rewind_queue_local_init_context_local_nolock_rewind_queue_local_nolock_next_element_nolock_next_element_end_of_queue_nolock_element_in_queue_nolock_destroy_queue_nolock_rewind_queue_base_name_base_len_basename_my_index_exchange_first_nonopt_last_nonopt__getopt_internal_nextchar_posixly_correct_ordering_signal_table_num_signal_names_init_signal_tables_signal_names_sys_siglist_sys_nsig_signo_max_strsignal_strsigno_strtosigno__pei386_runtime_relocator__fpreset_initialized___do_global_dtors___do_global_ctors_w32_atom_suffix___w32_sharedptr_default_unexpected___w32_sharedptr_getdw2_object_mutex.0dw2_once.1sjl_fc_key.2sjl_once.3___w32_sharedptr_initialize___umoddi3___divdi3___moddi3___udivdi3___fixunsdfdi___eprintf_fseeko64_closedir_rewinddir_strtoull_strtoumax__imp__strncat__imp__strtok___progname___RUNTIME_PSEUDO_RELOC_LIST____imp__read__imp__getenv__imp___fullpath_pthread_mutex_lock_QueryPerformanceCounter@4__imp___setmode__data_start_____DTOR_LIST___signal_caught__imp__mkdir__imp___onexit___p__fmode__imp__GetLastError@0_SetUnhandledExceptionFilter@4___w32_sharedptr_terminate__imp__fstat___tls_start____libmsvcrt_a_iname__imp__FindAtomA@4__imp__abort__imp___findnext___getopt_initialized__size_of_stack_commit____size_of_stack_reserve____major_subsystem_version_____crt_xl_start___AddAtomA@4___crt_xi_start_____chkstk___crt_xi_end____imp____mb_cur_max__imp__GetConsoleScreenBufferInfo@8_GetLastError@0__imp____p__environ__imp___pctype__imp__QueryPerformanceCounter@4__imp___iob__imp__strncmp__imp__strtoul__libmoldname_a_iname__imp__strdup_pthread_mutex_unlock__imp___isctype__imp__fgetpos__bss_start_____RUNTIME_PSEUDO_RELOC_LIST_END____size_of_heap_commit____imp___errno___p__environ___crt_xp_start____imp___snprintf___crt_xp_end____imp__signal__sch_tolower__sch_toupper__imp__puts__minor_os_version____imp__lseek__imp__atexit__imp__QueryPerformanceFrequency@4__head_libmsvcrt_a__imp__fsetpos__libpthreadGC1_a_iname_wildcard__image_base____imp__ceil__isctype__imp__exit__section_alignment____imp__toupper__imp__setmode__head_libmoldname_a__RUNTIME_PSEUDO_RELOC_LIST____imp____p__fmode__imp__GetFileAttributesA@4_ExitProcess@4__imp___findfirst_strerror_GetStdHandle@4__data_end_____getmainargs___w32_sharedptr__CTOR_LIST_____set_app_type__imp__sprintf__bss_end____CRT_fmode___crt_xc_end_____crt_xc_start____imp__fgets___CTOR_LIST___GetFileAttributesA@4__head_libpthreadGC1_a__imp__GetAtomNameA@12_ttywidth_QueryPerformanceFrequency@4__imp__fread__imp__memcpy__strnicmp__imp__strcmp__imp__pthread_mutex_lock__file_alignment____imp__time__imp__malloc__imp__strncpy__major_os_version____findfirst__imp__realloc__imp__ctime__imp___findclose_GetConsoleScreenBufferInfo@8__imp__GetStdHandle@4__imp__ldiv__DTOR_LIST____imp__fprintf__imp__memset__imp__fclose__fullpath__findclose__size_of_heap_reserve_____crt_xt_start____subsystem____imp__strlen__imp__fputs__imp__fflush__imp__pthread_mutex_unlock__imp__strcpy__filelengthi64___w32_sharedptr_unexpected_initial_mutex__imp__fopen__imp____getmainargs__imp___strnicmp___tls_end____imp__ExitProcess@4__imp__strerror__imp__free__imp__SetUnhandledExceptionFilter@4__snprintf__major_image_version____loader_flags____imp__tolower__CRT_glob__setmode__imp__printf__imp__AddAtomA@4_global_lock__head_libkernel32_a__imp___cexit__minor_subsystem_version____minor_image_version____imp__Sleep@4__imp__vfprintf__imp____set_app_type__imp___filelengthi64_FindAtomA@4__sch_istable_GetAtomNameA@12__findnext__RUNTIME_PSEUDO_RELOC_LIST_END____libkernel32_a_iname___crt_xt_end___vfprintf__imp__fwritescalpel-1.60/scalpel.h100666 0 0 27301 10536366476 13171 0ustar usergroup// Scalpel Copyright (C) 2005-6 by Golden G. Richard III. // Written by Golden G. Richard III. // // This program is free software; you can redistribute it and/or // modify it 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; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301, USA. // Scalpel is a complete rewrite of the foremost 0.69 file carver to // increase speed and support execution on machines with minimal // resources (e.g., < 256MB RAM). // // Thanks to Kris Kendall, Jesse Kornblum, et al for their work on // foremost. // #ifndef SCALPEL_H #define SCALPEL_H #define SCALPEL_VERSION "1.60" #define _USE_LARGEFILE 1 #define _USE_FILEOFFSET64 1 #define _USE_LARGEFILE64 1 #define _LARGEFILE_SOURCE 1 #define _LARGEFILE64_SOURCE 1 #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "base_name.h" #include "prioque.h" // // GGRIII: WARNING: Scalpel has NOT yet been thoroughly tested on OpenBSD, but is // known to compile and work correctly on Mac OS X (a BSD variant). // #ifdef __OPENBSD #define __UNIX #include #include #include #include // off_t on Mac OS X is 64 bits #define off64_t off_t #endif /* ifdef __OPENBSD */ #ifdef __LINUX #define __UNIX #include #include #include #endif /* ifdef __LINUX */ #ifdef __WIN32 #include #include #define gettimeofday(A,B) QueryPerformanceCounter(A) #define ftello ftello64 #define fseeko fseeko64 #define sleep Sleep #define snprintf _snprintf // macros for the Windows equivalent UNIX functions. (No worries // about lstat to stat; Windows doesn't have symbolic links) #define lstat(A,B) stat(A,B) char *basename(char *path); extern char *optarg; extern int optind; int getopt(int argc, char *const argv[], const char *optstring); #ifdef __MINGW32__ #define realpath(A,B) _fullpath(B,A,PATH_MAX) #endif #ifdef __CYGWIN32__ #define realpath(A,B) \ (getenv ("CYGWIN_USE_WIN32_PATHS") \ ? (cygwin_conv_to_full_win32_path ((A), (B)), B) \ : realpath ((A), (B))) #endif #endif /* ifdef __WIN32 */ #ifdef __GLIBC__ char *__progname; #else char *__progname; void setProgramName(char *s); #endif /* ifdef __GLIBC__ */ #ifndef __WIN32 #include #endif #define TRUE 1 #define FALSE 0 #define SEARCHTYPE_FORWARD 0 #define SEARCHTYPE_REVERSE 1 #define SEARCHTYPE_FORWARD_NEXT 2 // GGRIII: If you like having hair (on your head, not in clumps, in your // hands), then the following parens are pretty important #define KILOBYTE 1024 #define MEGABYTE (1024 * KILOBYTE) #define GIGABYTE (1024 * MEGABYTE) #define TERABYTE (1024 * GIGABYTE) #define PETABYTE (1024 * TERABYTE) #define EXABYTE (1024 * PETABYTE) // SIZE_OF_BUFFER indicates how much data to read from an image file // at a time. With the elimination of "quick" mode in Scalpel, the // restrictions on divisibility by block size are irrelevant, but they // don't hurt anything. #define SIZE_OF_BUFFER (10 * MEGABYTE) #define SCALPEL_SIZEOFBUFFER_PANIC_STRING \ "PANIC: SIZE_OF_BUFFER has been incorrectly configured.\n" #define SCALPEL_BLOCK_SIZE 512 #define MAX_STRING_LENGTH 4096 #define MAX_NEEDLES 254 #define NUM_SEARCH_SPEC_ELEMENTS 6 #define MAX_SUFFIX_LENGTH 8 #define MAX_FILE_TYPES 100 #define MAX_FILES_PER_SUBDIRECTORY 1000 #define SCALPEL_OK 0 #define SCALPEL_ERROR_NO_SEARCH_SPEC 1 #define SCALPEL_ERROR_FILE_OPEN 2 #define SCALPEL_ERROR_FILE_READ 3 #define SCALPEL_ERROR_FILE_WRITE 4 #define SCALPEL_ERROR_FILE_CLOSE 5 #define SCALPEL_ERROR_TOO_MANY_TYPES 6 #define SCALPEL_ERROR_FATAL_READ 7 #define SCALPEL_GENERAL_ABORT 999 #define UNITS_BYTES 0 #define UNITS_KILOB 1 #define UNITS_MEGAB 2 #define UNITS_GIGAB 3 #define UNITS_TERAB 4 #define UNITS_PETAB 5 #define UNITS_EXAB 6 // GLOBALS // signal has been caught by signal handler int signal_caught; // current wildcard character char wildcard; // width of tty, for progress bar int ttywidth; extern char *__progname; extern int errno; #define SCALPEL_NOEXTENSION_SUFFIX "NONE" #define SCALPEL_NOEXTENSION '\xFF' #define SCALPEL_DEFAULT_WILDCARD '?' #define SCALPEL_DEFAULT_CONFIG_FILE "scalpel.conf" #define SCALPEL_DEFAULT_OUTPUT_DIR "scalpel-output" #define SCALPEL_BANNER_STRING \ "Scalpel version %s\n"\ "Written by Golden G. Richard III, based on Foremost 0.69.\n", SCALPEL_VERSION #define SCALPEL_COPYRIGHT_STRING \ "Scalpel is (c) 2005-6 by Golden G. Richard III.\nThis program is based on Foremost 0.69, by Kris Kendall and Jesse Kornblum." #define NONEMPTYDIR_ERROR_MSG \ "ERROR: You have attempted to use a non-empty output directory. In order\n"\ " to maintain forensic soundness, this is not allowed.\n" // During the file carving operations (which occur after an initial // scan of an image file to build the header/footer database), we want // to read the image file only once more, sequentially, for all // carves. The following structure tracks the filename and first/last // bytes in the image file for a single file to be carved. When the // read buffer includes the first byte of a file, the file is opened // and the first write occurs. When the read buffer includes the end // byte, the last write operation occurs, the file is closed, and the // struct can be reused. // *****GGRIII: use of priority field to store these flags and the // data structures which track CarveInfo structs needs to be better // documented #define STARTCARVE 1 // carve operation for this CarveInfo struct // starts in current buffer #define STOPCARVE 2 // carve operation stops in current buffer #define STARTSTOPCARVE 3 // carve operation both starts and stops in // current buffer #define CONTINUECARVE 4 // carve operation includes entire contents // of current buffer typedef struct CarveInfo { char *filename; // output filename for file to carve FILE *fp; // file descriptor for file to carve unsigned long long start; // offset of first byte in file unsigned long long stop; // offset of last byte in file char chopped; // is carved file's length constrained // by max file size for type? (i.e., could // the file actually be longer? } CarveInfo; // Each struct SearchSpecLine defines a particular file type, // including header and footer information. The following structure, // SearchSpecOffsets, defines the absolute locations of all matching // headers and footers for a particular file type. Because the entire // header/footer database is built during a single pass over an image // or device file, the header and footer locations are sorted in // ascending order. typedef struct SearchSpecOffsets { unsigned long long *headers; // positions of discovered headers unsigned long long headerstorage; // space allocated for this many header offsets unsigned long long numheaders; // # stored header positions unsigned long long *footers; // positions of discovered headers unsigned long long footerstorage; // space allocated for this many footer offsets unsigned long long numfooters; // # stored footer positions } SearchSpecOffsets; // max files to open at once during carving--modify if you get // a "too many files open" error message during the second carving phase. #ifdef __WIN32 #define MAX_FILES_TO_OPEN 20 #else #define MAX_FILES_TO_OPEN 512 #endif typedef struct SearchSpecLine { char *suffix; int casesensitive; unsigned long long length; char *begin; int beginlength; size_t begin_bm_table[UCHAR_MAX+1]; char *end; int endlength; size_t end_bm_table[UCHAR_MAX+1]; int searchtype; // FORWARD, NEXT, REVERSE search type for footer struct SearchSpecOffsets offsets; unsigned long long numfilestocarve; // # files to carve of this type unsigned long organizeDirNum; // subdirectory # for organization // of files of this type } SearchSpecLine; typedef struct scalpelState { char *imagefile; char *conffile; char *outputdirectory; int specLines; struct SearchSpecLine* SearchSpec; unsigned long long fileswritten; int modeVerbose; int modeNoSuffix; FILE *auditFile; char *invocation; unsigned long long skip; char *coveragedirectory; unsigned int coverageblocksize; FILE *coverageblockmap; unsigned char *coveragebitmap; unsigned long long coveragenumblocks; int useInputFileList; char *inputFileList; int carveWithMissingFooters; int noSearchOverlap; int ignoreEmbedded; int generateHeaderFooterDatabase; int updateCoverageBlockmap; int useCoverageBlockmap; int organizeSubdirectories; unsigned long long organizeMaxFilesPerSub; int blockAlignedOnly; unsigned int alignedblocksize; int previewMode; } scalpelState; // one extent for a fragmented file. 'start' and 'stop' // are real disk image addresses that define the fragment's // location. typedef struct Fragment { unsigned long long start; unsigned long long stop; } Fragment; // prototypes for visible dig.c functions int digImageFile(struct scalpelState *state); int carveImageFile(struct scalpelState *state); // prototypes for visible helpers.c functions void checkMemoryAllocation(struct scalpelState *state, void *ptr, int line, char *file, char *structure); int skipInFile(struct scalpelState *state, FILE *infile); void scalpelLog(struct scalpelState *state, char *format, ...); void handleError(struct scalpelState *s, int error); int memwildcardcmp(const void* s1, const void* s2, size_t n, int caseSensitive); void init_bm_table(char *needle, size_t table[UCHAR_MAX + 1], size_t len, int casesensitive); int findLongestNeedle(struct SearchSpecLine* SearchSpec); char *bm_needleinhaystack(char *needle, size_t needle_len, char *haystack, size_t haystack_len, size_t table[UCHAR_MAX + 1], int casesensitive); int translate(char *str); char *skipWhiteSpace(char *str); void setttywidth(); // prototypes for visible files.c functions unsigned long long measureOpenFile(FILE *f, struct scalpelState *state); int openAuditFile(struct scalpelState* state); int closeFile(FILE* f); // WIN32 string.h wierdness #ifdef __WIN32 extern const char *strsignal(int sig); #else extern char *strsignal(int sig); #endif /* ifdef __WIN32 */ #endif /* ifndef SCALPEL_H */