blabberer

Dbgeng based Handles

Rate this Entry

Dbgeng based Handles


most of those who are reading this article would be aware of Sysinternal's (mark russinovich) handle.exe
it provides the details of all handles that are open in a system

this article is an attempt to retrieve the same information using dbgeng interfaces and its allied extensions

this article also builds upon previous articles that uses dbgeng interfaces and has components copy pasted
as it is so if you are suggested to glance these articles too for ease of understanding

http://www.woodmann.com/forum/entry.php?246-A-Simple-Dbgeng-Based-User-Mode-Debugger
http://www.woodmann.com/forum/entry.php?248-DbgEng-Based-Debugger-(PART2)
http://www.woodmann.com/forum/entry.php?249-DbgEng-Based-Debugger-(PART2-Contd-)
http://www.woodmann.com/forum/entry.php?250-DbgEng-based-Kernel-Debugger



so you are required to make a DbgEngHandle.cpp use visual studio to make a new project from existing code
and use wdk7 xpfre build to compile and link and have a test folder filled with windbg dlls to test the resulting binary

in the cpp
we create a client query for interfaces implement an output callback attach non invasively to each running process
recursively and get the handle details using an extension call

handle details in usermode are exported from ExtensionFunction handle in ntsdexts.dll
handle details in kernelmode are exported from ExtensionFunction handle in kdexts.dll

lets see the implementations

these are standard global declarations we want a client and a control interface only to get handle details

Code:
#include <stdio.h>  
#include <dbgeng.h>

IDebugClient2*          g_Client2       = NULL;
IDebugControl*          g_Control       = NULL;
HRESULT                 Status          = NULL;
these below are standard exit and output callback implementation (resusable code]

Code:
void Exit(int Code, PCSTR Format, ...)
{
    if (g_Control != NULL)
    {
        g_Control->Release();
        g_Control = NULL;
    }
    if (g_Client2 != NULL)
    {
        g_Client2->EndSession(DEBUG_END_PASSIVE);
        g_Client2->Release();
        g_Client2 = NULL;
    }
    if (Format != NULL)
    {
        va_list Args;
        va_start(Args, Format);
        vfprintf(stderr, Format, Args);
        va_end(Args);
    }
    exit(Code);
};

class StdioOutputCallbacks : public IDebugOutputCallbacks
{
public:
    STDMETHOD(QueryInterface)( THIS_ IN REFIID InterfaceId, OUT PVOID* Interface );
    STDMETHOD_(ULONG, AddRef)( THIS );
    STDMETHOD_(ULONG, Release)(THIS );
    STDMETHOD(Output)( THIS_ IN ULONG Mask, IN PCSTR Text );
};
STDMETHODIMP StdioOutputCallbacks::QueryInterface( THIS_ IN REFIID InterfaceId, OUT PVOID* Interface ) 
{
    *Interface = NULL;
    if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
        IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks)))
    {
        *Interface = (IDebugOutputCallbacks *)this;
        AddRef();
        return S_OK;
    }
    else
    {
        return E_NOINTERFACE;
    }
}
STDMETHODIMP_(ULONG) StdioOutputCallbacks::AddRef( THIS    )
{
    return 1;
}
STDMETHODIMP_(ULONG) StdioOutputCallbacks::Release(    THIS )
{
    return 0;
}
STDMETHODIMP StdioOutputCallbacks::Output( THIS_ IN ULONG Mask, IN PCSTR Text )
{
    UNREFERENCED_PARAMETER(Mask);
    fputs(Text, stdout);
    return S_OK;
}

StdioOutputCallbacks    g_OutputCb;
we start out main function by creating interface

Code:
void CreateInterfaces (void)
{
    if ((Status = DebugCreate(__uuidof(IDebugClient), (void**)&g_Client2)) != S_OK)
    {
        Exit(1, "DebugCreate failed, 0x%X\n", Status);
    }
    if ((Status = g_Client2->QueryInterface(__uuidof(IDebugControl),    (void**)&g_Control))    != S_OK )
    {
        Exit(1, "g_Client2->QueryInterface(__uuidof(IDebugControl) failed, 0x%X\n", Status);
    }
    return ;
}
then use the

Code:
g_Client2->GetRunningProcessSystemIds
g_Client2->GetRunningProcessDescription
we skip system idle process from attaching and querying the handle details

        if( Ids[i] == 0)
        {
            continue;
        }
for all other process that are currently running  we attach to them non invasively non suspending
g_Client2->AttachProcess(NULL,
            Ids[i],DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND ))
and wait for event
g_Control->WaitForEvent

then add the extension
g_Control->AddExtension("ntsdexts.dll",0,&Handle))

call the extension function
g_Control->CallExtension  (the output call back recieves the output from this call)

and detach from the process 
g_Client2->DetachCurrentProcess(
in a for loop for getting handle details from all running process

it is then built using wdk xp fre environemnt

and the resulting binary is executed from test folder that contains all the windbg dlls

full source

Code:
#include <stdio.h>
#include <dbgeng.h>

IDebugClient2*          g_Client2       = NULL;
IDebugControl*          g_Control       = NULL;
HRESULT                 Status          = NULL;

void Exit(int Code, PCSTR Format, ...)
{
    if (g_Control != NULL)
    {
        g_Control->Release();
        g_Control = NULL;
    }
    if (g_Client2 != NULL)
    {
        g_Client2->EndSession(DEBUG_END_PASSIVE);
        g_Client2->Release();
        g_Client2 = NULL;
    }
    if (Format != NULL)
    {
        va_list Args;
        va_start(Args, Format);
        vfprintf(stderr, Format, Args);
        va_end(Args);
    }
    exit(Code);
};

class StdioOutputCallbacks : public IDebugOutputCallbacks
{
public:
    STDMETHOD(QueryInterface)( THIS_ IN REFIID InterfaceId, OUT PVOID* Interface );
    STDMETHOD_(ULONG, AddRef)( THIS );
    STDMETHOD_(ULONG, Release)(THIS );
    STDMETHOD(Output)( THIS_ IN ULONG Mask, IN PCSTR Text );
};
STDMETHODIMP StdioOutputCallbacks::QueryInterface( THIS_ IN REFIID InterfaceId, OUT PVOID* Interface ) 
{
    *Interface = NULL;
    if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
        IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks)))
    {
        *Interface = (IDebugOutputCallbacks *)this;
        AddRef();
        return S_OK;
    }
    else
    {
        return E_NOINTERFACE;
    }
}
STDMETHODIMP_(ULONG) StdioOutputCallbacks::AddRef( THIS    )
{
    return 1;
}
STDMETHODIMP_(ULONG) StdioOutputCallbacks::Release(    THIS )
{
    return 0;
}
STDMETHODIMP StdioOutputCallbacks::Output( THIS_ IN ULONG Mask, IN PCSTR Text )
{
    UNREFERENCED_PARAMETER(Mask);
    fputs(Text, stdout);
    return S_OK;
}

StdioOutputCallbacks    g_OutputCb;

void CreateInterfaces (void)
{
    if ((Status = DebugCreate(__uuidof(IDebugClient), (void**)&g_Client2)) != S_OK)
    {
        Exit(1, "DebugCreate failed, 0x%X\n", Status);
    }
    if ((Status = g_Client2->QueryInterface(__uuidof(IDebugControl),    (void**)&g_Control))    != S_OK )
    {
        Exit(1, "g_Client2->QueryInterface(__uuidof(IDebugControl) failed, 0x%X\n", Status);
    }
    return ;
}

