예제 #1
0
        public void TestRegionChunking()
        {
            Random random = new Random();
            List <SnapshotRegion> groundTruth    = new List <SnapshotRegion>();
            List <SnapshotRegion> chunkedRegions = new List <SnapshotRegion>();

            UInt64 baseAddress = 0;

            for (Int32 i = 0; i < 10000; i++)
            {
                baseAddress += (UInt64)random.Next(1, 1024);
                UInt64 regionSize = random.Next(1, 1024).ToUInt64();
                UInt64 chunkSize  = random.Next(32, 128).ToUInt64();

                SnapshotRegion region = new SnapshotRegion(baseAddress.ToIntPtr(), regionSize);
                IEnumerable <SnapshotRegion> regions = region.ChunkNormalizedRegion(chunkSize).Select(x => new SnapshotRegion(x)).OrderBy(x => random.Next());

                groundTruth.Add(region);
                chunkedRegions.AddRange(regions);
                baseAddress += (UInt64)regionSize;
            }

            UInt64 originalSize = groundTruth.Sum(x => x.RegionSize);
            UInt64 newSize      = chunkedRegions.Sum(x => x.RegionSize);

            Assert.AreEqual(originalSize, newSize);
        }
        /// <summary>
        /// Gets the snapshot generated by the prefilter.
        /// </summary>
        /// <returns>The snapshot generated by the prefilter.</returns>
        public Snapshot GetPrefilteredSnapshot()
        {
            List <SnapshotRegion> regions = new List <SnapshotRegion>();

            lock (this.ChunkLock)
            {
                foreach (RegionProperties virtualPage in this.ChunkList)
                {
                    if (!virtualPage.HasChanged)
                    {
                        continue;
                    }

                    SnapshotRegion newRegion = new SnapshotRegion(virtualPage);
                    regions.Add(newRegion);
                }
            }

            // Create snapshot from valid regions, do standard expand/mask operations to catch lost bytes for larger data types
            Snapshot prefilteredSnapshot = new Snapshot(regions);

            prefilteredSnapshot.ExpandAllRegions(PrimitiveTypes.GetLargestPrimitiveSize() - 1);
            prefilteredSnapshot.MaskRegions(prefilteredSnapshot);

            return(prefilteredSnapshot);
        }
예제 #3
0
        public void TestSnapshotMerging()
        {
            Random random = new Random();
            List <SnapshotRegion> groundTruth    = new List <SnapshotRegion>();
            List <SnapshotRegion> chunkedRegions = new List <SnapshotRegion>();

            SettingsViewModel.GetInstance().Alignment = 1;

            UInt64 baseAddress = 0;

            for (Int32 i = 0; i < 10000; i++)
            {
                baseAddress += (UInt64)random.Next(1, 1024);
                Int32 regionSize = random.Next(1, 1024);
                Int32 chunkSize  = random.Next(32, 2048);

                SnapshotRegion region = new SnapshotRegion(baseAddress.ToIntPtr(), regionSize);
                IEnumerable <SnapshotRegion> regions = region.ChunkNormalizedRegion(chunkSize).Select(x => new SnapshotRegion(x)).OrderBy(x => random.Next());

                groundTruth.Add(region);
                chunkedRegions.AddRange(regions);

                baseAddress += (UInt64)regionSize;
            }

            Snapshot snapshot = new Snapshot(chunkedRegions);
            List <SnapshotRegion> reconstructedRegions = snapshot.GetSnapshotRegions().ToList();

            Assert.AreEqual(groundTruth.Count, reconstructedRegions.Count);

            Int32 originalSize = groundTruth.Sum(x => x.RegionSize);
            Int32 newSize      = reconstructedRegions.Sum(x => x.RegionSize);

            Assert.AreEqual(originalSize, newSize);
        }
예제 #4
0
        private ExtractedPointer ExtractRandomPointer(Snapshot snapshot)
        {
            SnapshotRegion         extractedRegion  = snapshot.SnapshotRegions[Random.Next(0, snapshot.SnapshotRegions.Length)];
            SnapshotElementIndexer extractedElement = extractedRegion[Random.Next(0, extractedRegion.GetElementCount(PointerSize.ToSize()))];

            return(this.ExtractPointerFromElement(extractedElement));
        }
