flat assembler
Message board for the users of flat assembler.
![]() |
Author |
|
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.
Last edited by Mat-Quasar on 18 Mar 2025, 08:08; edited 4 times in total |
|||||||||||||||||||||||||||||
![]() |
|
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:
|
|||
![]() |
|
Mat-Quasar 08 Mar 2025, 13:41
macomics, you're skillful in anything related to portable executable. Thumbs up!
|
|||
![]() |
|
macomics 08 Mar 2025, 14:27
Quote: My code also has bug in get command-line routine, cannot process path with quotes, e.g.: 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.
|
||||||||||
![]() |
|
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'
|
||||||||||||||||||||
![]() |
|
Mat-Quasar 09 Mar 2025, 07:04
macomics wrote:
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.
Last edited by Mat-Quasar on 09 Mar 2025, 13:00; edited 1 time in total |
||||||||||
![]() |
|
Mat-Quasar 09 Mar 2025, 07:07
Core i7 wrote: If there are structures, the rest is not a problem. 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. ![]() |
|||
![]() |
|
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
|
|||||||||||||||||||
![]() |
|
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. |
|||
![]() |
|
Mat-Quasar 10 Mar 2025, 01:58
Yes, your code now run flawlessly.
macomics wrote:
|
|||
![]() |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.