The following is a disassembly and analysis of the command line parsing for Visual C++ version 6 (VC6) as found in file msvcrt.dll. [Note the rules were later changed in 2008. See parameters.htm#WINCRULES
77C3AA6D SUB_L77C3AA6D: ; MSVCRT!__wsetargv+0xa6 (77c3aa6d) ; eax = command line (ASCII, address of) ; ecx = address to build output string (address of address?) ; [ebp+0Ch] address of argc ? ; [ebp+08h] address of argv ? ; ; are we being passed something in ecx? edi? ; returns argc in eax ; returns argv in edi ; [ebp-04h] - " flag. (in a double quoted part flag) 77C3AA6D 8BFF mov edi,edi 77C3AA6F 55 push ebp 77C3AA70 8BEC mov ebp,esp 77C3AA72 51 push ecx 77C3AA73 53 push ebx 77C3AA74 8B5D0C mov ebx,[ebp+0Ch] ;address for argc 77C3AA77 33D2 xor edx,edx ;edx=0 77C3AA79 395508 cmp [ebp+08h],edx ;address to build argv 77C3AA7C 57 push edi 77C3AA7D 8916 mov [esi],edx ;zero this counter 77C3AA7F 8BF9 mov edi,ecx ;dereference address of address 77C3AA81 C70301000000 mov dword ptr [ebx],00000001h 77C3AA87 7409 +---- jz L77C3AA92 ;no argv array to build 77C3AA89 8B4D08 | mov ecx,[ebp+08h] ;argv 77C3AA8C 83450804 | add dword ptr [ebp+08h],00000004h ;point to next argv element 77C3AA90 8939 v mov [ecx],edi ;pointer to beginning of output string to build ;parse off argv[0] (program filename) 77C3AA92 L77C3AA92: ;edx - " flag, (starts = 0) 77C3AA92 803822 +--------------------> cmp byte ptr [eax],22h ; " ? 77C3AA95 750E | +-- jnz L77C3AAA5 ;not a " 77C3AA97 33C9 | | xor ecx,ecx ; ecx=0 77C3AA99 85D2 | | test edx,edx ;toggle " flag 77C3AA9B 0F94C1 | | setz cl ;toggle " flag 77C3AA9E 40 | | inc eax ;move to next char in command line. (pointer into command line) 77C3AA9F 8BD1 | | mov edx,ecx ;store " flag 77C3AAA1 B122 | | mov cl,22h ; " current char is a " 77C3AAA3 EB2D | +----------------|-- jmp L77C3AAD2 77C3AAA5 | | L77C3AAA5:| 77C3AAA5 FF06 | | +-> inc [esi] ;count of output characters (used for dry run) 77C3AAA7 85FF | | test edi,edi ;are we building an output string? 77C3AAA9 7405 | | +-- jz L77C3AAB0 ;no 77C3AAAB 8A08 | | | mov cl,[eax] ;character from command line 77C3AAAD 880F | | | mov [edi],cl ;move character to output string 77C3AAAF 47 | | | inc edi ;point to next output byte 77C3AAB0 | | L77C3AAB0:| 77C3AAB0 8A08 | | +-> mov cl,[eax] ;character from command line 77C3AAB2 0FB6D9 | | movzx ebx,cl 77C3AAB5 40 | | inc eax ;next character 77C3AAB6 F6836125C67704| | test byte ptr [ebx+L77C62561],04h ;is this a wchar? 77C3AABD 740C | | +---------------- jz L77C3AACB ;if not a wchar we skip processing 2nd byte 77C3AABF FF06 | | | inc [esi] ;count of output characters (used for dry run) 77C3AAC1 85FF | | | test edi,edi ;are we building an output string? 77C3AAC3 7405 | | | +---- jz L77C3AACA ;no 77C3AAC5 8A18 | | | | mov bl,[eax] ;character from command line 77C3AAC7 881F | | | | mov [edi],bl ;move character to output string 77C3AAC9 47 | | | v inc edi ;point to next output byte 77C3AACA | | | L77C3AACA: 77C3AACA 40 | | | inc eax ;move to next input character 77C3AACB | | +-> L77C3AACB: 77C3AACB 84C9 | | test cl,cl ;end of string? 77C3AACD 8B5D0C | | mov ebx,[ebp+0Ch] ;address of argc 77C3AAD0 7432 +-|-|---dec eax--------- jz L77C3AB04 ;end of string, back up to 00 and process it 77C3AAD2 | | | L77C3AAD2: 77C3AAD2 85D2 | | +------------------> test edx,edx ; " flag 77C3AAD4 75BC | +--------------------- jnz L77C3AA92 ; accept character if we are in a double quoted part 77C3AAD6 80F920 | | cmp cl,20h ; space? 77C3AAD9 7405 | | +---- jz L77C3AAE0 ; end of parameter 77C3AADB 80F909 | | | cmp cl,09h ; tab? 77C3AADE 75B2 | +----------------|---- jnz L77C3AA92 ; no, go to next char | | | v 77C3AAE0 | L77C3AAE0: ;end of parameter 77C3AAE0 85FF | test edi,edi ;are we building an output string? 77C3AAE2 7404 | +-- jz L77C3AAE8 ;no 77C3AAE4 C647FF00 | | mov byte ptr [edi-01h],00h ;terminate this parameter in output string | | | | 77C3AAE8 | L77C3AAE8:v 77C3AAE8 8365FC00 +--------------------+-> and dword ptr [ebp-04h],00000000h ; clear " flag 77C3AAEC L77C3AAEC: ;PARSE OFF NEXT PARAMETER 77C3AAEC 803800 cmp byte ptr [eax],00h ;end of string? 77C3AAEF 0F84D6000000 return<-- jz L77C3ABCB ;return ;SKIP MULTIPLE SPACES/TABS BETWEEN PARAMETERS 77C3AAF5 L77C3AAF5: 77C3AAF5 8A08 +------------> mov cl,[eax] ;character from command line 77C3AAF7 80F920 | cmp cl,20h ; space. skip to next char 77C3AAFA 7405 | +---- jz L77C3AB01 77C3AAFC 80F909 | | cmp cl,09h ; tab. skip to next char 77C3AAFF 7506 | v +-- jnz L77C3AB07 ;not a space or tab 77C3AB01 |L77C3AB01:| 77C3AB01 40 | | inc eax ;next character 77C3AB02 EBF1 +----------|-- jmp L77C3AAF5 ;skip multiple spaces/tabs between parameters | 77C3AB04 L77C3AB04:| 77C3AB04 48 | dec eax ;back one character 77C3AB05 EBE1 | jmp L77C3AAE8 | | 77C3AB07 L77C3AB07:| ;not a space or tab. Beginning of next parameter 77C3AB07 803800 +-> cmp byte ptr [eax],00h ;end of string? 77C3AB0A 0F84BB000000 return<-- jz L77C3ABCB ;return 77C3AB10 837D0800 cmp dword ptr [ebp+08h],00000000h ;dry run? 77C3AB14 7409 +---- jz L77C3AB1F ;yes, dry run 77C3AB16 8B4D08 | mov ecx,[ebp+08h] ;save parameter starting address 77C3AB19 83450804 | add dword ptr [ebp+08h],00000004h ;pointer to next argv[] array element 77C3AB1D 8939 v mov [ecx],edi 77C3AB1F L77C3AB1F: 77C3AB1F FF03 inc [ebx] ;increment argc ;process this character 77C3AB21 L77C3AB21: 77C3AB21 33DB +--------------------> xor ebx,ebx ;ebx=0 77C3AB23 43 | inc ebx ;ebx=1 add this character to the output 77C3AB24 33D2 | xor edx,edx ;edx=0 77C3AB26 EB02 | +-- jmp L77C3AB2A | | | | ;COUNT \ 77C3AB28 | L77C3AB28:| 77C3AB28 40 | +---------------> inc eax ;next character 77C3AB29 42 | | | inc edx ;++count of backslashes 77C3AB2A | | L77C3AB2A:| 77C3AB2A 80385C | | +-> cmp byte ptr [eax],5Ch ; \ 77C3AB2D 74F9 | +---------------- jz L77C3AB28 | ;edx is now count of backslashes 77C3AB2F 803822 | cmp byte ptr [eax],22h ; " 77C3AB32 7526 |+-------------------- jnz L77C3AB5A || ;handle " 77C3AB34 F6C201 || test dl,01h ;test for even/odd 77C3AB37 751F || +------------------ jnz L77C3AB58 ;if odd, jump 77C3AB39 837DFC00 || | cmp dword ptr [ebp-04h],00000000h ;are we in a double quoted part? 77C3AB3D 740C || | +---------------- jz L77C3AB4B ;no 77C3AB3F 8D4801 || | | lea ecx,[eax+01h] ;peek at next character 77C3AB42 803922 || | | cmp byte ptr [ecx],22h ; " ( handle "" ) 77C3AB45 7504 || | +---------------- jnz L77C3AB4B 77C3AB47 8BC1 || | | mov eax,ecx ;move to next character (the ") 77C3AB49 EB02 || | | +-- jmp L77C3AB4D 77C3AB4B || | | L77C3AB4B:| 77C3AB4B 33DB || | +-------------|-> xor ebx,ebx ;ebx=0 flag to not add this char to the output 77C3AB4D || | L77C3AB4D:| 77C3AB4D 33C9 || | +-> xor ecx,ecx ;ecx=0 77C3AB4F 394DFC || | cmp [ebp-04h],ecx ;toggle " flag 77C3AB52 0F94C1 || | setz cl ;toggle " flag (in a double quoted part) 77C3AB55 894DFC || | mov [ebp-04h],ecx ;store " flag 77C3AB58 || +---> L77C3AB58: 77C3AB58 D1EA || shr edx,1 ;backslashes/2 (number to actually insert) || 77C3AB5A || L77C3AB5A: ;ADD BACKSLASHES TO OUTPUT STRING 77C3AB5A 85D2 |+-------------------> test edx,edx ;number of backslashes to insert 77C3AB5C 740D | +------------------ jz L77C3AB6B ;no more backslashes to insert 77C3AB5E | | +> L77C3AB5E: 77C3AB5E 85FF | | | test edi,edi 77C3AB60 7404 | | | +---- jz L77C3AB66 77C3AB62 C6075C | | | | mov byte ptr [edi],5Ch ; \ insert a backslash 77C3AB65 47 | | | v inc edi ;pointer into output string 77C3AB66 | | | L77C3AB66: 77C3AB66 FF06 | | | inc [esi] 77C3AB68 4A | | | dec edx ;number of backslashes left to insert 77C3AB69 75F3 | | +--------------- jnz L77C3AB5E | | | | 77C3AB6B | | L77C3AB6B: 77C3AB6B 8A08 | +-----------------> mov cl,[eax] ;character from command line 77C3AB6D 84C9 | test cl,cl ;end of string? 77C3AB6F 7448 | jz L77C3ABB9 77C3AB71 837DFC00 | cmp dword ptr [ebp-04h],00000000h ;are we not in a double quoted part? 77C3AB75 750A | +-- jnz L77C3AB81 ;jump if we are in a double quoted part 77C3AB77 80F920 | | cmp cl,20h ; space 77C3AB7A 743D | | jz L77C3ABB9 ; end of this parameter 77C3AB7C 80F909 | | cmp cl,09h ; tab 77C3AB7F 7438 | | jz L77C3ABB9 ; end of this parameter 77C3AB81 | L77C3AB81:| 77C3AB81 85DB | +-> test ebx,ebx ; add this char to the output? 77C3AB83 742E | jz L77C3ABB3 ; no, move to next character, jump to AB21 (process this character) 77C3AB85 85FF | test edi,edi ;are we building an output string? 77C3AB87 7419 | +-------------- jz L77C3ABA2 ;no 77C3AB89 0FB6D1 | | movzx edx,cl ;character from command line 77C3AB8C F6826125C6770 | | test byte ptr [edx+L77C62561],04h ;MSVCRT!_mbctype+0x1 multi-byte character? a special ASCII table, 255 bytes, each ascii byte gets a code. 04h is one code we are looking for. | | ;For us there are no 04h in the table. Just 01h for uppercase alpha, 02h for lowercase alpha. 77C3AB93 7406 | | +---- jz L77C3AB9B ;04 means this is a single byte char | | | ;THE MAKE A COPY VERSION 77C3AB95 880F | | | mov [edi],cl ;copy byte from command line to output 77C3AB97 47 | | | inc edi ;pointer to output 77C3AB98 40 | | | inc eax ;next byte 77C3AB99 FF06 | | v inc [esi] ;point to next output byte 77C3AB9B | | L77C3AB9B: 77C3AB9B 8A08 | | mov cl,[eax] ;get byte from command line 77C3AB9D 880F | | mov [edi],cl ;put byte from command line to output 77C3AB9F 47 | | inc edi ;point to next output byte 77C3ABA0 EB0F | | +-- jmp L77C3ABB1 77C3ABA2 | | L77C3ABA2:| ;THE DON'T MAKE A COPY VERSION 77C3ABA2 0FB6C9 | +-----------|-> movzx ecx,cl ;character from command line 77C3ABA5 F6816125C6770 | | test byte ptr [ecx+L77C62561],04h ;is this not a 2-byte wchar? 04h means 'not a wchar' 77C3ABAC 7403 | +-- jz L77C3ABB1 77C3ABAE 40 | | inc eax ;next byte ;yes, process extra byte 77C3ABAF FF06 | | inc [esi] ;move pointer to next byte 77C3ABB1 | L77C3ABB1:| 77C3ABB1 FF06 | +-> inc [esi] ;move pointer to next byte 77C3ABB3 | L77C3ABB3: 77C3ABB3 40 | inc eax ;next byte (next character if not multibyte wide char) 77C3ABB4 E968FFFFFF +--------------------- jmp L77C3AB21 77C3ABB9 L77C3ABB9: ;end of this parameter 77C3ABB9 85FF test edi,edi 77C3ABBB 7404 +---- jz L77C3ABC1 77C3ABBD C60700 | mov byte ptr [edi],00h 77C3ABC0 47 v inc edi 77C3ABC1 L77C3ABC1: 77C3ABC1 FF06 ^ inc [esi] 77C3ABC3 8B5D0C | mov ebx,[ebp+0Ch] ;address of argc 77C3ABC6 E921FFFFFF+------------------------ jmp L77C3AAEC ; ;PARSE OFF NEXT PARAMETER ;end 77C3ABCB L77C3ABCB: 77C3ABCB 8B4508 mov eax,[ebp+08h] ;argv? 77C3ABCE 85C0 test eax,eax 77C3ABD0 7403 +---- jz L77C3ABD5 77C3ABD2 832000 v and dword ptr [eax],00000000h 77C3ABD5 L77C3ABD5: 77C3ABD5 FF03 inc [ebx] ;pointer to argc counter 77C3ABD7 5F pop edi 77C3ABD8 5B pop ebx 77C3ABD9 C9 leave 77C3ABDA C3 retn