diff --git a/programs/develop/SPEDump/LScript.x b/programs/develop/SPEDump/LScript.x new file mode 100644 index 0000000000..d75bd7e54a --- /dev/null +++ b/programs/develop/SPEDump/LScript.x @@ -0,0 +1,25 @@ +PATH_SIZE = 1024; +PARAMS_SIZE = 256; +STACK_SIZE = 1024; + +"@@HandleFinally" = 0; + +SECTIONS +{ + .all : AT(0){ + LONG(0x554e454D); + LONG(0x31305445); + LONG(1); + LONG("@Main"); + LONG(END); + LONG($END + PATH_SIZE + PARAMS_SIZE + STACK_SIZE); + LONG($END + PATH_SIZE + PARAMS_SIZE + STACK_SIZE); + LONG($END + PATH_SIZE); + LONG($END); + *(.text) + *(.data) + } +END = .; + .bss ALIGN(16) : {*(.bss)} +$END = .; +} \ No newline at end of file diff --git a/programs/develop/SPEDump/SPEDump.kex b/programs/develop/SPEDump/SPEDump.kex new file mode 100644 index 0000000000..4393403e22 Binary files /dev/null and b/programs/develop/SPEDump/SPEDump.kex differ diff --git a/programs/develop/SPEDump/SPEDump.pas b/programs/develop/SPEDump/SPEDump.pas new file mode 100644 index 0000000000..1d034d4f5a --- /dev/null +++ b/programs/develop/SPEDump/SPEDump.pas @@ -0,0 +1,297 @@ +(************************************************************ + + 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 []') + 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. \ No newline at end of file diff --git a/programs/develop/SPEDump/make.bat b/programs/develop/SPEDump/make.bat new file mode 100644 index 0000000000..427416a778 --- /dev/null +++ b/programs/develop/SPEDump/make.bat @@ -0,0 +1,18 @@ +Set NAME=SPEDump + +: KOLIBRIOS_PAS - path to KolibriOS.pas +Set KOLIBRIOS_PAS= + +: KOLIBRIOS_LIB - path to KolibriOS.lib +Set KOLIBRIOS_LIB= + +dcc32 -J -U%KOLIBRIOS_PAS% %NAME%.pas +omf2d %NAME%.obj +link -edit %NAME%.obj +LD -T LScript.x %NAME%.obj -o %NAME%.kex -L %KOLIBRIOS_LIB% -l KolibriOS +objcopy -O binary -j .all %NAME%.kex + +Del %NAME%.obj +Del %NAME%.dcu + +Pause \ No newline at end of file