[HELP] Problems with URLDownloadToFileA

lShadowl's Avatar, Join Date: Jul 2009
Newbie Member
I am guessing why this code are not working

format PE GUI 4.0
entry start

include 'win32a.inc'
include 'cmd.inc'

    invoke    GetProcessHeap
    mov    [_hheap],eax
    invoke    HeapAlloc,[_hheap],HEAP_ZERO_MEMORY,1000h
    mov    [_b1],eax
    mov    [_b2],eax

    call    GetMainArgs
    mov    esi,[_argv]
    mov    ebx,[_argc]
    add    esi,4
    cinvoke wsprintf,[_b1],_fmt,[esi]
    add    esi,4
    cinvoke wsprintf,[_b2],_fmt,[esi]
    invoke URLDownloadToFileA,0,[_b1],[_b2],0,0
    invoke Sleep,7000

    invoke    HeapFree,[_hheap],0,[_argv]
    invoke    HeapFree,[_hheap],0,[_b1]
    invoke    HeapFree,[_hheap],0,[_b2]
    invoke    ExitProcess,0

_fmt     db '"%s"',0
_hheap     dd ?
_b1     dd ?
_b2     dd ?

data import
 library kernel,'KERNEL32.DLL',\

 import kernel,\
     Sleep, 'Sleep',\

 import user,\

 import urlmon,\
end data

Ok, the problem is in this line:

invoke URLDownloadToFileA,0,[_b1],[_b2],0,0

when i invoke the function defining _b1 and _b2 like:

_b1 db 'LINK',0
_b2 db 'FILE',0

and invoking like:

invoke URLDownloadToFileA,0,_b1,_b2,0,0

it works pretty good, but if i try to do it with the given cmd parameters it just doesnt work.

How can i get it work using the given parameters?

Thanks for the help!

; GetMainArgs v1.01
; Copyright © 2003 Theodor-Iulian Ciobanu

; uses heap instead of local

        invoke  GetCommandLine  ;_argc - number of args, _argv - ptr to arg table
        mov     [_argc],0
        xor     ebx,ebx
        cmp     byte [eax],22h  ;quotation mark
        jz      .startquote
        mov     [_argc],1
        push    eax

        cmp     byte [eax],0
        jz      .endcount
        cmp     byte [eax],22h  ;quotation mark
        jz      .solvequote
        cmp     ebx,1           ;is in quote
        jz      .isinquote
        cmp     byte [eax],20h  ;space
        jz      .pusharg
        cmp     byte [eax],09h  ;tab
        jz      .pusharg
        inc     eax
        jmp     .count

        mov     byte [eax],0
        inc     eax
        cmp     byte [eax],0
        jz      .endcount
        cmp     byte [eax],22h  ;quotation mark
        jz      .startquote
        cmp     byte [eax],20h  ;space
        jz      .isspace
        cmp     byte [eax],09h  ;tab
        jnz     .endremspaces
        inc     eax
        jmp     .remspaces
        inc     [_argc]
        push    eax
        jmp     .count

        cmp     ebx,1
        jz      .endquote
        mov     ebx,1
        inc     eax
        jmp     .endremspaces
        mov     ebx,0
        jmp     .pusharg

        mov     eax,[_argc]
        mov     ecx,4
        mul     ecx
        push    eax
        invoke  HeapAlloc,[_hheap],HEAP_ZERO_MEMORY,eax
        mov     [_argv],eax
        pop     eax
        sub     eax,4
        mov     esi,[_argv]
        add     esi,eax

        cmp     esi,[_argv]
        jb      .endsaveargs
        pop     eax
        mov     [esi],eax
        sub     esi,4
        jmp     .saveargs


_argc    dd ?
_argv    dd ?
xpi0t0s's Avatar, Join Date: Aug 2004
What's the difference between [_b1] and _b1?
If it works with _b1, why do you want to use [_b1] instead of _b1, especially knowing that [_b1] doesn't work?
How exactly doesn't it work - do you get an error, a warning, a crash, ...what?
If you're only guessing how the whole code doesn't work, how did you decide it was the URLDownloadToFileA line that was broken?

The first question has two aims: (1) to get you to think about the difference because that might show why it doesn't work, and (2) because I don't know. At a guess the square brackets transform the value in the register in some way, but I'm not clear what; thought perhaps it dereferenced the pointer but if that's the case then "mov [_argc],0" doesn't make sense. The prototype at
shows the two parameters in question are defined as LPCTSTR so maybe that has something to do with it.
lShadowl's Avatar, Join Date: Jul 2009
Newbie Member
Well, thanks for the reply.

1)about [_b1] and _b1, remember that it works if i define b1

_b1 db 'LINK',0
_b2 db 'FILE',0
but i dont want to define those variables, i want to give the parameters to the variables so i can call the program like:

>program LINK FILE

the code put "LINK" in b1 and "FILE" in b2 then invoke URLDownloadToFileA with those parameters.

2) The program doesn't crash, it compiles without any error or warning, but when i execute it, it just doesn't do what is supposed to do (download a file). But, as i said, if i define the variables and giving no parameters when i execute it, it work (it download the file).

3) The difference about [_b1] and _b1 is that _b1 is a pointer and [_b1] is the value contained in this address.
xpi0t0s's Avatar, Join Date: Aug 2004
OK, so [] does dereference the pointer as I guessed. Dereferencing isn't going to solve the problem. _b1 is defined as "_b1 db 'LINK',0", i.e. _b1 is the address of the L which is the first character of a null-terminated string. If you invoke the program as you want, i.e. "program LINK FILE" then LINK will be in argv[1] and FILE in argv[2] (*), so just set _b1 and _b2 equal to argv[1] and argv[2] (which also contain the address of the first character of a null-terminated string).
mov _b1, (whatever is equivalent to argv[1])
mov _b2, (whatever is equivalent to argv[2])
invoke URLDownloadToFileA,0,_b1,_b2,0,0
(*) Assuming that, say, program "C:\a b c\link" "C:\d e f\file" results in argv containing two items and not 6 (which would be "C:\a, b, c\link", "C:\d, e, f\file" (comma separated)) (yeah I know the first is a URL but this is illustrative only). If you get 6 items then obviously you're going to have to do some string manipulation before you can assign _b1 and _b2.
xpi0t0s's Avatar, Join Date: Aug 2004
Ref. "mov [_argc],0" In C argc is provided to the program as int, not pointer-to-int, so the equivalent of this, i.e. "*argc=0;" would crash the program. Make sure _argc is a pointer-to-int and not just an int. However why would you want to set argc zero anyway?