Skip to main content

Deep Dive to Windows, Part 4



Launched a process sample_Hello through WinDbg and observed following events:

ModLoad: 00400000 0041c000   Sample_Hello.exe
ModLoad: 77980000 77b00000   ntdll.dll
ModLoad: 76b10000 76c20000   C:\Windows\syswow64\kernel32.dll
ModLoad: 76d20000 76d67000   C:\Windows\syswow64\KERNELBASE.dll
ModLoad: 67fd0000 680ce000   C:\Windows\WinSxS\x86_microsoft.vc80.debugcrt_1fc8b3b9a1e18e3b_8.0.50727.6195_none_e4a70117006762dd\MSVCP80D.dll
ModLoad: 670e0000 67201000   C:\Windows\WinSxS\x86_microsoft.vc80.debugcrt_1fc8b3b9a1e18e3b_8.0.50727.6195_none_e4a70117006762dd\MSVCR80D.dll
ModLoad: 77050000 770fc000   C:\Windows\syswow64\msvcrt.dll
(3c0.1324): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=fb480000 edx=0008e3c8 esi=fffffffe edi=00000000
eip=77a20fab esp=0018fb08 ebp=0018fb34 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!LdrpDoDebuggerBreak+0x2c:
77a20fab cc              int     3

Process launched but execution halted with a Break instruction exception (please see highlighted line above). Why this happened?

This is due to the fact called “breaking into the debugger”.  We will see this later. Now let’s see how many threads are there in this state. I’m expecting 1 since my application is a single threaded application.

So, I’ve executed the command ~* on windbg.

0:000> ~*
.  0  Id: 3c0.1324 Suspend: 1 Teb: 7efdd000 Unfrozen
      Start: *** WARNING: Unable to verify checksum for Sample_Hello.exe
Sample_Hello!ILT+145(_wmainCRTStartup) (00411096)
      Priority: 0  Priority class: 32  Affinity: 3

Indeed I’ve a thread.  Let’s see the stack of the thread:

0:000> ~*kb

.  0  Id: 3c0.1324 Suspend: 1 Teb: 7efdd000 Unfrozen
ChildEBP RetAddr  Args to Child             
0018fb34 77a01383 7efdd000 7efde000 77a8206c ntdll!LdrpDoDebuggerBreak+0x2c
0018fcb0 779c52d6 0018fd24 77980000 7b14b7c0 ntdll!LdrpInitializeProcess+0x12cc
0018fd00 779b9e79 0018fd24 77980000 00000000 ntdll!_LdrpInitialize+0x78
0018fd10 00000000 0018fd24 77980000 00000000 ntdll!LdrInitializeThunk+0x10

So, after initialize process call there is a DebuggerBreak call.

Now I’ve executed the ‘g’ (go) and debugee will start running. Lets’s see:

Yes, Debugee is in running state:
Debuggee is running...

Since my program uses for user input to terminate so program is waiting for input. It is going to help me to see the state of the process.

Again I’ve used debugger break point to halt the application and now would like to see how many threads are there:

0:001> ~*
   0  Id: 3c0.1324 Suspend: 1 Teb: 7efdd000 Unfrozen
      Start: Sample_Hello!ILT+145(_wmainCRTStartup) (00411096)
      Priority: 0  Priority class: 32  Affinity: 3
.  1  Id: 3c0.14c4 Suspend: 1 Teb: 7efda000 Unfrozen
      Start: ntdll!DbgUiRemoteBreakin (77a1f85a)
      Priority: 0  Priority class: 32  Affinity: 3

Now we’ve two threads but my application is a single threaded application, so what’s the other thread?

Let’s see the stack:

   0  Id: 3c0.1324 Suspend: 1 Teb: 7efdd000 Unfrozen
ChildEBP RetAddr  Args to Child             
0018fa24 76bc7379 00000003 671f4aa0 00001000 kernel32!ReadConsoleInternal+0x15
0018faac 76b4f1b2 00000003 671f4aa0 00001000 kernel32!ReadConsoleA+0x40
0018faf4 67151b6a 00000003 671f4aa0 00001000 kernel32!ReadFileImplementation+0x75
0018fb88 671514c7 00000000 671f4aa0 00001000 MSVCR80D!_read_nolock+0x62a [f:\dd\vctools\crt_bld\self_x86\crt\src\read.c @ 233]
0018fbd8 67177da1 00000000 671f4aa0 00001000 MSVCR80D!_read+0x217 [f:\dd\vctools\crt_bld\self_x86\crt\src\read.c @ 93]
0018fc00 67180a7b 671f1d08 489faa4c 0018ff30 MSVCR80D!_filbuf+0x111 [f:\dd\vctools\crt_bld\self_x86\crt\src\_filbuf.c @ 136]
0018fc54 67fe6b2e 671f1d08 0018fd3f 0018fd4c MSVCR80D!fgetc+0x24b [f:\dd\vctools\crt_bld\self_x86\crt\src\fgetc.c @ 49]
0018fc64 67fe67c5 0018fd3f 671f1d08 489daae2 MSVCP80D!std::_Fgetc+0xe [f:\dd\vctools\crt_bld\self_x86\crt\src\fstream @ 37]
0018fd4c 67fe66ce 0018fe58 680c4950 00000000 MSVCP80D!std::basic_filebuf >::uflow+0xb5 [f:\dd\vctools\crt_bld\self_x86\crt\src\fstream @ 362]
0018fd64 67fe1018 00000000 680c4950 0018fdd0 MSVCP80D!std::basic_filebuf >::underflow+0x4e [f:\dd\vctools\crt_bld\self_x86\crt\src\fstream @ 341]
0018fd74 67fe1cb2 489daa7e 0018ff30 0018fe58 MSVCP80D!std::basic_streambuf >::sgetc+0x38 [f:\dd\vctools\crt_bld\self_x86\crt\src\streambuf @ 113]
0018fdd0 67fe0f57 00001300 489daa5e 0018fe2c MSVCP80D!std::basic_istream >::_Ipfx+0x102 [f:\dd\vctools\crt_bld\self_x86\crt\src\istream @ 113]
0018fdf0 68040f31 680c49a4 00000000 489da9e6 MSVCP80D!std::basic_istream >::sentry::sentry+0x47 [f:\dd\vctools\crt_bld\self_x86\crt\src\istream @ 86]
0018fe48 004115e6 680c49a4 0018ff2b 00000000 MSVCP80D!std::operator>> >+0x41 [f:\dd\vctools\crt_bld\self_x86\crt\src\istream @ 997]
0018ff30 004125b6 00000001 007d4778 007d57f0 Sample_Hello!wmain+0x66 [f:\fordebugging\sample_hello\sample_hello\sample_hello.cpp @ 28]
0018ff80 004123fd 0018ff94 76b233aa 7efde000 Sample_Hello!__tmainCRTStartup+0x1a6 [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 594]
0018ff88 76b233aa 7efde000 0018ffd4 779b9ef2 Sample_Hello!wmainCRTStartup+0xd [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 414]
0018ff94 779b9ef2 7efde000 7b14b514 00000000 kernel32!BaseThreadInitThunk+0xe
0018ffd4 779b9ec5 00411096 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70
0018ffec 00000000 00411096 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b

