Author Topic: Alternate command tail algo.  (Read 973 times)

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 4807
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Alternate command tail algo.
« on: November 26, 2015, 06:33:19 AM »
PowerBASIC has a COMMAND$ command that works fine in most instances, here is an alternative algorithm that can be called with either basic dynamic string or as a zero terminated string. Note that neither solve a problem with the API CreateProcess() where the file name and command tail are not parsed correctly. The assembler code was written in MASM and directly ported to PowerBASIC.

Code: [Select]
' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    #include "\basic\include\win32api.inc"

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FUNCTION PBmain as LONG

    LOCAL pCmt as ASCIIZ PTR

 '     cmd$ = command$
 '
 '     If cmd$ = "" Then
 '       StdOut "No command tail"
 '     Else
 '       StdOut cmd$                   ' display basic string
 '     End If
 '
 '     If cmd$ = "" Then
 '       StdOut "No command tail"
 '     Else
 '       StdOut cmd$                   ' display basic string
 '     End If

  ' --------------------
  ' BASIC string version
  ' --------------------
    cmd$ = GetCmdTail

    If cmd$ = "" Then
      StdOut "No command tail"
    Else
      StdOut cmd$                   ' display basic string
    End If

  ' ------------------------------
  ' zero terminated string version
  ' ------------------------------
    pCmt = szCmdTail

    If pCmt = 0 Then
      StdOut "No command tail"
    Else
      StdOut @pCmt                  ' display zero terminated string
      GlobalFree pCmt
    End If

End FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FUNCTION szCmdTail() as DWORD

  ' -----------------------------------------------------------------------
  ' If command tail is not empty and the memory pointer is returned, it
  ' must be freed in the same scope as the caller with theAPI GlobalFree().
  ' -----------------------------------------------------------------------

    LOCAL lCmd as DWORD
    LOCAL pCmd as DWORD
    LOCAL pBuf as DWORD

    pCmd = GetCommandLine()

    ! push pCmd             ; push cmdline pointer onto stack
    ! call slen             ; call the short lenth function
    ! mov lCmd, eax         ; allocate this much memory

    pBuf = GlobalAlloc(%GMEM_FIXED or %GMEM_ZEROINIT, lCmd+16)

    ! push pBuf
    ! push pCmd
    ! call cmdtail
    ! test eax, eax         ; check if the length is zero
    ! jne bye

    GlobalFree pBuf         ' deallocate the memory
    FUNCTION = 0            ' exit with zero and do
    Exit FUNCTION           ' not allocate memory

  bye:
    FUNCTION = pBuf         ' return the memory address

End FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FUNCTION GetCmdTail() as STRING

    LOCAL lCmd as DWORD
    LOCAL pCmd as DWORD
    LOCAL pBuf as DWORD
    LOCAL tLen as DWORD

    pCmd = GetCommandLine()

    ! push pCmd             ; push cmdline pointer onto stack
    ! call slen             ; call the short lenth function
    ! mov lCmd, eax         ; store it in lCmd

    outpt$ = space$(lCmd)
    pBuf = StrPtr(outpt$)

    ! push pBuf
    ! push pCmd
    ! call cmdtail
    ! mov tLen, eax

    FUNCTION = left$(outpt$,tLen)

End FUNCTION

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FASTPROC slen

    PREFIX "!"

    mov eax, [esp+4]
    sub eax, 1

  lbl:
    add eax, 1
    cmp BYTE PTR [eax], 0
    jne lbl

    sub eax, [esp+4]

    ret 4

    END PREFIX

END FASTPROC

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

FASTPROC cmdtail

    PREFIX "!"

  ; ------------------------------------------------------
  ; pCmd is the address of the command line
  ; pBuf is the target address for the command tail
  ; NOTE: The pBuf argument should be allocated to the size
  ;       of the command line returned by GetCommandLine()
  ;       API to ensure that the app can handle exploits
  ;
  ; The return value in EAX is the command tail length,
  ; if the length is 0 there is no command tail
  ; ------------------------------------------------------

  ; ***************************************************************
  ; ANSI quoted and unquoted file name version to get command tail.
  ; ***************************************************************
    mov ecx, [esp+4]
    mov edx, [esp+8]

  tstchar1:                     ; see if its a quote or not
    cmp BYTE PTR [ecx], 34      ; test for double quote character
    jne noquote                 ; if not 34 branch to noquote handler

  ; -------------------------------------------------------------
  ; strip the quoted file name from the start of the command line
  ; -------------------------------------------------------------
  quoted:
    add ecx, 1
    cmp BYTE PTR [ecx], 34      ; test for 2nd double quote character
    jne quoted
    jmp ftrim

  ; ---------------------------------------------------------------
  ; strip the unquoted file name from the start of the command line
  ; ---------------------------------------------------------------
  noquote:
    add ecx, 1
    cmp BYTE PTR [ecx], 32
    jg noquote                  ; if > 32, throw it away
    sub ecx, 1

  ; ------------------------------------------------
  ; trim any leading white space from command tail
  ; ------------------------------------------------
  ftrim:
    add ecx, 1
    cmp BYTE PTR [ecx], 32
    je ftrim
    cmp BYTE PTR [ecx], 9
    je ftrim

  ; ------------------------------------------
  ; copy the command tail to the output buffer
  ; ------------------------------------------
  copytail:
    movzx eax, BYTE PTR [ecx]
    mov [edx], al
    add ecx, 1
    add edx, 1
    test eax, eax
    jnz copytail
    mov BYTE PTR [edx], 0       ; append a terminator
    sub edx, 1

  ; ----------------------------------------------
  ; return value in EAX is the command tail length
  ; ----------------------------------------------
    sub edx, [esp+8]
    mov eax, edx

    ret 8

    END PREFIX

END FASTPROC

' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :biggrin: