Точка входа WinMain - ассемблерный код выглядит так, как будто в точку входа не переданы аргументы

В настоящее время я играюсь с сборкой Win32.

Я уже некоторое время борюсь с точкой входа WinMain в сборке. Для меня есть одно странное различие между тем, что NASM и link.exe создали из моего рукописного ассма, и тем, что придумал MSVC.

1) код C(++) - просто еще один приветственный мир MessageBox

#include <Windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MessageBoxA(NULL, "Hello world", "Window title", MB_OK | MB_ICONEXCLAMATION);
}


2) Монтажный эквивалент

global _main
    extern  _MessageBoxA@16
    extern _ExitProcess@4

section .text
_main:
    push 0x30
    push wintitle
    push message
    push 0
    call _MessageBoxA@16

    push    0
    call    _ExitProcess@4

    section .data
message:
    db      'Hello, World', 0
wintitle:
    db      'Window title', 0


Техническая спецификация":
- ОС является 32-битной Win7
- Программа C++ была скомпилирована с MS VC++ 2013
- Программа сборки была составлена ​​с nasm -fwin32 msgbox.asm, а затем связано с link /nodefaultlib /subsystem:windows msgbox.obj kernel32.lib user32.lib -entry:main


Теперь возникает актуальный вопрос.

Когда я разобрал их с OllyDbg 2.01, вот что я увидел:

1) версия C++
введите описание изображения здесь

2) версия ASM:
введите описание изображения здесь



Теперь, если мы посмотрим на окно стека, похоже, что Windows фактически не передала правильные аргументы моей точке входа в сборку. Перед возвратом в ntdll есть только два целых числа мусора, в отличие от версии C++, где присутствуют все четыре параметра.

Для меня это проблема, так как я хотел бы получить (в другой сборочной программе) переменную hInstance внутри точки входа. С помощью [EBP+8] дает мне мусор, о котором я говорил выше, вместо правильного значения hInstance.

Любая помощь с благодарностью.

2 ответа

Решение

WinMain точка входа в ваш код C++ вызывается библиотекой времени выполнения C, а не Windows.

Фактическая подпись точки входа Win32

void __stdcall NoCRTMain(void);

Вы можете получить командную строку, используя GetCommandLine и если вам нужно преобразовать его в формат argc/argv, вы можете использовать CommandLineToArgvW,

Ты можешь получить hInstance позвонив GetModuleHandle с аргументом, установленным в NULL, (Обратите внимание, что в Win32, в отличие от 16-битной Windows, HINSTANCE а также HMODULE это одно и то же.)

Эти четыре аргумента предоставляются средой выполнения, а не операционной системой. Если вы посмотрите на [esp] значение в точке входа, версия сборки возвращается к kernel32ОС, а версия C++ возвращается к коду времени выполнения вашего модуля.

Откройте версию C++ с OllyDbg на реальной точке входа, и вы увидите много кода инициализации, такого как синтаксический анализ аргументов, переменные TLS и т. Д. Кроме того, сравните размер двоичных файлов, и вы увидите около 4 КБ против 30-90 кб.

Другие вопросы по тегам