windows - WinExec Return 0x21, men hvad betyder det?

Indlæg af Hanne Mølgaard Plasc

Problem



Når du kalder WinExec for at køre en .exe, får jeg returværdi 0x21.

Ifølge MSDN betyder en returværdi større end 31 (0x1F), at funktionen lykkes.

Men hvad betyder det med 0x21, hvorfor returnerede jeg ikke anden værdi til mig?

Bedste reference


Det er ikke nyttigt for dig at vide, hvad det betyder. Det er en implementeringsdetalje. Selvom du vidste hvad det betød for denne version, kan betydningen ændre sig i den næste version. Som programmør er du kun optaget af programmering mod grænsefladen, ikke den underliggende implementering.


Men hvis du virkelig er interesseret, vil jeg tage dig gennem den tilgang, jeg ville tage for at omdanne funktionaliteten. På mit system er WinExec adskilt til dette:


764F2C21 > 8BFF             MOV EDI,EDI
764F2C23   55               PUSH EBP
764F2C24   8BEC             MOV EBP,ESP
764F2C26   81EC 80000000    SUB ESP,80
764F2C2C   53               PUSH EBX
764F2C2D   8B5D 0C          MOV EBX,DWORD PTR SS:[EBP+C]
764F2C30   56               PUSH ESI
764F2C31   57               PUSH EDI
764F2C32   33FF             XOR EDI,EDI
764F2C34   47               INC EDI
764F2C35   33F6             XOR ESI,ESI
764F2C37   85DB             TEST EBX,EBX
764F2C39   79 4F            JNS SHORT kernel32.764F2C8A
764F2C3B   8D45 FC          LEA EAX,DWORD PTR SS:[EBP-4]
764F2C3E   50               PUSH EAX
764F2C3F   56               PUSH ESI
764F2C40   57               PUSH EDI
764F2C41   8D45 C8          LEA EAX,DWORD PTR SS:[EBP-38]
764F2C44   50               PUSH EAX
764F2C45   C745 FC 20000000 MOV DWORD PTR SS:[EBP-4],20
764F2C4C   E8 90BE0200      CALL <JMP.&API-MS-Win-Core-ProcessThread>
764F2C51   85C0             TEST EAX,EAX
764F2C53   0F84 D2000000    JE kernel32.764F2D2B
764F2C59   56               PUSH ESI
764F2C5A   56               PUSH ESI
764F2C5B   6A 04            PUSH 4
764F2C5D   8D45 F8          LEA EAX,DWORD PTR SS:[EBP-8]
764F2C60   50               PUSH EAX
764F2C61   68 01000600      PUSH 60001
764F2C66   56               PUSH ESI
764F2C67   8D45 C8          LEA EAX,DWORD PTR SS:[EBP-38]
764F2C6A   50               PUSH EAX
764F2C6B   C745 0C 00000800 MOV DWORD PTR SS:[EBP+C],80000
764F2C72   897D F8          MOV DWORD PTR SS:[EBP-8],EDI
764F2C75   E8 5CBE0200      CALL <JMP.&API-MS-Win-Core-ProcessThread>
764F2C7A   85C0             TEST EAX,EAX
764F2C7C   0F84 95000000    JE kernel32.764F2D17
764F2C82   8D45 C8          LEA EAX,DWORD PTR SS:[EBP-38]
764F2C85   8945 C4          MOV DWORD PTR SS:[EBP-3C],EAX
764F2C88   EB 03            JMP SHORT kernel32.764F2C8D
764F2C8A   8975 0C          MOV DWORD PTR SS:[EBP+C],ESI
764F2C8D   6A 44            PUSH 44
764F2C8F   8D45 80          LEA EAX,DWORD PTR SS:[EBP-80]
764F2C92   56               PUSH ESI
764F2C93   50               PUSH EAX
764F2C94   E8 B5E9F7FF      CALL <JMP.&ntdll.memset>
764F2C99   83C4 0C          ADD ESP,0C
764F2C9C   33C0             XOR EAX,EAX
764F2C9E   3975 0C          CMP DWORD PTR SS:[EBP+C],ESI
764F2CA1   897D AC          MOV DWORD PTR SS:[EBP-54],EDI
764F2CA4   0F95C0           SETNE AL
764F2CA7   66:895D B0       MOV WORD PTR SS:[EBP-50],BX
764F2CAB   8D0485 44000000  LEA EAX,DWORD PTR DS:[EAX*4+44]
764F2CB2   8945 80          MOV DWORD PTR SS:[EBP-80],EAX
764F2CB5   8D45 E8          LEA EAX,DWORD PTR SS:[EBP-18]
764F2CB8   50               PUSH EAX
764F2CB9   8D45 80          LEA EAX,DWORD PTR SS:[EBP-80]
764F2CBC   50               PUSH EAX
764F2CBD   56               PUSH ESI
764F2CBE   56               PUSH ESI
764F2CBF   FF75 0C          PUSH DWORD PTR SS:[EBP+C]
764F2CC2   56               PUSH ESI
764F2CC3   56               PUSH ESI
764F2CC4   56               PUSH ESI
764F2CC5   FF75 08          PUSH DWORD PTR SS:[EBP+8]
764F2CC8   56               PUSH ESI
764F2CC9   E8 A4E3F7FF      CALL kernel32.CreateProcessA
764F2CCE   85C0             TEST EAX,EAX
764F2CD0   74 27            JE SHORT kernel32.764F2CF9
764F2CD2   A1 3C005476      MOV EAX,DWORD PTR DS:[7654003C]
764F2CD7   3BC6             CMP EAX,ESI
764F2CD9   74 0A            JE SHORT kernel32.764F2CE5
764F2CDB   68 30750000      PUSH 7530
764F2CE0   FF75 E8          PUSH DWORD PTR SS:[EBP-18]
764F2CE3   FFD0             CALL EAX
764F2CE5   FF75 E8          PUSH DWORD PTR SS:[EBP-18]
764F2CE8   8B35 A0054776    MOV ESI,DWORD PTR DS:[<&ntdll.NtClose>]  ; ntdll.ZwClose
764F2CEE   FFD6             CALL ESI
764F2CF0   FF75 EC          PUSH DWORD PTR SS:[EBP-14]
764F2CF3   FFD6             CALL ESI
764F2CF5   6A 21            PUSH 21
764F2CF7   EB 1D            JMP SHORT kernel32.764F2D16
764F2CF9   E8 C9E4F7FF      CALL <JMP.&API-MS-Win-Core-ErrorHandling>
764F2CFE   48               DEC EAX
764F2CFF   48               DEC EAX
764F2D00   74 12            JE SHORT kernel32.764F2D14
764F2D02   48               DEC EAX
764F2D03   74 0B            JE SHORT kernel32.764F2D10
764F2D05   2D BE000000      SUB EAX,0BE
764F2D0A   75 0B            JNZ SHORT kernel32.764F2D17
764F2D0C   6A 0B            PUSH 0B
764F2D0E   EB 06            JMP SHORT kernel32.764F2D16
764F2D10   6A 03            PUSH 3
764F2D12   EB 02            JMP SHORT kernel32.764F2D16
764F2D14   6A 02            PUSH 2
764F2D16   5E               POP ESI
764F2D17   F745 0C 00000800 TEST DWORD PTR SS:[EBP+C],80000
764F2D1E   74 09            JE SHORT kernel32.764F2D29
764F2D20   8D45 C8          LEA EAX,DWORD PTR SS:[EBP-38]
764F2D23   50               PUSH EAX
764F2D24   E8 A2BD0200      CALL <JMP.&API-MS-Win-Core-ProcessThread>
764F2D29   8BC6             MOV EAX,ESI
764F2D2B   5F               POP EDI
764F2D2C   5E               POP ESI
764F2D2D   5B               POP EBX
764F2D2E   C9               LEAVE
764F2D2F   C2 0800          RETN 8