예제 #5
0
        /// <summary>
        /// Called when the scan updates.
        /// </summary>
        /// <param name="cancellationToken">The cancellation token for handling canceled tasks.</param>
        protected override void OnUpdate(CancellationToken cancellationToken)
        {
            UInt64 processedPointers = 0;

            // Create a snapshot only containing the destination
            SnapshotRegion destinationRegion = new SnapshotRegion(baseAddress: this.TargetAddress.ToIntPtr(), regionSize: 1);

            destinationRegion.Expand(this.PointerRadius);

            // Start with the previous level as the destination (as this is a back-tracing algorithm, we work backwards from the destination)
            Snapshot previousLevelSnapshot = new Snapshot(destinationRegion);

            // Find all pointers that point to the previous level
            for (Int32 level = 0; level < this.PointerDepth; level++)
            {
                Boolean     isModuleLevel        = level == this.PointerDepth - 1;
                PointerPool currentLevelPointers = new PointerPool();

                // Iterate all of the heap or module pointers
                Parallel.ForEach(
                    isModuleLevel ? this.ModulePointers : this.HeapPointers,
                    SettingsViewModel.GetInstance().ParallelSettingsFullCpu,
                    (pointer) =>
                {
                    // Accept this pointer if it is points to the previous level snapshot
                    if (previousLevelSnapshot.ContainsAddress(pointer.Value))
                    {
                        currentLevelPointers[pointer.Key] = pointer.Value;
                    }

                    // Update scan progress
                    lock (this.ProgressLock)
                    {
                        processedPointers++;

                        // Limit how often we update the progress
                        if (processedPointers % 10000 == 0)
                        {
                            this.UpdateProgress((processedPointers / this.PointerDepth).ToInt32(), this.HeapPointers.Count + this.ModulePointers.Count, canFinalize: false);
                        }
                    }
                });

                // Create a snapshot from this level of pointers
                previousLevelSnapshot = currentLevelPointers.ToSnapshot(this.PointerRadius);

                // Add the pointer pool to the level structure
                if (isModuleLevel)
                {
                    this.LevelPointers.ModulePointerPool = currentLevelPointers;
                }
                else
                {
                    this.LevelPointers.AddHeapPointerPool(currentLevelPointers);
                }
            }

            // Add the destination pointer pool
            this.LevelPointers.DestinationPointerPool = new PointerPool(new KeyValuePair <UInt64, UInt64>(this.TargetAddress, 0));
        }
        protected override void OnUpdate()
        {
            ConcurrentDictionary <dynamic, Int64> histogram = new ConcurrentDictionary <dynamic, Int64>();
            Int32 processedPages = 0;

            lock (this.SnapshotLock)
            {
                if (this.Snapshot == null)
                {
                    this.Cancel();
                    return;
                }

                Parallel.ForEach(
                    this.Snapshot.Cast <Object>(),
                    SettingsViewModel.GetInstance().ParallelSettings,
                    (regionObject) =>
                {
                    SnapshotRegion region = regionObject as SnapshotRegion;

                    if (((dynamic)region).GetElementLabels() == null || region.GetElementCount() <= 0)
                    {
                        return;
                    }

                    foreach (SnapshotElementRef element in region)
                    {
                        lock (this.ItemLock)
                        {
                            if (histogram.ContainsKey(((dynamic)element).GetElementLabel()))
                            {
                                histogram[((dynamic)element).GetElementLabel()]++;
                            }
                            else
                            {
                                histogram.TryAdd(((dynamic)element).GetElementLabel(), 1);
                            }
                        }
                    }

                    lock (this.ProgressLock)
                    {
                        processedPages++;
                        this.UpdateProgress(processedPages, this.Snapshot.GetRegionCount());
                    }
                    //// End foreach element
                });
                //// End foreach region
            }

            this.Histogram = new SortedList <dynamic, Int64>(histogram);
            this.UpdateHistogram();
            this.Cancel();

            base.OnUpdate();
        }
