Search code examples
cwinapivisual-c++assemblyentry-point

WinMain entry point - assembly code looks as if there were no arguments passed to entry point


I'm currently playing around with Win32 assembly.

I've been struggling with the WinMain entry point in assembly for some time now. There's one bizarre - to me - difference between what NASM & link.exe produced from my hand-written asm and what MSVC has come up with.

1) The C(++) code - just another MessageBox hello world

#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) The assembly equivalent

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


Technical "specification":
- The OS is a 32bit Win7
- The C++ program has been compiled with MS VC++ 2013
- The assembly program has been compiled with nasm -fwin32 msgbox.asm, then linked with link /nodefaultlib /subsystem:windows msgbox.obj kernel32.lib user32.lib -entry:main


Now here comes the actual question.

When I disassembled these with OllyDbg 2.01, this is what I saw:

1) C++ version
enter image description here

2)ASM version:
enter image description here



Now, if we take a look at the stack window, it looks as if Windows didn't actually pass the right arguments to my assembly entry point. There are just two garbage integers before a return to ntdll, as opposed to the C++ version, where all four parameters are present.

This is a problem for me as I would like to obtain (in another assembly program) the hInstance variable inside the entry point. Using [EBP+8] gives me the garbage I've mentioned above instead of the right hInstance value.

Any help is greatly appreciated.


Solution

  • The WinMain entry point in your C++ code is called by the C runtime library, not by Windows.

    The actual Win32 entry point signature is

    void __stdcall NoCRTMain(void);
    

    You can obtain the command line using GetCommandLine and if you need to convert it to argc/argv format you can use CommandLineToArgvW.

    You can get hInstance by calling GetModuleHandle with the argument set to NULL. (Note that in Win32, unlike 16-bit Windows, HINSTANCE and HMODULE are the same thing.)