Reputation: 979
I need to parse a RAM dump for MFT records (from the NTFS filesystem).
I've done some programming in the past with regard to reading headers of multiple files (using FileSearcher class, etc.), but I'm not entirely sure how to start reading from the start of a large file, read through it, and when a certain value is found I need to read in 1024 bytes from the point that the magic value is found (FILE0
, in the case of MFT entries) and 'do stuff' with the values in between that and the end of the 1024 byte range. It then needs to carry on searching for the next FILE0
record.
So far I have the following - my intention is that it reads through the source file (which is a TFileStream) looking for 'FILE0'. When it finds it, at this stage I just want it to report that it has found a record and output the position, but in due course I need it to then read a series of bytes from the point at which FILE0 was found:
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;
This code compiles and runs (it starts to parse the file), but after several minutes of heavy CPU usage the program crashes and reports that it cannot read the stream. I have a feeling this has something to do with getting to the end of the file and there not been a full 'chunk' left to read so it crashes?
What is the solution?
Upvotes: 3
Views: 4308
Reputation: 76693
I'm posting an example of how I would write and read file of records using streams and seek for a certain ANSI text in it. You may check also the commented version
of this post.
Here is the record definition used in this example:
type
TFileRecord = packed record
Marker: array [0..4] of Byte;
Width: Integer;
Height: Integer;
Useful: Boolean;
end;
Here is how to create such file of records (what you already have :)
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;
And here is how to read such file:
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;
Upvotes: 6
Reputation: 3653
If you really suspect reading past EOF, try:
while (SourceFile.Position + SizeOf(MFTHeaderArray) <= SourceFile.Size) do
Upvotes: 2