예제 #7
0
        /// <summary>
        /// Gets a random pointer from the pointer collection.
        /// </summary>
        /// <returns>A random discovered pointer, or null if unable to find one.</returns>
        public Pointer GetRandomPointer(Int32 levelIndex)
        {
            if (levelIndex >= this.Levels.Count || this.Levels[levelIndex].StaticPointers == null)
            {
                return(null);
            }

            Snapshot         currentSnapshot = this.Levels[levelIndex].StaticPointers;
            ExtractedPointer pointer         = this.ExtractRandomPointer(currentSnapshot);

            UInt64       pointerBase = pointer.BaseAddress;
            List <Int32> offsets     = new List <Int32>();

            foreach (Level level in this.Levels.Take(levelIndex + 1).Reverse())
            {
                IEnumerable <Int32> shuffledOffsets = Enumerable.Range(-(Int32)this.MaxOffset, (Int32)(this.MaxOffset * 2) + 1).Shuffle();

                Boolean found = false;

                // Brute force all possible offsets in a random order to find the next path (this guarantees uniform path probabilities)
                foreach (Int32 nextRandomOffset in shuffledOffsets)
                {
                    UInt64         newDestination = nextRandomOffset < 0 ? pointer.Destination.Subtract(-nextRandomOffset, wrapAround: false) : pointer.Destination.Add(nextRandomOffset, wrapAround: false);
                    SnapshotRegion snapshotRegion = level.HeapPointers.SnapshotRegions.Select(x => x).Where(y => newDestination >= y.BaseAddress && newDestination <= y.EndAddress).FirstOrDefault();

                    if (snapshotRegion != null)
                    {
                        // We may have sampled an offset that results in a mis-aligned index, so just randomly take an element from this snapshot rather than using the random offset
                        SnapshotElementIndexer randomElement = snapshotRegion[Random.Next(0, snapshotRegion.GetElementCount(PointerSize.ToSize()))];
                        UInt64 baseAddress   = randomElement.GetBaseAddress(PointerSize.ToSize());
                        Int32  alignedOffset = pointer.Destination >= baseAddress ? -((Int32)(pointer.Destination - baseAddress)) : ((Int32)(baseAddress - pointer.Destination));

                        pointer = this.ExtractPointerFromElement(randomElement);
                        offsets.Add(alignedOffset);
                        found = true;
                        break;
                    }
                }

                if (!found)
                {
                    Logger.Log(LogLevel.Error, "Unable to collect a pointer, encountered dead end path");
                    return(null);
                }
            }

            return(new Pointer(pointerBase, this.PointerSize, offsets.ToArray()));
        }
예제 #8
0
        public Snapshot ToSnapshot(UInt64 pointerRadius)
        {
            Snapshot pointerPoolSnapshot = new Snapshot();

            IList <SnapshotRegion> levelRegions = new List <SnapshotRegion>();

            foreach (KeyValuePair <UInt64, UInt64> pointer in this)
            {
                SnapshotRegion levelRegion = new SnapshotRegion(pointer.Key.ToIntPtr(), 1);
                levelRegion.Expand(pointerRadius);
                levelRegions.Add(levelRegion);
            }

            pointerPoolSnapshot.AddSnapshotRegions(levelRegions);

            return(pointerPoolSnapshot);
        }
        protected override void OnUpdate()
        {
            Int32 processedPages = 0;

            // Read memory to get current values
            this.Snapshot.ReadAllMemory();

            Parallel.ForEach(
                this.Snapshot.Cast <Object>(),
                SettingsViewModel.GetInstance().ParallelSettings,
                (Object regionObject) =>
            {
                SnapshotRegion region = regionObject as SnapshotRegion;

                if (!region.CanCompare())
                {
                    return;
                }

                foreach (SnapshotElementRef element in region)
                {
                    if (element.Changed())
                    {
                        ((dynamic)element).ElementLabel++;
                    }
                }

                lock (this.ProgressLock)
                {
                    processedPages++;
                    this.UpdateProgress(processedPages, this.Snapshot.GetRegionCount());
                }
            });

            this.UpdateScanCount?.Invoke();

            base.OnUpdate();
        }
