Page 1 of 2

How to tell if a file is executable or not?

Posted: Sat Mar 06, 2021 11:18 pm
by stevylake
Hello
I was thinking of how to tell if a file is a renamed .exe or other executable file type?
Instead of PossibleVirus.exe it is renamed PossibleVirus.dat.
Or would that not even be a problem as the renamed file could never be run? Unless another program renamed it and ran it maybe.
There must be some kind of header within a file to determine what type of file it is? Mustn't there?
Thanks.

Re: How to tell if a file is executable or not?

Posted: Sat Mar 06, 2021 11:57 pm
by Mijikai

Re: How to tell if a file is executable or not?

Posted: Sun Mar 07, 2021 12:07 am
by Axolotl
There are special file formats.
The most common used formats are under Window PE, under Linux ELF and Mach-O on macOS.

Furthermore there are Permissions (Linux) and Data Execution Prevention (Windows).

I recommend the general search on the internet for details.

Re: How to tell if a file is executable or not?

Posted: Sun Mar 07, 2021 1:47 am
by Keya
this code tests for valid Windows PE executables (32bit/64bit).

Returns 0 if invalid (not a valid Windows PE executable), or the size of the executable as reported by its PE header (which isn't necessarily the same as its filesize). If the reported size is smaller than the filesize you can use that to determine how much extra data it has appended to it.

To call it, read the file data (you don't need to read the entire file, just enough to cover the PE header, 4kb is sufficient), and pass the pointer to that data, as well as the LOF() filesize.

Code: Select all

#IMAGE_DOS_SIGNATURE = $5A4D ;"MZ"
#IMAGE_NT_SIGNATURE  = $4550 ;"PE"
#IMAGE_NT_OPTIONAL_HDR32_MAGIC = $10b ;32bit
#IMAGE_NT_OPTIONAL_HDR64_MAGIC = $20b ;64bit


Procedure IsValidPE(*DOShdr.IMAGE_DOS_HEADER, imgsize)
  Protected *PEhdr32.IMAGE_NT_HEADERS32, PEimgsize  
  If *DOShdr = 0 Or imgsize <= SizeOf(IMAGE_DOS_HEADER)
    ProcedureReturn 0
  EndIf  
  PEimgsize = imgsize - SizeOf(IMAGE_DOS_HEADER)
  If *DOShdr\e_magic <> #IMAGE_DOS_SIGNATURE
    ProcedureReturn 0
  EndIf

  ;At this stage, you know it's seemingly a valid MZ DOS executable. Now check if it's a valid PE...

  If *DOShdr\e_lfanew = 0 Or *DOShdr\e_lfanew > PEimgsize
    ProcedureReturn 0
  EndIf
  *PEhdr32 = *DOShdr + *DOShdr\e_lfanew
  If *PEhdr32\Signature <> #IMAGE_NT_SIGNATURE
    ProcedureReturn 0
  EndIf
  If *PEhdr32\FileHeader\SizeOfOptionalHeader = 0 Or *PEhdr32\FileHeader\SizeOfOptionalHeader > PEimgsize
    ProcedureReturn 0
  EndIf  
  If *PEhdr32\FileHeader\NumberOfSections = 0 Or *PEhdr32\FileHeader\NumberOfSections > 255
    ProcedureReturn 0
  EndIf
  If Not (*PEhdr32\OptionalHeader\Magic = #IMAGE_NT_OPTIONAL_HDR64_MAGIC Or *PEhdr32\OptionalHeader\Magic = #IMAGE_NT_OPTIONAL_HDR32_MAGIC)
    ProcedureReturn 0
  EndIf
  ProcedureReturn *PEhdr32\OptionalHeader\SizeOfImage
EndProcedure

Re: How to tell if a file is executable or not?

Posted: Sun Mar 07, 2021 3:29 am
by stevylake
Thanks for the code I just got stuck at this bit.

To call it, read the file data (you don't need to read the entire file, just enough to cover the PE header, 4kb is sufficient), and pass the pointer to that data, as well as the LOF() filesize.

:-)

Re: How to tell if a file is executable or not?

Posted: Sun Mar 07, 2021 3:40 am
by Keya
stevylake wrote:Thanks for the code I just got stuck at this bit.
To call it, read the file data (you don't need to read the entire file, just enough to cover the PE header, 4kb is sufficient), and pass the pointer to that data, as well as the LOF() filesize.
:-)

Code: Select all

szFile.s = "c:\windows\system32\calc.exe"
hFile = ReadFile(#PB_Any, szFile)
fSize = Lof(hFile)
If fSize > 4096: fSize = 4096: EndIf  ;we don't need to read any more than 4kb as we're only looking at the file header
*fData = AllocateMemory(fSize)
ReadData(hFile, *fData, fSize)
IsPE = IsValidPE(*fData, Lof(hFile))
FreeMemory(*fData)
CloseFile(hFile)
If IsPE = 0
 Debug "Not a valid PE executable"
Else
 Debug "Valid PE executable, the reported image size is " + Str(IsPE)
EndIf

Re: How to tell if a file is executable or not?

Posted: Sun Mar 07, 2021 7:37 am
by TI-994A
stevylake wrote:... some kind of header within a file to determine what type of file it is?
There's a Windows API function for that, actually:

source: Microsoft Win32 API Documentation

Code: Select all

Procedure.s checkBinaryType(fileName.s)
  Protected SCS_64BIT_BINARY = 6
  Protected fileExt$ = UCase(GetExtensionPart(fileName))
  Protected binaryType$ = Trim(fileExt$ + " file type (unconfirmed)")
 
  If FileSize(fileName) > -1 And
     GetBinaryType_(fileName, @binaryType)   
    Select binaryType     
      Case #SCS_DOS_BINARY
        binaryType$ = "MS-DOS–based application"
      Case #SCS_WOW_BINARY
        binaryType$ = "16-bit Windows-based application"
      Case #SCS_32BIT_BINARY
        binaryType$ = "32-bit Windows-based application"
      Case SCS_64BIT_BINARY
        binaryType$ = "64-bit Windows-based application" 
      Case #SCS_OS216_BINARY
        binaryType$ = "16-bit OS/2-based application"
      Case #SCS_POSIX_BINARY
        binaryType$ = "POSIX–based application"
      Case #SCS_PIF_BINARY
        binaryType$ = "PIF for MS-DOS–based application"
      Default
        binaryType$ = "Unknown binary type"
    EndSelect   
  EndIf
 
  ProcedureReturn binaryType$ 
EndProcedure

Repeat 
  file.s = OpenFileRequester("Select file to check", "",
                             "All files (*.*) | *.*", 0)
  Debug checkBinaryType(file) 
  If MessageRequester("Binary File Type", "Check another file?",
                      #PB_MessageRequester_YesNo) = #PB_MessageRequester_No
    Break
  EndIf
ForEver

Re: How to tell if a file is executable or not?

Posted: Sun Mar 07, 2021 1:07 pm
by stevylake
TI-994A wrote:
stevylake wrote:... some kind of header within a file to determine what type of file it is?
There's a Windows API function for that, actually:

source: Microsoft Win32 API Documentation

Code: Select all

Procedure.s checkBinaryType(fileName.s)
  Protected SCS_64BIT_BINARY = 6
  Protected fileExt$ = UCase(GetExtensionPart(fileName))
  Protected binaryType$ = Trim(fileExt$ + " file type (unconfirmed)")
 
  If FileSize(fileName) > -1 And
     GetBinaryType_(fileName, @binaryType)   
    Select binaryType     
      Case #SCS_DOS_BINARY
        binaryType$ = "MS-DOS–based application"
      Case #SCS_WOW_BINARY
        binaryType$ = "16-bit Windows-based application"
      Case #SCS_32BIT_BINARY
        binaryType$ = "32-bit Windows-based application"
      Case SCS_64BIT_BINARY
        binaryType$ = "64-bit Windows-based application" 
      Case #SCS_OS216_BINARY
        binaryType$ = "16-bit OS/2-based application"
      Case #SCS_POSIX_BINARY
        binaryType$ = "POSIX–based application"
      Case #SCS_PIF_BINARY
        binaryType$ = "PIF for MS-DOS–based application"
      Default
        binaryType$ = "Unknown binary type"
    EndSelect   
  EndIf
 
  ProcedureReturn binaryType$ 
EndProcedure

Repeat 
  file.s = OpenFileRequester("Select file to check", "",
                             "All files (*.*) | *.*", 0)
  Debug checkBinaryType(file) 
  If MessageRequester("Binary File Type", "Check another file?",
                      #PB_MessageRequester_YesNo) = #PB_MessageRequester_No
    Break
  EndIf
ForEver


Seems good. Just wondering where you find a list of all those constants? Are they Microsoft constants or Pure Basic or something else?

Re: How to tell if a file is executable or not?

Posted: Sun Mar 07, 2021 1:18 pm
by TI-994A
stevylake wrote:...where you find a list of all those constants? Are they Microsoft constants or Pure Basic...
They're part of the Microsoft Win32 API, integrated as native constants in Windows versions of PureBasic.

They can be referenced here:
> Microsoft Win32 API Documentation

Re: How to tell if a file is executable or not?

Posted: Sun Mar 07, 2021 1:23 pm
by stevylake
TI-994A wrote:
stevylake wrote:...where you find a list of all those constants? Are they Microsoft constants or Pure Basic...
They're part of the Microsoft Win32 API, integrated as native constants in Windows versions of PureBasic.

They can be referenced here:
> Microsoft Win32 API Documentation
is it that SCS_64BIT_BINARY hasn't been integrated so the code had to use a variable instead then?

Is there somewhere to find a list of all the Microsoft constants used by PB?

Re: How to tell if a file is executable or not?

Posted: Sun Mar 07, 2021 1:29 pm
by NicTheQuick
On Linux and Mac every file with execution rights could possibly be an executable. Either it's a real binary or it's a script with a Shebang in the first line or an appropriate file extensions. But in general file extensions on Linux/Mac are just a suggestion.
You can call the `file` tool with a filename you want to check for its type. For example:

Code: Select all

nicolas@tp-w530:~/git/FractalSoundExplorer$ file FractalSoundExplorer 
FractalSoundExplorer: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=cabc8f367f97790c528f174cf07001e7ac378bac, for GNU/Linux 3.2.0, not stripped

Re: How to tell if a file is executable or not?

Posted: Sun Mar 07, 2021 2:35 pm
by TI-994A
stevylake wrote:is it that SCS_64BIT_BINARY hasn't been integrated so the code had to use a variable instead then?

Is there somewhere to find a list of all the Microsoft constants used by PB?
Yes, and yes. These might be good places to start:

> PureBasic Windows Resident Data (Fantaisie Software Git)

> Windows API Index (Microsoft Documentation)

Re: How to tell if a file is executable or not?

Posted: Sun Mar 07, 2021 3:14 pm
by Marc56us
Hi stevylake,

Understanding how it works is very useful: Search wikipedia for Magic number (programming)
https://en.wikipedia.org/wiki/Magic_num ... ogramming)

and use PB file functions
https://www.purebasic.com/documentation/file/index.html

:wink:

Re: How to tell if a file is executable or not?

Posted: Sun Mar 07, 2021 4:34 pm
by Axolotl
Your question suggests that you are concerned with preventing "attacks" by malware.

Let's see where this thread takes us.
In general, however, other types of files can cause damage in addition to directly executable files.

You have to consider that scripts are also executed under Windows. For example the good old MS-DOS scripts *.BAT (*.cmd) or Powershell or or. (under Linux there is BASH etc.)

Otherwise there is under Windows still the environment variable PathExt, so that you dont have to add the extension on the console. (Looks like this PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC)

Additionally there is the option that the files that are not executed are started because of a file association.

Re: How to tell if a file is executable or not?

Posted: Sun Mar 07, 2021 9:17 pm
by stevylake
Axolotl wrote:Your question suggests that you are concerned with preventing "attacks" by malware.

Let's see where this thread takes us.
In general, however, other types of files can cause damage in addition to directly executable files.

You have to consider that scripts are also executed under Windows. For example the good old MS-DOS scripts *.BAT (*.cmd) or Powershell or or. (under Linux there is BASH etc.)

Otherwise there is under Windows still the environment variable PathExt, so that you dont have to add the extension on the console. (Looks like this PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC)

Additionally there is the option that the files that are not executed are started because of a file association.
Yes I was kindof thinking that. It's just that I have set up a way where a user can send me a message with a file attachment via one of my servers. All works good. What I was thinking is how much testing would I have to do to ensure that any file uploaded couldn't be run and do horrible things to my server. That was what I was thinking and that got me to how does one know an executable file when it's been disguised. :-)