flat assembler
Message board for the users of flat assembler.

Index > Windows > PEbasic - Get two basic Windows app info

Author
Thread Post new topic Reply to topic
Mat-Quasar



Joined: 02 Mar 2025
Posts: 26
Mat-Quasar 08 Mar 2025, 09:31
I built the console version first, later might do GUI window version, with Open File dialog and menu.

This PEbasic is just retrieving two basic PE header info from any PE file.

To run, just drop any PE file on top of pebasic.exe and you'll get simple description such as:
1. "32-bit Console App"
2. "32-bit GUI App"
3. "64-bit Console App"
4. "64-bit GUI App"

For any other type of subsystem, it will just merely states:
1. "32-bit PE file"
2. "64-bit PE file"

Enjoy!

UPDATE v0.02: New version has minor bug fix, now support long filename enclosed in quotes. Previously you can't open file with path like:
Code:
 "C:\Program Files\dosbox.exe"    

...now this is fixed.

Known Bug: (March 18, 2025) If you place your program in path enclosed in quotes with space in between, e.g. "C:\Documents and Settings\USER\My Documents\pebasic.EXE", then drag-and-drop input filename will not work correctly.

When I tested it, I assume the pebasic.EXE is always located in path without space in between, e.g. "C:\Users\USER\Projects\pebasic.EXE". My code only work with this type of path (argument 0).
In v0.02, I only fix argument 1 in enclosed quotes with space between, never expect agument 0, the program name itself can be also enclosed in quotes with space in between.
Currently there is no fix.


Description: Recommended usage: Place pebasic.exe on Desktop, then drag file from File Explorer and drop it on pebasic.exe icon
Filesize: 122.92 KB
Viewed: 442 Time(s)

usage.png


Description: Just drop any PE file on top of pebasic.exe will do
Filesize: 4.93 KB
Viewed: 631 Time(s)

pebasic.PNG


Description: v0.02 - Support long filename enclosed in quotes
Download
Filename: pebasic.ASM
Filesize: 6.13 KB
Downloaded: 24 Time(s)



Last edited by Mat-Quasar on 18 Mar 2025, 08:08; edited 4 times in total
Post 08 Mar 2025, 09:31
View user's profile Send private message Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1066
Location: Russia
macomics 08 Mar 2025, 12:46
Code:
format PE CONSOLE 4.0
include "WIN32A.INC"


section '.idata' import data readable writeable
library kernel32, "KERNEL32.DLL"
include "API/KERNEL32.INC"


PE_MAGIC_TYPE_I386   = 0x10B
PE_MAGIC_TYPE_X86_64 = 0x20B

IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
IMAGE_SUBSYSTEM_WINDOWS_CUI = 3

struc ASSUME base*, type& { if ~ type eq
    virtual at base
      . type
      if ~ definite .Length
        label .Length at ( $ - $$ )
      end if
    end virtual
  else
    label . at base
    label .Length at 0
  end if }

struc MZ_FILE_HEADER { label .
   .e_magic             dw ?
   .e_cblp              dw ?
   .e_cp                dw ?
   .e_crlc              dw ?
   .e_cparhdr           dw ?
   .e_minalloc          dw ?
   .e_maxalloc          dw ?
   .e_ss                dw ?
   .e_sp                dw ?
   .e_csum              dw ?
   .e_ip                dw ?
   .e_cs                dw ?
   .e_lfarlc            dw ?
   .e_ovno              dw ?
   .e_res               dw 4 dup ?
   .e_oemid             dw ?
   .e_oeminfo           dw ?
   .e_reserved          dw 10 dup ?
   .e_lfanew            dd ?
  label .Length at ( $ - . ) }

struc PE_FILE_HEADER { label .
   .Signature           dd ?
   .Machine             dw ?
   .SectionsCount       dw ?
   .TimeDateStamp       dd ?
   .pSymbolTable        dd ?
   .SymbolsCount        dd ?
   .OptHeaderSize       dw ?
   .Chracteristics      dw ?
   .OptionalHeader:
  label .Length at ( $ - . ) }

struc PE_OPTIONAL_HEADER { label .
   .Magic               dw ?
   .majLinkerVer        db ?
   .minLinkerVer        db ?
   .CodeSize            dd ?
   .IdatSize            dd ?
   .UdatSize            dd ?
   .EntryPoint          dd ?
   .BaseOfCode          dd ?
   .BaseOfData          dd ?
   .ImageBase           dd ?
   .AlignSections       dd ?
   .AlignFile           dd ?
   .majOSVer            dw ?
   .minOSVer            dw ?
   .majPE32Ver          dw ?
   .minPE32Ver          dw ?
   .majSubsysVer        dw ?
   .minSubsysVer        dw ?
   .Win32VerValue       dd ?
   .PE32Size            dd ?
   .HeaderSize          dd ?
   .Checksum            dd ?
   .SubSystem           dw ?
   .DLLCharacters       dw ?
   .StackReserved       dd ?
   .StackCommit         dd ?
   .HeapReserved        dd ?
   .HeapCommit          dd ?
   .LoaderFlags         dd ?
   .DataDirSize         dd ?
  label .Length at ( $ - . ) }

