Windows WinExec返回0x21,但它的确切含义是什么?

Windows WinExec返回0x21,但它的确切含义是什么?,windows,winapi,Windows,Winapi,当调用WinExec运行.exe时,我得到返回值0x21 根据MSDN,返回值大于31(0x1F)表示函数成功 但是0x21的含义是什么,为什么它没有向我返回其他值?除了这意味着成功之外,返回值的含义没有定义。也许选择它是为了让遗留应用程序能够很好地处理这个特定的价值。有一件事是肯定的:还有更重要的事情要担心 编辑:此答案错误,因为OP的结果不是错误代码。我误以为这是一个错误代码。我仍然认为下面的实用信息是有用的,另外,看看错误的假设会导致什么是有用的,所以我坚持这个答案。 如果您已安装Vis

当调用WinExec运行.exe时,我得到返回值0x21
根据MSDN,返回值大于31(0x1F)表示函数成功

但是0x21的含义是什么,为什么它没有向我返回其他值?

除了这意味着成功之外,返回值的含义没有定义。也许选择它是为了让遗留应用程序能够很好地处理这个特定的价值。有一件事是肯定的:还有更重要的事情要担心


编辑:此答案错误,因为OP的结果不是错误代码。我误以为这是一个错误代码。我仍然认为下面的实用信息是有用的,另外,看看错误的假设会导致什么是有用的,所以我坚持这个答案。
如果您已安装Visual Studio(完整版或快速版),则有一个名为
errlook
的工具,它使用
FormatMessage
API函数告诉您错误代码或
HRESULT
值的含义

在这种情况下,

该进程无法访问该文件,因为另一个进程已锁定该文件的一部分

您可以通过查看
文件手动执行大部分相同的操作。例如,在VisualStudio C++源文件中键入A<代码>包含“< /代码>”,然后右击并要求它打开标题。你在哪里找到的

//
// 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

顺便说一下,
WinExec
只是一个旧的兼容性函数。最好使用
ShellExecute
CreateProcess
。使用Windows Vista和7用户访问控制,ShellExecute功能可以更好地发挥作用,而且使用起来更简单,因此通常更可取。

您不知道它的含义。这是一个实现细节。即使您知道它对这个版本意味着什么,在下一个版本中它的含义可能会改变。作为一名程序员,您只关心针对接口的编程,而不关心底层实现

然而,如果你真的感兴趣,我将带你通过我将采取的方法来反向工程的功能。在我的系统上,
WinExec
被反汇编为:

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
进一步追溯,
ESI
本身是从
POP-ESI
设置的,它将堆栈顶部弹出到
ESI
。其值取决于以前在堆栈上推送的内容。在0x21的情况下,这种情况发生在:

764F2CF5   6A 21            PUSH 21
紧接着,对
POP ESI
进行JMP。只有在调用了
CreateProcess
之后,我们才对
push21
感兴趣

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
这意味着如果
CreateProcess
返回0,则调用
Win Core ErrorHandling
。然后以不同的方式设置返回值(如果
CreateProcess
失败,则0x2、0x3和0xB都是可能的返回值)

下一个分支对于逆向工程来说不那么明显:

764F2CD9   74 0A            JE SHORT kernel32.764F2CE5
它所做的是读取一个可能包含函数指针的内存地址(我们知道这一点,因为读取的结果稍后会被调用)。此
JE
仅指示是否进行此呼叫。无论是否调用,下一步都是调用
ZwClose
(两次)。最后返回0x21

因此,一种简单的方法是,当
CreateProcess
成功时,返回0x21,否则返回0x2、0x3或0xB。这并不是说这些是唯一的返回值。例如,0x0也可以从
0x764F2C53
处的分支返回(在这种情况下,ESI的使用方式完全不同)。还有一些可能的返回值,但我将留给您自己研究

我向您展示的是如何对专门针对0x21返回的
WinExec
进行非常肤浅的分析。如果你想了解更多,你需要更深入地探索,并尝试从更高的层次了解正在发生的事情。您可以通过中断函数并单步执行它(这样您就可以观察数据值)来了解更多信息


另一种方法是看一看,有人已经为你做了所有艰苦的工作:

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\n", 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\n", ret );
        ret = 11;
    }
    HeapFree( GetProcessHeap(), 0, cmdline );
    return ret;
}
33d是0x21,所以这实际上证实了我们之前分析的结果


关于返回0x21的原因,我的猜测是,可能存在更多的内部文档,使得它在某些方面更有用。

任何不能使用
CreateProcess
的原因?历史上,在win16下,它会返回hinstance.Hm,这不是一个好主意。那是一个倒票的吸引者。现在,只有不需要它的高代表性用户才能看到该信息。因为它确实包含其他有用的信息,请留下您的答案+1。
764F2CD9   74 0A            JE SHORT kernel32.764F2CE5
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\n", 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\n", ret );
        ret = 11;
    }
    HeapFree( GetProcessHeap(), 0, cmdline );
    return ret;
}