#How do I detect if a windows executable has defined main or _wmain?
1 messages · Page 1 of 1 (latest)
When your question is answered use !solved or the button below to mark the question as resolved.
Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.
I wonder whether one can access the call stack in c++, and whether that helps in figuring out the name of the main function
Anyway, you might want to take a look at <stacktrace>
not unless you have debug symbols
I am talking about third party random exetutables, not your own recompiled executables
Ah, that's out of my scope. Sorry
if you're asking how to differentiate between console and GUI apps, you can check the subsystem field in the PE header
the Optional header at offset 68 contains a 2-byte subsystem field which will be 3 for terminal apps and 2 for GUI ones
supposedly
tested it with PE Bear and yeah it works
I think they're asking how to detect -municode (and whatever MSVC calls it)
look at the imports, if those are ansi then it's not unicode 😄
unless the c runtime is builtin statically
a console app can be written with
int main(int argc, char** argv)
or with
int _wmain(int argc, wchar_t** argv)
same goes for GUI programs
nope
let me check with fopen and fread at offset 68 with 2 bytes
Optional Header Windows-Specific Fields (Image Only)
The next 21 fields are an extension to the COFF optional header format. They contain additional information that is required by the linker and loader in Windows.
so this header here,
68/68
2
Subsystem
The subsystem that is required to run this image. For more information, see Windows Subsystem.
is this what you meant?
ok so I opened PE Bear, and the goddamn optional header is located starting from offset B0 somehow, and yes I found the field
This program is so
D O P E
I am trying to run hello world with wmain, I am getting linker errors with MinGW 64-bit saying that WinMain is an undefined reference
what linker flags do I need?
g++.exe -D__DEBUG__ -c main.cpp -o main.o -I"%CppIncludeDir0%" -I"%CppIncludeDir1%" -I"%CppIncludeDir2%" -I"%CppIncludeDir2%\c++" -O0 -g3 -std=c++14 -Wall -Wextra -Wpedantic -Weffc++ -Wvla -Wshadow -Wconversion -Wunused-result -Wswitch -Wswitch-default -Wswitch-enum -O0 -g3 -march=native -ftrapv -Wmain
main.cpp:609:15: warning: unused parameter 'argc' [-Wunused-parameter]
int wmain(int argc, wchar_t** argv)
^
main.cpp:609:31: warning: unused parameter 'argv' [-Wunused-parameter]
int wmain(int argc, wchar_t** argv)
^
g++.exe -D__DEBUG__ main.o -o Project1.exe -L"%LibDir0%" -L"%LibDir1%" -static-libgcc -lpthread
%LibDir1%\libmingw32.a(lib64_libmingw32_a-crt0_c.o): In function `main':
C:\crossdev\src\mingw-w64-v3-git\mingw-w64-crt\crt\crt0_c.c:18: undefined reference to `WinMain'
collect2.exe: error: ld returned 1 exit status
yeah but I realized you didn't mean main vs winmain but main vs wmain for unicode
sorry
Try -municode during both compilation and linking
It it doesn't work, tell your mingw version
Or use a real compiler
If you know any specific issues with it, tell what they are 
It's a single pass linker, delay loads are broken, the headers shipped with it are often incomplete
Mingw doesn't lock you to a specific linker, I use LLD with it. Are you saying single-pass linkers are bad in general, not only on windows?
Do you mean winapi headers, or which ones? I admit I haven't used winapi that much. What's missing from them?
Single pass are bad in general.
It lags behind in windows headers, and is generally less suited for windows stuff imo.
the culprit was that, the flag is needed not only during the compilation of each translation unit but also during linking
so now, let me check with PE Bear
both wmain binary and main binary show Optional header, subsystem 0x03
so, I found the first difference by hexdump diffing the binaries
the main binary has Optional Header, Entry Point equal to 1520,
and the wmain binay has Optional Header, Entry Point equal to 1500
What possible 4-byte values can be written in this pointer Entry Point ?
welp, testing some old executables shows me many diffent values for the Entry Point pointer
okay so with MinGW's objdump.exe I can see that my two hello world programs which have no optimizations and have debug symbols, are showing the function names which hint who is using wmain and who is using main
but for opaque third party binaries there's just assembly, no function names no nothing, there are no key C-string literals stored in some section that can leak if wmain or main is used
any other assembler algorithm patterns that can reveal when wmain runs? 
No idea 😛
how tf is there no tooling for inspecting this critical libc feature 😭
can ghidra decrypt the assembler and detect the argv conversion magic which main binary runs before main, but wmain doesn't?
i think u can check which calls are being made in the entry point, it will eventually call GetCommandLineA/W and WideCharToMultiByte
Holy sh*t yes, lemme check...
there are multiple ways to construct argv from wargv so u likely want to check if such behavior exists
I mean, there's one, it's called BestFit, documented in msdn right?
found one thing in the executable with main defined
will keep looking
however this thing here applies for console applications only, I need something more generic for GUI programs
Nope, even for wmain the same TSAppCompat thing shows GetEnvironmentStringsA, so that's not a deciding factor
maybe the compiler optimized out the main args completely, let me print them to force it to use them and retry
these are funcitons running directly in-memory, they do not touch kernel32.dll, they are not revealed by Process Monitor
I was so close goddamnit
what is this
so, try recompiling these
int main(int argc, char** argv)
{
}
and
int wmain(int argc, wchar_t** argv)
{
}
^ this one with -municode for compiling and linking
and see what your tooling reveals
I can't even get it to show me the answer manually, tf do you mean automation 
well what i mean is that are u trying to run this check on lots of binaries? or just a few that u can manually analyze
yes, the goal is to easily bulk analyze binaries, but I can't recognize hello world at the moment
did you try to recompile the 2 snippets and test manually?
the thing is i cant do that on a phone 
bruh
GET A COMPUTER
@iron cedar
bump
nope
you can grab the C compiler and produce the 2 programs from my snippets above
your computer broke?
yes
Read the header
Ah forget it I am not gonna read this entire forum
the headers don't show the answer, I already checked
YOOOOOOOOOOO
I FOUND THE ANSWER AT LAST
So now I need a script to programatically take in an executable name and return, does the library kernel32.dll contain a call to GetStartupInfoA or GetStartupInfoW
it also matters where the call is being made and how its used if u want to improve it further
do check the result of different crts in a disassembler
now that i think about it actually i doubt this is what u really need
I already suggested that days ago
i know, its a reminder to not rely only on the import table
!solved
Thank you and let us know if you have any more questions!
This thread is now set to auto-hide after an hour of inactivity
I mean yes, if the main function in the body programatically calls GetStartupInfoA and GetStartupInfoW then we are screwed, but I can at least check if both of these are used, and if so, print and error message
what if the program is packed and has no import table other than for GetProcAddress