예제 #10
0
        /// <summary>
        /// Gradually gathers pointers in the running process.
        /// </summary>
        private void GatherPointers()
        {
            Boolean isOpenedProcess32Bit             = EngineCore.GetInstance().Processes.IsOpenedProcess32Bit();
            dynamic invalidPointerMin                = isOpenedProcess32Bit ? (UInt32)UInt16.MaxValue : (UInt64)UInt16.MaxValue;
            dynamic invalidPointerMax                = isOpenedProcess32Bit ? Int32.MaxValue : Int64.MaxValue;
            ConcurrentHashSet <IntPtr> foundPointers = new ConcurrentHashSet <IntPtr>();

            // Test for conditions where we set the final found set and take a new snapshot to parse
            if (this.CurrentSnapshot == null || this.CurrentSnapshot.GetRegionCount() <= 0 || this.processedCount >= this.CurrentSnapshot.GetRegionCount())
            {
                this.processedCount  = 0;
                this.CurrentSnapshot = SnapshotManager.GetInstance().CollectSnapshot(useSettings: true, usePrefilter: false).Clone();
                this.FoundPointers   = this.ConstructingSet;
                this.ConstructingSet = new HashSet <IntPtr>();
            }

            List <SnapshotRegion> sortedRegions = new List <SnapshotRegion>(this.CurrentSnapshot.GetSnapshotRegions().OrderBy(x => x.GetTimeSinceLastRead()));

            // Process the allowed amount of chunks from the priority queue
            Parallel.For(
                0,
                Math.Min(sortedRegions.Count, PointerCollector.RegionLimit),
                SettingsViewModel.GetInstance().ParallelSettings,
                (index) =>
            {
                Interlocked.Increment(ref this.processedCount);

                SnapshotRegion region = sortedRegions[index];
                Boolean success;

                // Set to type of a pointer
                region.ElementType = EngineCore.GetInstance().Processes.IsOpenedProcess32Bit() ? typeof(UInt32) : typeof(UInt64);

                // Enforce 4-byte alignment of pointers
                region.Alignment = sizeof(Int32);

                // Read current page data for chunk
                region.ReadAllRegionMemory(out success);

                // Read failed; Deallocated page
                if (!success)
                {
                    return;
                }

                if (region.GetCurrentValues() == null || region.GetCurrentValues().Length <= 0)
                {
                    return;
                }

                foreach (SnapshotElementRef element in region)
                {
                    // Enforce user mode memory pointers
                    if (element.LessThanValue(invalidPointerMin) || element.GreaterThanValue(invalidPointerMax))
                    {
                        continue;
                    }

                    // Enforce 4-byte alignment of destination
                    if (element.GetCurrentValue() % 4 != 0)
                    {
                        continue;
                    }

                    IntPtr Value = new IntPtr(element.GetCurrentValue());

                    // Check if it is possible that this pointer is valid, if so keep it
                    if (this.CurrentSnapshot.ContainsAddress(Value))
                    {
                        foundPointers.Add(Value);
                    }
                }

                // Clear the saved values, we do not need them now
                region.SetCurrentValues(null);
            });

            IEnumerable <IntPtr> pointers = foundPointers.ToList();

            this.ConstructingSet.UnionWith(pointers);
            this.FoundPointers.UnionWith(pointers);
        }
예제 #11
0
        protected override void OnUpdate()
        {
            // Read memory to update previous and current values
            this.Snapshot.ReadAllMemory();

            Boolean conditionValid = this.IsInputConditionValid(this.Snapshot.GetTimeSinceLastUpdate());
            Int32   processedPages = 0;

            // Note the duplicated code here is an optimization to minimize comparisons done per iteration
            if (conditionValid)
            {
                Parallel.ForEach(
                    this.Snapshot.Cast <Object>(),
                    SettingsViewModel.GetInstance().ParallelSettings,
                    (regionObject) =>
                {
                    SnapshotRegion region = regionObject as SnapshotRegion;

                    if (!region.CanCompare())
                    {
                        return;
                    }

                    foreach (SnapshotElementRef element in region)
                    {
                        if (element.Changed())
                        {
                            ((dynamic)element).ElementLabel++;
                        }
                    }

                    lock (this.ProgressLock)
                    {
                        processedPages++;
                        this.UpdateProgress(processedPages, this.Snapshot.GetRegionCount());
                    }
                });
            }
            else
            {
                Parallel.ForEach(
                    this.Snapshot.Cast <Object>(),
                    SettingsViewModel.GetInstance().ParallelSettings,
                    (regionObject) =>
                {
                    SnapshotRegion region = regionObject as SnapshotRegion;

                    if (!region.CanCompare())
                    {
                        return;
                    }

                    foreach (SnapshotElementRef element in region)
                    {
                        if (element.Changed())
                        {
                            ((dynamic)element).ElementLabel--;
                        }
                    }

                    lock (this.ProgressLock)
                    {
                        processedPages++;
                        this.UpdateProgress(processedPages, this.Snapshot.GetRegionCount());
                    }
                });
            }

            this.UpdateScanCount?.Invoke();

            base.OnUpdate();
        }