section '.text' code readable executable
entry $
        push    ebp
        mov     ebp, esp
        invoke  GetCommandLineA
        mov     esi, eax
        mov     dl,  ' '
        mov     edi, esi
        mov     ebx, eax
        jmp     start_loop

  @@:
        cmp     al,  '"'
        jz      @f
        cmp     al,  dl
        jz      found_arg

  start_loop:
        lods    byte [esi]
        test    al,  al
        jnz     @b
        jmp     end_loop

  @@:
        xor     dl,  '"' xor ' '
        jmp     start_loop

  found_arg:
        mov     edi, esi
        and     dl,  0
        jmp     start_loop

  end_loop:
        invoke  GetStdHandle, STD_OUTPUT_HANDLE
        mov     esi, eax
        cmp     ebx, edi
        jz      show_usage
        invoke  CreateFileA, edi, GENERIC_READ, FILE_SHARE_READ or \
                                  FILE_SHARE_WRITE or FILE_SHARE_DELETE,\
                                  NULL, OPEN_EXISTING, NULL, NULL
        cmp     eax, INVALID_HANDLE_VALUE
        jz      show_open_file_error
        mov     ebx, eax
  mzFileHeader ASSUME ebp - mzFileHeader.Length, MZ_FILE_HEADER
        sub     esp, mzFileHeader.Length
        mov     eax, esp
        xor     edx, edx
        mov     ecx, mzFileHeader.Length
        call    block_read
        cmp     eax, mzFileHeader.Length
        jnz     show_read_file_error
        cmp     [mzFileHeader.e_magic], 'MZ'
        jnz     show_file_has_no_mz_header
        mov     edi, [mzFileHeader.e_lfanew]
  peFileHeader ASSUME ebp - peFileHeader.Length, PE_FILE_HEADER
        add     esp, mzFileHeader.Length - peFileHeader.Length
        mov     eax, esp
        mov     edx, edi
        mov     ecx, peFileHeader.Length
        call    block_read
        cmp     eax, peFileHeader.Length
        jnz     show_read_file_error
        cmp     [peFileHeader.Signature], 'PE'
        jnz     show_file_has_no_pe_header
        lea     edx, [peFileHeader.OptionalHeader - peFileHeader + edi]
        movzx   eax, [peFileHeader.OptHeaderSize]
        add     eax, 3  ; staack alignment
        and     al, 0xFC
  peOptionalHeader ASSUME esp, PE_OPTIONAL_HEADER
        add     esp, peFileHeader.Length
        sub     esp, eax
        mov     eax, esp
        mov     ecx, peOptionalHeader.Length
        call    block_read
        cmp     eax, peOptionalHeader.Length
        jnz     show_read_file_error
        movzx   eax, [peOptionalHeader.Magic]
        movzx   edi, [peOptionalHeader.SubSystem]
        add     esp, peOptionalHeader.Length
        cmp     eax, PE_MAGIC_TYPE_I386
        jz      show_i386
        cmp     eax, PE_MAGIC_TYPE_X86_64
        jnz     show_unknown
        lea     eax, [sz_Arch_x86_64]
        mov     ecx, sz_Arch_x86_64.Length
        call    write_file
        jmp     show_subsystem

  show_unknown:
        lea     eax, [szUnknown_Arch]
        mov     ecx, szUnknown_Arch.Length
        call    write_file
        jmp     show_subsystem

  show_i386:
        lea     eax, [sz_Arch_i386]
        mov     ecx, sz_Arch_i386.Length
        call    write_file
        jmp     close_file

  show_subsystem:
        cmp     edi, IMAGE_SUBSYSTEM_WINDOWS_CUI
        jz      show_gui_sybsystem
        cmp     edi, IMAGE_SUBSYSTEM_WINDOWS_GUI
        jnz     show_unknown_sybsystem
        lea     eax, [szGUI_Subsystem]
        mov     ecx, szGUI_Subsystem.Length
        call    write_file
        jmp     close_file

  show_gui_sybsystem:
        lea     eax, [szCUI_Subsystem]
        mov     ecx, szCUI_Subsystem.Length
        call    write_file
        jmp     close_file

  show_unknown_sybsystem:
        lea     eax, [szUnknown_Subsystem]
        mov     ecx, szUnknown_Subsystem.Length
        call    write_file
        jmp     close_file

  show_open_file_error:
        lea     eax, [szOpenFileError]
        mov     ecx, szOpenFileError.Length
        call    write_file
        jmp     close_file

  show_read_file_error:
        lea     eax, [szReadFileError]
        mov     ecx, szReadFileError.Length
        call    write_file
        jmp     close_file

  show_file_has_no_mz_header:
        lea     eax, [szNoMZHeader]
        mov     ecx, szNoMZHeader.Length
        call    write_file
        jmp     close_file

  show_file_has_no_pe_header:
        lea     eax, [szNoPEHeader]
        mov     ecx, szNoPEHeader.Length
        call    write_file
        jmp     close_file

  show_usage:
        lea     eax, [szUsage]
        mov     ecx, szUsage.Length
        call    write_file
        jmp     @f

  close_file:
        invoke  CloseHandle, ebx

  @@:
        leave
        invoke  ExitProcess, NULL

  write_file:
        push    0
        mov     edx, esp
        invoke  WriteConsoleA, esi, eax, ecx, edx, NULL
        pop     eax
        retn

  block_read:
        invoke  SetFilePointer, ebx, edx, 0, FILE_BEGIN, eax, ecx
        pop     edx
        pop     ecx
        push    0
        mov     eax, esp
        invoke  ReadFile, ebx, edx, ecx, eax, 0
        pop     eax
        retn


  struc STRING [text] { common label .
    forward db text
    common label .Length at ( $ - . )
    db NULL
    label .Bytes at ( $ - . ) }

  sz_Arch_i386        STRING "Windows (i386)", 13, 10
  sz_Arch_x86_64      STRING "Windows (x86_64)", 13, 10
  szUnknown_Arch      STRING "Unknown!", 13, 10
  szGUI_Subsystem     STRING " GUI application", 13, 10
  szCUI_Subsystem     STRING " CUI application", 13, 10
  szUnknown_Subsystem STRING " Unknow application", 13, 10
  szOpenFileError     STRING "Open file error!", 13, 10
  szReadFileError     STRING "Read file error!", 13, 10
  szNoMZHeader        STRING "File has no MZ header!", 13, 10
  szNoPEHeader        STRING "File has no PE header!", 13, 10
  szUsage             STRING "pebasic <exe_file_name>", 13, 10    

1) The headers of the PE files are not so big to read their individual fields. It will become much easier to work with them if you read the entire structure.
2) To read blocks from different file positions, it is better to make a subfunction to call a pair of API functions than to constantly write separate calls in the code.
Post 08 Mar 2025, 12:46
View user's profile Send private message Reply with quote
Mat-Quasar



Joined: 02 Mar 2025
Posts: 26
Mat-Quasar 08 Mar 2025, 13:39
Thanks for showing your way of doing it! It is quite eye-opening.

But at the moment, there is bug in your get command-line routine I think? Because I get "Open file error" in CMD.

My code also has bug in get command-line routine, cannot process path with quotes, e.g.:
1) pebasic "C:\Program Files\dosbox.exe" -- not working
2) pebasic C:\Program Files\dosbox.exe -- only this working

I keep the below for reference.

macomics wrote:
Code:
format PE CONSOLE 4.0
include "WIN32A.INC"


section '.idata' import data readable writeable
library kernel32, "KERNEL32.DLL"
include "API/KERNEL32.INC"


PE_MAGIC_TYPE_I386   = 0x10B
PE_MAGIC_TYPE_X86_64 = 0x20B

IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
IMAGE_SUBSYSTEM_WINDOWS_CUI = 3

struc ASSUME base*, type& { if ~ type eq
    virtual at base
      . type
      if ~ definite .Length
        label .Length at ( $ - $$ )
      end if
    end virtual
  else
    label . at base
    label .Length at 0
  end if }

struc MZ_FILE_HEADER { label .
   .e_magic             dw ?
   .e_cblp              dw ?
   .e_cp                dw ?
   .e_crlc              dw ?
   .e_cparhdr           dw ?
   .e_minalloc          dw ?
   .e_maxalloc          dw ?
   .e_ss                dw ?
   .e_sp                dw ?
   .e_csum              dw ?
   .e_ip                dw ?
   .e_cs                dw ?
   .e_lfarlc            dw ?
   .e_ovno              dw ?
   .e_res               dw 4 dup ?
   .e_oemid             dw ?
   .e_oeminfo           dw ?
   .e_reserved          dw 10 dup ?
   .e_lfanew            dd ?
  label .Length at ( $ - . ) }

struc PE_FILE_HEADER { label .
   .Signature           dd ?
   .Machine             dw ?
   .SectionsCount       dw ?
   .TimeDateStamp       dd ?
   .pSymbolTable        dd ?
   .SymbolsCount        dd ?
   .OptHeaderSize       dw ?
   .Chracteristics      dw ?
   .OptionalHeader:
  label .Length at ( $ - . ) }

struc PE_OPTIONAL_HEADER { label .
   .Magic               dw ?
   .majLinkerVer        db ?
   .minLinkerVer        db ?
   .CodeSize            dd ?
   .IdatSize            dd ?
   .UdatSize            dd ?
   .EntryPoint          dd ?
   .BaseOfCode          dd ?
   .BaseOfData          dd ?
   .ImageBase           dd ?
   .AlignSections       dd ?
   .AlignFile           dd ?
   .majOSVer            dw ?
   .minOSVer            dw ?
   .majPE32Ver          dw ?
   .minPE32Ver          dw ?
   .majSubsysVer        dw ?
   .minSubsysVer        dw ?
   .Win32VerValue       dd ?
   .PE32Size            dd ?
   .HeaderSize          dd ?
   .Checksum            dd ?
   .SubSystem           dw ?
   .DLLCharacters       dw ?
   .StackReserved       dd ?
   .StackCommit         dd ?
   .HeapReserved        dd ?
   .HeapCommit          dd ?
   .LoaderFlags         dd ?
   .DataDirSize         dd ?
  label .Length at ( $ - . ) }

section '.text' code readable executable
entry $
        push    ebp
        mov     ebp, esp
        invoke  GetCommandLineA
        mov     esi, eax
        mov     dl,  ' '
        mov     edi, esi
        mov     ebx, eax
        jmp     start_loop

  @@:
        cmp     al,  '"'
        jz      @f
        cmp     al,  dl
        jz      found_arg

  start_loop:
        lods    byte [esi]
        test    al,  al
        jnz     @b
        jmp     end_loop

  @@:
        xor     dl,  '"' xor ' '
        jmp     start_loop

  found_arg:
        mov     edi, esi
        and     dl,  0
        jmp     start_loop

  end_loop:
        invoke  GetStdHandle, STD_OUTPUT_HANDLE
        mov     esi, eax
        cmp     ebx, edi
        jz      show_usage
        invoke  CreateFileA, edi, GENERIC_READ, FILE_SHARE_READ or \
                                  FILE_SHARE_WRITE or FILE_SHARE_DELETE,\
                                  NULL, OPEN_EXISTING, NULL, NULL
        cmp     eax, INVALID_HANDLE_VALUE
        jz      show_open_file_error
        mov     ebx, eax
  mzFileHeader ASSUME ebp - mzFileHeader.Length, MZ_FILE_HEADER
        sub     esp, mzFileHeader.Length
        mov     eax, esp
        xor     edx, edx
        mov     ecx, mzFileHeader.Length
        call    block_read
        cmp     eax, mzFileHeader.Length
        jnz     show_read_file_error
        cmp     [mzFileHeader.e_magic], 'MZ'
        jnz     show_file_has_no_mz_header
        mov     edi, [mzFileHeader.e_lfanew]
  peFileHeader ASSUME ebp - peFileHeader.Length, PE_FILE_HEADER
        add     esp, mzFileHeader.Length - peFileHeader.Length
        mov     eax, esp
        mov     edx, edi
        mov     ecx, peFileHeader.Length
        call    block_read
        cmp     eax, peFileHeader.Length
        jnz     show_read_file_error
        cmp     [peFileHeader.Signature], 'PE'
        jnz     show_file_has_no_pe_header
        lea     edx, [peFileHeader.OptionalHeader - peFileHeader + edi]
        movzx   eax, [peFileHeader.OptHeaderSize]
        add     eax, 3  ; staack alignment
        and     al, 0xFC
  peOptionalHeader ASSUME esp, PE_OPTIONAL_HEADER
        add     esp, peFileHeader.Length
        sub     esp, eax
        mov     eax, esp
        mov     ecx, peOptionalHeader.Length
        call    block_read
        cmp     eax, peOptionalHeader.Length
        jnz     show_read_file_error
        movzx   eax, [peOptionalHeader.Magic]
        movzx   edi, [peOptionalHeader.SubSystem]
        add     esp, peOptionalHeader.Length
        cmp     eax, PE_MAGIC_TYPE_I386
        jz      show_i386
        cmp     eax, PE_MAGIC_TYPE_X86_64
        jnz     show_unknown
        lea     eax, [sz_Arch_x86_64]
        mov     ecx, sz_Arch_x86_64.Length
        call    write_file
        jmp     show_subsystem

  show_unknown:
        lea     eax, [szUnknown_Arch]
        mov     ecx, szUnknown_Arch.Length
        call    write_file
        jmp     show_subsystem

  show_i386:
        lea     eax, [sz_Arch_i386]
        mov     ecx, sz_Arch_i386.Length
        call    write_file
        jmp     close_file

  show_subsystem:
        cmp     edi, IMAGE_SUBSYSTEM_WINDOWS_CUI
        jz      show_gui_sybsystem
        cmp     edi, IMAGE_SUBSYSTEM_WINDOWS_GUI
        jnz     show_unknown_sybsystem
        lea     eax, [szGUI_Subsystem]
        mov     ecx, szGUI_Subsystem.Length
        call    write_file
        jmp     close_file

  show_gui_sybsystem:
        lea     eax, [szCUI_Subsystem]
        mov     ecx, szCUI_Subsystem.Length
        call    write_file
        jmp     close_file

  show_unknown_sybsystem:
        lea     eax, [szUnknown_Subsystem]
        mov     ecx, szUnknown_Subsystem.Length
        call    write_file
        jmp     close_file

  show_open_file_error:
        lea     eax, [szOpenFileError]
        mov     ecx, szOpenFileError.Length
        call    write_file
        jmp     close_file

  show_read_file_error:
        lea     eax, [szReadFileError]
        mov     ecx, szReadFileError.Length
        call    write_file
        jmp     close_file

  show_file_has_no_mz_header:
        lea     eax, [szNoMZHeader]
        mov     ecx, szNoMZHeader.Length
        call    write_file
        jmp     close_file

  show_file_has_no_pe_header:
        lea     eax, [szNoPEHeader]
        mov     ecx, szNoPEHeader.Length
        call    write_file
        jmp     close_file

  show_usage:
        lea     eax, [szUsage]
        mov     ecx, szUsage.Length
        call    write_file
        jmp     @f

  close_file:
        invoke  CloseHandle, ebx

  @@:
        leave
        invoke  ExitProcess, NULL

  write_file:
        push    0
        mov     edx, esp
        invoke  WriteConsoleA, esi, eax, ecx, edx, NULL
        pop     eax
        retn

  block_read:
        invoke  SetFilePointer, ebx, edx, 0, FILE_BEGIN, eax, ecx
        pop     edx
        pop     ecx
        push    0
        mov     eax, esp
        invoke  ReadFile, ebx, edx, ecx, eax, 0
        pop     eax
        retn


  struc STRING [text] { common label .
    forward db text
    common label .Length at ( $ - . )
    db NULL
    label .Bytes at ( $ - . ) }

  sz_Arch_i386        STRING "Windows (i386)", 13, 10
  sz_Arch_x86_64      STRING "Windows (x86_64)", 13, 10
  szUnknown_Arch      STRING "Unknown!", 13, 10
  szGUI_Subsystem     STRING " GUI application", 13, 10
  szCUI_Subsystem     STRING " CUI application", 13, 10
  szUnknown_Subsystem STRING " Unknow application", 13, 10
  szOpenFileError     STRING "Open file error!", 13, 10
  szReadFileError     STRING "Read file error!", 13, 10
  szNoMZHeader        STRING "File has no MZ header!", 13, 10
  szNoPEHeader        STRING "File has no PE header!", 13, 10
  szUsage             STRING "pebasic <exe_file_name>", 13, 10    

