4

Microsoft documentation gives WinMain() as the entry point for a Windows program, but unlike DllMain() it seems to be a pure fiction arranged by the compiler-provided startup code.

I've looked at the output of a few Win32 compilers (32-bit and 64-bit) and in all cases the information passed to WinMain() was synthesised by the startup code and not based on any parameters passed to the entry point by the Windows loader. Also, all the samples I analysed - and all the examples I remember seeing on the 'net - used ExitProcess() even though a simple return from the entry point seems to have exactly the same effect.

Does anyone know of any documentation - official or otherwise - regarding the game rules for PE32(+) entry points?

2 Answers 2

8

Microsoft documentation gives WinMain() as the entry point for a Windows program

No, Microsoft's documentation doesn't give WinMain() as the entry point for a Windows program.

From the WinMain() documentation to which you linked above (emphasis mine) - "WinMain entry point [is] the user-provided entry point for a graphical Windows-based application... Depending on the programming framework, the call to the WinMain function can be preceded and followed by additional activities specific to that framework."

In other words, if you're building a native application, your compiler will likely build your executable file such that its framework initialization code is executed before your WinMain() function.

Does anyone know of any documentation - official or otherwise - regarding the game rules for PE32(+) entry points?

Yes, from the Microsoft PE and COFF Specification, the AddressOfEntryPoint field in the PE header is defined as "For program images, this is the starting address." It's this field that will typically point to the framework initialization code described above.

Note that despite AddressOfEntryPoint being the starting address of the program, the code at that address will be executed after TLS callback functions (also documented in the PE/COFF documentation) if they exist, and after statically loaded DLLs' DllMain() functions.

parameters passed to the entry point by the Windows loader

As explained here by @igor-skochinsky, "the registers at the entry point of PE file do not have defined values." However, as he points out, EAX often points to the AddressOfEntryPoint and EBX often points to the PEB.

You may want to refer to @Ange's Initial values documentation to find other unofficial register values at entry point.

1
  • Thanks for pointing out igorsk's post; if he says that there are no defined parameters then that is good enough for me, since he knows his stuff and his research is always very thorough. It seems that much of what we know about things going on under the hood (post-Pietrek/Schulman) we know only because of his excellent work... The reminder regarding TLS callbacks will be useful for people dealing with unknown packers and similar stuff.
    – DarthGizka
    Commented Dec 28, 2014 at 18:45
0

What do you mean by real PE entry point?

I think you are confused with WinMain and AddressOfEntryPoint.

WinMain is not the AddressOfEntryPoint they are different things.

AddressOfEntryPoint

Address of entry point, relative to image base, when executable file is loaded into memory. For program images, this is the starting address. For device drivers, this is the address of the initialization function. An entry point is optional for DLLs. When none is present this field should be 0.

AddressOfEntryPoint has no parameters it is simply the starting address of the executable. (except on Windows Vista+ maybe, I have seen that the PEB address is passed as a parameter by kernel32.BaseThreadInitThunk)

You are right. A simple RET from entry point would be enough to exit the process. But I guess that way you have to keep the stack balanced.

Have a look at Microsoft Portable Executable and Common Object File Format

PE File Format

2
  • Clarification: for DllMain(), the user-visible contract realised by compiler startup code is exactly the same as that for the real DLL entry point that is called by Windows, which is what's documented under DllMain() on MSDN. For WinMain() that may have been the case in 16-bit Windows but in 32-bit/64-bit Windows it is definitely not the case. I'm interested in finding out what's really going on at the process entry point, whether there are any dependable (documented) invariants or not, and whether there are any contracts that the entry point code needs to adhere to.
    – DarthGizka
    Commented Dec 28, 2014 at 17:30
  • My debugger tells me that EBX (32-bit) and RCX (64-bit) do indeed hold a pointer to the PEB while most other registers are equal to the entry point, on the system I'm currently playing with (Win 8.1 x64). But the only thing I can take away from that experiment is that the WinMain() contract does definitely not hold for the real entry point, at least not on this particular system. That's why I was trying to find out what we really now about the PE32 entry point...
    – DarthGizka
    Commented Dec 28, 2014 at 17:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.