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

I am currently playing with Win32 build.

I have been struggling with WinMain entry point into assembly for a while now. There's one strange one - for me, the difference between NASM and link.exe is produced from my handwritten asm and what MSVC came up with.

1) C (++) Code is just another world of Greeting 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) assembly equivalent

global _main
    extern  _MessageBoxA@16
    extern _ExitProcess@4

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

    push    0
    call    _ExitProcess@4

    section .data
    db      'Hello, World', 0
    db      'Window title', 0


Technical "specification":
- OS - 32-bit Win7
- C ++ program was compiled with MS VC ++ 2013
- Build program compiled with nasm -fwin32 msgbox.asm

and then linked withlink /nodefaultlib /subsystem:windows msgbox.obj kernel32.lib user32.lib -entry:main

Now here's a topical question .

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

1) C ++
enter image description here

version 2) ASM version:
enter image description here

Now, if we look at the stack window, it looks like Windows did not actually pass the correct arguments to my assembly entry point. There are only two garbage chains before returning to ntdll, unlike the C ++ version where all four parameters are present.

This is a problem for me as I would like to get (in a different assembly) the hInstance variable inside the entry point. Usage [EBP+8]

gives me the garbage I mentioned above instead of the correct hInstance value.

Any help is greatly appreciated.


source to share

2 answers

The entry point WinMain

in C ++ code is called by the C runtime library, not Windows.

Win32 entry point actual signature

void __stdcall NoCRTMain(void);


You can get the command line using GetCommandLine

, and if you need to convert it to argc / argv format, you can use CommandLineToArgvW


You can get hInstance

it by calling GetModuleHandle

with the argument set to NULL

. (Note that in Win32, as opposed to 16-bit Windows, hInstance


are the same thing.)



These four arguments are provided by the runtime, not the operating system. If you look at the value [esp]

at the entry point, the assembly version falls back to kernel32

, that is, the OS, and the C ++ version falls back to your module's execution code.

Open the C ++ version with OllyDbg at a real entry point and you will see a lot of initialization code like argument parsing, TLS variables, etc. Also compare the size of the binaries and you will see about 4kb versus about 30-90kb.



All Articles