老外开源的代码,使用了各种新语法,测试了能用,支持05 ?? EB这种,不支持老版本Delphi
unit uPatternFinder;
interface
uses
SysUtils, Generics.Collections, Threading;
type
TPattern = class sealed(TObject)
public
type
TByte = record
strict private
type
TNibble = record
private
Wildcard: Boolean;
Data: Byte;
end;
private
N1, N2: TNibble;
end;
type
TPatternTByte = TPattern.TByte;
type
TPatternTByteArray = array of TPatternTByte;
public
class function Format(const _pattern: string): string; static;
class function Transform(_pattern: string): TPatternTByteArray;
class function Find(Data: TBytes; _pattern: TPatternTByteArray): Boolean; overload; static;
class function Find(Data: TBytes; _pattern: TPatternTByteArray; out offsetFound: Int64): Boolean; overload; static;
strict private
class function hexChToInt(ch: Char): Integer; static;
class function matchByte(b: Byte; var p: TByte): Boolean; static;
end;
type
TPatternTByteArray = TPattern.TPatternTByteArray;
type
ISignature = interface(IInterface)
['{26232742-3742-43C1-8E5C-032BE9B0F91B}']
function GetName: string;
property Name: string read GetName;
function GetPattern: TPatternTByteArray;
property Pattern: TPatternTByteArray read GetPattern;
function GetFoundOffset: Int64;
procedure SetFoundOffset(value: Int64);
property FoundOffset: Int64 read GetFoundOffset write SetFoundOffset;
function ToString(): string;
end;
type
TISignatureArray = array of ISignature;
type
TSignature = class sealed(TInterfacedObject, ISignature)
strict private
FName: string;
FPattern: TPatternTByteArray;
FFoundOffset: Int64;
function GetName: string;
property Name: string read GetName;
function GetPattern: TPatternTByteArray;
function GetFoundOffset: Int64;
procedure SetFoundOffset(value: Int64);
public
constructor Create(const _name: string; _pattern: TPatternTByteArray); overload;
constructor Create(const _name: string; const _pattern: string); overload;
function ToString(): string; override;
end;
type
TSignatureFinder = class sealed(TObject)
public
class function Scan(Data: TBytes; signatures: TISignatureArray): TISignatureArray; static;
end;
var
tsList: TThreadList<ISignature>;
implementation
//格式化字符串,只留数字、字符与?号
class function TPattern.Format(const _pattern: string): string;
var
_length, i: Integer;
tempRes: string;
ch: Char;
begin
_length := Length(_pattern);
tempRes := '';
for i := 0 to Pred(_length) do
begin
ch := _pattern[i + 1];
if (((ch >= '0') and (ch <= '9')) or ((ch >= 'A') and (ch <= 'F')) or ((ch >= 'a') and (ch <= 'f')) or (ch = '?')) then
begin
tempRes := tempRes + (ch);
end;
end;
result := tempRes;
end;
class function TPattern.Transform(_pattern: string): TPatternTByteArray;
var
_length, i, j, k: Integer;
tempRes: TList<TByte>;
newbyte: TByte;
ch: Char;
b: TByte;
begin
_pattern := Format(_pattern);
_length := Length(_pattern);
if (_length = 0) then
begin
result := Nil;
Exit;
end;
tempRes := TList<TByte>.Create();
tempRes.Capacity := (_length + 1) div 2;
try
if (_length mod 2 <> 0) then
begin
_pattern := _pattern + '?';
Inc(_length);
end;
newbyte := Default(TByte);
i := 0;
j := 0;
while i < _length do
begin
ch := _pattern[i + 1];
if (ch = '?') then // wildcard
begin
if (j = 0) then
newbyte.N1.Wildcard := true
else
newbyte.N2.Wildcard := true;
end
else // hex
begin
if (j = 0) then
begin
newbyte.N1.Wildcard := false;
newbyte.N1.Data := Byte(hexChToInt(ch) and $F);
end
else
begin
newbyte.N2.Wildcard := false;
newbyte.N2.Data := Byte(hexChToInt(ch) and $F);
end;
end;
Inc(j);
if (j = 2) then
begin
j := 0;
tempRes.Add(newbyte);
end;
Inc(i);
end;
k := 0;
SetLength(result, tempRes.Count);
for b in tempRes do
begin
result[k] := b;
Inc(k);
end;
finally
tempRes.Free;
end;
end;
class function TPattern.Find(Data: TBytes; _pattern: TPatternTByteArray): Boolean;
var
temp: Int64;
begin
result := Find(Data, _pattern, temp);
end;
class function TPattern.matchByte(b: Byte; var p: TByte): Boolean;
var
N1, N2: Integer;
begin
if (not p.N1.Wildcard) then // if not a wildcard we need to compare the data.
begin
N1 := b shr 4;
if (N1 <> p.N1.Data) then // if the data is not equal b doesn't match p.
begin
result := false;
Exit;
end;
end;
if (not p.N2.Wildcard) then // if not a wildcard we need to compare the data.
begin
N2 := b and $F;
if (N2 <> p.N2.Data) then // if the data is not equal b doesn't match p.
begin
result := false;
Exit;
end;
end;
result := true;
end;
class function TPattern.Find(Data: TBytes; _pattern: TPatternTByteArray; out offsetFound: Int64): Boolean;
var
patternSize, i, pos: Int64;
begin
offsetFound := -1;
if ((Data = Nil) or (_pattern = Nil)) then
begin
result := false;
Exit;
end;
patternSize := Length(_pattern);
if ((Length(Data) = 0) or (patternSize = 0)) then
begin
result := false;
Exit;
end;
i := 0;
pos := 0;
while i < Length(Data) do
begin
if (matchByte(Data[i], _pattern[pos])) then
// check if the current data byte matches the current pattern byte
begin
Inc(pos);
if (pos = patternSize) then // everything matched
begin
offsetFound := i - patternSize + 1;
result := true;
Exit;
end
end
else // fix by Computer_Angel
begin
i := i - pos;
pos := 0; // reset current pattern position
end;
Inc(i);
end;
result := false;
end;
class function TPattern.hexChToInt(ch: Char): Integer;
begin
if ((ch >= '0') and (ch <= '9')) then
begin
result := Ord(ch) - Ord('0');
Exit;
end;
if ((ch >= 'A') and (ch <= 'F')) then
begin
result := Ord(ch) - Ord('A') + 10;
Exit;
end;
if ((ch >= 'a') and (ch <= 'f')) then
begin
result := Ord(ch) - Ord('a') + 10;
Exit;
end;
result := -1;
end;
constructor TSignature.Create(const _name: string; _pattern: TPatternTByteArray);
begin
inherited Create();
FName := _name;
FPattern := _pattern;
FFoundOffset := -1;
end;
constructor TSignature.Create(const _name: string; const _pattern: string);
begin
inherited Create();
FName := _name;
FPattern := TPattern.Transform(_pattern);
FFoundOffset := -1;
end;
function TSignature.GetName: string;
begin
result := FName;
end;
function TSignature.GetPattern: TPatternTByteArray;
begin
result := FPattern;
end;
function TSignature.GetFoundOffset: Int64;
begin
result := FFoundOffset;
end;
procedure TSignature.SetFoundOffset(value: Int64);
begin
FFoundOffset := value;
end;
function TSignature.ToString(): string;
begin
result := Name;
end;
class function TSignatureFinder.Scan(Data: TBytes; signatures: TISignatureArray): TISignatureArray;
var
found: TList<ISignature>;
tempOffset: Int64;
sig: ISignature;
j: Integer;
begin
tsList := TThreadList<ISignature>.Create;
found := tsList.LockList;
try
TParallel.&For(0, Length(signatures) - 1,
procedure(Idx: Int64)
begin
if (TPattern.Find(Data, signatures[Idx].Pattern, tempOffset)) then
begin
signatures[Idx].FoundOffset := tempOffset;
found.Add(signatures[Idx]);
end
end);
j := 0;
SetLength(result, found.Count);
for sig in found do
begin
result[j] := sig;
Inc(j);
end;
finally
tsList.UnlockList;
tsList.Free;
end;
end;
end.
测试单元:
unit PatternFinderConsoleTests;
interface
uses
SysUtils, Winapi.Windows, uPatternFinder, CnDebug, MainUnit;
type
testProgram = class(TObject)
public
class procedure Tests; static;
class procedure SignatureTest; static;
end;
implementation
class procedure testProgram.Tests;
var
pattern: TPatternTByteArray;
data1, data2, data3: TBytes;
o1, o2, o3: Int64;
begin
pattern := TPattern.Transform('456?89?B');
data1 := TBytes.Create($01, $23, $45, $67, $89, $AB, $CD, $EF);
if (not (TPattern.Find(data1, pattern, o1) and (o1 = 2))) then
WriteLn('Test 1 failed...');
data2 := TBytes.Create($01, $23, $45, $66, $89, $6B, $CD, $EF);
if (not (TPattern.Find(data2, pattern, o2) and (o2 = 2))) then
WriteLn('Test 2 failed...');
data3 := TBytes.Create($11, $11, $11, $11, $11, $11, $11, $11);
if (TPattern.Find(data3, pattern, o3)) then
WriteLn('Test 3 failed...');
WriteLn('Done testing!');
end;
class procedure testProgram.SignatureTest();
var
data: TBytes;
signatures, result: TISignatureArray;
sig1, sig2, sig3, sig4, signature: ISignature;
begin
//data := TBytes.Create();
SetLength(data, $4235000);
CopyMemory(@data[0], Pointer($00400000), $4235000);
//data := TBytes.Create($01, $23, $45, $67, $89, $AB, $CD, $EF, $45, $65, $67, $89);
sig1 := TSignature.Create('pattern1', 'CC456?89?B');
sig2 := TSignature.Create('pattern2', Form1.edit2.text);
sig3 := TSignature.Create('pattern3', 'CCAB??EF');
sig4 := TSignature.Create('pattern4', 'CC45??67');
signatures := TISignatureArray.Create(sig1, sig2, sig3, sig4);
result := TSignatureFinder.Scan(data, signatures);
for signature in result do
begin
CnDebugger.LogMsg(Format('found %s at %x', [signature.Name, $00400000 + signature.FoundOffset]))
end;
end;
end.
标签:function,begin,ch,end,特征,pattern,Delphi,搜索,class
From: https://www.cnblogs.com/YXGust/p/16649669.html