📄 peheader.dpr
字号:
// dcc PEHeader -uc:\ext\jedi\api
// COPY/Y C:\ext\ls\Apps\PEHeader\PEHeader.exe c:\dos\peh.exe
// PEHeader e:\delphi7\bin\delphi32.exe
// DLLTools
{$APPTYPE CONSOLE}
{$RANGECHECKS OFF}
uses
JwaWinNT, windows, classes, SysUtils;
type
TSectionHeaderArr = array [Word] of TImageSectionHeader;
PSectionHeaderArr = ^TSectionHeaderArr;
TSectionName = packed array[0..IMAGE_SIZEOF_SHORT_NAME-1] of char;
TResourceDirectoryEntryArr = array [WORD] of TImageResourceDirectoryEntry;
PResourceDirectoryEntryArr = ^TResourceDirectoryEntryArr;
TFunctionRVA = array [0..0] of DWORD;
_IMAGE_BASE_RELOCATION = record
VirtualAddress: DWORD;
SizeOfBlock: DWORD;
// WORD TypeOffset[1];
end;
PImageBaseRelocation = ^_IMAGE_BASE_RELOCATION;
var
p : PByte;
i, tempSize : Integer;
Str : pChar;
pBASE, VABase, RawAddr, sRVA : DWORD;
ThunkData : DWORD;
isFileMap : Boolean = true;
pNameRVA : PDWord;
pOrdinal: PWord;
pFunctionRVA : ^TFunctionRVA;
pRelocItem : PWord;
const
ResourceTypeArr : array [1..24] of String
= ('CURSOR',
'BITMAP',
'ICON',
'MENU',
'DIALOG',
'STRING',
'FONTDIR',
'FONT',
'ACCELERATOR',
'RCDATA',
'MESSAGETABLE',
'GROUP_CURSOR',
'Unknow',
'GROUP_ICON',
'Unknow',
'VERSION',
'DLGINCLUDE',
'Unknow',
'PLUGPLAY',
'VXD',
'ANICURSOR',
'ANIICON',
'HTML',
'MANIFEST');
//取资源类别, 仅对根级目录有效
function GetResourceClass(NameOffset:DWORD) : String;
begin
case NameOffset of
low(ResourceTypeArr)..high(ResourceTypeArr) :
Result := ResourceTypeArr[NameOffset];
else
Result := 'Unknow';
end;
end;
//名字是基于节起点的偏移
function GetNameFromOffset(sRVA, BaseAddr : Integer) : String; overload;
var
pStr : PImageResourceDirStringU;
S : WideString;
begin
Integer(pStr) := BaseAddr + sRVA;
SetLength(S, pStr^.Length);
move(pStr^.NameString, S[1], pStr^.Length*2);
Result := S;
end;
//数据是基于节起点的RVA
function GetStringFromRVA(sRVA, BaseVA, BaseAddr : Integer) : String;
begin
Result := GetNameFromOffset(sRVA - BaseVA, BaseAddr);
end;
//取资源名
function GetResourceName(NameOffset:DWORD; BaseVA, BaseAddr: Integer) : String;
begin
if (NameOffset and IMAGE_RESOURCE_NAME_IS_STRING)=0 then
Result := IntToStr(NameOffset)
else
Result := GetNameFromOffset(NameOffset and $7FFFFFFF, BaseAddr);
end;
// BASE = 文件映像在内存中的起始地址
// Section = [0..IMAGE_DIRECTORY_ENTRY_IAT]
// sRVA = 节的VirtualAddress(RVA)
// RawAddr = 节的物理地址(Phys Off), 相对于BASE的偏移
// 如果指定的节(Section)中的信息无效, 则返回False;
function PosToSectionEntry(BASE: Pointer; Section: SmallInt; var sRVA, RawAddr: DWORD): Boolean;
var
p : pByte;
i : Integer;
Size : DWORD;
begin
Result := False;
RawAddr := 0;
// 定位到PE头, 取导入表的VirtualAddress
p := BASE;
inc(p, PImageDosHeader(p)^._lfanew);
with PImageNtHeaders(p)^ do
begin
Size := FileHeader.NumberOfSections;
sRVA := OptionalHeader.DataDirectory[Section].VirtualAddress;
if sRVA = 0 then
Exit;
end;
// 定位到节表数组, 取导入表的物理地址
inc(p, PImageNtHeaders(p)^.FileHeader.SizeOfOptionalHeader-SizeOf(TImageOptionalHeader));
inc(p, SizeOF(TImageNtHeaders));
for i := 0 to Size - 1 do
with PSectionHeaderArr(p)^[i] do
// 如果虚地址相等或者sRVA落在节的内部
if (sRVA = VirtualAddress) or
((sRVA > VirtualAddress) and (sRVA <= VirtualAddress + Misc.VirtualSize)) then
begin
RawAddr := PointerToRawData + (sRVA - VirtualAddress);
Result := True;
Exit;
end;
end;
// Offset : 结构起点的偏移
// BaseVA : 资源节起点的相对虚地址
// BaseAddr : 资源节在内存中的起点
function EnumResources(Offset, BaseVA, BaseAddr : DWORD; ResName : String = '') : Integer;
var
pResStart : PImageResourceDirectory;
pEntryArr : PResourceDirectoryEntryArr;
pData : PImageResourceDataEntry;
tempSize : Integer;
NameOrID : String;
isRoot : Boolean;
isDir : Boolean;
i : integer;
begin
Integer(pResStart) := Offset + BaseAddr;
isRoot := Offset = 0;
// 使用id的元素 + 使用名称的元素
Result := pResStart^.NumberOfIdEntries + pResStart^.NumberOfNamedEntries;
tempSize := Result;
// 跳过目录结构
inc(pResStart);
pEntryArr := Pointer(pResStart);
for i := 0 to tempSize - 1 do
with pEntryArr^[i] do
if isRoot then
begin
writeln('-----------------------------------------');
writeln(GetResourceClass(Name.NameOffSet));
writeln('-----------------------------------------');
dec(Result);
Result := Result + EnumResources(Directory.OffsetToDirectory and $7FFFFFFF, BaseVA, BaseAddr);
end
else
begin
isDir := Directory.OffsetToData and IMAGE_RESOURCE_DATA_IS_DIRECTORY <> 0;
NameOrID := GetResourceName(Name.NameOffSet, BaseVA, BaseAddr);
//数据目录
if isDir then
begin
dec(Result);
Result := Result + EnumResources(Directory.OffsetToDirectory and $7FFFFFFF, BaseVA, BaseAddr, NameOrID);
end
else
begin
if NameOrId = '0' then NameOrId := ResName;
Integer(pData) := Directory.OffsetToData + BaseAddr;
with pData^ do
begin
writeln(format('%-15s%-8u%-10.8x%-8u',[NameOrID, Size, OffsetToData, CodePage]));
//writeln(GetStringFromRVA(OffsetToData, BaseVA, BaseAddr));
end;
end;
end;
end;
begin
with TMemoryStream.Create do
begin
if ParamCount > 0 then
LoadFromFile(ParamStr(1))
else
LoadFromFile(ParamStr(0));
// DOS 头部
p := memory;
writeln('DOS头部标志: $', IntToHex(PImageDosHeader(p)^.e_magic, 4), ' --> MZ');
// PE 头部标志
inc(p, PImageDosHeader(p)^._lfanew);
writeln(' PE头部标志: $', IntToHex(PImageNtHeaders(p)^.Signature, 8), ' --> PE');
// PE 头部
with PImageNtHeaders(p)^.FileHeader do
begin
writeln(' PE头部的域 ==> ');
writeln(' NumberOfSections : ', NumberOfSections);
writeln(' TimeDateStamp : $', IntToHex(TimeDateStamp, 8));
end;
// PE 可选头部
writeln(' 数据目录信息 ==> ');
writeln('Size':16, 'VirtualAddress':16);
with PImageNtHeaders(p)^.OptionalHeader do
for i := 0 to NumberOfRvaAndSizes - 1 do
begin
if DataDirectory[i].VirtualAddress = 0 then continue;
system.write('--> ':8);
system.write(IntToHex(DataDirectory[i].Size, 8));
writeln(IntToHex(DataDirectory[i].VirtualAddress, 8):10);
end;
tempSize := PImageNtHeaders(p)^.FileHeader.NumberOfSections;
// 修正数据目录
inc(p, PImageNtHeaders(p)^.FileHeader.SizeOfOptionalHeader-SizeOf(TImageOptionalHeader));
// 节表
inc(p, SizeOF(TImageNtHeaders));
writeln('节表起始地址: $', IntToHex(Integer(p)-Integer(memory), 8));
writeln('VirtualAddress':32);
for i := 0 to tempSize - 1 do
with PSectionHeaderArr(p)^[i] do
Writeln(TSectionName(Name):13, ' --> ', IntToHex(VirtualAddress, 8));
// 定位到资源节, 输出
p := memory;
PosToSectionEntry(p, IMAGE_DIRECTORY_ENTRY_RESOURCE, VABase, RawAddr);
inc(p, RawAddr);
writeln('资源表起始地址: ', IntToHex(RawAddr, 8));
writeln(format('%-15s%-8s%-10s%-8s',['资源','长度','RVA','CodePage']));
Writeln('共检索到资源数: ', EnumResources(0, VABase, Integer(p)));
// 定位到导入表, 输出
p := memory;
PosToSectionEntry(p, IMAGE_DIRECTORY_ENTRY_IMPORT, VABase, RawAddr);
writeln('导入表起始地址: ', IntToHex(RawAddr, 8));
inc(p, RawAddr);
pBASE := DWORD(p);
while PImageImportDecriptor(p)^.Name <> 0 do
with PImageImportDecriptor(p)^ do
begin
sRVA := Name;
if Union.OriginalFirstThunk <> 0 then
writeln(pChar(pBASE + (Name - VABase)):16, IntToHex(Union.OriginalFirstThunk, 8):10)
else
writeln(pChar(pBASE + (Name - VABase)):16, IntToHex(FirstThunk, 8):10);
inc(p, SizeOf(TImageImportDecriptor));
end;
// 第一个导入文件的导入例程列表
if PImageImportDecriptor(pBASE)^.Union.OriginalFirstThunk <> 0 then
DWORD(p) := pBASE + (PImageImportDecriptor(pBASE)^.Union.OriginalFirstThunk - VABase)
else
DWORD(p) := pBASE + (PImageImportDecriptor(pBASE)^.FirstThunk - VABase);
while PImageThunkData(p)^.Function_ <> 0 do
begin
if PImageThunkData(p)^.Ordinal and IMAGE_ORDINAL_FLAG32 <> 0 then //高位为1
writeln(format('ord: %17.8x', [PImageThunkData(p)^.Ordinal and $7FFFFFFF]))
else
begin
sRVA := PImageThunkData(p)^.AddressOfData;
with PImageImportByName(pBASE + (sRVA - VABase))^ do
writeln(format('name: %-16s Hint: %.4x', [String(pChar(@Name)), Hint]));
end;
inc(p, SizeOf(PImageThunkData));
end;
//导出表(仅使用名字访问)
p := memory;
if PosToSectionEntry(p, IMAGE_DIRECTORY_ENTRY_EXPORT, VABase, RawAddr) then
begin
writeln('导出表起始地址: ', IntToHex(RawAddr, 8));
inc(p, RawAddr);
pBASE := DWORD(p);
with PImageExportDirectory(p)^ do
begin
DWORD(pFunctionRVA) := pBASE + (DWORD(AddressOfFunctions) - VABase);
DWORD(pNameRVA) := pBASE + (DWORD(AddressOfNames) - VABase);
DWORD(pOrdinal) := pBASE + (DWORD(AddressOfNameOrdinals) - VABase);
for i := 0 to NumberOfNames - 1 do
begin
writeln(format('Func: %.8x Ord: %.4x %S',
[pFunctionRVA^[pOrdinal^],
pOrdinal^ + Base,
String(pChar(pBASE + (pNameRVA^ - VABase)))]));
inc(pNameRVA);
inc(pOrdinal);
end;
end;
end;
//重定位表
p := memory;
if PosToSectionEntry(p, IMAGE_DIRECTORY_ENTRY_BASERELOC, VABase, RawAddr) then
begin
writeln('重定位表起始地址: ', IntToHex(RawAddr, 8));
inc(p, RawAddr);
pBASE := DWORD(p);
while PImageBaseRelocation(p)^.VirtualAddress <> 0 do
with PImageBaseRelocation(p)^ do
begin
if pBASE <> DWORD(p) then
writeln('Next Relocation Table Section...');
tempSize := (SizeOfBlock - SizeOf(TImageBaseRelocation)) div SizeOf(WORD);
DWORD(pRelocItem) := DWORD(p) + SizeOf(TImageBaseRelocation);
for i := 0 to tempSize - 1 do
begin
Writeln(format('RVA: %.8x, Type: %.4x', [VirtualAddress + pRelocItem^ AND $0FFF, pRelocItem^ SHR 12]));
inc(pRelocItem);
end;
p := Pointer(pRelocItem);
//DWORD(p) := DWORD(p) + SizeOfBlock;
end;
end;
free;
end;
//readln;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -