Published by OpenTask, Republic of Ireland

Copyright © 2009 by OpenTask

 

DLL Injection DebugWare: An Anatomy of Needle © Kapildev Ramlal

Modeling CPU Spikes © Konstantin Chebotarev and Dmitry Vostokov

All other articles in this issue © Dmitry Vostokov

 

All rights reserved.

 

 

Debugged! MZ/PE: MagaZine for/from Practicing Engineers

                                                                           

Volume 1, Issue 2, June 2009

           

            Welcome to the second issue of Debugged! MZ/PE magazine! After publishing the first issue some engineers asked why we chose MZ/PE abbreviation. This is because ‘MZ’ is the first 2 bytes of every MS-DOS executable and ‘PE’ is the signature of the Windows program header that follows. Recall that we can launch every Windows program in MS-DOS and the output will be “This program cannot be run in DOS mode”. If we load any program into WinDbg as a crash dump file we can inspect its file contents or we can use any hex editor for this purpose:

 

MZ-PE-WinDbg.png

 

 

 


Fault Injection: A New Perspective

Dmitry Vostokov, 15th June 2009
http://www.dumpanalysis.org

 

 

Why should we be interested in constructing (or modeling) software defects? Besides fun and developing debugging exercises there is a scientific side to it: we can construct software bugs to check hypotheses when troubleshooting and debugging complex and hard to reproduce issues. The closest term is called “fault injection”. When working on this issue I ac­cidentally discovered this now out-of print book published more than 10 years ago:

 

SoftwareFaultInjection_book.jpg

 

Software Fault Injection:

Inoculating Programs Against Errors

ISBN: 978-0471183815

 

Software defect construction is a more general term than fault injection. The latter is used for testing but we want to simulate bugs and abnormal system conditions to study debugging and memory dump analysis techniques or to build reproduction environments. In this issue, Kapildev Ramlal, a senior Citrix escalation engineer, recollects his experience with DLL injection tools he wrote to effec­tively and efficiently debug numerous problems in ter­minal services environments. Then Konstantin Chebotarev, a Citrix development analysis engineer, shows us how to construct a CPU spike and finally I discuss how to model a runaway exception handling.

 

There are many tools that inject faults, for example NotMyFault sysinternals tool[1]. It is very useful for studying crash dump analysis of kernel memory dumps and minidumps. Another use for these tools is to check certain debugging configurations like a postmortem debugger or WER settings are set up correctly. Typical example for user space is TestDefaultDebugger package[2]. Generalizing above, we can say that injecting bugs helps to test troubleshooting methods and tools. This is what I call metatroubleshooting, troubleshooting and debugging troubleshooting and debugging tools (DebugWare).

 

Creating software defects deliberately is entertaining and has great educational value for understanding internals and doing deep down debugging. I’m currently working on the following title:

 

Software Defect Construction:

Simulation and Modeling of Software Bugs ISBN: 978-1906717759

 

The book will cover all spectrum of software faults including kernel space bugs, implementation and design defects, provide debugging suggestions and compilations of resources.

 

 


DLL Injection DebugWare: An Anatomy of Needle

Kapildev Ramlal, 1st June 2009
http://www.mindarray.org

 

When debugging software sometimes we’re faced with challenging and complex problems, forc­ing us to deviate from the traditional path and create new and clever ways to catch the bug. Some cases require intense research on the software component being debugged, including the lower level API’s that it utilizes. In Windows debugging, we are referring to the Windows API, however this can even go as far as an application specific API in some cases (although in most cases appli­cation symbols are not available).

 

So in considering the architecture of an application that is being debugged, one key point here is that the application will at some level utilize the Windows API. In C/C++ programming, these API’s are typically exposed by func­tion calls exported from DLL’s.

 

In Windows, each process file starts with a PE format header which has several sections used for various pur­poses[3].

 

One of these sections is Import Address Table (IAT). This table contains the list of DLL modules that the ex­ecutable links against and calls functions from. It also contains the function name and relative address of the function within the imported module. Leveraging the knowledge of how this works, the imported function ad­dress can be hooked to point to a different function – one that can be used for debugging, such as printing out the function parameters and return code. It’s a great concept and one that has been used for years within several ver­sions of Windows. It’s not the only way to implement hooking in Windows, as there are also other mechanisms such as the SetWindowsHookEx API.

 

So we have a problematic EXE, and need to figure out what it is doing and if the function calls within it are working. To be more specific, we want to see if the Windows function calls are working. For example, we fig­ure out that it is the EnumPrinterDrivers() function that is under suspicion, and we would like to dig deeper into its parameters and return code. Timing is critical for this problem, so any interception from a debugger such as WinDbg or NTSD causes the problem to subside…

We decide to hook the EnumPrinterDrivers() call to print out the debug information… How would we get our code loaded into the problem EXE to be hooked?

 

The most common method would be to create a DLL which can be loaded by, or injected into the process being debugged. It’s really not as difficult as one would imagine because a DLL is very similar to an EXE and we just need to supply it with the appropriate entry point. Here is a sample skeleton that can be used to flesh out a real work­ing DLL:

 