void __cdecl main(int Argc, char* Argv[])
{
    ULONG Ids[0x100];
    char Exename[0x100];
    ULONG ActualCount = 0;
    ULONG64 Handle = 0;

    memset(&Ids,0,sizeof(Ids));
    memset(&Exename,0,sizeof(Exename));
    CreateInterfaces();
    if ((Status = g_Client2->GetRunningProcessSystemIds(NULL,
        Ids,_countof(Ids),&ActualCount) ) != S_OK) 
    {
        Exit(1,"g_Client2->GetRunningProcessSystemIds failed, 0x%X\n", Status);
    }
    printf ("No of Running Process is 0n%d\n\nSRNo\tPID\tProcessName\n\n", ActualCount);
    for (ULONG i = 0; i < ActualCount;i++)
    {
        if (( g_Client2->GetRunningProcessDescription( 
            NULL, Ids[i], 
            DEBUG_PROC_DESC_NO_PATHS | DEBUG_PROC_DESC_NO_SERVICES | 
            DEBUG_PROC_DESC_NO_MTS_PACKAGES | DEBUG_PROC_DESC_NO_COMMAND_LINE,
            Exename, sizeof(Exename),NULL,NULL,NULL,NULL  ) ) != S_OK) 
        {
            Exit(1,"g_Client2->GetRunningProcessDescription Failed, 0x%X\n", Status);
        }
        printf("%02d\t0n%04d\t%s\n",i+1,Ids[i],Exename);
        if( Ids[i] == 0)
        {
            continue;
        }
        if (( Status = g_Client2->AttachProcess(NULL,
            Ids[i],DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND )) != S_OK)
        {
            Exit(1,"g_Client2->AttachProcess Failed, 0x%X\n", Status);
        }
        if (( Status = g_Control->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE))!=S_OK)
        {
            Exit(1,"g_Control->WaitForEvent Failed, 0x%X\n", Status);
        }
        if (( Status = g_Control->AddExtension("ntsdexts.dll",0,&Handle)) != S_OK)
        {
            Exit(1,"g_Control->AddExtension failed,0x%X\n",Status);
        }
        if ((Status = g_Client2->SetOutputCallbacks    (&g_OutputCb))    != S_OK)
        {
            Exit(1,"g_Client2->SetOutputCallbacks failed, 0x%X\n", Status);
        }
        if (( Status = g_Control->CallExtension(Handle,"handle","0 5")) != S_OK)
        {
            Exit(1,"g_Control->CallExtension failed,0x%X\n",Status);
        }
        if ((Status = g_Client2->SetOutputCallbacks    (0))    != S_OK)
        {
            Exit(1,"g_Client2->SetOutputCallbacks failed, 0x%X\n", Status);
        }
        if (( Status = g_Client2->DetachCurrentProcess() ) != S_OK)
        {
            Exit(1,"g_Client2->DetachCurrentProcess failed,0x%X\n",Status);
        }
    }
    Exit(0, "Finished Debugging Quitting\n");
}
since there is no error handling and graceful recovery but fatal exit on every failure
run the binary when the process count is stable race conditions arent handled in the code
so attach may happen but the process might have exited before handle enumeration or symbol loading
and it may fail during callExtension() or process id might be there in the array but process might have exited even
before attaching happens and may result in failure

in normal cases where process ids match running process from start of execution of this binary till end
it will get you all the handles from all the running process and it will match the results of sysinternals handle -a output

use redirection to capture the output

result

Code:
dbgenghandle:\>DbgEngHandle.exe > res.txt
Finished Debugging Quitting

dbgenghandle:\>

No of Running Process is 0n32

SRNo    PID    ProcessName

01    0n0000    System Process
02    0n0004    System

Handle 4
  Type             Process
  Name             <none>
Handle 8
  Type             Thread
  Name             <none>
Handle c
  Type             Key
  Name             \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Memory Management\PrefetchParameters
Handle 10
  Type             Key
  Name             \REGISTRY
Handle 14
  Type             Key
  Name             \REGISTRY\MACHINE\SYSTEM\Setup
Handle 18
  Type             Key
  Name             \REGISTRY\MACHINE\HARDWARE\DESCRIPTION\System\MultifunctionAdapter
Handle 1c
  Type             Key
  Name             \REGISTRY\MACHINE\SYSTEM\WPA\MediaCenter
Handle 20
  Type             Key
  Name             \REGISTRY\MACHINE\SYSTEM\WPA\PnP
Handle 24
  Type             Key
  Name             \REGISTRY\MACHINE\SYSTEM\WPA\Key-4F3B2RFXKC9C637882MBM
