/// <summary> /// Initializes a new instance of the <see cref="SnapshotElementVectorComparer" /> class. /// </summary> /// <param name="region">The parent region that contains this element.</param> /// <param name="constraints">The set of constraints to use for the element comparisons.</param> public SnapshotElementVectorComparer(SnapshotRegion region, ScanConstraints constraints) { this.Region = region; this.VectorSize = Vectors.VectorSize; this.VectorReadBase = this.Region.ReadGroupOffset - this.Region.ReadGroupOffset % this.VectorSize; this.VectorReadIndex = 0; this.DataType = constraints.ElementType; this.DataTypeSize = constraints.ElementType.Size; this.ResultRegions = new List <SnapshotRegion>(); this.SetConstraintFunctions(); this.VectorCompare = this.BuildCompareActions(constraints?.RootConstraint); }
/// <summary> /// Starts the scan using the current constraints. /// </summary> private void StartScan() { // Create a constraint manager that includes the current active constraint DataTypeBase dataType = ScanResultsViewModel.GetInstance().ActiveType; ScanConstraints scanConstraints = new ScanConstraints(dataType, this.ActiveConstraint?.Clone()); if (!scanConstraints.IsValid()) { Logger.Log(LogLevel.Warn, "Unable to start scan with given constraints"); return; } try { // Collect values TrackableTask <Snapshot> valueCollectorTask = ValueCollector.CollectValues( SessionManager.Session.OpenedProcess, SessionManager.Session.SnapshotManager.GetActiveSnapshotCreateIfNone(SessionManager.Session.OpenedProcess), TrackableTask.UniversalIdentifier ); TaskTrackerViewModel.GetInstance().TrackTask(valueCollectorTask); // Perform manual scan on value collection complete valueCollectorTask.OnCompletedEvent += ((completedValueCollectionTask) => { Snapshot snapshot = valueCollectorTask.Result; TrackableTask <Snapshot> scanTask = ManualScanner.Scan( snapshot, scanConstraints, TrackableTask.UniversalIdentifier); TaskTrackerViewModel.GetInstance().TrackTask(scanTask); SessionManager.Session.SnapshotManager.SaveSnapshot(scanTask.Result); }); } catch (TaskConflictException) { } }
/// <summary> /// Filters the given snapshot to find all values that are valid pointers. /// </summary> /// <param name="snapshot">The snapshot on which to perfrom the scan.</param> /// <returns></returns> public static TrackableTask <Snapshot> Filter(TrackableTask parentTask, Snapshot snapshot, IVectorSearchKernel searchKernel, PointerSize pointerSize, Snapshot DEBUG, UInt32 RADIUS_DEBUG) { return(TrackableTask <Snapshot> .Create(PointerFilter.Name, out UpdateProgress updateProgress, out CancellationToken cancellationToken) .With(Task <Snapshot> .Run(() => { try { parentTask.CancellationToken.ThrowIfCancellationRequested(); ConcurrentBag <IList <SnapshotRegion> > regions = new ConcurrentBag <IList <SnapshotRegion> >(); ParallelOptions options = ParallelSettings.ParallelSettingsFastest.Clone(); options.CancellationToken = parentTask.CancellationToken; // ISearchKernel DEBUG_KERNEL = new SpanSearchKernel(DEBUG, RADIUS_DEBUG); Parallel.ForEach( snapshot.OptimizedSnapshotRegions, options, (region) => { // Check for canceled scan parentTask.CancellationToken.ThrowIfCancellationRequested(); if (!region.ReadGroup.CanCompare(null)) { return; } ScanConstraints constraints = new ScanConstraints(pointerSize.ToDataType(), null); SnapshotElementVectorComparer vectorComparer = new SnapshotElementVectorComparer(region: region, constraints: constraints); vectorComparer.SetCustomCompareAction(searchKernel.GetSearchKernel(vectorComparer)); // SnapshotElementVectorComparer DEBUG_COMPARER = new SnapshotElementVectorComparer(region: region); // DEBUG_COMPARER.SetCustomCompareAction(DEBUG_KERNEL.GetSearchKernel(DEBUG_COMPARER)); IList <SnapshotRegion> results = vectorComparer.Compare(); // When debugging, these results should be the same as the results above // IList<SnapshotRegion> DEBUG_RESULTS = vectorComparer.Compare(); if (!results.IsNullOrEmpty()) { regions.Add(results); } }); // Exit if canceled parentTask.CancellationToken.ThrowIfCancellationRequested(); snapshot = new Snapshot(PointerFilter.Name, regions.SelectMany(region => region)); } catch (OperationCanceledException ex) { Logger.Log(LogLevel.Warn, "Pointer filtering canceled", ex); throw ex; } catch (Exception ex) { Logger.Log(LogLevel.Error, "Error performing pointer filtering", ex); return null; } return snapshot; }, parentTask.CancellationToken))); }
/// <summary> /// Performs a pointer scan for a given address. /// </summary> /// <param name="address">The address for which to perform a pointer scan.</param> /// <param name="maxOffset">The maximum pointer offset.</param> /// <param name="depth">The maximum pointer search depth.</param> /// <param name="alignment">The pointer scan alignment.</param> /// <param name="taskIdentifier">The unique identifier to prevent duplicate tasks.</param> /// <returns>Atrackable task that returns the scan results.</returns> public static TrackableTask <PointerBag> Scan(Process process, PointerBag previousPointerBag, Boolean readMemory, Boolean performUnchangedScan, String taskIdentifier = null) { try { TrackableTask <PointerBag> pointerScanTask = TrackableTask <PointerBag> .Create(PointerRebase.Name, taskIdentifier, out UpdateProgress updateProgress, out CancellationToken cancellationToken); return(pointerScanTask.With(Task <PointerBag> .Run(() => { try { cancellationToken.ThrowIfCancellationRequested(); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); DataTypeBase pointerDataType = previousPointerBag.PointerSize.ToDataType(); ScanConstraint scanConstraint = new ScanConstraint(ScanConstraint.ConstraintType.Unchanged); ScanConstraints scanConstraints = new ScanConstraints(pointerDataType, scanConstraint); IList <Level> oldLevels = previousPointerBag.Levels; IList <Level> newLevels = new List <Level>(); for (Int32 levelIndex = 0; levelIndex < oldLevels.Count; levelIndex++) { Snapshot updatedStaticPointers = oldLevels[levelIndex].StaticPointers; Snapshot updatedHeapPointers = oldLevels[levelIndex].HeapPointers; // Step 1) Re-read values of all pointers if (readMemory) { TrackableTask <Snapshot> staticValueCollector = ValueCollector.CollectValues(process, updatedStaticPointers); // Does not apply to target address if (levelIndex > 0) { TrackableTask <Snapshot> heapValueCollector = ValueCollector.CollectValues(process, updatedHeapPointers); updatedHeapPointers = heapValueCollector.Result; } updatedStaticPointers = staticValueCollector.Result; } // Step 2) A neat (optional) trick: Scan for unchanged values to filter out dynamic pointers if (performUnchangedScan) { TrackableTask <Snapshot> staticValueScanner = ManualScanner.Scan(updatedStaticPointers, scanConstraints); // Does not apply to target address if (levelIndex > 0) { TrackableTask <Snapshot> heapValueScanner = ManualScanner.Scan(updatedHeapPointers, scanConstraints); updatedHeapPointers = heapValueScanner.Result; } updatedStaticPointers = staticValueScanner.Result; } Stopwatch levelStopwatch = new Stopwatch(); levelStopwatch.Start(); // Step 3) Rebase heap onto new previous heap if (levelIndex > 0) { IVectorSearchKernel heapSearchKernel = SearchKernelFactory.GetSearchKernel(newLevels.Last().HeapPointers, previousPointerBag.MaxOffset, previousPointerBag.PointerSize); TrackableTask <Snapshot> heapFilterTask = PointerFilter.Filter(pointerScanTask, updatedHeapPointers, heapSearchKernel, previousPointerBag.PointerSize, newLevels.Last().HeapPointers, previousPointerBag.MaxOffset); updatedHeapPointers = heapFilterTask.Result; } // Step 4) Filter static pointers that still point into the updated heap IVectorSearchKernel staticSearchKernel = SearchKernelFactory.GetSearchKernel(updatedHeapPointers, previousPointerBag.MaxOffset, previousPointerBag.PointerSize); TrackableTask <Snapshot> staticFilterTask = PointerFilter.Filter(pointerScanTask, updatedStaticPointers, staticSearchKernel, previousPointerBag.PointerSize, updatedHeapPointers, previousPointerBag.MaxOffset); updatedStaticPointers = staticFilterTask.Result; levelStopwatch.Stop(); Logger.Log(LogLevel.Info, "Pointer rebase from level " + (levelIndex) + " => " + (levelIndex + 1) + " completed in: " + levelStopwatch.Elapsed); newLevels.Add(new Level(updatedHeapPointers, updatedStaticPointers)); } // Exit if canceled cancellationToken.ThrowIfCancellationRequested(); PointerBag pointerBag = new PointerBag(newLevels, previousPointerBag.MaxOffset, previousPointerBag.PointerSize); stopwatch.Stop(); Logger.Log(LogLevel.Info, "Pointer rebase complete in: " + stopwatch.Elapsed); return pointerBag; } catch (OperationCanceledException ex) { Logger.Log(LogLevel.Warn, "Pointer rebase canceled", ex); } catch (Exception ex) { Logger.Log(LogLevel.Error, "Error performing pointer rebase", ex); } return null; }, cancellationToken))); } catch (TaskConflictException ex) { Logger.Log(LogLevel.Warn, "A pointer scan is already scheduled."); throw ex; } }
/// <summary> /// Begins the manual scan based on the provided snapshot and parameters. /// </summary> /// <param name="snapshot">The snapshot on which to perfrom the scan.</param> /// <param name="constraints">The collection of scan constraints to use in the manual scan.</param> /// <param name="taskIdentifier">The unique identifier to prevent duplicate tasks.</param> /// <returns></returns> public static TrackableTask <Snapshot> Scan(Snapshot snapshot, ScanConstraints constraints, String taskIdentifier = null) { try { return(TrackableTask <Snapshot> .Create(ManualScanner.Name, taskIdentifier, out UpdateProgress updateProgress, out CancellationToken cancellationToken) .With(Task <Snapshot> .Run(() => { Snapshot result = null; try { cancellationToken.ThrowIfCancellationRequested(); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); Int32 processedPages = 0; ConcurrentBag <IList <SnapshotRegion> > regions = new ConcurrentBag <IList <SnapshotRegion> >(); ParallelOptions options = ParallelSettings.ParallelSettingsFastest.Clone(); options.CancellationToken = cancellationToken; Parallel.ForEach( snapshot.OptimizedSnapshotRegions, options, (region) => { // Check for canceled scan cancellationToken.ThrowIfCancellationRequested(); if (!region.ReadGroup.CanCompare(constraints: constraints)) { return; } SnapshotElementVectorComparer vectorComparer = new SnapshotElementVectorComparer(region: region, constraints: constraints); IList <SnapshotRegion> results = vectorComparer.Compare(); if (!results.IsNullOrEmpty()) { regions.Add(results); } // Update progress every N regions if (Interlocked.Increment(ref processedPages) % 32 == 0) { updateProgress((float)processedPages / (float)snapshot.RegionCount * 100.0f); } }); //// End foreach Region // Exit if canceled cancellationToken.ThrowIfCancellationRequested(); result = new Snapshot(ManualScanner.Name, regions.SelectMany(region => region)); stopwatch.Stop(); result.LoadMetaData(constraints.ElementType.Size); Logger.Log(LogLevel.Info, "Scan complete in: " + stopwatch.Elapsed); Logger.Log(LogLevel.Info, "Results: " + result.ElementCount + " (" + Conversions.ValueToMetricSize(result.ByteCount) + ")"); } catch (OperationCanceledException ex) { Logger.Log(LogLevel.Warn, "Scan canceled", ex); } catch (Exception ex) { Logger.Log(LogLevel.Error, "Error performing scan", ex); } return result; }, cancellationToken))); } catch (TaskConflictException ex) { Logger.Log(LogLevel.Warn, "Unable to start scan. Scan is already queued."); throw ex; } }