#include <Windows.h>

 

HWND g_hMod = 0;

 

#ifdef __cplusplus // If used by C++ code,

extern "C"// we need to export the C interface

#endif

 

 

// Entry point for DLL (main function for DLL)

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)

{

    //Check load reason

    switch(ul_reason_for_call)

    {

       case DLL_PROCESS_ATTACH:

       {

  // Eliminate un-necessary overhead...

  DisableThreadLibraryCalls(hModule);

  //Save the handle to the DLL for later use

         g_hMod = (HWND)hModule;

         break;

       }

 

       case DLL_PROCESS_DETACH:

       {

         break;

       }

 

       default:

         break;

    }

    return TRUE;

}

#ifdef __cplusplus

}

#endif

 

Very simple. So we see that there’s a case statement when the DLL gets attached to the process and another for when it gets detached. That gives us a good opportunity to plant our hook, and another opportunity to unhook and cleanup our tracks. We can include our hook code in sepa­rate files in the DLL project, and then write our own hook functions that match the exact signature as the function being hooked. Keep in mind that Microsoft typedef’s a lot of their API’s, so don’t forget to check if an API really expands to an ANSI or UNICODE version ending with “A” or “W” (OutputDebugStringA vs. OutputDebug StringW). Our hook function signature needs to match exactly. Detailed instructions on creating hook functions are documented in Windows via C/C++ book by Jeffrey Richter and Christophe Nasarre (ISBN 978-0735624245).

So having a DLL, how do we invade the remote process being debugged and get our DebugWare DLL loaded? Well we have a few methods we can choose, and each comes with its own caveats.

 

The easiest method to inject a DLL is by using the regi­stry. Simply edit the “AppInit_DLLs” value under HKLM\Software\Microsoft\WindowsNT\CurrentVersion\Windows and add the hook DLL to the list. The path to the DLL must not contain spaces and an accompanying value, LoadAppInit_DLLs of REG_DWORD type must also be created (under the same key) with a value set to 1. As long as the process being debugged is linked against user32.dll (like all GUI based apps) then this method should work. One major thing to consider is that all GUI apps will load the hook DLL.    

 

Another method is by using SetWindowsHookEx me­thod. This method uses the Windows API (generally for hooking window procedure message calls) called SetWindowsHookEx, by specifying a DLL handle as the 3rd parameter which causes the DLL to get loaded indi­rectly by the processes being hooked. This method is use­ful for GUI DebugWare applications.

 

We can also trick the process by thinking that it’s loading one of its own DLL’s (the Trojan DLL approach) or we can spawn the process being debugged as a child process and leverage the CreateProcess API to perform injection. These methods are discussed elsewhere (such as in Windows via C/C++ book), so we won’t go into more de­tails here.

 

My favorite method which we discuss here in details is a method of DLL injection using remote threads. Yes it requires some understanding of several architectural con­cepts, but it is quite powerful. The beauty of this tech­nique lies within the CreateRemoteThread API. We simply spawn a new thread in the process being debugged, and have that new thread to load the DLL being injected. In fact, we’ve once come across a problem so unique, that it has actually pushed me far enough to create my own DLL injection utility called Needle.

 

We’ll go ahead and share some of the core ingredients that make Needle pierce.

 

Get Debug Privileges

 

Needle doesn’t require debug privileges to inject all processes, but for some system processes it might be re­quired. Here’s some code that shows how to do this:

 

bool NEEDLE::TweakPrivilege(TCHAR * pszPrivilege, BOOL bEnabled)