예제 #12
0
        /// <summary>
        /// Called when the scan updates.
        /// </summary>
        protected override void OnUpdate()
        {
            Int32 processedPages = 0;

            // Read memory to get current values
            Parallel.ForEach(
                this.Snapshot.Cast <Object>(),
                SettingsViewModel.GetInstance().ParallelSettings,
                (regionObject) =>
            {
                SnapshotRegion region = regionObject as SnapshotRegion;
                Boolean readSuccess;

                region.ReadAllRegionMemory(out readSuccess, keepValues: true);

                if (!readSuccess)
                {
                    region.SetAllValidBits(false);
                    return;
                }

                // Ignore region if it requires current & previous values, but we cannot find them
                if (this.ScanConstraintManager.HasRelativeConstraint() && !region.CanCompare())
                {
                    region.SetAllValidBits(false);
                    return;
                }

                foreach (SnapshotElementRef element in region)
                {
                    // Enforce each value constraint on the element
                    foreach (ScanConstraint scanConstraint in this.ScanConstraintManager)
                    {
                        switch (scanConstraint.Constraint)
                        {
                        case ConstraintsEnum.Unchanged:
                            if (!element.Unchanged())
                            {
                                element.SetValid(false);
                            }

                            break;

                        case ConstraintsEnum.Changed:
                            if (!element.Changed())
                            {
                                element.SetValid(false);
                            }

                            break;

                        case ConstraintsEnum.Increased:
                            if (!element.Increased())
                            {
                                element.SetValid(false);
                            }

                            break;

                        case ConstraintsEnum.Decreased:
                            if (!element.Decreased())
                            {
                                element.SetValid(false);
                            }

                            break;

                        case ConstraintsEnum.IncreasedByX:
                            if (!element.IncreasedByValue(scanConstraint.ConstraintValue))
                            {
                                element.SetValid(false);
                            }

                            break;

                        case ConstraintsEnum.DecreasedByX:
                            if (!element.DecreasedByValue(scanConstraint.ConstraintValue))
                            {
                                element.SetValid(false);
                            }

                            break;

                        case ConstraintsEnum.Equal:
                            if (!element.EqualToValue(scanConstraint.ConstraintValue))
                            {
                                element.SetValid(false);
                            }

                            break;

                        case ConstraintsEnum.NotEqual:
                            if (!element.NotEqualToValue(scanConstraint.ConstraintValue))
                            {
                                element.SetValid(false);
                            }

                            break;

                        case ConstraintsEnum.GreaterThan:
                            if (!element.GreaterThanValue(scanConstraint.ConstraintValue))
                            {
                                element.SetValid(false);
                            }

                            break;

                        case ConstraintsEnum.GreaterThanOrEqual:
                            if (!element.GreaterThanOrEqualToValue(scanConstraint.ConstraintValue))
                            {
                                element.SetValid(false);
                            }

                            break;

                        case ConstraintsEnum.LessThan:
                            if (!element.LessThanValue(scanConstraint.ConstraintValue))
                            {
                                element.SetValid(false);
                            }

                            break;

                        case ConstraintsEnum.LessThanOrEqual:
                            if (!element.LessThanOrEqualToValue(scanConstraint.ConstraintValue))
                            {
                                element.SetValid(false);
                            }

                            break;

                        case ConstraintsEnum.NotScientificNotation:
                            if (element.IsScientificNotation())
                            {
                                element.SetValid(false);
                            }

                            break;
                        }
                    }
                    //// End foreach Constraint
                }
                //// End foreach Element

                lock (this.ProgressLock)
                {
                    processedPages++;
                    this.UpdateProgress(processedPages, this.Snapshot.GetRegionCount());
                }
            });
            //// End foreach Region

            base.OnUpdate();
        }