#  1  Id: 3c0.14c4 Suspend: 1 Teb: 7efda000 Unfrozen
ChildEBP RetAddr  Args to Child             
0051ff58 77a1f896 7b5db548 00000000 00000000 ntdll!DbgBreakPoint
0051ff88 76b233aa 00000000 0051ffd4 779b9ef2 ntdll!DbgUiRemoteBreakin+0x3c
0051ff94 779b9ef2 00000000 7b5db514 00000000 kernel32!BaseThreadInitThunk+0xe
0051ffd4 779b9ec5 77a1f85a 00000000 00000000 ntdll!__RtlUserThreadStart+0x70
0051ffec 00000000 77a1f85a 00000000 00000000 ntdll!_RtlUserThreadStart+0x1b

Thread 0 stack is known to me but what’s the thread 1. Actually the thread 1 is the debugger thread. This injects this (thread 1) thread to target process as part of break in command.  So the call was:

0051ff88 76b233aa 00000000 0051ffd4 779b9ef2 ntdll!DbgUiRemoteBreakin+0x3c

Since thread 1 is the active thread (marked with ‘.’) and ntdll!DbgBreakPoint is the last call in the stack, lets unassembled it:

0:001> uf ntdll!DbgBreakPoint
ntdll!DbgBreakPoint:
7799000c cc              int     3
7799000d c3              ret

Got it; this calls INT 3 (Interrupt 3). Execution freezes here. So we’ve used the term “breaking into the debugger” at the beginning. It says that user mode debugger can interrupt at any point of time to freeze the target process.  In response to this interrupt, OS raises a structured exception (Windows SEH) in the context of break-in thread and as result, first chance exception occurred with exception code 80000003 (first chance).

Happy Debugging...

Comments

Popular posts from this blog

Reversing char array without splitting the array to tokens

 I was reading about strdup, a C++ function and suddenly an idea came to my mind if this can be leveraged to aid in reversing a character array without splitting the array into words and reconstructing it again by placing spaces and removing trailing spaces. Again, I wanted an array to be passed as a function argument and an array size to be passed implicitly with the array to the function. Assumed, a well-formed char array has been passed into the function. No malformed array checking is done inside the function. So, the function signature and definition are like below: Below is the call from the client code to reverse the array without splitting tokens and reconstructing it. Finally, copy the reversed array to the destination.  For GNU C++, we should use strdup instead _strdup . On run, we get the following output: Demo code

XOR (Exclusive OR) for branchless coding

The following example shows the array reversing using the  XOR operator . No need to take any additional variable to reverse the array.   int main(int argc, _TCHAR* argv[]) { char str[] = "I AM STUDENT"; int length = strlen(str); for(int i = 0; i < ((length/2)); i++) { str[i] ^= str[length - (1+i)]; str[length - (1+i)] ^= str[i]; str[i] ^= str[length - (1+i)]; } cout << str << endl; return 0; } The above example is one of the uses of XOR but XOR comes in handy when we can do branchless coding  methods like butterfly switch etc. Sometimes this is very effective in speeding up the execution.  Let's see one of the uses of XOR in branchless coding. I am taking a simple example of Y = | X |.  Yes, I am generating abs of a supplied number. So, my function signature/definition in C++ looks like below: int absoluteBranch( int x) {     if (x < 0 ) {         return -x;     }     else {         retur

Power of Two

  I n this post will be discussing how to calculate if a number is a power of two or not. As an example, 8 is a power of two but the number 10 is not. There are many ways we can solve this. First , we will take an approach which is simple and iterative. In this case, we will calculate the power of two one by one and check with the supplied number. The below code illustrates it. bool isPowerofTwo(unsigned num) { auto y = 1; while (0 != y) { if (num == y) return true; if (num < y) return false; y <<= 1; } return false; } Second , assuming, the number is a 32-bit number, this is also an iterative solution. In this scenario, iterating all bits and counting the set bits. Any number which is a power of 2 will have only one bit set and the rest will be zeros. As an example, 8 in binary representation is 1000. Using this observation, we can implement an iterative solution. bool isPowerofTwo(unsigned num) { auto one_count = 0; for (auto index = 0; index < 32;