I have an executable without debug symbols, and I want to get to its' main() function.

What I do is putting breakpoint at $exentry address, but this address of some CRT-initialization. To get to the main() I need to single-step until I see some changes in working application.

Is there any other procedure to skip CRT code?

1 Answer 1


no there is no shortcut loader knows only about the $exentry because it is an embedded pointer in the PeHeader
from there to main is mostly traversed by either single stepping or observing and recognizing known functions by practice and experience
the crt code is fairly common and the source for crt is available in crt folder of any visual studio installation (this will help if you have the binary with debug info

if the binary is stripped or built without debuginfo in release mode crt src wont help you pinpoint the main()

in those case you should be able to recognize certain standard calls that the crt is going to make for example it would normally call kernel32!GetCommandLineXXXX settig a bp on that function brings you closer to the main() another function you can set a breakpoint is kernel32!GetEnvironemStringXXXX and then set hardware breaks on the results once you have hit these breakpoints you can you can use the standard prototype of main int main (int argc , char **argv , char* envp) construct to identify your main

:\>cdb -c "bp $exentry;g;bp kernel32!GetCommandlineA;g;g poi(@esp)" hell.exe

0:000> cdb: Reading initial command 'bp $exentry;g;bp kernel32!GetCommandlineA;g;g poi(@esp)'
Breakpoint 0 hit
Breakpoint 1 hit
eax=002b36d8 ebx=7ffdf000 ecx=002b47e8 edx=002b4813 esi=00000000 edi=00000000
eip=01314082 esp=0024f9b0 ebp=0024f9e4 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
01314082 a3c4933201      mov     dword ptr [image01310000+0x193c4 (013293c4)],ea
x ds:0023:013293c4=00000000

the same area and the distance between exec_main and getcommandline function as an image of ollydbg debugging the same executable

enter image description here

the same src built with debuginfo /Zi msvc compiler and snap shotted enter image description here

to get more nearer you can employ the int argc you execute the binary so you know how many arguments you passed if you passed no arguments to the binary then int argc will be equal to 1 if you passed 8 arguments int argc will be equal to 9

with that in mind once you reached the breakpoint as enumerated above you can run a loop that enumerates the int argc in stack

bp $exentry
bp kernel32!GetCommandLineA
g poi(@esp)
.while(@$t0= 0) {
.if ( poi(@esp) == 1) {r $t0 = 1} .else { r $t0 = 0}

result of running the script notice the address in screen shot above you have just one call to step to the wrapper for main()

cdb -c "$$>a< findwmain.txt" hell.exe

0:000> cdb: Reading initial command '$$>a< findwmain.txt'
Breakpoint 0 hit
Breakpoint 1 hit

eax=00000000 ebx=7ffd3000 ecx=00461228 edx=00461228 esi=00000000 edi=00000000
eip=000a40b5 esp=0034fb5c ebp=0034fb94 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
000a40b5 e8e4420000      call    image000a0000+0x839e (000a839e)

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.