📄 unitpefile.pas
字号:
offset := iSize + fCommentSize;
align := fOptionalHeader^.FileAlignment;
addrAlign := fOptionalHeader^.SectionAlignment;
address := addrAlign;
offset := DWORD ((integer (offset) + align - 1) div align * align);
// First section starts at $1000 (when loaded)
// and at 'offset' in file.
fOptionalHeader^.SizeOfHeaders := DWORD ((integer (iSize) + align - 1) div align * align);
fOptionalHeader^.BaseOfCode := $ffffffff;
fOptionalHeader^.CheckSum := 0; // Calculate it during 'SaveToStream' when
// we've got all the info.
iSize := DWORD ((integer (iSize) + addrAlign - 1) div addrAlign * addrAlign);
for i := 0 to fSectionList.Count - 1 do // Recalculate the section offsets
begin
section := TImageSection (fSectionList [i]);
section.fSectionHeader.PointerToRawData := offset;
section.fSectionHeader.VirtualAddress := address;
// Virtual size is size of data in memory, and is not padded to an 'alignment'.
//
// SizeOfRawData is size of data in file, padded to (file) alignment.
//
// 1. If VirtualSize < SizeOfRawData, that's simply because the raw data is aligned, and virt data isn't.
//
// 2. If VirtualSize > SizeOfRawData, the additional memory is filled with zeros when it's loaded.
//
// Because SizeOfRawData is padded it's impossible to tell how much Virtual Memory is really required.
//
// We do our best by saving the original difference in '2.' above in fUninitializeDataSize
section.fSectionHeader.Misc.VirtualSize := section.fRawData.Size + section.fUninitializedDataSize;
section.fSectionHeader.SizeOfRawData := (section.fRawData.Size + align - 1) div align * align;
alignedSize := (Integer (section.fSectionHeader.Misc.VirtualSize) + align - 1) div align * align;
addrAlignedSize := (Integer (section.fSectionHeader.Misc.VirtualSize) + addrAlign - 1) div addrAlign * addrAlign;
if (section.fSectionHeader.Characteristics and IMAGE_SCN_MEM_EXECUTE) <> 0 then
begin
Inc (codeSize, alignedSize);
if DWORD (address) < fOptionalHeader^.BaseOfCode then
fOptionalHeader^.BaseOfCode := address
end
else
if (section.fSectionHeader.Characteristics and IMAGE_SCN_CNT_INITIALIZED_DATA) <> 0 then
Inc (iDataSize, alignedSize)
else
if (section.fSectionHeader.Characteristics and IMAGE_SCN_CNT_UNINITIALIZED_DATA) <> 0 then
Inc (uDataSize, alignedSize);
Inc (iSize, addrAlignedSize);
Inc (offset, section.fSectionHeader.SizeOfRawData);
Inc (address, (Integer (section.fSectionHeader.Misc.VirtualSize) + addrAlign - 1) div addrAlign * addrAlign);
end;
fOptionalHeader^.SizeOfCode := codeSize;
fOptionalHeader^.SizeOfInitializedData := iDataSize;
fOptionalHeader^.SizeOfUninitializedData := uDataSize;
i := SizeOf (DWORD) + // NT signature
sizeof (fCoffHeader) +
fCOFFHeader.SizeOfOptionalHeader +
codeSize;
i := (i + addrAlign - 1) div addrAlign * addrAlign;
// With explorer.exe, codeSize is $14800, i is 148E8, so aligned 'i' is $15000
// .. so BaseOfData should be $15000 + BaseOfCode ($1000) = $16000.
//
// ... but it's not - it's $15000, which means that the last $8e8 bytes of code
// should be stampled over by the data!
//
// But obviously explorer.exe works, so I'm, missing a trick here. Never mind - it
// doesn't do any harm making it $16000 instead, and the formula works for everything
// else I've tested...
fOptionalHeader^.BaseOfData := fOptionalHeader.BaseOfCode + DWORD (i);
fOptionalHeader^.SizeOfImage := iSize;
end;
(*----------------------------------------------------------------------*
| function PEModule.FindDictionaryEntrySection |
| |
| Return the index of the specified section. The 'entryNo' to find |
| should be a 'IMAGE_DIRECTORY_ENTRY_xxxx' constant defined in |
| Windows.pas. |
*----------------------------------------------------------------------*)
function TPEModule.FindDictionaryEntrySection (entryNo: Integer): Integer;
var
i : Integer;
p : PImageDataDirectory;
begin
result := -1;
p := DataDictionary [entryNo];
// Find section with matching virt address.
for i := 0 to ImageSectionCount - 1 do
if ImageSection [i].fSectionHeader.VirtualAddress = p^.VirtualAddress then
begin
result := i;
break
end
end;
(*----------------------------------------------------------------------*
| function TPEModule.GetCOFFHeader |
| |
| Return COFF header |
*----------------------------------------------------------------------*)
function TPEModule.GetCOFFHeader: TImageFileHeader;
begin
result := fCoffHeader;
end;
(*----------------------------------------------------------------------*
| function TPEModule.GetDataDictionary |
| |
| Return the data dictionary for a specified |
| IMAGE_DIRECTORY_ENTRY_xxxx index |
*----------------------------------------------------------------------*)
function TPEModule.GetDataDictionary(index: Integer): PImageDataDirectory;
var
p : PImageDataDirectory;
begin
if index < DataDictionaryCount then
begin
p := @fOptionalHeader.DataDirectory [0];
Inc (p, index);
result := p
end
else
raise ERangeError.Create (rstBadDictionaryIndex);
end;
(*----------------------------------------------------------------------*
| function TPEModule.GetDataDictionaryCount |
| |
| Return no of entries in the Data Directory |
*----------------------------------------------------------------------*)
function TPEModule.GetDataDictionaryCount: Integer;
begin
result := fOptionalHeader^.NumberOfRvaAndSizes
end;
(*----------------------------------------------------------------------*
| function TPEModule.GetDosHeader |
| |
| Return DOS header |
*----------------------------------------------------------------------*)
function TPEModule.GetDOSHeader: TImageDosHeader;
begin
result := fDOSHeader;
end;
(*----------------------------------------------------------------------*
| function TPEModule.GetImageSection () : TImageSection |
| |
| Get the specified image section |
*----------------------------------------------------------------------*)
function TPEModule.GetImageSection(index: Integer): TImageSection;
begin
result := TImageSection (fSectionList [index]);
end;
(*----------------------------------------------------------------------*
| function TPEModule.GetImageSectionCount |
| |
| Return no of image sections |
*----------------------------------------------------------------------*)
function TPEModule.GetImageSectionCount: Integer;
begin
result := fSectionList.Count
end;
(*----------------------------------------------------------------------*
| function TPEModule.GetImageSectionCount |
| |
| Get the optional header |
*----------------------------------------------------------------------*)
function TPEModule.GetOptionalHeader: TImageOptionalHeader;
begin
result := fOptionalHeader^
end;
(*----------------------------------------------------------------------*
| procedure TPEModule.LoadFromFile |
| |
| Load the module from a file |
*----------------------------------------------------------------------*)
procedure TPEModule.LoadFromFile(const name: string);
var
f : TFileStream;
begin
f := TFileStream.Create (name, fmOpenRead or fmShareDenyNone);
try
LoadFromStream (f)
finally
f.Free
end
end;
(*----------------------------------------------------------------------*
| procedure TPEModule.LoadFromFile |
| |
| Load the module from a stream |
*----------------------------------------------------------------------*)
procedure TPEModule.LoadFromStream(s: TStream);
var
m : TMemoryStream;
begin
m := TMemoryStream.Create;
try
m.CopyFrom (s, 0);
Decode (m.memory, m.size)
finally
m.Free
end
end;
(*----------------------------------------------------------------------*
| procedure TPEModule.SaveToFile |
| |
| Save the module to a file |
*----------------------------------------------------------------------*)
procedure TPEModule.SaveToFile(const name: string);
var
f : TFileStream;
begin
f := TFileStream.Create (name, fmCreate);
try
SaveToStream (f)
finally
f.Free
end
end;
(*----------------------------------------------------------------------*
| procedure TPEModule.SaveToStream |
| |
| Save the module to a stream |
*----------------------------------------------------------------------*)
procedure TPEModule.SaveToStream(s: TStream);
var
NTSignature : DWORD;
i : Integer;
section : TImageSection;
paddingSize, paddingLen : Integer;
padding : PChar;
f : TMemoryStream;
oldCheckSum, newCheckSum : DWORD;
ntHeaders : PImageNTHEaders;
ckOffset : DWORD;
begin
Encode; // Encode the data.
NTSignature := IMAGE_NT_SIGNATURE;
// Write the DOS stub
s.Write (fDOSHeader, sizeof (fDOSHeader));
s.CopyFrom (fDOSStub, 0);
// Write NT sig and COFF header
s.Write (NTSignature, sizeof (NTSignature));
s.Write (fCOFFHeader, sizeof (fCOFFHeader));
ckOffset := s.Position + Integer (@fOptionalHeader^.CheckSum) - Integer (@fOptionalHeader^);
s.Write (fOptionalHeader^, fCOFFHeader.SizeOfOptionalHeader);
// Write the section headers
for i := 0 to fSectionList.Count - 1 do
begin
section := TImageSection (fSectionList [i]);
s.Write (section.fSectionHeader, sizeof (section.fSectionHeader))
end;
if fCommentSize > 0 then // Save the 'comment' section. See 'Decode' for details
s.Write (fCommentBlock^, fCommentSize);
// Write the sections
padding := Nil;
paddingLen := 0;
try
for i := 0 to fSectionList.Count - 1 do
begin
// Write padding up to file offset of the section
section := TImageSection (fSectionList [i]);
paddingSize := section.fSectionHeader.PointerToRawData - DWORD (s.Position);
if paddingSize > paddingLen then
begin
paddingLen := paddingSize + 65536;
ReallocMem (padding, paddingLen);
ZeroMemory (padding, paddingLen);
end;
if paddingSize > 0 then // Put our signature at the start of the first
s.Write (padding^, paddingSize);
// Write the section data.
s.CopyFrom (section.fRawData, 0);
// Write data
with section.fSectionHeader do
paddingSize := SizeOfRawData - misc.VirtualSize;
// Pad data
if paddingSize > paddingLen then
begin
paddingLen := paddingSize + 65536;
ReallocMem (padding, paddingLen);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -