2012-03-26 8 views
4

Когда вы вызываете WinExec для запуска .exe, я получаю возвращаемое значение 0x21.
Согласно MSDN, возвращаемое значение, превышающее 31 (0x1F), означает, что функция выполнена успешно.
Но что это означает 0x21, почему он не возвратил мне другого значения?WinExec Return 0x21, но что именно это означает?

+1

По какой-либо причине вы не можете использовать 'CreateProcess'? – Konrad

+0

* Исторически * под win16 он перенастроил hinstance. –

ответ

9

Не полезно знать, что это значит. Это деталь реализации. Даже если бы вы знали, что это значит для этой версии, значение может измениться в следующей версии. Как программист, вас интересует только программирование против интерфейса, а не базовая реализация.

Однако, если вы действительно заинтересованы, я возьму вас через подход, который я бы предпринял для обратной инженерии функции. В моей системе, 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 

Конвенция вызова используется под Win32 является stdcall, который предписывает возвращаемые значения проводиться в EAX. В случае WinExec имеется только один выход из функции (0x764F2D2F). Трассировка оттуда, EAX устанавливается (по крайней мере, когда возвращение 0x21):

764F2D29 8BC6    MOV EAX,ESI 

Трассировка еще дальше назад, сам по себе ESI устанавливается от POP ESI, который выскакивает в верхней части стека в ESI. Значение этого зависит от того, что ранее было нажато в стек.В случае 0x21, это происходит при:

764F2CF5 6A 21   PUSH 21 

Сразу же после этого, JMP делается на POP ESI. Как мы дошли до PUSH 21, интересно только после вызова CreateProcess.

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 

Чтобы увидеть, как путь приведет вас к PUSH 21, наблюдать различные ветви. Первым происходит:

764F2CD0 74 27   JE SHORT kernel32.764F2CF9 

Это говорит, если CreateProcess возвращается 0, вызовите Win-Core-ErrorHandling. Значения возврата затем устанавливаются по-разному (0x2, 0x3 и 0xB - все возможные возвращаемые значения, если CreateProcess не удалось).

Следующая ветвь намного менее очевидно, перепроектировать:

764F2CD9 74 0A   JE SHORT kernel32.764F2CE5 

Что она делает для чтения адреса памяти, который, вероятно, содержит указатель на функцию (мы знаем это, потому что результат чтения называется позже на). Этот JE просто указывает, нужно ли вообще выполнять этот вызов. Независимо от того, сделан ли звонок, следующим шагом является вызов ZwClose (дважды). Наконец, возвращается 0x21.

Таким образом, один простой способ взглянуть на это, когда CreateProcess преуспевает, возвращается 0x21, в противном случае возвращаются 0x2, 0x3 или 0xB. Это не означает, что это единственные возвращаемые значения. Например, 0x0 также может быть возвращено из ветки на 0x764F2C53 (в этом случае ESI не используется одинаково). Есть еще несколько возможных возвращаемых значений, но я оставлю их для вас, чтобы заглянуть в себя.

Что я показал вам, как сделать очень мелкий анализ WinExec специально для возврата 0x21. Если вы хотите узнать больше, вам нужно больше толкнуть и попытаться понять с более высокого уровня, что происходит. Вы сможете узнать намного больше, просто нарушив функцию и пройдя через нее (таким образом вы сможете наблюдать за данными).


Еще один способ посмотреть на Wine source, где кто-то уже сделал всю тяжелую работу за вас:

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, я предполагаю, что, возможно, существует более внутренняя документация, которая делает ее более полезной в некотором роде.

+2

Yay для магических чисел: p – Deanna

+1

Интересно, спасибо, что прошли через него. – Konrad

+1

Это преданность делу! –

3

Кроме этого это означает успех, значение возвращаемого значения не определено. Возможно, он был выбран таким образом, чтобы устаревшие приложения хорошо работали с этим конкретным значением. Одно можно сказать наверняка: есть более важные вещи, о которых нужно беспокоиться!

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

0

EDIT: Этот ответ является неправильным, потому что результат в OP не является кодом ошибки. Я ошибочно подумал, что было сказано, что это код ошибки. Я по-прежнему думаю, что практическая информация ниже может быть полезна, плюс то, что может быть полезно увидеть, что может привести к неправильному предположению, поэтому я даю ей ответ.


Если вы установили Visual Studio (полный или экспресс-выпуск), то у вас есть инструмент под названием errlook, которая использует функцию FormatMessage API, чтобы сказать вам, что код ошибки или HRESULT означает значение.

В этом случае

Процесс не может получить доступ к файлу, так как другой процесс заблокировал часть файла.

Вы можете сделать это вручную, просмотрев файл <winerror.h>. Например, введите #include в исходном файле C++ в Visual Studio, затем щелкните правой кнопкой мыши и попросите его открыть заголовок. Где вы находите, что

// 
// 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. Функция ShellExecute может играть более красиво с Windows Vista и 7 User Access Control, и ее проще использовать, поэтому она обычно предпочтительнее.

+0

Downvoted, потому что это не код ошибки! –

+0

@Frederik: спасибо, я добавлю, что это неправильно. :-) –

+0

Хм, это была не очень хорошая идея. Это был аттрактор нисходящего потока. Теперь только пользователи высокой репутации, которые не нуждаются в этом, могут видеть эту информацию. –

Смежные вопросы