首页 > 其他分享 >Delphi 搜索特征码

Delphi 搜索特征码

时间:2022-09-02 14:12:36浏览次数:60  
标签:function begin ch end 特征 pattern Delphi 搜索 class

老外开源的代码,使用了各种新语法,测试了能用,支持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

相关文章