297 lines
12 KiB
ObjectPascal
297 lines
12 KiB
ObjectPascal
|
(************************************************************
|
||
|
|
||
|
Simple Stripped PE Binary File Dumper
|
||
|
|
||
|
************************************************************)
|
||
|
Unit SPEDump;
|
||
|
(* -------------------------------------------------------- *)
|
||
|
Interface
|
||
|
(* -------------------------------------------------------- *)
|
||
|
Uses KolibriOS;
|
||
|
(* -------------------------------------------------------- *)
|
||
|
Type
|
||
|
Dword = LongWord;
|
||
|
|
||
|
PDword = ^Dword;
|
||
|
|
||
|
TDwordArray = Packed Array[0..0] Of Dword;
|
||
|
|
||
|
PDwordArray = ^TDwordArray;
|
||
|
|
||
|
Const
|
||
|
STRIPPED_PE_SIGNATURE = $4503; // 'PE' Xor 'S'
|
||
|
SPE_DIRECTORY_IMPORT = 0;
|
||
|
SPE_DIRECTORY_EXPORT = 1;
|
||
|
SPE_DIRECTORY_BASERELOC = 2;
|
||
|
|
||
|
SPE_MAX_DIRECTORY_ENTRIES = SPE_DIRECTORY_BASERELOC;
|
||
|
|
||
|
Type
|
||
|
TStrippedPEHeader = Packed Record
|
||
|
Signature: Word;
|
||
|
Characteristics: Word;
|
||
|
AddressOfEntryPoint: Dword;
|
||
|
ImageBase: Dword;
|
||
|
SectionAlignmentLog: Byte;
|
||
|
FileAlignmentLog: Byte;
|
||
|
MajorOSVersion: Byte;
|
||
|
MinorOSVersion: Byte;
|
||
|
SizeOfImage: Dword;
|
||
|
SizeOfStackReserve: Dword;
|
||
|
SizeOfHeapReserve: Dword;
|
||
|
SizeOfHeaders: Dword;
|
||
|
Subsystem: Byte;
|
||
|
NumberOfRvaAndSizes: Byte;
|
||
|
NumberOfSections: Word;
|
||
|
End;
|
||
|
|
||
|
PStrippedPEHeader = ^TStrippedPEHeader;
|
||
|
|
||
|
TStrippedSectionHeader = Packed Record
|
||
|
Name: Packed Array[0..7] Of Char;
|
||
|
VirtualSize: Dword;
|
||
|
VirtualAddress: Dword;
|
||
|
SizeOfRawData: Dword;
|
||
|
PointerToRawData: Dword;
|
||
|
Characteristics: Dword;
|
||
|
End;
|
||
|
|
||
|
PStrippedSectionHeader = ^TStrippedSectionHeader;
|
||
|
|
||
|
TDataDirectory = Packed Record
|
||
|
VirtualAddress: Dword;
|
||
|
Size: Dword;
|
||
|
End;
|
||
|
|
||
|
PDataDirectory = ^TDataDirectory;
|
||
|
|
||
|
TDataDirectoryArray = Packed Array[0..SPE_MAX_DIRECTORY_ENTRIES] Of TDataDirectory;
|
||
|
|
||
|
PDataDirectoryArray = ^TDataDirectoryArray;
|
||
|
|
||
|
TImportDescriptor = Packed Record
|
||
|
OriginalFirstThunk: Dword;
|
||
|
TimeDateStamp: Dword;
|
||
|
ForwarderChain: Dword;
|
||
|
Name: Dword;
|
||
|
FirstThunk: Dword;
|
||
|
End;
|
||
|
|
||
|
PImportDescriptor = ^TImportDescriptor;
|
||
|
|
||
|
TExportDescriptor = Packed Record
|
||
|
Characteristics: Dword;
|
||
|
TimeDateStamp: Dword;
|
||
|
MajorVersion: Word;
|
||
|
MinorVersion: Word;
|
||
|
Name: Dword;
|
||
|
Base: Dword;
|
||
|
NumberOfFunctions: Dword;
|
||
|
NumberOfNames: Dword;
|
||
|
AddressOfFunctions: Dword;
|
||
|
AddressOfNames: Dword;
|
||
|
AddressOfNameOrdinals: Dword;
|
||
|
End;
|
||
|
|
||
|
PExportDescriptor = ^TExportDescriptor;
|
||
|
|
||
|
Var
|
||
|
FileName: PChar;
|
||
|
FileHandle: Integer;
|
||
|
FileLength: Dword;
|
||
|
BytesRead: Dword;
|
||
|
Buffer: PStrippedPEHeader;
|
||
|
Section: PStrippedSectionHeader;
|
||
|
DataDirectory: PDataDirectoryArray;
|
||
|
ImportDescriptor: PImportDescriptor;
|
||
|
ExportDescriptor: PExportDescriptor;
|
||
|
Thunk: PDword;
|
||
|
|
||
|
(* --------------------- Console stuff -------------------- *)
|
||
|
hConsole: Pointer;
|
||
|
ConsoleInit: Procedure(WndWidth, WndHeight, ScrWidth, ScrHeight: Dword; Caption: PChar); StdCall;
|
||
|
ConsoleExit: Procedure(bCloseWindow: Boolean); StdCall;
|
||
|
Printf: Function(Const Format: PChar): Integer; CDecl VarArgs;
|
||
|
GetCh: Function: Integer; StdCall;
|
||
|
WriteN: Procedure(Const Str: PChar; Count: Dword); StdCall;
|
||
|
Write: Procedure(Const Str: PChar); StdCall;
|
||
|
|
||
|
(* -------------------------------------------------------- *)
|
||
|
Procedure Main;
|
||
|
Function FileIsValid: Boolean;
|
||
|
Procedure WriteHex(Number: Dword);
|
||
|
Procedure WriteLn(Text: PChar);
|
||
|
(* -------------------------------------------------------- *)
|
||
|
Implementation
|
||
|
(* -------------------------------------------------------- *)
|
||
|
Function FileIsValid : Boolean;
|
||
|
Begin
|
||
|
FileIsValid := FALSE;
|
||
|
With Buffer^ Do Begin
|
||
|
If BytesRead < SizeOf(TStrippedPEHeader) Then Exit;
|
||
|
If Signature <> STRIPPED_PE_SIGNATURE Then Exit;
|
||
|
End;
|
||
|
FileIsValid := TRUE;
|
||
|
End;
|
||
|
(* -------------------------------------------------------- *)
|
||
|
Function RVA2Offset(RVA: Dword; StrippedPEHeader: PStrippedPEHeader): Dword;
|
||
|
Var
|
||
|
i: Dword;
|
||
|
StrippedSectionHeader: PStrippedSectionHeader;
|
||
|
Begin
|
||
|
With StrippedPEHeader^ Do Begin
|
||
|
StrippedSectionHeader := PStrippedSectionHeader(Dword(StrippedPEHeader) + SizeOf(TStrippedPEHeader) + NumberOfRvaAndSizes * SizeOf(TDataDirectory));
|
||
|
For i := 0 To NumberOfSections Do Begin
|
||
|
With StrippedSectionHeader^ Do Begin
|
||
|
If (RVA >= VirtualAddress) And (RVA < VirtualAddress + SizeOfRawData) Then Begin
|
||
|
Result := PointerToRawData + RVA - VirtualAddress;
|
||
|
Exit;
|
||
|
End;
|
||
|
End;
|
||
|
Inc(StrippedSectionHeader);
|
||
|
End;
|
||
|
End;
|
||
|
Result := 0;
|
||
|
End;
|
||
|
(* -------------------------------------------------------- *)
|
||
|
Procedure WriteHex(Number: Dword); Begin Printf('%X', Number); End;
|
||
|
(* -------------------------------------------------------- *)
|
||
|
Procedure WriteLn(Text: PChar); Begin Printf('%s'#10, Text); End;
|
||
|
(* -------------------------------------------------------- *)
|
||
|
Procedure Main;
|
||
|
Const
|
||
|
CmdLine = PPChar(28);
|
||
|
Var
|
||
|
i: Dword;
|
||
|
Begin
|
||
|
hConsole := LoadLibrary('/sys/lib/console.obj');
|
||
|
ConsoleInit := GetProcAddress(hConsole, 'con_init');
|
||
|
ConsoleExit := GetProcAddress(hConsole, 'con_exit');
|
||
|
Printf := GetProcAddress(hConsole, 'con_printf');
|
||
|
GetCh := GetProcAddress(hConsole, 'con_getch');
|
||
|
WriteN := GetProcAddress(hConsole, 'con_write_string');
|
||
|
Write := GetProcAddress(hConsole, 'con_write_asciiz');
|
||
|
ConsoleInit($FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF, 'SPEDump');
|
||
|
|
||
|
(* skip spaces *)
|
||
|
i := 0; While CmdLine^[i] = ' ' Do Inc(i);
|
||
|
FileName := @CmdLine^[i];
|
||
|
|
||
|
WriteLn('Simple Stripped PE Binary File Dumper Version 0.1; 2018.');
|
||
|
If FileName[0] = #0 Then Begin
|
||
|
WriteLn('Usage: SPEDump [<file>]')
|
||
|
End Else Begin
|
||
|
WriteLn(''); Write('Dump of "'); Write(FileName); WriteLn('"'); WriteLn('');
|
||
|
Buffer := PStrippedPEHeader(LoadFile(FileName, BytesRead));
|
||
|
If Buffer <> Nil Then Begin
|
||
|
|
||
|
If FileIsValid Then Begin
|
||
|
WriteLn('File header');
|
||
|
WriteLn('-----------');
|
||
|
|
||
|
With Buffer^ Do Begin
|
||
|
Write(' Signature = '); WriteHex(Signature); WriteLn('');
|
||
|
Write(' Characteristics = '); WriteHex(Characteristics); WriteLn('');
|
||
|
Write(' AddressOfEntryPoint = '); WriteHex(AddressOfEntryPoint); WriteLn('');
|
||
|
Write(' ImageBase = '); WriteHex(ImageBase); WriteLn('');
|
||
|
Write(' SectionAlignmentLog = '); WriteHex(SectionAlignmentLog); WriteLn('');
|
||
|
Write(' FileAlignmentLog = '); WriteHex(FileAlignmentLog); WriteLn('');
|
||
|
Write(' MajorOSVersion = '); WriteHex(MajorOSVersion); WriteLn('');
|
||
|
Write(' MinorOSVersion = '); WriteHex(MinorOSVersion); WriteLn('');
|
||
|
Write(' SizeOfImage = '); WriteHex(SizeOfImage); WriteLn('');
|
||
|
Write(' SizeOfStackReserve = '); WriteHex(SizeOfStackReserve); WriteLn('');
|
||
|
Write(' SizeOfHeapReserve = '); WriteHex(SizeOfHeapReserve); WriteLn('');
|
||
|
Write(' SizeOfHeaders = '); WriteHex(SizeOfHeaders); WriteLn('');
|
||
|
Write(' Subsystem = '); WriteHex(Subsystem); WriteLn('');
|
||
|
Write(' NumberOfRvaAndSizes = '); WriteHex(NumberOfRvaAndSizes); WriteLn('');
|
||
|
Write(' NumberOfSections = '); WriteHex(NumberOfSections); WriteLn('');
|
||
|
|
||
|
WriteLn('');
|
||
|
|
||
|
If NumberOfSections > 0 Then Begin
|
||
|
i := 1;
|
||
|
Section := PStrippedSectionHeader(Dword(Buffer) + SizeOf(TStrippedPEHeader) + NumberOfRvaAndSizes * SizeOf(TDataDirectory));
|
||
|
Repeat
|
||
|
Write('Section #'); WriteHex(i); WriteLn('');
|
||
|
WriteLn('-----------');
|
||
|
With Section^ Do Begin
|
||
|
Write(' Name = ');
|
||
|
(* Handle situation when Name length = 8 Then Name is NOT ASCIIZ *)
|
||
|
If Name[High(Name)] <> #0 Then WriteN(Name, 8) Else Write(Name);
|
||
|
WriteLn('');
|
||
|
Write(' VirtualSize = '); WriteHex(VirtualSize); WriteLn('');
|
||
|
Write(' VirtualAddress = '); WriteHex(VirtualAddress); WriteLn('');
|
||
|
Write(' SizeOfRawData = '); WriteHex(SizeOfRawData); WriteLn('');
|
||
|
Write(' PointerToRawData = '); WriteHex(PointerToRawData); WriteLn('');
|
||
|
Write(' Flags = '); WriteHex(Characteristics); WriteLn('');
|
||
|
End;
|
||
|
WriteLn('');
|
||
|
inc(Section);
|
||
|
inc(i);
|
||
|
Until i > NumberOfSections;
|
||
|
|
||
|
DataDirectory := PDataDirectoryArray(Dword(Buffer) + SizeOf(TStrippedPEHeader));
|
||
|
|
||
|
If NumberOfRvaAndSizes > SPE_DIRECTORY_IMPORT Then Begin
|
||
|
If DataDirectory[SPE_DIRECTORY_IMPORT].VirtualAddress <> 0 Then Begin
|
||
|
WriteLn('Imports');
|
||
|
WriteLn('-------');
|
||
|
ImportDescriptor := PImportDescriptor(RVA2Offset(DataDirectory[SPE_DIRECTORY_IMPORT].VirtualAddress, Buffer) + Dword(Buffer));
|
||
|
While ImportDescriptor.Name <> 0 Do Begin
|
||
|
With ImportDescriptor^ Do Begin
|
||
|
Write(' OriginalFirstThunk = '); WriteHex(OriginalFirstThunk); WriteLn('');
|
||
|
Write(' TimeDateStamp = '); WriteHex(TimeDateStamp); WriteLn('');
|
||
|
Write(' ForwarderChain = '); WriteHex(ForwarderChain); WriteLn('');
|
||
|
Write(' Name = '); WriteLn(PChar(RVA2Offset(Name, Buffer) + Dword(Buffer)));
|
||
|
Write(' FirstThunk = '); WriteHex(FirstThunk); WriteLn('');
|
||
|
End;
|
||
|
Thunk := PDword(RVA2Offset(ImportDescriptor.FirstThunk, Buffer) + Dword(Buffer));
|
||
|
While Thunk^ <> 0 Do Begin
|
||
|
Write(' '); WriteLn(PChar(RVA2Offset(Thunk^, Buffer) + Dword(Buffer) + SizeOf(Word)));
|
||
|
Inc(Thunk);
|
||
|
End;
|
||
|
WriteLn('');
|
||
|
Inc(ImportDescriptor);
|
||
|
End;
|
||
|
End;
|
||
|
End;
|
||
|
|
||
|
If NumberOfRvaAndSizes > SPE_DIRECTORY_EXPORT Then Begin
|
||
|
If DataDirectory[SPE_DIRECTORY_EXPORT].VirtualAddress <> 0 Then Begin
|
||
|
WriteLn('Exports');
|
||
|
WriteLn('-------');
|
||
|
ExportDescriptor := PExportDescriptor(RVA2Offset(DataDirectory[SPE_DIRECTORY_EXPORT].VirtualAddress, Buffer) + Dword(Buffer));
|
||
|
With ExportDescriptor^ Do Begin
|
||
|
Write(' Characteristics = '); WriteHex(Characteristics); WriteLn('');
|
||
|
Write(' TimeDateStamp = '); WriteHex(TimeDateStamp); WriteLn('');
|
||
|
Write(' MajorVersion = '); WriteHex(MajorVersion); WriteLn('');
|
||
|
Write(' MinorVersion = '); WriteHex(MinorVersion); WriteLn('');
|
||
|
Write(' Name = '); WriteLn(PChar(RVA2Offset(Name, Buffer) + Dword(Buffer)));
|
||
|
Write(' Base = '); WriteHex(Base); WriteLn('');
|
||
|
Write(' NumberOfFunctions = '); WriteHex(NumberOfFunctions); WriteLn('');
|
||
|
Write(' NumberOfNames = '); WriteHex(NumberOfNames); WriteLn('');
|
||
|
Write(' AddressOfFunctions = '); WriteHex(AddressOfFunctions); WriteLn('');
|
||
|
Write(' AddressOfNames = '); WriteHex(AddressOfNames); WriteLn('');
|
||
|
Write(' AddressOfNameOrdinals = '); WriteHex(AddressOfNameOrdinals); WriteLn('');
|
||
|
For i := 0 To NumberOfNames - 1 Do Begin
|
||
|
Write(' '); WriteLn(PChar(RVA2Offset(PDwordArray(RVA2Offset(AddressOfNames, Buffer) + Dword(Buffer))^[i], Buffer)) + Dword(Buffer));
|
||
|
End;
|
||
|
End;
|
||
|
End;
|
||
|
End;
|
||
|
|
||
|
End;
|
||
|
End;
|
||
|
End Else Begin
|
||
|
WriteLn('File corrupted or invalid.')
|
||
|
End;
|
||
|
End Else Begin
|
||
|
WriteLn('ReadFile Error.');
|
||
|
End;
|
||
|
End;
|
||
|
GetCh;
|
||
|
ConsoleExit(TRUE);
|
||
|
ThreadTerminate;
|
||
|
End;
|
||
|
(* -------------------------------------------------------- *)
|
||
|
End.
|