/// <summary> /// Constructor. /// </summary> /// <param name="id"></param> /// <param name="stream"></param> /// <param name="start"></param> /// <param name="end"></param> /// <param name="queue"></param> /// <param name="imgFiles"></param> public ImageFilesThread(int id, BufferedStream stream, long start, long end, BlockingCollection <int> queue, ImageFiles imgFiles) { this.id = id; this.stream = stream; this.imgFiles = imgFiles; this.start = start; this.end = end; // inclusive this.queue = queue; }
/// <summary> /// Begins the process of removing image block from phone's memory by calling several methods of ImageFiles. /// </summary> /// <param name="filterResult">The blocks remianing after block hash filtering. It is modified to being free from any image blocks too, by the end of the method.</param> /// <param name="imageFiles">The image blocks that were previosuly located on the phone's memory.</param> public static FilterResult FilterOutImages(FilterResult filterResult, ImageFiles imageFiles) { List <ImageBlock> reduced = RemoveImages(imageFiles.ImageBlocks, filterResult); WorkerThread.write("Filtered {0} images", imageFiles.ImageBlocks.Count - reduced.Count); long oldFilteredCount = filterResult.FilteredBytesCount; filterResult = FilterImageBlocks(imageFiles, filterResult); WorkerThread.write("Filtered an additional {0} bytes", filterResult.FilteredBytesCount - oldFilteredCount); imageFiles.ImageBlocks = reduced; return(filterResult); }
/// <summary> /// Calls methods to begin locating image blocks in the memory file. /// </summary> /// <param name="filePath">Path of the phone's memory file.</param> /// <returns>A list of image blocks present in the phone's memory.</returns> public static ImageFiles LocateImages(string filePath) { ImageFiles imageFiles = null; try { imageFiles = new ImageFiles(filePath); imageFiles.Process(); imageFiles.Close(); } catch (Exception ex) { WorkerThread.write("Error locating images: " + ex.Message); } finally { if (imageFiles != null) { imageFiles.Close(); } else { imageFiles = new ImageFiles(); } } return(imageFiles); }
/// <summary> /// Called after two independant operations have been performed: finding /// images in the memory, and excluding memory blocks because their hashes /// were known. Here we further reduce the memory that we'll use for /// searching for fields by removing memory consumed by images. /// </summary> /// <param name="imageFiles">Locations of found memory files.</param> /// <param name="filterResult">The filtered memory blocks.</param> /// <returns>An updated filtered memory block object.</returns> private static FilterResult FilterImageBlocks(ImageFiles imageFiles, FilterResult filterResult) { int imgCount = imageFiles.ImageBlocks.Count; if (imgCount == 0) { // No images had been found: nothing to do. return(filterResult); } bool foundOverlap = false; List <Block> reducedUnfilteredBlocks = new List <Block>(); // For each memory block, update it if it contains all or part of an image. foreach (Block block in filterResult.UnfilteredBlocks) { long blockStart = block.OffsetFile; long blockEnd = blockStart + block.Length - 1; // inclusive bool modified = false; int indx = 0; // Go through the images and see if one is contained in the // memory block. while (!modified && (indx < imgCount)) { long imgStart = imageFiles.ImageBlocks[indx].Offset; if (blockEnd < imgStart) { // We can assume image locations are ordered, so we can // stop looking. All subsequent images will start after // this memory block. Move on to the next block. break; } long imgEnd = imgStart + imageFiles.ImageBlocks[indx].Length - 1; // inclusive if (blockStart > imgEnd) { // The image ends before the block starts. indx++; continue; } if (((blockStart >= imgStart) && (blockStart <= imgEnd)) || ((blockEnd >= imgStart) && (blockEnd <= imgEnd)) || ((imgStart >= blockStart) && (imgStart <= blockEnd)) || ((imgEnd >= blockStart) && (imgEnd <= blockEnd))) { // All or part of the image is within the memory block. modified = true; foundOverlap = true; List <Block> reduced = RemoveImageBlock(block, imageFiles.ImageBlocks[indx]); if (reduced.Count == 1) { reducedUnfilteredBlocks.Add(reduced[0]); } else if (reduced.Count > 0) { reducedUnfilteredBlocks.AddRange(reduced); } // It's possible there are more images that overlap, but // we'll get them in a recursive call. break; } indx++; } if (!modified) { reducedUnfilteredBlocks.Add(block); } } // If we didn't find any overlaps, we're done. if (!foundOverlap) { return(filterResult); } long unfilteredCount = 0; foreach (Block block in reducedUnfilteredBlocks) { unfilteredCount += block.Length; } long filteredCount = filterResult.FilteredBytesCount + (filterResult.UnfilteredBytesCount - unfilteredCount); // A block can have multiple images within it. We remove one image // at a time, so we recursively call this function to remove images // from updated blocks. It may not be the most efficient method, // but it's a little cleaner. FilterResult newFilterResult = new FilterResult { Duration = filterResult.Duration, FilteredBytesCount = filteredCount, UnfilteredBytesCount = unfilteredCount, UnfilteredBlocks = reducedUnfilteredBlocks }; return(FilterImageBlocks(imageFiles, newFilterResult)); }
/// <summary> /// This is where all of the work is done to extract information from /// the phone's binary file. /// It calls methods for image block identification, removal, block hash filtering, field and record level Viterbi infrerence, postprocessing of results. /// </summary> private void Run() { bool success = false; PostProcessor postProcess = null; PhoneInfo phoneInfo = null; try { // Use the SHA1 of the binary file to identify it. _canAbort = true; StartStep(1); write("Calculating file SHA1"); fileSha1 = DcUtils.CalculateFileSha1(this.filePath); if (_cancel) { return; } NextStep(1); // We scan the file to locate images. This is done independent // of block hashes. write("Extracting graphical images"); #if LOADONLY || SKIPIMAGES ImageFiles imageFiles = new ImageFiles(); #else ImageFiles imageFiles = ImageFiles.LocateImages(this.filePath); if (_cancel) { return; } _canAbort = false; write("Extracted {0} graphical images", imageFiles.ImageBlocks.Count); #endif NextStep(2); if (_cancel) { return; } // Load the block hashes into the DB (if they're not already // there). HashLoader.HashLoader hashloader = HashLoader.HashLoader.LoadHashesIntoDB(fileSha1, this.filePath, this.manufacturer, this.model, this.note, this.doNotStoreHashes); if (_cancel || (hashloader == null)) { return; } int phoneId = hashloader.PhoneId; #if LOADONLY _cancel = true; return; #endif _canAbort = true; NextStep(3); if (_cancel) { return; } // Identify block hashes that are already in the DB, which we // will then filter out. FilterResult filterResult = RunBlockHashFilter(fileSha1, phoneId, hashloader.GetAndForgetStoredHashes()); hashloader = null; NextStep(4); // Since images were located before block hash filter, forget // about any image that overlaps a filtered block hash. write("Filtering image locations"); //filterResult = ImageFiles.FilterOutImages(filterResult, imageFiles); //Dump_Filtered_Blocks(filterResult, filePath); NextStep(5); // Finally, we're ready to use the Viterbi state machine. // Start by identifying fields. ViterbiResult viterbiResultFields = RunViterbi(filterResult, fileSha1); // Allow garbage collection. filterResult.UnfilteredBlocks.Clear(); NextStep(6); List <MetaField> addressBookEntries = new List <MetaField>(); List <MetaField> callLogs = new List <MetaField>(); List <MetaField> sms = new List <MetaField>(); // Second run of Viterbi, this time for records. //ViterbiResult viterbiResultRecord = RunMetaViterbi(viterbiResultFields,addressBookEntries,callLogs,sms); RunMetaViterbi(viterbiResultFields, addressBookEntries, callLogs, sms); viterbiResultFields = null; NextStep(7); // Perform post processing. This may remove some records. postProcess = new PostProcessor(callLogs, addressBookEntries, sms, imageFiles.ImageBlocks); success = PerformPostProcessing(postProcess); NextStep(8); GTC_CSV_Writer wr = new GTC_CSV_Writer(this.metaResults, postProcess, filePath); wr.Write_CSV(); wr.Write_Field_Paths(this.fieldPaths); // Finished. phoneInfo = new PhoneInfo(manufacturer, model, note, doNotStoreHashes); write("Finished work"); FinishedStep(9); } finally { if (_cancel) { MainForm.Program.EndWork(false, null, null, null); } else { MainForm.Program.EndWork(success, postProcess, this.filePath, phoneInfo); } } }