From 36c2d5ee13e25c585c2eb5f604242eceb48a0036 Mon Sep 17 00:00:00 2001 From: Freeman Date: Sat, 16 Jan 2021 13:27:53 +0300 Subject: [PATCH] Stripped PE Dumper tool added --- Lib/KolibriOS.pas | 1 + Lib/StrippedPE.inc | 81 ++++++++++++++ Tools/.dof | 7 ++ Tools/SPEDump/SPEDump.dpr | 216 ++++++++++++++++++++++++++++++++++++++ Tools/SPEDump/build.bat | 1 + build-all.bat | 10 +- build-tools.bat | 8 ++ init-for-IDE.bat | 3 + 8 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 Lib/StrippedPE.inc create mode 100644 Tools/.dof create mode 100644 Tools/SPEDump/SPEDump.dpr create mode 100644 Tools/SPEDump/build.bat create mode 100644 build-tools.bat diff --git a/Lib/KolibriOS.pas b/Lib/KolibriOS.pas index 11d68bb..b410a02 100644 --- a/Lib/KolibriOS.pas +++ b/Lib/KolibriOS.pas @@ -10,6 +10,7 @@ unit KolibriOS; interface {$I ImageFormats.inc} +{$I StrippedPE.inc} type TSize = packed record diff --git a/Lib/StrippedPE.inc b/Lib/StrippedPE.inc new file mode 100644 index 0000000..04694ed --- /dev/null +++ b/Lib/StrippedPE.inc @@ -0,0 +1,81 @@ +(* + Stripped PE file format definition + + Copyright (c) 2018 0CodErr + Copyright (c) 2021 Delphi SDK for KolibriOS team +*) + +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 + PLongWordArray = ^TLongWordArray; + TLongWordArray = array[0..0] of LongWord; + + PStrippedImageFileHeader = ^TStrippedImageFileHeader; + TStrippedImageFileHeader = packed record + Signature: Word; + Characteristics: Word; + AddressOfEntryPoint: LongWord; + ImageBase: LongWord; + SectionAlignmentLog2: Byte; + FileAlignmentLog2: Byte; + MajorOSVersion: Byte; + MinorOSVersion: Byte; + SizeOfImage: LongWord; + SizeOfStackReserve: LongWord; + SizeOfHeapReserve: LongWord; + SizeOfHeaders: LongWord; + Subsystem: Byte; + NumberOfRvaAndSizes: Byte; + NumberOfSections: Word; + end; + + PStrippedImageSectionHeader = ^TStrippedImageSectionHeader; + TStrippedImageSectionHeader = packed record + Name: array[0..7] of KolibriChar; + VirtualSize: LongWord; + VirtualAddress: LongWord; + SizeOfRawData: LongWord; + PointerToRawData: LongWord; + Characteristics: LongWord; + end; + + PImageDataDirectory = ^TImageDataDirectory; + TImageDataDirectory = packed record + VirtualAddress: LongWord; + Size: LongWord; + end; + + PDataDirectoryArray = ^TDataDirectoryArray; + TDataDirectoryArray = array[0..SPE_MAX_DIRECTORY_ENTRIES] of TImageDataDirectory; + + PImportDescriptor = ^TImportDescriptor; + TImportDescriptor = packed record + OriginalFirstThunk: LongWord; + TimeDateStamp: LongWord; + ForwarderChain: LongWord; + Name: LongWord; + FirstThunk: LongWord; + end; + + PExportDescriptor = ^TExportDescriptor; + TExportDescriptor = packed record + Characteristics: LongWord; + TimeDateStamp: LongWord; + MajorVersion: Word; + MinorVersion: Word; + Name: LongWord; + Base: LongWord; + NumberOfFunctions: LongWord; + NumberOfNames: LongWord; + AddressOfFunctions: LongWord; + AddressOfNames: LongWord; + AddressOfNameOrdinals: LongWord; + end; diff --git a/Tools/.dof b/Tools/.dof new file mode 100644 index 0000000..fc9d4ec --- /dev/null +++ b/Tools/.dof @@ -0,0 +1,7 @@ +[Directories] +OutputDir=..\..\Bin\KoW +UnitOutputDir=..\..\Bin\KoW\DCU +SearchPath=..\..\Lib;..\..\Bin\KoW\DCU +Conditionals=Debug +UnitAliases= +UsePackages=0 \ No newline at end of file diff --git a/Tools/SPEDump/SPEDump.dpr b/Tools/SPEDump/SPEDump.dpr new file mode 100644 index 0000000..8bfd11c --- /dev/null +++ b/Tools/SPEDump/SPEDump.dpr @@ -0,0 +1,216 @@ +(* + Stripped PE File Dumper + + Copyright (c) 2018 0CodErr + Copyright (c) 2021 Delphi SDK for KolibriOS team +*) + +program SPEDump; + +{$IFNDEF KolibriOS} + {$APPTYPE Console} +{$ENDIF} + +uses + KolibriOS, CRT; + +var + FileName: PKolibriChar; + I, BytesRead: LongWord; + Buffer: PStrippedImageFileHeader; + Section: PStrippedImageSectionHeader; + DataDir: PDataDirectoryArray; + Imp: PImportDescriptor; + Exp: PExportDescriptor; + Thunk: PLongWord; + +procedure WriteLn(Str: PKolibriChar = nil); +begin + con_write_asciiz(Str); + con_write_asciiz(#10); +end; + +function FileIsValid: Boolean; +begin + Result := False; + with Buffer^ do + begin + if BytesRead < SizeOf(TStrippedImageFileHeader) then + Exit; + if Signature <> STRIPPED_PE_SIGNATURE then + Exit; + end; + Result := True; +end; + +function RVA2Offset(RVA: LongWord; Header: PStrippedImageFileHeader): LongWord; +var + I: LongWord; + SectionHeader: PStrippedImageSectionHeader; +begin + with Header^ do + begin + SectionHeader := PStrippedImageSectionHeader(PKolibriChar(Header) + SizeOf(TStrippedImageFileHeader) + NumberOfRvaAndSizes * SizeOf(TImageDataDirectory)); + for I := 0 to NumberOfSections do + begin + with SectionHeader^ do + begin + if (RVA >= VirtualAddress) And (RVA < VirtualAddress + SizeOfRawData) then + begin + Result := PointerToRawData + RVA - VirtualAddress; + Exit; + end; + end; + Inc(SectionHeader); + end; + end; + Result := 0; +end; + +function StrNLen(Src: PKolibriChar; MaxLen: LongWord): LongWord; +begin + Result := 0; + while (Src^ <> #0) and (Result <> MaxLen) do + begin + Inc(Src); + Inc(Result); + end; +end; + +begin +{$IF defined(KolibriOS) or defined(Debug)} + InitConsole('Stripped PE File Dumper', False, LongWord(-1), 30); +{$IFEND} + +{$IFDEF KolibriOS} + FileName := nil; +{$ELSE} + FileName := 'EHCI.SYS'; +{$ENDIF} + + WriteLn('Stripped PE File Dumper version 0.2.1'); + WriteLn('Copyright (c) 2018 0CodErr'); + WriteLn('Copyright (c) 2021 Delphi SDK for KolibriOS team'); + + if (FileName = nil) or (FileName^ = #0) then + begin + WriteLn('Usage: SPEDump []'); + Exit; + end; + + WriteLn; + con_printf('Dump of "%s"'#10#10, FileName); + + Buffer := LoadFile(FileName, BytesRead); + if Buffer = nil then + begin + WriteLn('ReadFile Error'); + Exit; + end; + + if not FileIsValid then + begin + WriteLn('File corrupted or invalid'); + Exit; + end; + + WriteLn('File Header'); + WriteLn('-----------'); + + with Buffer^ do + begin + con_printf(' Signature = %04Xh'#10, Signature); + con_printf(' Characteristics = %04Xh'#10, Characteristics); + con_printf(' AddressOfEntryPoint = %08Xh'#10, AddressOfEntryPoint); + con_printf(' ImageBase = %08Xh'#10, ImageBase); + con_printf(' SectionAlignmentLog2 = %u (%08Xh)'#10, SectionAlignmentLog2, 1 shl SectionAlignmentLog2); + con_printf(' FileAlignmentLog2 = %u (%08Xh)'#10, FileAlignmentLog2, 1 shl FileAlignmentLog2); + con_printf(' MajorOSVersion = %u'#10, MajorOSVersion); + con_printf(' MinorOSVersion = %u'#10, MinorOSVersion); + con_printf(' SizeOfImage = %08Xh'#10, SizeOfImage); + con_printf(' SizeOfStackReserve = %08Xh'#10, SizeOfStackReserve); + con_printf(' SizeOfHeapReserve = %08Xh'#10, SizeOfHeapReserve); + con_printf(' SizeOfHeaders = %08Xh'#10, SizeOfHeaders); + con_printf(' Subsystem = %02Xh'#10, Subsystem); + con_printf(' NumberOfRvaAndSizes = %u'#10, NumberOfRvaAndSizes); + con_printf(' NumberOfSections = %u'#10, NumberOfSections); + + WriteLn; + + if NumberOfSections > 0 then + begin + I := 1; + Section := PStrippedImageSectionHeader(PKolibriChar(Buffer) + SizeOf(TStrippedImageFileHeader) + + NumberOfRvaAndSizes * SizeOf(TImageDataDirectory)); + repeat + con_printf('Section #%u'#10, I); + WriteLn('-----------'); + with Section^ do + begin + con_write_asciiz( + ' Name = '); con_write_string(Name, StrNLen(Name, 8)); + WriteLn; + con_printf(' VirtualSize = %08Xh'#10, VirtualSize); + con_printf(' VirtualAddress = %08Xh'#10, VirtualAddress); + con_printf(' SizeOfRawData = %08Xh'#10, SizeOfRawData); + con_printf(' PointerToRawData = %08Xh'#10, PointerToRawData); + con_printf(' Flags = %08Xh'#10#10, Characteristics); + end; + Inc(Section); + Inc(I); + until I > NumberOfSections; + + DataDir := PDataDirectoryArray(PKolibriChar(Buffer) + SizeOf(TStrippedImageFileHeader)); + + if (NumberOfRvaAndSizes > SPE_DIRECTORY_IMPORT) and (DataDir[SPE_DIRECTORY_IMPORT].VirtualAddress <> 0) then + begin + WriteLn('Imports'); + WriteLn('-------'); + Imp := PImportDescriptor(PKolibriChar(Buffer) + RVA2Offset(DataDir[SPE_DIRECTORY_IMPORT].VirtualAddress, Buffer)); + while Imp.Name <> 0 do + begin + with Imp^ do + begin + con_printf(' OriginalFirstThunk = %08Xh'#10, OriginalFirstThunk); + con_printf(' TimeDateStamp = %08Xh'#10, TimeDateStamp); + con_printf(' ForwarderChain = %08Xh'#10, ForwarderChain); + con_printf(' Name = %s'#10, PKolibriChar(Buffer) + RVA2Offset(Name, Buffer)); + con_printf(' FirstThunk = %08Xh'#10, FirstThunk); + end; + Thunk := PLongWord(PKolibriChar(Buffer) + RVA2Offset(Imp.FirstThunk, Buffer)); + while Thunk^ <> 0 do + begin + con_printf(' %s'#10, PKolibriChar(Buffer) + RVA2Offset(Thunk^, Buffer) + SizeOf(Word)); + Inc(Thunk); + end; + WriteLn; + Inc(Imp); + end; + end; + + if (NumberOfRvaAndSizes > SPE_DIRECTORY_EXPORT) and (DataDir[SPE_DIRECTORY_EXPORT].VirtualAddress <> 0) then + begin + WriteLn('Exports'); + WriteLn('-------'); + Exp := PExportDescriptor(RVA2Offset(DataDir[SPE_DIRECTORY_EXPORT].VirtualAddress, Buffer) + LongWord(Buffer)); + with Exp^ do + begin + con_printf(' Characteristics = %08Xh'#10, Characteristics); + con_printf(' TimeDateStamp = %08Xh'#10, TimeDateStamp); + con_printf(' MajorVersion = %u'#10, MajorVersion); + con_printf(' MinorVersion = %u'#10, MinorVersion); + con_printf(' Name = %s'#10, PKolibriChar(Buffer) + RVA2Offset(Name, Buffer)); + con_printf(' Base = %08Xh'#10, Base); + con_printf(' NumberOfFunctions = %u'#10, NumberOfFunctions); + con_printf(' NumberOfNames = %u'#10, NumberOfNames); + con_printf(' AddressOfFunctions = %08Xh'#10, AddressOfFunctions); + con_printf(' AddressOfNames = %08Xh'#10, AddressOfNames); + con_printf(' AddressOfNameOrdinals = %08Xh'#10, AddressOfNameOrdinals); + for I := 0 to NumberOfNames - 1 do + con_printf(' %s'#10, PKolibriChar(Buffer) + + RVA2Offset(PLongWordArray(PKolibriChar(Buffer) + RVA2Offset(AddressOfNames, Buffer))[I], Buffer)); + end; + end; + end; + end; +end. diff --git a/Tools/SPEDump/build.bat b/Tools/SPEDump/build.bat new file mode 100644 index 0000000..ed000f1 --- /dev/null +++ b/Tools/SPEDump/build.bat @@ -0,0 +1 @@ +@call "%~dp0..\build.bat" "%~dp0SPEDump" \ No newline at end of file diff --git a/build-all.bat b/build-all.bat index d9c171b..dce70fd 100644 --- a/build-all.bat +++ b/build-all.bat @@ -1,3 +1,11 @@ @echo off + call "%~dp0build-examples.bat" -call "%~dp0build-my.bat" \ No newline at end of file +if errorlevel 1 goto exit + +call "%~dp0build-my.bat" +if errorlevel 1 goto exit + +call "%~dp0build-tools.bat" + +:exit \ No newline at end of file diff --git a/build-tools.bat b/build-tools.bat new file mode 100644 index 0000000..8cb9260 --- /dev/null +++ b/build-tools.bat @@ -0,0 +1,8 @@ +@echo off + +for /d %%f in ("%~dp0Tools\*") do ( + if exist "%%f\build.bat" call "%%f\build.bat" + if errorlevel 1 goto exit +) + +:exit \ No newline at end of file diff --git a/init-for-IDE.bat b/init-for-IDE.bat index 0df0e51..e7d2f61 100644 --- a/init-for-IDE.bat +++ b/init-for-IDE.bat @@ -18,6 +18,9 @@ if #%1#==## ( if errorlevel 1 goto exit call %0 My My + if errorlevel 1 goto exit + + call %0 Tools Tools goto exit )