{

    TOKEN_PRIVILEGES tp = {0};

    LUID luid;

    //Handle of token to adjust

    HANDLE hToken = 0;

 

if (!LookupPrivilegeValue(NULL, pszPrivilege,

&luid))       

    {

this->DebugTrace(TEXT("NEEDLE: Failed to lookup privelege value. Error code: "), GetLastError());

       return false;

    }

 

    //Retrieves token from current process

    if(!OpenProcessToken(GetCurrentProcess(),

TOKEN_ADJUST_PRIVILEGES, &hToken))

    {

this->DebugTrace(TEXT("NEEDLE: Failed to retrieve token handle. Error code: "), GetLastError());

       return false;

    }

 

    tp.PrivilegeCount     = 1;

    tp.Privileges[0].Luid = luid;

    if (bEnabled)

    {

tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    }

    else

    {

       tp.Privileges[0].Attributes = 0;

 

// Enable the privilege or disable all privileges.

 

       if ( !AdjustTokenPrivileges(

              hToken,

              FALSE,

              &tp,

              sizeof(TOKEN_PRIVILEGES),

              (PTOKEN_PRIVILEGES) NULL,

              (PDWORD) NULL) )

       {

this->DebugTrace(TEXT("NEEDLE: Error

adjusting token privelege: "), GetLastError());

           CloseHandle(hToken);

    return false;

       }

 

       if (GetLastError() ==

    ERROR_NOT_ALL_ASSIGNED)

 

       {

this->DebugTrace(TEXT("NEEDLE: The token

does not have the requested privelege"), 0);

    CloseHandle(hToken);

    return false;

       }

       CloseHandle(hToken);

       return true;

    }

 


Grab the Process ID of the process being debugged

 

The Windows Terminal Services API exposes a nice func­tion that allows easy process enumeration, where the re­sults are stored in a neat array which can be easily looped to walk the results. It’s called WTSEnumerateProcesses(). After the PID is obtained, we can then proceed to get the proc address of the LoadLibrary function, and then open a handle to the remote process.

 

BOOL NEEDLE::GetPID(TCHAR * pProcName)

{

    //First enumerate all processes on the system

    if(!WTSEnumerateProcesses(

   WTS_CURRENT_SERVER_HANDLE, 0, 1,

          &this->m_pWtsPInfo, &this->m_dwCount))

    {

this->DebugTrace(TEXT("NEEDLE: Enumerating

    processes failed! Error code: "),     

    GetLastError());

       return FALSE;

    }

 

    //Now parse processes and find Application.exe

    for(unsigned int c=0; c<this->m_dwCount; c++)

    {

       //Find Application.exe

       if(!lstrcmpi(

      this->m_pWtsPInfo[c].pProcessName,

pProcName))

       {

           //Use PID to open handle to process

           return this->m_pWtsPInfo[c].ProcessId;

       }

    }

 

    this->DebugTrace(TEXT("NEEDLE: Failed to match

       process name with enumerated processes!"),   

       GetLastError());

    //If we arrived here, then we failed

    return FALSE;

}

 

Get the LoadLibrary method

 

We need to extract the address of the LoadLibrary function that is specific to the LoadLibrary version we need to use. For example, LoadLibraryW vs.

LoadLibraryA.

 

Example:

 

    this->m_hKern32 =

GetModuleHandle(TEXT("kernel32.dll"));

    if(!this->m_hKern32) return false;

 

#ifdef _UNICODE

    this->m_pLoadLib = (PVOID) GetProcAddress(

        this->m_hKern32, "LoadLibraryW");

#else

    this->m_pLoadLib = (PVOID) GetProcAddress(

        this->m_hKern32, "LoadLibraryA");

#endif

    if(!this->m_pLoadLib) return false;

     

 

Open a handle to the remote process

   

Since we’ve obtained the PID, we can open a handle to the remote process using OpenProcess. Instead of using PROCESS_ALL_ACCESS we can specify the granular flags such as

PROCESS_CREATE_THREAD| PROCESS_VM_OPERATION| PROCESS_VM_WRITE.

 

this->m_hProcess =  

   OpenProcess(PROCESS_CREATE_THREAD|

     PROCESS_VM_OPERATION|PROCESS_VM_WRITE,

     0, iPID);

 

The serum is getting loaded (Injection time)

 

After obtaining the remote process’ handle, we then proceed to allocate memory in the remote process to store the path to the injected DLL, and then write that path into the processes address space before creating the remote thread.

 

Example:

 

    //First we need to allocate memory in the remote

    process for our string

    this->m_pBaseAddr =

VirtualAllocEx(this->m_hProcess,

    0, this->m_dwModLen,  

    MEM_RESERVE|MEM_COMMIT,

           PAGE_READWRITE);

    if(!this->m_pBaseAddr)

    {

       this->DebugTrace(TEXT("NEEDLE: Failed to

allocate memory in remote process! Error code: "), GetLastError());

       return 0;

    }

             

    if(!WriteProcessMemory(this->m_hProcess,

(LPVOID)this->m_pBaseAddr, (LPCVOID)pszModPath, this->m_dwModLen, 0))

    {

       this->DebugTrace(TEXT("NEEDLE:

    WriteProcessMemory Failed!

    Error code: "), GetLastError());

       return 0;

    }

 

    // Now let us inject Application.exe

    // with our module

    if(!CreateRemoteThread(this->m_hProcess, 0, 0,  

  (LPTHREAD_START_ROUTINE)this->m_pLoadLib,  

  this->m_pBaseAddr, 0, 0))

    {

       this->DebugTrace(TEXT("NEEDLE: Failed to

    create remote thread! Error code: "),  

    GetLastError());

       return 0;

    }

    else

    {

       this->DebugTrace(TEXT("NEEDLE: Successfully

    created remote thread!"),

    GetLastError());

       return true;

    }

 


Bringing it all together

 

We’ve seen firsthand what makes Needle work. Now when cornered with a complex problem, we can consider writing a hook DLL to get more insights, and using DLL injection to get the hook DLL loaded into the remote process. We have seen how writing a DLL is easy, and implementing hooks within it really depends on our creativity and the situation at hand.

 

Developing a DLL injection utility like Needle is simple using the points outlined in this article, which involves using the following Windows API’s (OpenProcess,

VirtualAllocEx, WriteProcessMemory,

CreateRemoteThread).

 

Some gotcha’s that we encountered while developing Needle

 

It is helpful to call CreateProcess function and create the process being debugged suspended, giving a perfect op­portunity to inject the debug DLL. Be sure to cleanup any memory allocated by the API’s used to inject the remote process.

 

It is tricky to inject Windows services. We believe this de­pends on the point in time when the injection is at­tempted, since the service process is managed by the Service Control Manager.

 

CreateRemoteThread fails when attempting to run against processes which exist in a separate session. There is a way around this using an undocumented Microsoft API, but we won’t go into the details of that here.

 

 

 

 

 

Modeling CPU Spikes

Konstantin Chebotarev and

Dmitry Vostokov, 25th June 2009
http://support.citrix.com

 

 

Once we were discussing various ways to save memory dumps during high CPU consumption and both of us independently had an idea about writing such a small tool which allows to model different types of CPU load with different number of threads and different priorities. Because this tool can help people to understand CPU spike issues and play with dif­ferent scenarios we decided to write an article for this magazine issue.

 

Cpuload tool was created usign MFC framework. Almost all our tools are created with the help of MFC instead of raw Win32 API to save developing time. First, we briefly discuss the code we added to MFC skeleton. Most of error handling is omitted for clarity there. Then we show the tool in action, and finally, show it internals from the debugger point of view (WinDbg).

 

The tool dialog resource is very simple. It consists from a slider to dynamically adjust CPU load and a static field to show CPU load percentage as a number:

 

cpuload1.png

 

cpuload2.png

 

The dialog initialization code sets realtime priority level for the current thread to boost GUI response. Because it is relative to the thread priority class (normal by default) this doesn’t freeze the system even on a uniprocessor machine.  We need a good timer to model CPU balance so we are goimg to use the multimedia timer and set its resolution to 1 millisecond. Then we query the number of processors and call a function to create a CPU spiking thread for each processor.

 

BOOL CcpuloadDlg::OnInitDialog()

{

    CDialog::OnInitDialog();

// …

 

    SetThreadPriority(GetCurrentThread(),

        THREAD_PRIORITY_TIME_CRITICAL);

 

    MMRESULT res=timeBeginPeriod(1);

 

    SYSTEM_INFO SystemInfo;

    GetSystemInfo(&SystemInfo);

    CPU_Num = SystemInfo.dwNumberOfProcessors;

 

    for(int i=0;i<CPU_Num;++i)

    {

        CreateCPUSpiking(i);

    }

 

    return TRUE;

}

 

The following MFC code handles slider events and should be self-explanatory for MFC developers. If you don’t use MFC then after any slider move cpuval variable (int) is set to the value between 0 and 100:

 


CcpuloadDlg::CcpuloadDlg(CWnd* pParent /*=NULL*/)

    : CDialog(CcpuloadDlg::IDD, pParent)

      , m_CPU_val(0)

{

    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

}

 

void CcpuloadDlg::DoDataExchange(CDataExchange* pDX)

{

    CDialog::DoDataExchange(pDX);

    DDX_Control(pDX, IDC_CPULOAD_SLIDER, mSlider);

    DDX_Text(pDX, IDC_CPU_PERCENT, m_CPU_val);

}

 

BEGIN_MESSAGE_MAP(CcpuloadDlg, CDialog)

    ON_WM_SYSCOMMAND()

    ON_WM_PAINT()

    ON_WM_QUERYDRAGICON()

    //}}AFX_MSG_MAP

    ON_WM_HSCROLL()

END_MESSAGE_MAP()

 

void CcpuloadDlg::OnHScroll(UINT nSBCode, UINT nPos,

                            CScrollBar* pScrollBar)

{

    if(nSBCode==TB_THUMBTRACK)

    {

       m_CPU_val=cpuval=nPos;

       UpdateData(FALSE);

       CDialog::OnHScroll(nSBCode, nPos,

          pScrollBar);

    }

}

 

The function that creates spiking threads also sets their thread affinity (assigns a unique processor for each thread):

 

void CreateCPUSpiking(int CPU_idx)

{

    DWORD ThreadID;

    HANDLE hThread;

 

    hThread=::CreateThread(NULL,0,SpikingThread,

                           NULL,0,&ThreadID);

 

    DWORD_PTR mask=1<<CPU_idx;

    SetThreadAffinityMask(hThread,mask);

}

 

Thread routine that runs thread code sleeps appropriate amount of milliseconds necessary to model CPU load:

 

DWORD WINAPI SpikingThread(LPVOID lpParameter)

{

    double a=1.1;

    DWORD time1=timeGetTime();

    DWORD time2;

    DWORD dt=100; // time to loop in milliseconds

    DWORD ts;    // time to sleep in milliseconds

 

    do

    {

       a=a+0.1; // some dummy code to make CPU busy

       a=a-0.1; //

       time2=timeGetTime();

       if((time2-time1) > dt) // if time to loop

      // finished calculate new times

       {

           dt=cpuval*10; ts=1000-dt;

           Sleep(ts);

           time1=timeGetTime();

       }

    }

    while(true);

      

    return 0;

}

 

This code models CPU load almost exactly and its value corresponds to one that we see in Task Manager (all pictures were taken from 2 processor PC running x64 Windows Server 2008):

 

cpuload3.png 

 

However 100% is not attainable when Task Manager is running because it eats approximately 1% of CPU time:

 

cpuload4.png

Other processes can eat CPU too, for example, this screenshot was taken while Windows Media Player was playing a CD (wmplayer.exe) with graphical animation turned on that ate csrss.exe time too:

 

cpuload5.png 

 

In order to see what’s inside cpuload process we set CPU load to 100% and noninvasively attached WinDbg to it:

 

0:000> ~*k

 

.  0  Id: 710.ec4 Suspend: 1 Teb: 7efdd000 Unfrozen

ChildEBP RetAddr 

0017fba0 778a67f0 USER32!NtUserGetMessage+0x15

0017fbbc 00510211 USER32!GetMessageW+0x33

WARNING: Stack unwind information not available. Following frames may be wrong.

0017fbe8 0051173c cpuload+0x110211

0017fbf4 0051031f cpuload+0x11173c

0017fc00 00535ea5 cpuload+0x11031f

0017fc28 00515561 cpuload+0x135ea5

0017fc94 004f814d cpuload+0x115561

0017fe84 006a43b2 cpuload+0xf814d

0017fea8 006a42a8 cpuload+0x2a43b2

0017fec0 00626d0f cpuload+0x2a42a8

0017ff80 00626a4d cpuload+0x226d0f

0017ff88 775de4a5 cpuload+0x226a4d

0017ff94 77eecfed kernel32!BaseThreadInitThunk+0xe

0017ffd4 77eed1ff ntdll!__RtlUserThreadStart+0x23

0017ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

 

   1  Id: 710.994 Suspend: 1 Teb: 7efda000 Unfrozen

ChildEBP RetAddr 

02e7ff88 775de4a5 WINMM!_alldiv+0x4d

02e7ff94 77eecfed kernel32!BaseThreadInitThunk+0xe

02e7ffd4 77eed1ff ntdll!__RtlUserThreadStart+0x23

02e7ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

 

   2  Id: 710.d20 Suspend: 1 Teb: 7efd7000 Unfrozen

ChildEBP RetAddr 

WARNING: Stack unwind information not available. Following frames may be wrong.

02f7ff88 775de4a5 cpuload+0xf87cf

02f7ff94 77eecfed kernel32!BaseThreadInitThunk+0xe

02f7ffd4 77eed1ff ntdll!__RtlUserThreadStart+0x23

02f7ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

 

We deliberately not applied symbol files for cpuload to show real life CPU spike scenario when symbol files are not available for 3rd-party software vendor modules. We see that threads 1 and 2 consumed plenty of CPU time in user mode relative to their life span:

 

0:000> !runaway f

 User Mode Time

  Thread       Time

   1:994       0 days 0:05:06.089

   2:d20       0 days 0:04:45.076

   0:ec4       0 days 0:00:00.156

 Kernel Mode Time

  Thread       Time

   0:ec4       0 days 0:00:00.452

   2:d20       0 days 0:00:00.062

   1:994       0 days 0:00:00.015

 Elapsed Time

  Thread       Time

   0:ec4       0 days 0:18:56.449

   2:d20       0 days 0:18:56.143

   1:994       0 days 0:18:56.143

 

So we have all information to diagnose Spiking Thread memory dump analysis pattern pointing to cpuload module[4]. Notice also that even noninvasive attach suspended threads and real CPU load becomes 0%. To resume the program we use ~m WinDbg command:

 

0:000> ~*m

 

Then we can randomly catch our thread stack traces:

 

0:000> ~*k

 

.  0  Id: 710.ec4 Suspend: 0 Teb: 7efdd000 Unfrozen

ChildEBP RetAddr 

0017fba0 778a67f0 USER32!NtUserGetMessage+0x15

0017fbbc 00510211 USER32!GetMessageW+0x33

WARNING: Stack unwind information not available. Following frames may be wrong.

0017fbe8 0051173c cpuload+0x110211

0017fbf4 0051031f cpuload+0x11173c

0017fc00 00535ea5 cpuload+0x11031f

0017fc28 00515561 cpuload+0x135ea5

0017fc94 004f814d cpuload+0x115561

0017fe84 006a43b2 cpuload+0xf814d

0017fea8 006a42a8 cpuload+0x2a43b2

0017fec0 00626d0f cpuload+0x2a42a8

0017ff80 00626a4d cpuload+0x226d0f

0017ff88 775de4a5 cpuload+0x226a4d

0017ff94 77eecfed kernel32!BaseThreadInitThunk+0xe

0017ffd4 77eed1ff ntdll!__RtlUserThreadStart+0x23

0017ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

 

   1  Id: 710.994 Suspend: 0 Teb: 7efda000 Unfrozen

ChildEBP RetAddr 

WARNING: Stack unwind information not available. Following frames may be wrong.

02e7ff88 775de4a5 cpuload+0xf87cf

02e7ff94 77eecfed kernel32!BaseThreadInitThunk+0xe

02e7ffd4 77eed1ff ntdll!__RtlUserThreadStart+0x23

02e7ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

 

2  Id: 710.d20 Suspend: 0 Teb: 7efd7000 Unfrozen

ChildEBP RetAddr 

WARNING: Stack unwind information not available. Following frames may be wrong.

02f7ff88 775de4a5 cpuload+0xf87cf

02f7ff94 77eecfed kernel32!BaseThreadInitThunk+0xe

02f7ffd4 77eed1ff ntdll!__RtlUserThreadStart+0x23

02f7ffec 00000000 ntdll!_RtlUserThreadStart+0x1b  

 

If we apply symbols we get nicer stack traces:

 

0:000> ~*kL

 

.  0  Id: 710.ec4 Suspend: 0 Teb: 7efdd000 Unfrozen

ChildEBP RetAddr 

0017fba0 778a67f0 USER32!NtUserGetMessage+0x15

0017fbbc 00510211 USER32!GetMessageW+0x33

0017fbe8 0051173c cpuload!AfxInternalPumpMessage+0x21

0017fbf4 0051031f cpuload!CWinThread::PumpMessage+0xc

0017fc00 00535ea5 cpuload!AfxPumpMessage+0x1f

0017fc28 00515561 cpuload!CWnd::RunModalLoop+0x1d5

0017fc94 004f814d cpuload!CDialog::DoModal+0x1e1

0017fe84 006a43b2 cpuload!CcpuloadApp::InitInstance+0xad

0017fea8 006a42a8 cpuload!AfxWinMain+0x82

0017fec0 00626d0f cpuload!wWinMain+0x18

0017ff80 00626a4d cpuload!__tmainCRTStartup+0x2af

0017ff88 775de4a5 cpuload!wWinMainCRTStartup+0xd

0017ff94 77eecfed kernel32!BaseThreadInitThunk+0xe

0017ffd4 77eed1ff ntdll!__RtlUserThreadStart+0x23

0017ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

 

   1  Id: 710.994 Suspend: 0 Teb: 7efda000 Unfrozen

ChildEBP RetAddr 

02e7fe74 004f87e7 WINMM!timeGetTime+0x14

02e7ff88 775de4a5 cpuload!SpikingThread+0x67

02e7ff94 77eecfed kernel32!BaseThreadInitThunk+0xe

02e7ffd4 77eed1ff ntdll!__RtlUserThreadStart+0x23

02e7ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

 

   2  Id: 710.d20 Suspend: 0 Teb: 7efd7000 Unfrozen

ChildEBP RetAddr 

02f7ff88 775de4a5 cpuload!SpikingThread+0x58

02f7ff94 77eecfed kernel32!BaseThreadInitThunk+0xe

02f7ffd4 77eed1ff ntdll!__RtlUserThreadStart+0x23

02f7ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

 

We have highlighted in red the currently executing module and function.

 

The cpuload application and its symbols can be downloaded from:

 

http://www.dumpanalysis.org/Debugged/Jun09/ download/cpuload.zip

 

 

 

 

Modeling Exception Handling

Dmitry Vostokov, 15th June 2009
http://www.dumpanalysis.org

 

 

Once we got a process memory dump with a stack overflow pattern[5]. There were hundreds of repeated frames involving exception dispatch:

 

(d70.111c): Stack overflow - code c00000fd (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

eax=00113354 ebx=00113068 ecx=0011307c edx=7c9485ec esi=001133c8 edi=00000000

eip=7c95153e esp=00112ff4 ebp=00113050 iopl=0 nv up ei pl nz ac po nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000 efl=00210212

ntdll!RtlDispatchException+0x8:

7c95153e 56              push    esi

 

0:000> k 1000

ChildEBP RetAddr 

00113050 7c94855e ntdll!RtlDispatchException+0x8

00113050 7c978002 ntdll!KiUserExceptionDispatcher+0xe

001133b0 7c94855e ntdll!RtlDispatchException+0xf7

001133b0 7c978002 ntdll!KiUserExceptionDispatcher+0xe

00113710 7c94855e ntdll!RtlDispatchException+0xf7

00113710 7c978002 ntdll!KiUserExceptionDispatcher+0xe

00113a70 7c94855e ntdll!RtlDispatchException+0xf7

00113a70 7c978002 ntdll!KiUserExceptionDispatcher+0xe

00113dd0 7c94855e ntdll!RtlDispatchException+0xf7

00113dd0 7c978002 ntdll!KiUserExceptionDispatcher+0xe

00114130 7c94855e ntdll!RtlDispatchException+0xf7

00114130 7c978002 ntdll!KiUserExceptionDispatcher+0xe

00114490 7c94855e ntdll!RtlDispatchException+0xf7

[...]

0020f830 7c978002 ntdll!KiUserExceptionDispatcher+0xe

0020fb90 7c94863c ntdll!RtlDispatchException+0xf7

0020fe70 7c80bee7 ntdll!RtlRaiseException+0x3d

0020fed0 00058dc9 kernel32!RaiseException+0x53

WARNING: Stack unwind information not available. Following frames may be wrong.

0020ff34 000a7d5a Application+0x48dc9

0020ff54 000a7bf2 Application+0x97d5a

0020ff78 000a7de2 Application+0x97bf2

0020ffc0 7c82f23b Application+0x97de2

0020fff0 00000000 kernel32!BaseProcessStart+0x23

 

If we look at raw stack we could see repeated hidden exception pattern[6]:

 

0:000> dds esp

00112ff4  00000000

00112ff8  00000000

00112ffc  00000000

00113000  00000000

00113004  00000000

00113008  00000000

0011300c  00000000

00113010  00000000

00113014  00000000

00113018  00000000

0011301c  00000000

00113020  00000000

00113024  00000000

00113028  00000000

0011302c  00000000

00113030  00000000

00113034  00000000

00113038  00000000

0011303c  00000000

00113040  00000000

00113044  00000000

00113048  00000000

0011304c  00000000

00113050  001133b0

00113054  7c94855e ntdll!KiUserExceptionDispatcher+0xe

00113058  00113068

0011305c  0011307c ; .cxr

00113060  00113068 ; .exr

00113064  0011307c

00113068  c0000025

0011306c  00000001

00113070  001133c8

 

0:000> .exr 00113068

ExceptionAddress: 7c978002 (ntdll!RtlDispatchException+0x000000f7)

   ExceptionCode: c0000025

  ExceptionFlags: 00000001

NumberParameters: 0

 

0:000> !error c0000025

Error code: (NTSTATUS) 0xc0000025 (3221225509) - {EXCEPTION}  Cannot Continue  Windows cannot continue from this exception.

 

Looking closer at RaiseException call we noticed that its second parameter is 1:

 

0:000> kv 100

ChildEBP RetAddr  Args to Child

[...]

0020fed0 00058dc9 0eedfade 00000001 00000007 kernel32!RaiseException+0x53

[...]

 

This function has the following prototype[7]:

 

void RaiseException(

  DWORD dwExceptionCode,

  DWORD dwExceptionFlags,

  DWORD nNumberOfArguments,

  const DWORD* lpArguments

);

 

What caught our attention was the fact that dwExceptionFlags paramater can have the value EXCEPTION_NONCONTINUABLE and if we continue to execute the code afterwards another exception is raised:

 

EXCEPTION_NONCONTINUABLE_EXCEPTION

 

Therefore, to test our hypothesis that the code of Application module attempted to continue code excution after raising non-continuable exception we created a small C++ application:

 

#include "stdafx.h"

#include <excpt.h>

#include <windows.h>

 

int _tmain(int argc, _TCHAR* argv[])

{

    __try

    {

       RaiseException (0xdeaddead,

           EXCEPTION_NONCONTINUABLE, NULL, NULL);

    }

    __except (EXCEPTION_CONTINUE_EXECUTION)

    {

    }

 

    return 0;

}

 

The application raises a non-continuable exception but SEH exception filter attempts to continue execution. If the second parameter is 0 then the program quietly exits as expected. However if this parameter is set to 1 (EXCEPTION_NONCONTINUABLE) then the program crashes:

 

 

We then attached WinDbg non-invasively to SEHTest.exe:

 

0:000> k

ChildEBP RetAddr 

00081128 00000000 ntdll!RtlRaiseException+0xa

 

0:000> r

eax=00081140 ebx=0017ff34 ecx=00000000 edx=ffffffd8 esi=000811bc edi=00000000

eip=77052fb2 esp=00080e58 ebp=00081128 iopl=0         nv up ei pl nz na po nc

cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202

ntdll!RtlRaiseException+0xa:

77052fb2 54              push    esp

 

Unfortunately WinDbg was unable to reconstruct stack trace so we did that manually[8]:

 

0:000> dds ebp

00081128  000811a4

0008112c  77096fb7 ntdll!RtlDispatchException+0x18a

00081130  00081140

00081134  00000000

00081138  000811bc

0008113c  00081560

00081140  c0000025

00081144  00000001

00081148  000811bc

0008114c  00000000

00081150  00000000

00081154  00000000

00081158  00000000

0008115c  00000000

00081160  00000000

00081164  00000000

00081168  00000000

0008116c  00000000

00081170  00000000

00081174  00000000

00081178  00000000

0008117c  00000000

00081180  00000000

00081184  00000000

00081188  00000000

0008118c  00000000

00081190  00000000

00081194  00000000

00081198  00180000

0008119c  00081000

000811a0  00000000

000811a4  00081548

 

0:000> k L=00081128 00081128 77052fb2 1000

ChildEBP RetAddr 

00081128 77096fb7 ntdll!RtlRaiseException+0xa

000811a4 77052eff ntdll!RtlDispatchException+0x18a

000811a4 77096fb7 ntdll!KiUserExceptionDispatcher+0xf

00081548 77052eff ntdll!RtlDispatchException+0x18a

00081548 77096fb7 ntdll!KiUserExceptionDispatcher+0xf

000818ec 77052eff ntdll!RtlDispatchException+0x18a

000818ec 77096fb7 ntdll!KiUserExceptionDispatcher+0xf

00081c90 77052eff ntdll!RtlDispatchException+0x18a

00081c90 77096fb7 ntdll!KiUserExceptionDispatcher+0xf

00082034 77052eff ntdll!RtlDispatchException+0x18a

00082034 77096fb7 ntdll!KiUserExceptionDispatcher+0xf

000823d8 77052eff ntdll!RtlDispatchException+0x18a

000823d8 77096fb7 ntdll!KiUserExceptionDispatcher+0xf

0008277c 77052eff ntdll!RtlDispatchException+0x18a

0008277c 77096fb7 ntdll!KiUserExceptionDispatcher+0xf

00082b20 77052eff ntdll!RtlDispatchException+0x18a

00082b20 77096fb7 ntdll!KiUserExceptionDispatcher+0xf

00082ec4 77052eff ntdll!RtlDispatchException+0x18a

00082ec4 77096fb7 ntdll!KiUserExceptionDispatcher+0xf

00083268 77052eff ntdll!RtlDispatchException+0x18a

[...]

0017f7dc 77096fb7 ntdll!KiUserExceptionDispatcher+0xf

0017fb80 77052eff ntdll!RtlDispatchException+0x18a

0017fb80 75b7f328 ntdll!KiUserExceptionDispatcher+0xf

0017ff04 0040104b kernel32!RaiseException+0x58

0017ff44 004011d8 SEHTest!wmain+0x4b

0017ff88 75bde4a5 SEHTest!__tmainCRTStartup+0x10f

0017ff94 770acfed kernel32!BaseThreadInitThunk+0xe

0017ffd4 770ad1ff ntdll!__RtlUserThreadStart+0x23

0017ffec 00000000 ntdll!_RtlUserThreadStart+0x1b

 

0:000> kv L=00081128 00081128 77052fb2 1000

ChildEBP RetAddr  Args to Child

[...]

0017ff04 0040104b deaddead 00000001 00000000 kernel32!RaiseException+0x58 (FPO: [4,20,0])

[...]

 

We can also see the same hidden exception on raw stack: c0000025. Therefore we conclude that we sucessfully modeled the problem.

 

The SEHTest application and its symbols can be downloaded from:

 

http://www.dumpanalysis.org/Debugged/Jun09/ download/SEHTest.zip

 


 

 

Memory Dump Analysis Certification Voucher can be found in the printed version.

 

 

 


 

Memory Dump Analysis Certification Resources (Part 1)

 

WDPF_frontcover_draft_s.jpg

Windows Debugging: Practical Foundations

ISBN: 978-1-906717-10-0 (Paperback)

ISBN: 978-1-906717-67-4 (Hardcover)

Written by the founder of DumpAnalysis.org this book is not about bugs or debugging techniques but about background knowledge everyone needs to start experimenting with WinDbg, learn from practical experience and read other advanced debugging books. Solid understanding of fundamentals like pointers is needed to analyze stack traces beyond !analyze -v and lmv WinDbg commands. This is the book to help technical support and escalation engineers and Windows software testers without the knowledge of assembly language to master necessary prerequisites to understand and start debugging and crash dump analysis on Windows platforms. It doesn't require any specific know­ledge, fills the gap and lowers the learning curve. The book is also useful for software engineers coming from managed code or Java background, engineers coming from non-Wintel environments, Windows C/C++ software engineers without assembly language background, security researchers and beginners learning Windows software disassembling and reverse engineering techniques. This book can also be used as Intel assembly language and Windows debug­ging supplement for relevant undergraduate level courses.

MDAA-Final-Front-Cover.jpg

Memory Dump Analysis Anthology, Volume 1

ISBN: 978-0-9558328-0-2 (Paperback)

ISBN: 978-0-9558328-1-9 (Hardcover)

This is a revised, edited, cross-referenced and thematically organized volume of selected DumpAnalysis.org blog posts about crash dump analysis and debug­ging written in 2006 - 2007 for software engineers developing and maintaining products on Windows platforms, technical support and escalation engineers dealing with complex software issues and general Windows users.

MDAA2-Final-Front-Cover-LS.jpg

Memory Dump Analysis Anthology, Volume 2

ISBN: 978-0-9558328-7-1 (Paperback)

ISBN: 978-1-906717-22-3 (Hardcover)

This is a revised, edited, cross-referenced and thematically organized volume of selected DumpAnalysis.org blog posts about crash dump analysis and debug­ging written in January - September 2008 for software engineers developing and maintaining products on Windows platforms, quality assurance engineers testing software on Windows platforms and technical support and escalation engineers dealing with complex software issues. The second volume features: - 45 new crash dump analysis patterns - Pattern interaction and case studies - Updated checklist - Fully cross-referenced with Volume 1 - New appendixes