Opkaldskonventionen, der anvendes under Win32, er stdcall, som bestemmer, at returværdier holdes i EAX. I tilfælde af WinExec er der kun en udgang fra funktionen (0x764F2D2F). Sporing tilbage derfra er EAX indstillet af (i det mindste når afkastet er 0x21):


764F2D29   8BC6             MOV EAX,ESI


Sporing tilbage, ESI i sig selv er indstillet fra POP ESI, som popper toppen af ​​stakken i ESI. Værdien af ​​dette afhænger af, hvad der tidligere blev trykket på stakken. I tilfælde af 0x21 sker dette ved:


764F2CF5   6A 21            PUSH 21


Umiddelbart efterfølgende oprettes en JMP til POP ESI. Hvordan vi kom til PUSH 21 er kun interessant fra efter CreateProcess opkaldet.


764F2CC9    E8 A4E3F7FF     CALL kernel32.CreateProcessA
764F2CCE    85C0            TEST EAX,EAX
764F2CD0    74 27           JE SHORT kernel32.764F2CF9
764F2CD2    A1 3C005476     MOV EAX,DWORD PTR DS:[7654003C]
764F2CD7    3BC6            CMP EAX,ESI
764F2CD9    74 0A           JE SHORT kernel32.764F2CE5
764F2CDB    68 30750000     PUSH 7530
764F2CE0    FF75 E8         PUSH DWORD PTR SS:[EBP-18]
764F2CE3    FFD0            CALL EAX
764F2CE5    FF75 E8         PUSH DWORD PTR SS:[EBP-18]
764F2CE8    8B35 A0054776   MOV ESI,DWORD PTR DS:[<&ntdll.NtClose>]  ; ntdll.ZwClose
764F2CEE    FFD6            CALL ESI
764F2CF0    FF75 EC         PUSH DWORD PTR SS:[EBP-14]
764F2CF3    FFD6            CALL ESI
764F2CF5    6A 21           PUSH 21


For at se, hvordan stien fører dig til PUSH 21, skal du observere forskellige grene. Den første forekommer som:


764F2CD0   74 27            JE SHORT kernel32.764F2CF9


