kolibrios/programs/develop/SPEDump/SPEDump.pas

297 lines
12 KiB
Plaintext

(************************************************************
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.