📄 unitpefile.pas
字号:
unit unitPEFile;
interface
uses Windows, Classes, SysUtils, ConTnrs, unitResourceDetails, ImageHlp;
type
TPEModule = class;
//----------------------------------------------------------------------
// TImageSection class
TImageSection = class
private
fParent: TPEModule;
fSectionHeader : TImageSectionHeader;
fRawData : TMemoryStream;
fUninitializedDataSize : Integer;
function GetSectionName: string;
public
constructor Create (AParent : TPEModule; const AHeader : TImageSectionHeader; rawData : pointer);
destructor destroy; override;
property Parent : TPEModule read fParent;
property SectionName : string read GetSectionName;
property SectionHeader : TImageSectionHeader read fSectionHeader;
property RawData : TMemoryStream read fRawData;
end;
//----------------------------------------------------------------------
// TPEModule class
TPEModule = class (TResourceModule)
private
fDOSHeader : TImageDosHeader;
fCOFFHeader : TImageFileHeader;
fOptionalHeader : PImageOptionalHeader;
fSectionList : TObjectList; // List of TImageSection objects
fDOSStub : TMemoryStream;
fCommentBlock : PChar;
fCommentSize : Integer;
fEndComment : PChar;
fEndCommentSize : Integer;
function GetOptionalHeader: TImageOptionalHeader;
function GetImageSection(index: Integer): TImageSection;
function GetImageSectionCount: Integer;
function GetDataDictionary(index: Integer): PImageDataDirectory;
function GetDataDictionaryCount: Integer;
function GetDOSHeader: TImageDosHeader;
function GetCOFFHeader: TImageFileHeader;
protected
procedure Decode (memory : pointer; exeSize : Integer); virtual;
procedure Encode; virtual;
property OptionalHeaderPtr : PImageOptionalHeader read fOptionalHeader;
function FindDictionaryEntrySection (entryNo : Integer): Integer;
public
constructor Create;
destructor Destroy; override;
property DOSHeader : TImageDosHeader read GetDOSHeader;
property COFFHeader : TImageFileHeader read GetCOFFHeader;
property OptionalHeader : TImageOptionalHeader read GetOptionalHeader;
property ImageSectionCount : Integer read GetImageSectionCount;
property ImageSection [index : Integer] : TImageSection read GetImageSection;
property DataDictionaryCount : Integer read GetDataDictionaryCount;
property DataDictionary [index : Integer] : PImageDataDirectory read GetDataDictionary;
procedure LoadFromStream (s : TStream); override;
procedure LoadFromFile (const name : string); override;
procedure SaveToStream (s : TStream); override;
procedure SaveToFile (const name : string); override;
end;
//----------------------------------------------------------------------
// TResourceDirectoryTable record
TResourceDirectoryTable = packed record
characteristics : DWORD; // Resource flags, reserved for future use; currently set to zero.
timeDateStamp : DWORD; // Time the resource data was created by the resource compiler.
versionMajor : WORD; // Major version number, set by the user.
versionMinor : WORD; // Minor version number.
cNameEntries : WORD; // Number of directory entries, immediately following the table, that use strings to identify Type, Name, or Language (depending on the level of the table).
cIDEntries : WORD; // Number of directory entries, immediately following the Name entries, that use numeric identifiers for Type, Name, or Language.
end;
PResourceDirectoryTable = ^TResourceDirectoryTable;
//----------------------------------------------------------------------
// TPEModule record
TResourceDirectoryEntry = packed record
name : DWORD; // RVA Address of integer or string that gives the Type, Name, or Language identifier, depending on level of table.
RVA : DWORD; // RVA High bit 0. Address of a Resource Data Entry (a leaf).
// RVA High bit 1. Lower 31 bits are the address of another Resource Directory Table (the next level down).
end;
PResourceDirectoryEntry = ^TResourceDirectoryEntry;
//----------------------------------------------------------------------
// TResourceDirectoryEntry record
TResourceDataEntry = packed record
OffsetToData : DWORD;
Size : DWORD;
CodePage : DWORD;
Reserved : DWORD
end;
PResourceDataEntry = ^TResourceDataEntry;
//----------------------------------------------------------------------
// TPEResourceModule class
TPEResourceModule = class (TPEModule)
private
fDetailList : TObjectList; // List of TResourceDetails objects
function GetResourceSection : TImageSection;
protected
procedure Decode (memory : pointer; exeSize : Integer); override;
procedure Encode; override;
function GetResourceCount: Integer; override;
function GetResourceDetails(idx: Integer): TResourceDetails; override;
public
constructor Create;
destructor Destroy; override;
property ResourceCount : Integer read GetResourceCount;
property ResourceDetails [idx : Integer] : TResourceDetails read GetResourceDetails;
procedure DeleteResource (resourceNo : Integer); override;
procedure InsertResource (idx : Integer; details : TResourceDetails); override;
function AddResource (details : TResourceDetails) : Integer; override;
function IndexOfResource (details : TResourceDetails) : Integer; override;
procedure SortResources; override;
end;
EPEException = class (Exception);
implementation
{ TPEModule }
resourcestring
rstInvalidDOSSignature = 'Invalid DOS signature';
rstInvalidCOFFSignature = 'Invalid COFF signature';
rstInvalidOptionalHeader = 'Invalid Windows Image';
rstBadDictionaryIndex = 'Index exceeds data dictionary count';
rstBadLangID = 'Unsupported non-integer language ID in resource';
rstEncode = 'Error encoding module';
type
TResourceNode = class
count : Integer;
nodes : array of record
id : string;
intID : boolean;
case leaf : boolean of
false : (next : TResourceNode);
true : (data : TMemoryStream; CodePage : DWORD)
end;
constructor Create (const AType, AName : string; ALang : Integer; aData : TMemoryStream; CodePage : DWORD);
constructor CreateNameNode (const AName : string; ALang : Integer; aData : TMemoryStream; CodePage : DWORD);
constructor CreateLangNode (ALang : Integer; aData : TMemoryStream; CodePage : DWORD);
procedure Add (const AType, AName : string; ALang : Integer; aData : TMemoryStream; CodePage : DWORD);
procedure AddName (const AName : string; ALang : Integer; aData : TMemoryStream; CodePage : DWORD);
procedure AddLang (ALang : Integer; aData : TMemoryStream; CodePage : DWORD);
function IsID (idx : Integer): boolean;
destructor Destroy; override;
end;
(*----------------------------------------------------------------------*
| constructor PEModule.Create |
| |
| Constructor for TPEModule instance. Create empty section list |
*----------------------------------------------------------------------*)
constructor TPEModule.Create;
begin
inherited Create;
fSectionList := TObjectList.Create;
fDOSStub := TMemoryStream.Create;
end;
(*----------------------------------------------------------------------*
| procedure PEModule.Decode |
| |
| Decode the PE file. Load the DOS header, the COFF header and the |
| 'optional' header, then load each section into fSectionList |
*----------------------------------------------------------------------*)
procedure TPEModule.Decode (Memory : pointer; exeSize : Integer);
var
offset : LongInt;
i : Integer;
sectionHeader : PImageSectionHeader;
commentOffset : Integer;
begin
fSectionList.Clear;
// Check it's really a PE file.
if PWORD (Memory)^ <> IMAGE_DOS_SIGNATURE then
raise EPEException.Create (rstInvalidDOSSignature);
// Load the DOS header
fDOSHeader := PImageDosHeader (Memory)^;
offset := fDOSHeader._lfanew;
fDOSStub.Write ((PChar (Memory) + sizeof (fDOSHeader))^, fDOSHeader._lfanew - sizeof (fDOSHeader));
// Check the COFF signature
if PDWORD (PChar (Memory) + offset)^ <> IMAGE_NT_SIGNATURE then
raise EPEException.Create (rstInvalidCOFFSignature);
// Load the COFF header
Inc (offset, sizeof (DWORD));
fCOFFHeader := PImageFileHEader (PChar (Memory) + offset)^;
Inc (offset, sizeof (fCOFFHeader));
// Check the Optional Header signature. nb
// the optional header is compulsory for
// 32 bit windows modules!
if PWORD (PChar (Memory) + offset)^ <> IMAGE_NT_OPTIONAL_HDR_MAGIC then
raise EPEException.Create (rstInvalidOptionalHeader);
// Save the 'optional' header
ReallocMem (fOptionalHeader, fCOFFHeader.SizeOfOptionalHeader);
Move ((PChar (Memory) + Offset)^, fOptionalHeader^, fCOFFHeader.SizeOfOptionalHeader);
Inc (offset, fCOFFHeader.SizeOfOptionalHeader);
sectionHeader := PImageSectionHeader (PChar (memory) + offset);
commentOffset := offset + fCOFFHeader.NumberOfSections * sizeof (TImageSectionHeader);
// Save padding between the end of the section headers, and the start of the
// 1st section. TDump reports this as 'comment', and it seems to be important
// to MS clock.exe...
fCommentSize := Integer (sectionHeader^.PointerToRawData) - commentOffset;
if fCommentSize > 0 then
begin
GetMem (fCommentBlock, fCommentSize);
Move ((PChar (memory) + commentOffset)^, fCommentBlock^, fCommentSize)
end;
// Now save each image section in the fSectionList
for i := 0 to fCOFFHeader.NumberOfSections - 1 do
begin
sectionHeader := PImageSectionHeader (PChar (memory) + offset);
fSectionList.Add (TImageSection.Create (self, sectionHeader^, PChar (memory) + sectionHeader^.PointertoRawData));
Inc (offset, sizeof (TImageSectionHeader));
end;
i := sectionHeader^.PointerToRawData + sectionHeader^.SizeOfRawData;
// Save the padding between the last section and the end of the file.
// This appears to hold debug info and things ??
fEndCommentSize := exeSize - i;
if fEndCommentSize > 0 then
begin
GetMem (fEndComment, fEndCommentSize);
Move ((PChar (memory) + i)^, fEndComment^, fEndCommentSize)
end
end;
(*----------------------------------------------------------------------*
| destructor PEModule.Destroy |
| |
| Destructor for TPEModule instance. |
*----------------------------------------------------------------------*)
destructor TPEModule.Destroy;
begin
ReallocMem (fOptionalHeader, 0);
fSectionList.Free;
fDOSStub.Free;
ReallocMem (fCommentBlock, 0);
ReallocMem (fEndComment, 0);
inherited;
end;
(*----------------------------------------------------------------------*
| procedure PEModule.Encode |
| |
| Fix up the data prior to writing to stream. |
| |
| Ensure that the headers match what we've got... |
*----------------------------------------------------------------------*)
procedure TPEModule.Encode;
var
offset : DWORD;
i : Integer;
section : TImageSection;
align : Integer;
addrAlign : Integer;
address : Integer;
alignedSize, AddrAlignedSize : Integer;
codeSize, iDataSize, uDataSize, iSize : Integer;
begin
codeSize := 0;
iDataSize := 0;
uDataSize := 0;
// Use the DOS stub from their .EXE
fDOSHeader._lfanew := sizeof (fDosHeader) + fDOSStub.Size;
// Fixup sections count
fCOFFHeader.NumberOfSections := fSectionList.Count;
iSize := fDOSHeader._lfanew + // File offset for start of sections
SizeOf (DWORD) + // NT signature
sizeof (fCoffHeader) +
fCOFFHeader.SizeOfOptionalHeader +
fSectionList.Count * sizeof (TImageSectionHeader);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -