Использование Free Pascal \ Lazarus для анализа большого двоичного файла на предмет определенных значений - PullRequest
3 голосов
/ 30 марта 2012

Мне нужно разобрать дамп памяти для MFT записей (из файловой системы NTFS ).

В прошлом я занимался программированием в отношении чтения заголовков нескольких файлов (с использованием класса FileSearcher и т. Д.), Но я не совсем уверен, как начать чтение с начала большого файла, прочитать через это, и когда определенное значение найдено, мне нужно прочитать 1024 байта с того момента, когда найдено магическое значение (FILE0, в случае записей MFT), и «делать вещи» со значениями между ними и конец диапазона 1024 байта. Затем необходимо продолжить поиск следующей записи FILE0.

Пока у меня есть следующее - я собираюсь прочитать исходный файл (который является TFileStream) в поисках «FILE0». Когда он его находит, на данном этапе я просто хочу, чтобы он сообщил, что он нашел запись, и вывел позицию, но со временем мне нужно, чтобы он затем прочитал серию байтов из точки, в которой был найден FILE0:

type
    MFTRecordsStore = packed record
    FILE0MagicMarker: array[0..4] of byte;
    // Lots more follow....
end;

var
    MFTHeaderArray : MFTRecordsStore;
    FILE0Present : string;
    i : integer;

begin
    SourceFile.Position := 0;
    while (SourceFile.Position < SourceFile.Size) do
        begin
            SourceFile.ReadBuffer(MFTHeaderArray, SizeOf(MFTHeaderArray));
            for i := 0 to 4 do
                FILE0Present := FILE0Present + IntToHex(MFTHeaderArray.FILE0MagicMarker[i], 2);
                if FILE0Present = 'FILE0' then
                    begin
                        Memo1.Lines.Add('FILE0 Entry found at '+ IntToStr(SourceFile.Position));
                    end;
        end;
  end;

Этот код компилируется и запускается (начинает анализировать файл), но после нескольких минут интенсивной загрузки ЦП программа вылетает и сообщает, что не может прочитать поток. У меня такое ощущение, что это как-то связано с тем, как добраться до конца файла, и не осталось полного «чанка» для чтения, чтобы он вылетал?

Какое решение?

Ответы [ 2 ]

3 голосов
/ 31 марта 2012

Я публикую пример того, как я буду писать и читать файл записей, используя потоки, и искать в нем определенный текст ANSI. Вы также можете проверить commented version этого сообщения.

Вот определение записи, использованное в этом примере:

type
  TFileRecord = packed record
    Marker: array [0..4] of Byte;
    Width: Integer;
    Height: Integer;
    Useful: Boolean;
  end;

Вот как создать такой файл записей (что у вас уже есть:)

procedure TForm1.Button1Click(Sender: TObject);
var
  FileStream: TFileStream;
  FileRecord: TFileRecord;
const
  RecordSize = SizeOf(TFileRecord);

  procedure FillFileRecord(const AMarker: string; const AWidth: Integer;
    const AHeight: Integer; const AUseful: Boolean);
  begin
    FillChar(FileRecord, RecordSize, 0);
    Move(AMarker[1], FileRecord.Marker, Length(FileRecord.Marker));
    FileRecord.Width := AWidth;
    FileRecord.Height := AHeight;
    FileRecord.Useful := AUseful;
  end;

begin
  FileStream := TFileStream.Create('File.dat', fmCreate);
  try
    FillFileRecord('FILE1', 111, 112, False);
    FileStream.Write(FileRecord, RecordSize);
    FillFileRecord('FILE2', 211, 212, False);
    FileStream.Write(FileRecord, RecordSize);
    FillFileRecord('FILE3', 311, 312, False);
    FileStream.Write(FileRecord, RecordSize);
    FillFileRecord('FILE4', 411, 412, False);
    FileStream.Write(FileRecord, RecordSize);
    FillFileRecord('FILE0', 666, 777, True);
    FileStream.Write(FileRecord, RecordSize);
    FillFileRecord('FILE5', 511, 512, False);
    FileStream.Write(FileRecord, RecordSize);
    FillFileRecord('FILE0', 11111, 22222, True);
    FileStream.Write(FileRecord, RecordSize);
    FillFileRecord('FILE6', 611, 612, False);
    FileStream.Write(FileRecord, RecordSize);
  finally
    FileStream.Free;
  end;
end;

А вот как читать такой файл:

procedure TForm1.Button2Click(Sender: TObject);
var
  FileStream: TFileStream;
  FileRecord: TFileRecord;
const
  HeaderSeq = 'FILE0';
  HeaderLen = Length(HeaderSeq);
  RecordSize = SizeOf(TFileRecord);
begin
  FileStream := TFileStream.Create('File.dat', fmOpenRead);
  try
    while FileStream.Read(FileRecord, RecordSize) = RecordSize do
    begin
      if CompareMem(@HeaderSeq[1], @FileRecord.Marker[0], HeaderLen) then
      begin
        Memo1.Lines.Add('FILE0 entry found at '+
          IntToStr(FileStream.Position - RecordSize));
        Memo1.Lines.Add('FileRecord.Width = ' +
          IntToStr(FileRecord.Width));
        Memo1.Lines.Add('FileRecord.Height = ' +
          IntToStr(FileRecord.Height));
        Memo1.Lines.Add('FileRecord.Useful = ' +
          BoolToStr(FileRecord.Useful, True));
      end;
    end;
  finally
    FileStream.Free;
  end;
end;   
2 голосов
/ 30 марта 2012

Если вы действительно подозреваете, что читаете мимо EOF, попробуйте:

while (SourceFile.Position + SizeOf(MFTHeaderArray) <= SourceFile.Size) do

...