Reloaded.Memory.SigScan
, is a pattern matching library for scanning byte signatures.
Signature scanning is often used in malware analysis (AV Software) and game hacking.
Usually both of those are the domain of native C/C++ code and at the time of writing this library, there existed very little on the managed .NET front that focuses on performance.
Reloaded.Memory.SigScan
is biased towards ease of use and most importantly speed, achieving a staggering > 5GB/s on a in non-vectorised searches and over 30GB/s on vectorised searches on a single thread.
Patterns are specified as hex values, without prefix and delimited by spaces.
??
represents a wildcard, i.e. any byte can be present in the place of the wildcard.
Search the code of the current process:
// `FindPattern` will automatically use the most
// efficient scanning method available on the current machine.
var thisProcess = Process.GetCurrentProcess();
var scanner = new Scanner(thisProcess, thisProcess.MainModule);
int offset = scanner.FindPattern("04 25 12 ?? ?? E5 E3");
Search an offset in a byte array:
var scanner = new Scanner(data);
int offset = scanner.FindPattern("02 11 25 AB");
Scan for multiple signatures (multithreaded)
var scanner = new Scanner(data);
var multiplePatterns = new string[]
{
"7A BB",
"9F AB",
"7A BB"
};
// Note: Use FindPatternsCached if your list of
// patterns might contain duplicates.
var results = scanner.FindPatterns(multiplePatterns);
All benchmarks were performed on a machine running:
- Core i7 4790k (4.4GHz OC)
- DDR3 1866MHz RAM (CL9 timings)
- .NET 5 Runtime
The provided "Speed" column is an effective measure of pattern matching speed in MB/s.
NumItems
: Number of signatures scanned.ST
: Single Threaded. (baseline reference)MT
: Multi Threaded.LB
: Load Balancing On.Compiled
: Non-Vectorized implementation.
Scanning a small data (3MiB) with known signature at end of data.
| Method | Mean | Error | StdDev | Ratio | RatioSD | Speed (MB/s) |
|--------- |-----------:|---------:|---------:|------:|--------:|------------- |
| Avx | 232.4 us | 2.76 us | 2.58 us | 0.32 | 0.00 | 13535.33 |
| Sse | 284.7 us | 2.17 us | 2.03 us | 0.40 | 0.00 | 11049.62 |
| Compiled | 715.7 us | 5.68 us | 5.03 us | 1.00 | 0.00 | 4395.52 |
| Simple | 3,098.3 us | 36.51 us | 34.15 us | 4.33 | 0.05 | 1015.31 |
Scanning a small data (3MiB) with random pre-selected 12 byte signatures.
| Method | NumItems | Speed (MB/s) |
|--------------- |--------- |------------- |
| Random_ST | 1 | 13618.03 |
| Random_MT_NoLB | 4 | 26394.96 |
| Random_MT_LB | 4 | 26326.17 |
| Random_MT_LB | 16 | 46032.68 |
| Random_MT_NoLB | 16 | 50459.84 |
| Random_MT_LB | 64 | 56748.39 |
| Random_MT_NoLB | 64 | 57970.04 |
| Random_MT_LB | 256 | 63418.04 |
| Random_MT_NoLB | 256 | 63746.84 |
Scanning a random big data (200MiB) with random pre-selected 12 byte signatures.
| Method | NumItems | Speed (MB/s) |
|------------------- |--------- |------------- |
| Random_ST_Compiled | 1 | 10308.65 |
| Random_ST | 1 | 30025.36 |
| Random_MT_NoLB | 4 | 44669.77 |
| Random_MT_LB | 4 | 44572.28 |
| Random_MT_LB | 16 | 60354.57 |
| Random_MT_NoLB | 16 | 64928.73 |
| Random_MT_LB | 64 | 59824.99 |
| Random_MT_NoLB | 64 | 60502.48 |
| Random_MT_NoLB | 256 | 55931.01 |
| Random_MT_LB | 256 | 56763.69 |
Speed loss in cases of >16 items suggests increased cache misses.
Might be worth investigating in a future version.
For other benchmarks, please see the Reloaded.Memory.Sigscan.Benchmark
project in this repository.
To run the benchmarks yourself, simply run Reloaded.Memory.Sigscan.Benchmark
after compiling in Release
mode.
Reloaded.Memory.Sigscan.Benchmark
is powered by BenchmarkDotNet.
See Reloaded-II SigScan Shared Library.
Vectorised implementations of Reloaded.Memory.Sigscan
are based off of a modified version of LazySIMD
by uberhalit.