Author Topic: Get full path from the command line  (Read 2375 times)

Offline alexbnc

  • Jr. Member
  • *
  • Posts: 6
Get full path from the command line
« on: July 29, 2013, 06:02:26 PM »
I've been torturing myself with this issue for a month and I'm about to give up. It is a simple program and I just can't see why is not working properly.
So, what I am trying to do create is a simple application that will parse the command line and display the first argument, which is the full path to the executable.
This is how my code looks like:

Code: [Select]
use32

[EXTERN GetStdHandle]
[EXTERN GetCommandLineW]
[EXTERN WriteConsoleW]
[EXTERN ExitProcess]

[section .bss]
StdHandle resd 1
PathStart resw 1
PathEnd resw 1
WrittenChars resw 1

[section .data]
message db __utf16__(""Hello everybody"), 13, 10, 0

[section .text]
global start

start:
    call GetHandler
    call GetCommandLine
    end:
        mov eax, e
        ret

    GetHandler:
        push -11
        call GetStdHandle
        cmp eax, 1
        push ebx
        mov ebx, 1
        jl CloseApp
        pop ebx
        mov dword[StdHandle], eax
        ret

    GetCommandLine:
        cld
        call GetCommandLineW ; UNICODE
        mov esi, eax
        mov bh, 0 ; here we save the argc
        mov ecx, eax ; here we save the pointer of the first arg

        Parse:
            lodsw
            cmp ax, __utf16__(' ')
            je NewArg
            jmp ContinueParsing

            NewArg:
                inc bh
                cmp bh, 1
                jne Parse
                ; if the first arg was just read save the start from ecx and end from esi to the BSS variables
                mov dword[PathStart], ecx
                mov dword[PathEnd], esi
                jmp ShowPath

        ContinueParsing:
            cmp ax, 0
            jne Parse

        ShowPath:
            mov ecx, [PathEnd]
            mov ebx, [PathStart]
            sub ecx, ebx ; text size
            shr ecx, 1 ; is UNICODE
            push dword[PathStart]
            push dword[ecx]
            call ShowText
            ret
           
    ShowText:
        push ebp
        mov ebp, esp
        push 0
        push dword WrittenChars
        push dword [ebp+8]
        push dword [ebp+12]
        push dword [StdHandle]
        call WriteConsoleW
        pop
        ret 8

    CloseApp:
        push ebx
        call ExitProcess
        pop ebx
        ret


Well, I might have misspelled or missed something but that is not the problem. The code is compiled and built successfully but the message that I see is only the name of the executable, not the full path that I expect. If the full path is "D:\My Projects\NASM\Demo.exe" I only see "Demo". If before calling ShowText I prepare the arguments for the message variable it works and I can see the text correctly, so I think the problem lies in getting the pointer and length of the full path correctly. Yet, when studying the running of the application with OllyDbg I can see that correct values are stored in the BSS section. This is very weird and maybe somebody with a better eye can catch the cause of it. Thanks in advance

Offline Gunner

  • Jr. Member
  • *
  • Posts: 74
  • Country: us
    • Gunners Software
Re: Get full path from the command line
« Reply #1 on: July 30, 2013, 03:32:38 AM »
To make life easier, you could use CommandLineToArgvW which will return the count of args.  To simplify, I used printf:

Code: [Select]
%define     STD_OUTPUT_HANDLE -11

; Shell32.dll
extern  CommandLineToArgvW

; Kernel32.dll
extern ExitProcess, WriteConsoleW, LocalFree
extern GetStdHandle, GetCommandLineW
%define GetCommandLine GetCommandLineW

;  msvcrt.dll
extern _printf

section .bss
stdout          resd 1
szArglist       resd 1
nArgs           resd 1

section .data
fmtst     db  "%ws", 13, 10, 0

section .text
global start

start:
    push    STD_OUTPUT_HANDLE
    call    GetStdHandle
    mov     dword [stdout], eax

    call    GetCommandLine
   
    push    nArgs
    push    eax
    call    CommandLineToArgvW
    mov     dword [szArglist], eax
    mov     esi, eax
    xor     ebx, ebx
    sub     dword [nArgs], 1
   
.DisplayArgs:
    push    dword [esi + 4 * ebx]
    push    fmtst
    call    _printf
    add     esp, 4 * 2
   
    inc     ebx
    cmp     ebx, dword [nArgs]
    jle     .DisplayArgs
   
    push    dword [szArglist]
    call    LocalFree
   
    push    0
    call    ExitProcess
   

 


Offline alexbnc

  • Jr. Member
  • *
  • Posts: 6
Re: Get full path from the command line
« Reply #2 on: July 30, 2013, 11:15:00 AM »
Thanks for that solution. It is a good alternative yet I would really like to understand what is the problem in my case. It is frustrating to see that something that is supposed to work just doesn't. Computers don't do things at random and without explanation. Today I tried this
Code: [Select]
    ...
    GetCommandLine:
            cld
            call GetCommandLineW ; UNICODE
            mov esi, eax
            ; display it here
            push    dword       eax
            push    dword       128
            call    ShowText
    ...
I am trying to get the entire, or at least the first 128 characters of the full command line. I still get weird characters, so I am really really lost right now. So, if I have my executable in "D:\Project\My Demo\Test.exe", I add this to Path and I execute "Test --firstarg" in the cmd what I get is
Quote
Test  --firstarg Test  --firstarg Winsta0\Default =::=:: \=C:=C:\Users\Alex =D:=D:\Project\MyDemo\ ALLUSERSPROFILE