1) The headers of the PE files are not so big to read their individual fields. It will become much easier to work with them if you read the entire structure.
2) To read blocks from different file positions, it is better to make a subfunction to call a pair of API functions than to constantly write separate calls in the code.
Post 08 Mar 2025, 13:39
View user's profile Send private message Reply with quote
Mat-Quasar



Joined: 02 Mar 2025
Posts: 26
Mat-Quasar 08 Mar 2025, 13:41
macomics, you're skillful in anything related to portable executable. Thumbs up!
Post 08 Mar 2025, 13:41
View user's profile Send private message Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1066
Location: Russia
macomics 08 Mar 2025, 14:27
Quote:
My code also has bug in get command-line routine, cannot process path with quotes, e.g.:
1) pebasic "C:\Program Files\dosbox.exe" -- not working
2) pebasic C:\Program Files\dosbox.exe -- only this working

Let's see where the problem is

As you can see from the screenshot, the problem is in the quotes. My code bypasses the quotes in the executable file name, if there are any, and finds the first argument. But CreateFileA requires you to specify file name without quotes. And so code does not split the next line into arguments. Therefore, the file name can be specified without quotes. It will not be split into substrings, and everything will be passed to CreateFileA.


Description:
Filesize: 76.26 KB
Viewed: 574 Time(s)

Снимок экрана_20250308_182058.png


Post 08 Mar 2025, 14:27
View user's profile Send private message Reply with quote
Core i7



Joined: 14 Nov 2024
Posts: 41
Location: Socket in motherboard
Core i7 08 Mar 2025, 18:54
If there are structures, the rest is not a problem.
He put the headlines for PE32/PE64 in the archive, and now you can take it to the console for example ..
To select a file, I use the GetOpenFileName() system window from Comdlg32.dll.
This is only for 32-bit , although you can also assemble a universal one
Code:
format   pe console
include 'win32ax.inc'
include 'equates\pe32.inc'
entry    start
;//-----------
section '.data' data readable writeable
struct OPENFILENAME
  SizeOf     dd  sizeof.OPENFILENAME
  Res0       rd  2
  Filter     dd  filter
  Res1       rd  3
  FileName   dd  buff
  MaxFile    dd  512
  Res2       rd  4
  ofnFlags   dd  OFN_EXPLORER
  Res3       rd  5
ends
ofn          OPENFILENAME

filter       db  '  exe, dll, sys, ocx',0
             db  '*.exe;*.dll;*.sys;*.ocx',0,0
peOffset     dd  0
Magic        dd  0
buff         rb  2048

;//----------
section '.text' code readable executable
start:   invoke  SetConsoleTitle,<'*** PE file info ***',0>

;//---- Open file dialog box ---------------------
       cinvoke  printf,<10,' Select 32-bit executable file...',0>
        invoke  GetOpenFileName, ofn
        or      eax,eax
        jnz     @f
       cinvoke  printf,<10,' ERROR! File not found.',0>
        jmp     @exit

@@:     invoke  CharToOem,buff,buff
       cinvoke  printf,<10,' File: %s',10,0>,buff
        invoke  OemToChar,buff,buff

;//---- Read in buff 1K file header ----------------
        invoke  _lopen,buff,0
        push    eax
        invoke  _lread,eax,buff,1024
        pop     eax
        invoke  _lclose,eax

;//---- Dump РЕ info from header -------------------
        mov     eax,dword[buff+3ch]
        mov     ebx,eax
        add     ebx,buff
        mov     [peOffset],ebx
       cinvoke  printf,<10,' Signature..........:  %.2s',\
                        10,' PE-Header offset...:  0x%04X',0>,buff,eax

        mov     esi,[peOffset]
        push    esi
        movzx   eax,[esi + PE_HEADER.Machine]
        movzx   ebx,[esi + PE_HEADER.NumberOfSection]
        movzx   ecx,[esi + PE_HEADER.Flags]
        movzx   edx,[esi + PE_HEADER.Magic]
        mov     ebp,[esi + PE_HEADER.ImageBase]
        mov     edi,[esi + PE_HEADER.EntryPointRVA]
        mov     [Magic],edx
       cinvoke  printf,<10,' Machine............:  0x%04x',\
                        10,' Section count......:  %d',\
                        10,' Flags..............:  0x%04x',\
                        10,' Magic..............:  0x%04x',\
                        10,' ImageBase..........:  0x%08x',\
                        10,' Entry point........:  0x%08x',0>,\
                        eax,ebx,ecx,edx,ebp,edi

        pop     esi
        movzx   eax,byte[esi + PE_HEADER.LinkerVersion]
        movzx   ebx,byte[esi + PE_HEADER.LinkerVersion+1]
       cinvoke  printf,<10,' Section align......:  %d',\
                        10,' File align.........:  %d',\
                        10,' Size of image......:  %d byte',10,\
                        10,' Stack reserved.....:  0x%08x',\
                        10,' Stack commit.......:  0x%08x',\
                        10,' Heap  reserved.....:  0x%08x',\
                        10,' Heap  commit.......:  0x%08x',10,\
                        10,' Linker version.....:  %d.%d',0>,\
                        [esi + PE_HEADER.SectionAlign],     [esi + PE_HEADER.FileAlign],\
                        [esi + PE_HEADER.SizeOfImage],      [esi + PE_HEADER.SizeOfStackReserve],\
                        [esi + PE_HEADER.SizeOfStackCommit],[esi + PE_HEADER.SizeOfHeapReserve],\
                        [esi + PE_HEADER.SizeOfHeapCommit],  eax,ebx

@exit:  cinvoke  _getch
        cinvoke  exit, 0
;//--------------------------
section '.idata' import data readable
library  msvcrt,'msvcrt.dll',kernel32,'kernel32.dll',\
         user32,'user32.dll',comdlg32,'comdlg32.dll'
include 'api\msvcrt.inc'
include 'api\kernel32.inc'
include 'api\user32.inc'
import   comdlg32,GetOpenFileName,'GetOpenFileNameA'
    


Description: Result
Filesize: 10.75 KB
Viewed: 543 Time(s)

peinfo.png


Description:
Download
Filename: PEinfo.zip
Filesize: 15.86 KB
Downloaded: 31 Time(s)

Post 08 Mar 2025, 18:54
View user's profile Send private message Reply with quote
Mat-Quasar



Joined: 02 Mar 2025
Posts: 26
Mat-Quasar 09 Mar 2025, 07:04
macomics wrote:

Let's see where the problem is

As you can see from the screenshot, the problem is in the quotes. My code bypasses the quotes in the executable file name, if there are any, and finds the first argument. But CreateFileA requires you to specify file name without quotes. And so code does not split the next line into arguments. Therefore, the file name can be specified without quotes. It will not be split into substrings, and everything will be passed to CreateFileA.


If detect first character is " and last character is ", then just remove it.

However, when I run your pebasic.exe to dump the filename, I also noticed extra white space at the beginning of filename.


Description: I fixed my program to handle command line correctly
Filesize: 10.71 KB
Viewed: 431 Time(s)

cmdline.PNG




Last edited by Mat-Quasar on 09 Mar 2025, 13:00; edited 1 time in total
Post 09 Mar 2025, 07:04
View user's profile Send private message Reply with quote
Mat-Quasar



Joined: 02 Mar 2025
Posts: 26
Mat-Quasar 09 Mar 2025, 07:07
Core i7 wrote:
If there are structures, the rest is not a problem.
He put the headlines for PE32/PE64 in the archive, and now you can take it to the console for example ..
To select a file, I use the GetOpenFileName() system window from Comdlg32.dll.
This is only for 32-bit , although you can also assemble a universal one
Code:
format   pe console
include 'win32ax.inc'
include 'equates\pe32.inc'
entry    start
;//-----------
section '.data' data readable writeable
struct OPENFILENAME
  SizeOf     dd  sizeof.OPENFILENAME
  Res0       rd  2
  Filter     dd  filter
  Res1       rd  3
  FileName   dd  buff
  MaxFile    dd  512
  Res2       rd  4
  ofnFlags   dd  OFN_EXPLORER
  Res3       rd  5
ends
ofn          OPENFILENAME

filter       db  '  exe, dll, sys, ocx',0
             db  '*.exe;*.dll;*.sys;*.ocx',0,0
peOffset     dd  0
Magic        dd  0
buff         rb  2048

;//----------
section '.text' code readable executable
start:   invoke  SetConsoleTitle,<'*** PE file info ***',0>

;//---- Open file dialog box ---------------------
       cinvoke  printf,<10,' Select 32-bit executable file...',0>
        invoke  GetOpenFileName, ofn
        or      eax,eax
        jnz     @f
       cinvoke  printf,<10,' ERROR! File not found.',0>
        jmp     @exit

@@:     invoke  CharToOem,buff,buff
       cinvoke  printf,<10,' File: %s',10,0>,buff
        invoke  OemToChar,buff,buff

;//---- Read in buff 1K file header ----------------
        invoke  _lopen,buff,0
        push    eax
        invoke  _lread,eax,buff,1024
        pop     eax
        invoke  _lclose,eax

;//---- Dump РЕ info from header -------------------
        mov     eax,dword[buff+3ch]
        mov     ebx,eax
        add     ebx,buff
        mov     [peOffset],ebx
       cinvoke  printf,<10,' Signature..........:  %.2s',\
                        10,' PE-Header offset...:  0x%04X',0>,buff,eax

        mov     esi,[peOffset]
        push    esi
        movzx   eax,[esi + PE_HEADER.Machine]
        movzx   ebx,[esi + PE_HEADER.NumberOfSection]
        movzx   ecx,[esi + PE_HEADER.Flags]
        movzx   edx,[esi + PE_HEADER.Magic]
        mov     ebp,[esi + PE_HEADER.ImageBase]
        mov     edi,[esi + PE_HEADER.EntryPointRVA]
        mov     [Magic],edx
       cinvoke  printf,<10,' Machine............:  0x%04x',\
                        10,' Section count......:  %d',\
                        10,' Flags..............:  0x%04x',\
                        10,' Magic..............:  0x%04x',\
                        10,' ImageBase..........:  0x%08x',\
                        10,' Entry point........:  0x%08x',0>,\
                        eax,ebx,ecx,edx,ebp,edi

        pop     esi
        movzx   eax,byte[esi + PE_HEADER.LinkerVersion]
        movzx   ebx,byte[esi + PE_HEADER.LinkerVersion+1]
       cinvoke  printf,<10,' Section align......:  %d',\
                        10,' File align.........:  %d',\
                        10,' Size of image......:  %d byte',10,\
                        10,' Stack reserved.....:  0x%08x',\
                        10,' Stack commit.......:  0x%08x',\
                        10,' Heap  reserved.....:  0x%08x',\
                        10,' Heap  commit.......:  0x%08x',10,\
                        10,' Linker version.....:  %d.%d',0>,\
                        [esi + PE_HEADER.SectionAlign],     [esi + PE_HEADER.FileAlign],\
                        [esi + PE_HEADER.SizeOfImage],      [esi + PE_HEADER.SizeOfStackReserve],\
                        [esi + PE_HEADER.SizeOfStackCommit],[esi + PE_HEADER.SizeOfHeapReserve],\
                        [esi + PE_HEADER.SizeOfHeapCommit],  eax,ebx

@exit:  cinvoke  _getch
        cinvoke  exit, 0
;//--------------------------
section '.idata' import data readable
library  msvcrt,'msvcrt.dll',kernel32,'kernel32.dll',\
         user32,'user32.dll',comdlg32,'comdlg32.dll'
include 'api\msvcrt.inc'
include 'api\kernel32.inc'
include 'api\user32.inc'
import   comdlg32,GetOpenFileName,'GetOpenFileNameA'
    


I saw this program when you helped answer my question about doing CPUID, I think.

You code is so short!!! Amazing. It works on 64-bit PE as well, but I am not sure about the values, because PE32+ offset is different for certain header fields.

Looks like I don't need to do my GUI window version anymore, you already have one with Open File dialog. Laughing
Post 09 Mar 2025, 07:07
View user's profile Send private message Reply with quote
Mat-Quasar