Dette siger, hvis CreateProcess returneres 0, ring Win-Core-ErrorHandling. Returværdierne indstilles derefter forskelligt (0x2, 0x3 og 0xB er alle mulige returværdier, hvis CreateProcess mislykkedes).


Den næste gren er meget mindre indlysende for at vende ingeniør:


764F2CD9   74 0A            JE SHORT kernel32.764F2CE5


Hvad det gør er at læse en hukommelsesadresse, som sandsynligvis indeholder en funktionspeger (vi ved det, fordi resultatet af læsningen kaldes senere). Dette JE angiver simpelthen, om du ikke skal foretage dette opkald eller ej. Uanset om opkaldet er lavet, er det næste trin at ringe ZwClose (to gange). Endelig returneres 0x21.


Så en enkel måde at se på er at når CreateProcess lykkes, returneres 0x21, ellers 0x2, 0x3 eller 0xB returneres. Dette er ikke at sige, at disse er de eneste returværdier. For eksempel kan 0x0 også returneres fra filialen på 0x764F2C53 (i dette tilfælde er ESI ikke brugt på samme måde). Der er nogle få mulige returværdier, men jeg vil forlade dem for dig at se på dig selv.


Hvad jeg har vist dig, er hvordan man gør en meget lav analyse af WinExec specifikt til 0x21-afkastet. Hvis du vil vide mere, skal du kigge mere dybtgående og forsøge at forstå fra en højere niveau hvad der foregår. Du kan finde ud af meget mere bare ved at bryde funktionen og træde igennem den (på denne måde kan du observere dataværdier).





En anden måde er at se på vinkilden, hvor nogen allerede har gjort alt det hårde arbejde for dig: [38]


UINT WINAPI WinExec( LPCSTR lpCmdLine, UINT nCmdShow )
{
    PROCESS\_INFORMATION info;
    STARTUPINFOA startup;
    char *cmdline;
    UINT ret;

    memset( &startup, 0, sizeof(startup) );
    startup.cb = sizeof(startup);
    startup.dwFlags = STARTF\_USESHOWWINDOW;
    startup.wShowWindow = nCmdShow;

    /* cmdline needs to be writable for CreateProcess */
    if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(lpCmdLine)+1 ))) return 0;
    strcpy( cmdline, lpCmdLine );

     if (CreateProcessA( NULL, cmdline, NULL, NULL, FALSE,
                        0, NULL, NULL, &startup, &info ))
    {
        /* Give 30 seconds to the app to come up */
        if (wait\_input\_idle( info.hProcess, 30000 ) == WAIT\_FAILED)
            WARN("WaitForInputIdle failed: Error \%d
", GetLastError() );
        ret = 33;
        /* Close off the handles */
        CloseHandle( info.hThread );
        CloseHandle( info.hProcess );
    }
    else if ((ret = GetLastError()) >= 32)
    {
        FIXME("Strange error set by CreateProcess: \%d
", ret );
        ret = 11;
    }
    HeapFree( GetProcessHeap(), 0, cmdline );
    return ret;
}


33d er 0x21, så det bekræfter faktisk kun frugterne i vores tidligere analyse.


Hvad angår årsagen til at 0x21 er returneret, er mit gæt at der måske er mere intern dokumentation, der gør det mere nyttigt på en eller anden måde.

Andre referencer 1


Bortset fra det betyder det succes, er betydningen af ​​returværdien ikke defineret. Måske blev det valgt sådan, at gamle applikationer vil fungere godt med denne særlige værdi. En ting er sikker: der er flere vigtige ting at bekymre sig om!


http://msdn.microsoft.com/en-us/library/windows/desktop/ms687393(v=vs.85).aspx[39]

Andre referencer 2


REDIGER : Dette svar er forkert, fordi OP-resultatet ikke er en fejlkode. Jeg troede fejlagtigt, at det var en fejlkode. Jeg tror stadig, at den praktiske info nedenfor kan være nyttigt plus at det kan være nyttigt at se, hvad en forkert antagelse kan føre til, så jeg lader dette svar stå.


Hvis du har installeret Visual Studio (fuld eller hurtig udgave), har du et værktøj kaldet errlook , som bruger API'ens FormatMessage -funktion til at fortælle dig, hvad en fejlkode eller HRESULT værdi betyder.


I dette tilfælde,



  Processen kan ikke få adgang til filen, fordi en anden proces har låst en del af filen.



Du kan gøre meget af det samme manuelt ved at kigge i filen <winerror.h>. Skriv f.eks. En #include af den i en C ++-kildefil i Visual Studio, og højreklik og bede om at åbne overskriften. Hvor finder du det


//
// MessageId: ERROR\_LOCK\_VIOLATION
//
// MessageText:
//
// The process cannot access the file because another process has locked a portion of the file.
//
#define ERROR\_LOCK\_VIOLATION             33L


Forresten er WinExec bare en gammel kompatibilitetsfunktion. Brug helst ShellExecute eller CreateProcess. Funktionen ShellExecute kan spille mere pænt med Windows Vista og 7 User Access Control, og det er lettere at bruge, så det er generelt at foretrække.