我正在寫一個小型PE文件分析器,並且必須讀取PE文件的內容。我通過ReadFile
功能這樣做,如下圖所示:Delphi中的異步讀取文件XE2
function TMainForm.GetPEData(var filename: string) : boolean;
var
hFile: DWORD;
IDH: TImageDosHeader;
INH: TImageNtHeaders;
ISH: TImageSectionHeader;
dwRead: DWORD;
szBuff: array[0..7] of Char;
i: WORD;
PE: TPEFile;
begin
Result := False;
PE := TPeFile.Create;
if PE.LoadFromFile (filename) then
Form2.edEntryPoint.Text := IntToHex(PE.RvaToFileOffset(PE.AddressOfEntryPoint), 8);
SplashScreen.sLabel1.Caption := 'PE File Loaded';
hFile := CreateFile(PChar(filename), GENERIC_READ,
FILE_SHARE_WRITE, nil,
OPEN_EXISTING, 0, 0);
if hFile <> INVALID_HANDLE_VALUE then
begin
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
SplashScreen.sLabel1.Caption := 'Reading DOS File Headers...';
ReadFile(hFile, IDH, 64, dwRead, nil);
if IDH.e_magic = IMAGE_DOS_SIGNATURE then
begin
SetFilePointer(hFile, IDH._lfanew, nil, FILE_BEGIN);
SplashScreen.sLabel1.Caption := 'Reading NT File Headers...';
//Here is where the UI freezes while the file is read...
ReadFile(hFile, INH, 248, dwRead, nil);
if INH.Signature = IMAGE_NT_SIGNATURE then
begin
Form2.edImageBase.Text := IntToHex(INH.OptionalHeader.ImageBase, 8);
Form2.edSizeOfImage.Text := IntToHex(INH.OptionalHeader.SizeOfImage, 8);
Form2.edLinkerVersion.Text := IntToStr(INH.OptionalHeader.MajorLinkerVersion) + '.' +
IntToStr(INH.OptionalHeader.MinorLinkerVersion);
Form2.edFileAlignment.Text := IntToHex(INH.OptionalHeader.FileAlignment, 8);
Form2.edSectionAlignment.Text := IntToHex(INH.OptionalHeader.SectionAlignment, 8);
Form2.edSubSystem.Text := IntToHex(INH.OptionalHeader.Subsystem, 4);
Form2.edEPFilestamp.Text := IntToStr(INH.FileHeader.TimeDateStamp);
Form2.edFileType.Text := GetPEFileType(PE.ImageNtHeaders.Signature);
for i := 0 to INH.FileHeader.NumberOfSections - 1 do
begin
SetFilePointer(hFile, IDH._lfanew + 248 + i * 40, nil, FILE_BEGIN);
ReadFile(hFile, ISH, 40, dwRead, nil);
CopyMemory(@szBuff[0], @ISH.Name[0], 8);
with Form2.sListView1.Items.Add do
begin
Caption := ShortString(szBuff);
SubItems.Add(IntToHex(ISH.VirtualAddress, 8));
SubItems.Add(IntToHex(ISH.Misc.VirtualSize, 8));
SubItems.Add(IntToHex(ISH.PointerToRawData, 8));
SubItems.Add(IntToHex(ISH.SizeOfRawData, 8));
SubItems.Add(IntToHex(ISH.Characteristics, 8));
end;
end;
end;
end;
CloseHandle(hFile);
Result := True;
end;
end;
壞的事情是,根據文件的大小,我注意到ReadFile
經常滯後 - 和它同步發生。與此同時,用戶界面凍結,看起來可怕的錯誤,誰會試圖終止它。我曾考慮過線程,但我只想看看是否有任何方法可以在異步模式下使用ReadFile
。如果沒有,我會跳到線程,即使我需要在代碼中修改很多。
預先感謝您。
出於好奇,是否有一個原因,你在這裏重新發明輪子? 2007年之前的Delphi版本有一個轉儲PE信息的演示(這裏沒有演示名稱,但稍後會發布),[JEDI代碼庫](http://delphi-jedi.org)有一個整個單元('JclPEImage')包含爲您準備好所有這些東西的即用功能。 (甚至有一個PEViewer演示程序以與DependencyWalker非常相似的方式顯示所有內容)。即使是非常大的可執行文件(5 MB +),所有代碼都可以很好地執行,而且不存在任何UI問題或滯後。 – 2012-07-17 20:19:26
嗨,@KenWhite,我對這個實現沒有任何偏好。事實上,我排除了JEDI,因爲一個單元與另一個單元相連,而且這個 - 恕我直言 - 使得整個項目難以維護,比起我只有一個單一的功能。我會看看舊的德爾福演示,我想我仍然有德爾福7的光盤。 – 2012-07-17 20:33:56
當我到達我的家庭系統時,我會從D7中找到演示名稱,並在此處發表評論。 'JCL'比'JVCL'好一點,因爲它是嚴格的代碼。它確實增加了一些其他的東西,但是在這種情況下,你需要在你的uses子句中添加一個單元名稱來包含'JclPEImage',並從代碼中調用簡單的函數。這並不糟糕(儘管我同意JVCL與其他單位共同依賴它)。 – 2012-07-17 20:40:47