Handle 28
  Type             Key
  Name             \REGISTRY\MACHINE\SYSTEM\WPA\SigningHash-V44KQMCFXKQCTQ
Handle 2c
  Type             Key
  Name             \REGISTRY\MACHINE\SYSTEM\ControlSet001\Control\ProductOptions
Handle 30
  Type             Key
  Name             \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\Eventlog
Handle 34
  Type             Event
  Name             \Security\TRKWKS_EVENT

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Handle 2b98
  Type             SymbolicLink
  Name             \GLOBAL??\C:
Handle 2bc0
  Type             File
2593 Handles
Type               Count
None               4
Event              6
Section            1
File               2400
Port               4
Directory          5
SymbolicLink       101
Key                30
Token              1
Process            17
Thread             23
Desktop            1
03    0n0512    smss.exe
Handle 4
  Type             KeyedEvent
  Name             \KernelObjects\CritSecOutOfMemoryEvent
Handle 8
  Type             File
Handle c
  Type             Port
  Name             \SmApiPort
Handle 10
  Type             Port
  Name             <none>
Handle 14
  Type             Directory
  Name             \GLOBAL??
Handle 18
  Type             Directory
  Name             \Sessions
Handle 1c
  Type             File
Handle 20
  Type             SymbolicLink
  Name             \KnownDlls\KnownDllPath
Handle 24
  Type             Directory
  Name             \KnownDlls
Handle 28
  Type             Event
  Name             <none>
Handle 2c
  Type             Event
  Name             \UniqueSessionIdEvent
Handle 30
  Type             Process
  Name             <none>
Handle 34
  Type             Process
  Name             <none>



Handle v3.41
Copyright (C) 1997-2008 Mark Russinovich
Sysinternals - www.sysinternals.com

------------------------------------------------------------------------------
System pid: 4 NT AUTHORITY\SYSTEM
    4: Process       System(4)
    8: Thread        System(4): 12
    C: Key           HKLM\SYSTEM\ControlSet001\Control\Session Manager\Memory Management\PrefetchParameters
   10: Key           \REGISTRY
   14: Key           HKLM\SYSTEM\Setup
   18: Key           HKLM\HARDWARE\DESCRIPTION\System\MultifunctionAdapter
   1C: Key           HKLM\SYSTEM\WPA\MediaCenter
   20: Key           HKLM\SYSTEM\WPA\PnP
   24: Key           HKLM\SYSTEM\WPA\Key-4F3B2RFXKC9C637882MBM
   28: Key           HKLM\SYSTEM\WPA\SigningHash-V44KQMCFXKQCTQ
   2C: Key           HKLM\SYSTEM\ControlSet001\Control\ProductOptions
   30: Key           HKLM\SYSTEM\ControlSet001\Services\Eventlog
   34: Event         \Security\TRKWKS_EVENT

XXXXXXXXXXXXXXXXXXXXXXXXX
 2B98: SymbolicLink  \GLOBAL??\C:
 2BC0: File  (---)   \Device\Tcp
------------------------------------------------------------------------------
smss.exe pid: 512 NT AUTHORITY\SYSTEM
    4: KeyedEvent    \KernelObjects\CritSecOutOfMemoryEvent
    8: File  (RW-)   C:\WINDOWS
    C: Port          \SmApiPort
   10: Port          
   14: Directory     \GLOBAL??
   18: Directory     \Sessions
   1C: File  (RW-)   C:\WINDOWS\system32
   20: SymbolicLink  \KnownDlls\KnownDllPath
   24: Directory     \KnownDlls
   28: Event         
   2C: Event         \UniqueSessionIdEvent
   30: Process       csrss.exe(564)
   34: Process       csrss.exe(564)
part 2 continued for kernel mode handles (it is same details just a different implementation

attached below is source and a compiled binary
Attached Thumbnails Attached Files

Submit "Dbgeng based Handles" to Digg Submit "Dbgeng based Handles" to del.icio.us Submit "Dbgeng based Handles" to StumbleUpon Submit "Dbgeng based Handles" to Google

Categories
Uncategorized

Comments