Joined: 02 Mar 2025
Posts: 26
Mat-Quasar 09 Mar 2025, 13:44
I modified the source code by macomics a little bit, and now it can process command-line argument correctly, also can drag and drop the file on pebasic.exe (@macomics' version). It will wait for Enter key to close the window.

But I found one thing, if 32-bit (i386) PE, no "CUI Application" or "GUI Application" word printed. It works correctly for 64-bit (x86_64) PE though.

The fix is easy:
Code:
  show_i386:
        lea     eax, [sz_Arch_i386]
        mov     ecx, sz_Arch_i386.Length
        call    write_file
        jmp     show_subsystem
;        jmp     close_file      


Description: 64-bit PE shows subsystem correctly
Filesize: 5.03 KB
Viewed: 427 Time(s)

64.PNG


Description: 32-bit PE doesn't show CUI or GUI
Filesize: 4.68 KB
Viewed: 427 Time(s)

32.PNG


Post 09 Mar 2025, 13:44
View user's profile Send private message Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1066
Location: Russia
macomics 09 Mar 2025, 15:52
Code:
format PE CONSOLE 4.0
include "WIN32A.INC"


section '.idata' import data readable writeable
library kernel32, "KERNEL32.DLL"
include "API/KERNEL32.INC"


PE_MAGIC_TYPE_I386   = 0x10B
PE_MAGIC_TYPE_X86_64 = 0x20B

IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
IMAGE_SUBSYSTEM_WINDOWS_CUI = 3

struc ASSUME base*, type& { if ~ type eq
    virtual at base
      . type
      if ~ definite .Length
        label .Length at ( $ - $$ )
      end if
    end virtual
  else
    label . at base
    label .Length at 0
  end if }

struc MZ_FILE_HEADER { label .
   .e_magic             dw ?
   .e_cblp              dw ?
   .e_cp                dw ?
   .e_crlc              dw ?
   .e_cparhdr           dw ?
   .e_minalloc          dw ?
   .e_maxalloc          dw ?
   .e_ss                dw ?
   .e_sp                dw ?
   .e_csum              dw ?
   .e_ip                dw ?
   .e_cs                dw ?
   .e_lfarlc            dw ?
   .e_ovno              dw ?
   .e_res               dw 4 dup ?
   .e_oemid             dw ?
   .e_oeminfo           dw ?
   .e_reserved          dw 10 dup ?
   .e_lfanew            dd ?
  label .Length at ( $ - . ) }

struc PE_FILE_HEADER { label .
   .Signature           dd ?
   .Machine             dw ?
   .SectionsCount       dw ?
   .TimeDateStamp       dd ?
   .pSymbolTable        dd ?
   .SymbolsCount        dd ?
   .OptHeaderSize       dw ?
   .Chracteristics      dw ?
   .OptionalHeader:
  label .Length at ( $ - . ) }

struc PE_OPTIONAL_HEADER { label .
   .Magic               dw ?
   .majLinkerVer        db ?
   .minLinkerVer        db ?
   .CodeSize            dd ?
   .IdatSize            dd ?
   .UdatSize            dd ?
   .EntryPoint          dd ?
   .BaseOfCode          dd ?
   .BaseOfData          dd ?
   .ImageBase           dd ?
   .AlignSections       dd ?
   .AlignFile           dd ?
   .majOSVer            dw ?
   .minOSVer            dw ?
   .majPE32Ver          dw ?
   .minPE32Ver          dw ?
   .majSubsysVer        dw ?
   .minSubsysVer        dw ?
   .Win32VerValue       dd ?
   .PE32Size            dd ?
   .HeaderSize          dd ?
   .Checksum            dd ?
   .SubSystem           dw ?
   .DLLCharacters       dw ?
   .StackReserved       dd ?
   .StackCommit         dd ?
   .HeapReserved        dd ?
   .HeapCommit          dd ?
   .LoaderFlags         dd ?
   .DataDirSize         dd ?
  label .Length at ( $ - . ) }

section '.text' code readable executable
entry $
        push    ebp
        mov     ebp, esp
        invoke  GetCommandLineA
        mov     esi, eax
        mov     dl,  ' '
        mov     edi, esi
        mov     ebx, eax
        jmp     start_loop

  @@:
        cmp     al,  '"'
        jz      @f
        cmp     al,  dl
        jz      found_arg

  start_loop:
        lods    byte [esi]
        test    al,  al
        jnz     @b
        jmp     end_loop

  @@:
        xor     dl,  '"' xor ' '
        jmp     start_loop

  @@:
        lodsb

  found_arg:
        cmp     [esi], al
        jz      @b
        mov     edi, esi

  end_loop:
        invoke  GetStdHandle, STD_OUTPUT_HANDLE
        mov     esi, eax
        cmp     ebx, edi
        jz      show_usage
        cmp     byte [edi], '"'
        jnz     open_file
        lea     edx, [edi + 1]

  @@:
        inc     edi
        cmp     byte [edi], 0
        jz      show_usage
        cmp     byte [edi], '"'
        jnz     @b
        sub     edi, edx
        jz      show_usage
        lea     eax, [edi + 4]
        mov     ecx, edi
        and     al, 0xFC
        sub     esp, eax
        and     byte [esp + edi], 0

  @@:
        mov     al, [edx + ecx - 1]
        mov     [esp + ecx - 1], al
        loop    @b
        mov     edi, esp

  open_file:
        invoke  CreateFileA, edi, GENERIC_READ, FILE_SHARE_READ or \
                                  FILE_SHARE_WRITE or FILE_SHARE_DELETE,\
                                  NULL, OPEN_EXISTING, NULL, NULL
        mov     esp, ebp
        cmp     eax, INVALID_HANDLE_VALUE
        jz      show_open_file_error
        mov     ebx, eax
  mzFileHeader ASSUME ebp - mzFileHeader.Length, MZ_FILE_HEADER
        sub     esp, mzFileHeader.Length
        mov     eax, esp
        xor     edx, edx
        mov     ecx, mzFileHeader.Length
        call    block_read
        cmp     eax, mzFileHeader.Length
        jnz     show_read_file_error
        cmp     [mzFileHeader.e_magic], 'MZ'
        jnz     show_file_has_no_mz_header
        mov     edi, [mzFileHeader.e_lfanew]
  peFileHeader ASSUME ebp - peFileHeader.Length, PE_FILE_HEADER
        add     esp, mzFileHeader.Length - peFileHeader.Length
        mov     eax, esp
        mov     edx, edi
        mov     ecx, peFileHeader.Length
        call    block_read
        cmp     eax, peFileHeader.Length
        jnz     show_read_file_error
        cmp     [peFileHeader.Signature], 'PE'
        jnz     show_file_has_no_pe_header
        lea     edx, [peFileHeader.OptionalHeader - peFileHeader + edi]
        movzx   eax, [peFileHeader.OptHeaderSize]
        add     eax, 3  ; staack alignment
        and     al, 0xFC
  peOptionalHeader ASSUME esp, PE_OPTIONAL_HEADER
        add     esp, peFileHeader.Length
        sub     esp, eax
        mov     eax, esp
        mov     ecx, peOptionalHeader.Length
        call    block_read
        cmp     eax, peOptionalHeader.Length
        jnz     show_read_file_error
        movzx   eax, [peOptionalHeader.Magic]
        movzx   edi, [peOptionalHeader.SubSystem]
        add     esp, peOptionalHeader.Length
        cmp     eax, PE_MAGIC_TYPE_I386
        jz      show_i386
        cmp     eax, PE_MAGIC_TYPE_X86_64
        jnz     show_unknown
        lea     eax, [sz_Arch_x86_64]
        call    write_file
        jmp     show_subsystem

  show_unknown:
        lea     eax, [szUnknown_Arch]
        call    write_file
        jmp     close_file

  show_i386:
        lea     eax, [sz_Arch_i386]
        call    write_file

  show_subsystem:
        cmp     edi, IMAGE_SUBSYSTEM_WINDOWS_CUI
        jz      show_gui_sybsystem
        cmp     edi, IMAGE_SUBSYSTEM_WINDOWS_GUI
        jnz     show_unknown_sybsystem
        lea     eax, [szGUI_Subsystem]
        call    write_file
        jmp     close_file

  show_gui_sybsystem:
        lea     eax, [szCUI_Subsystem]
        call    write_file
        jmp     close_file

  show_unknown_sybsystem:
        lea     eax, [szUnknown_Subsystem]
        call    write_file
        jmp     close_file

  show_open_file_error:
        lea     eax, [szOpenFileError]
        call    write_file
        jmp     close_file

  show_read_file_error:
        lea     eax, [szReadFileError]
        call    write_file
        jmp     close_file

  show_file_has_no_mz_header:
        lea     eax, [szNoMZHeader]
        call    write_file
        jmp     close_file

  show_file_has_no_pe_header:
        lea     eax, [szNoPEHeader]
        call    write_file
        jmp     close_file

  show_usage:
        lea     eax, [szUsage]
        call    write_file
        jmp     @f

  close_file:
        invoke  CloseHandle, ebx

  @@:
        leave
        invoke  ExitProcess, NULL

  write_file:
        push    0
        movzx   ecx, word [eax - 2]
        mov     edx, esp
        invoke  WriteConsoleA, esi, eax, ecx, edx, NULL
        pop     eax
        retn

  block_read:
        invoke  SetFilePointer, ebx, edx, 0, FILE_BEGIN, eax, ecx
        pop     edx
        pop     ecx
        push    0
        mov     eax, esp
        invoke  ReadFile, ebx, edx, ecx, eax, 0
        pop     eax
        retn


  struc STRING [text] { common dw .Length
    label .
    forward db text
    common label .Length at ( $ - . )
            db NULL
    label .Bytes at ( $ - . ) }

  sz_Arch_i386        STRING "Windows (i386)"
  sz_Arch_x86_64      STRING "Windows (x86_64)"
  szUnknown_Arch      STRING "Unknown!", 13, 10
  szGUI_Subsystem     STRING " GUI application", 13, 10
  szCUI_Subsystem     STRING " CUI application", 13, 10
  szUnknown_Subsystem STRING " Unknow application", 13, 10
  szOpenFileError     STRING "Open file error!", 13, 10
  szReadFileError     STRING "Read file error!", 13, 10
  szNoMZHeader        STRING "File has no MZ header!", 13, 10
  szNoPEHeader        STRING "File has no PE header!", 13, 10
  szUsage             STRING "pebasic <exe_file_name>", 13, 10    

I have corrected errors due to the presence of quotes or additional spaces in the command line. I also fixed a bug in the text output interface.

Initially, I wrote this example to demonstrate not how to work with strings, but rather the convenience of using structures that are fully loaded into memory instead of reading individual fields of these structures from a file.
Post 09 Mar 2025, 15:52
View user's profile Send private message Reply with quote
Mat-Quasar



Joined: 02 Mar 2025
Posts: 26
Mat-Quasar 10 Mar 2025, 01:58
Yes, your code now run flawlessly.

macomics wrote:
Code:
format PE CONSOLE 4.0
include "WIN32A.INC"


section '.idata' import data readable writeable
library kernel32, "KERNEL32.DLL"
include "API/KERNEL32.INC"


PE_MAGIC_TYPE_I386   = 0x10B
PE_MAGIC_TYPE_X86_64 = 0x20B

IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
IMAGE_SUBSYSTEM_WINDOWS_CUI = 3

struc ASSUME base*, type& { if ~ type eq
    virtual at base
      . type
      if ~ definite .Length
        label .Length at ( $ - $$ )
      end if
    end virtual
  else
    label . at base
    label .Length at 0
  end if }

struc MZ_FILE_HEADER { label .
   .e_magic             dw ?
   .e_cblp              dw ?
   .e_cp                dw ?
   .e_crlc              dw ?
   .e_cparhdr           dw ?
   .e_minalloc          dw ?
   .e_maxalloc          dw ?
   .e_ss                dw ?
   .e_sp                dw ?
   .e_csum              dw ?
   .e_ip                dw ?
   .e_cs                dw ?
   .e_lfarlc            dw ?
   .e_ovno              dw ?
   .e_res               dw 4 dup ?
   .e_oemid             dw ?
   .e_oeminfo           dw ?
   .e_reserved          dw 10 dup ?
   .e_lfanew            dd ?
  label .Length at ( $ - . ) }

struc PE_FILE_HEADER { label .
   .Signature           dd ?
   .Machine             dw ?
   .SectionsCount       dw ?
   .TimeDateStamp       dd ?
   .pSymbolTable        dd ?
   .SymbolsCount        dd ?
   .OptHeaderSize       dw ?
   .Chracteristics      dw ?
   .OptionalHeader:
  label .Length at ( $ - . ) }

struc PE_OPTIONAL_HEADER { label .
   .Magic               dw ?
   .majLinkerVer        db ?
   .minLinkerVer        db ?
   .CodeSize            dd ?
   .IdatSize            dd ?
   .UdatSize            dd ?
   .EntryPoint          dd ?
   .BaseOfCode          dd ?
   .BaseOfData          dd ?
   .ImageBase           dd ?
   .AlignSections       dd ?
   .AlignFile           dd ?
   .majOSVer            dw ?
   .minOSVer            dw ?
   .majPE32Ver          dw ?
   .minPE32Ver          dw ?
   .majSubsysVer        dw ?
   .minSubsysVer        dw ?
   .Win32VerValue       dd ?
   .PE32Size            dd ?
   .HeaderSize          dd ?
   .Checksum            dd ?
   .SubSystem           dw ?
   .DLLCharacters       dw ?
   .StackReserved       dd ?
   .StackCommit         dd ?
   .HeapReserved        dd ?
   .HeapCommit          dd ?
   .LoaderFlags         dd ?
   .DataDirSize         dd ?
  label .Length at ( $ - . ) }

section '.text' code readable executable
entry $
        push    ebp
        mov     ebp, esp
        invoke  GetCommandLineA
        mov     esi, eax
        mov     dl,  ' '
        mov     edi, esi
        mov     ebx, eax
        jmp     start_loop

  @@:
        cmp     al,  '"'
        jz      @f
        cmp     al,  dl
        jz      found_arg

  start_loop:
        lods    byte [esi]
        test    al,  al
        jnz     @b
        jmp     end_loop

  @@:
        xor     dl,  '"' xor ' '
        jmp     start_loop

  @@:
        lodsb

  found_arg:
        cmp     [esi], al
        jz      @b
        mov     edi, esi

  end_loop:
        invoke  GetStdHandle, STD_OUTPUT_HANDLE
        mov     esi, eax
        cmp     ebx, edi
        jz      show_usage
        cmp     byte [edi], '"'
        jnz     open_file
        lea     edx, [edi + 1]

  @@:
        inc     edi
        cmp     byte [edi], 0
        jz      show_usage
        cmp     byte [edi], '"'
        jnz     @b
        sub     edi, edx
        jz      show_usage
        lea     eax, [edi + 4]
        mov     ecx, edi
        and     al, 0xFC
        sub     esp, eax
        and     byte [esp + edi], 0

  @@:
        mov     al, [edx + ecx - 1]
        mov     [esp + ecx - 1], al
        loop    @b
        mov     edi, esp

  open_file:
        invoke  CreateFileA, edi, GENERIC_READ, FILE_SHARE_READ or \
                                  FILE_SHARE_WRITE or FILE_SHARE_DELETE,\
                                  NULL, OPEN_EXISTING, NULL, NULL
        mov     esp, ebp
        cmp     eax, INVALID_HANDLE_VALUE
        jz      show_open_file_error
        mov     ebx, eax
  mzFileHeader ASSUME ebp - mzFileHeader.Length, MZ_FILE_HEADER
        sub     esp, mzFileHeader.Length
        mov     eax, esp
        xor     edx, edx
        mov     ecx, mzFileHeader.Length
        call    block_read
        cmp     eax, mzFileHeader.Length
        jnz     show_read_file_error
        cmp     [mzFileHeader.e_magic], 'MZ'
        jnz     show_file_has_no_mz_header
        mov     edi, [mzFileHeader.e_lfanew]
  peFileHeader ASSUME ebp - peFileHeader.Length, PE_FILE_HEADER
        add     esp, mzFileHeader.Length - peFileHeader.Length
        mov     eax, esp
        mov     edx, edi
        mov     ecx, peFileHeader.Length
        call    block_read
        cmp     eax, peFileHeader.Length
        jnz     show_read_file_error
        cmp     [peFileHeader.Signature], 'PE'
        jnz     show_file_has_no_pe_header
        lea     edx, [peFileHeader.OptionalHeader - peFileHeader + edi]
        movzx   eax, [peFileHeader.OptHeaderSize]
        add     eax, 3  ; staack alignment
        and     al, 0xFC
  peOptionalHeader ASSUME esp, PE_OPTIONAL_HEADER
        add     esp, peFileHeader.Length
        sub     esp, eax
        mov     eax, esp
        mov     ecx, peOptionalHeader.Length
        call    block_read
        cmp     eax, peOptionalHeader.Length
        jnz     show_read_file_error
        movzx   eax, [peOptionalHeader.Magic]
        movzx   edi, [peOptionalHeader.SubSystem]
        add     esp, peOptionalHeader.Length
        cmp     eax, PE_MAGIC_TYPE_I386
        jz      show_i386
        cmp     eax, PE_MAGIC_TYPE_X86_64
        jnz     show_unknown
        lea     eax, [sz_Arch_x86_64]
        call    write_file
        jmp     show_subsystem

  show_unknown:
        lea     eax, [szUnknown_Arch]
        call    write_file
        jmp     close_file

  show_i386:
        lea     eax, [sz_Arch_i386]
        call    write_file

  show_subsystem:
        cmp     edi, IMAGE_SUBSYSTEM_WINDOWS_CUI
        jz      show_gui_sybsystem
        cmp     edi, IMAGE_SUBSYSTEM_WINDOWS_GUI
        jnz     show_unknown_sybsystem
        lea     eax, [szGUI_Subsystem]
        call    write_file
        jmp     close_file

  show_gui_sybsystem:
        lea     eax, [szCUI_Subsystem]
        call    write_file
        jmp     close_file

  show_unknown_sybsystem:
        lea     eax, [szUnknown_Subsystem]
        call    write_file
        jmp     close_file

  show_open_file_error:
        lea     eax, [szOpenFileError]
        call    write_file
        jmp     close_file

  show_read_file_error:
        lea     eax, [szReadFileError]
        call    write_file
        jmp     close_file

  show_file_has_no_mz_header:
        lea     eax, [szNoMZHeader]
        call    write_file
        jmp     close_file

  show_file_has_no_pe_header:
        lea     eax, [szNoPEHeader]
        call    write_file
        jmp     close_file

  show_usage:
        lea     eax, [szUsage]
        call    write_file
        jmp     @f

  close_file:
        invoke  CloseHandle, ebx

  @@:
        leave
        invoke  ExitProcess, NULL

  write_file:
        push    0
        movzx   ecx, word [eax - 2]
        mov     edx, esp
        invoke  WriteConsoleA, esi, eax, ecx, edx, NULL
        pop     eax
        retn

  block_read:
        invoke  SetFilePointer, ebx, edx, 0, FILE_BEGIN, eax, ecx
        pop     edx
        pop     ecx
        push    0
        mov     eax, esp
        invoke  ReadFile, ebx, edx, ecx, eax, 0
        pop     eax
        retn


  struc STRING [text] { common dw .Length
    label .
    forward db text
    common label .Length at ( $ - . )
            db NULL
    label .Bytes at ( $ - . ) }

  sz_Arch_i386        STRING "Windows (i386)"
  sz_Arch_x86_64      STRING "Windows (x86_64)"
  szUnknown_Arch      STRING "Unknown!", 13, 10
  szGUI_Subsystem     STRING " GUI application", 13, 10
  szCUI_Subsystem     STRING " CUI application", 13, 10
  szUnknown_Subsystem STRING " Unknow application", 13, 10
  szOpenFileError     STRING "Open file error!", 13, 10
  szReadFileError     STRING "Read file error!", 13, 10
  szNoMZHeader        STRING "File has no MZ header!", 13, 10
  szNoPEHeader        STRING "File has no PE header!", 13, 10
  szUsage             STRING "pebasic <exe_file_name>", 13, 10    

I have corrected errors due to the presence of quotes or additional spaces in the command line. I also fixed a bug in the text output interface.

Initially, I wrote this example to demonstrate not how to work with strings, but rather the convenience of using structures that are fully loaded into memory instead of reading individual fields of these structures from a file.
Post 10 Mar 2025, 01:58
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.