Dbgeng based Handles (PART 2 .............)


in part 1 we saw how to retrieve the handle details of all running process in a system using usermode handle

in this article we will see how to retrieve the same info in kernel mode (we use local kernel mode in this example
but there is no stopping you from using a real kernel debugging session and retrieving handles from a target

in usermode the handles are real handles and we attached to each process to retrieve the handle details

but in kernel mode there is a single virtual implicit process and we cant attach to any running process
we can only set the implicit process

but the extension kdexts.dll has done all this work internally so we can simply use it to retrieve the handle details

the !handle extension in kernel mode takes an EPROCESS or Pid as a third parameter so we dont have to much with setting the implicit process everytime

the code is similar to what we saw in part 1 of dbgeng handles

read the previous (links below) articles for explanation of the implementation

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
http://www.woodmann.com/forum/entry.php?251-Dbgeng-based-Handles



a small summary of the implementation

we start as usual by creating a client then query for interface
implement output callback methods
then get the pids and thier description (refer to dbgengHandle part 1)
the nattach to kernel ad extesnion kdexts.dll and call extions handle
handle in kernel mode takes EPROCESS or Cid as third param
so we sprintf_s the argument and pass it a buffer
also we set a Boolean to skip attaching to kernel on every iteration
and that is it


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;
    BOOL IsAttached =FALSE;
    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 (IsAttached == TRUE)
        {
            if ((Status = g_Client2->SetOutputCallbacks    (&g_OutputCb))    != S_OK)
            {
                Exit(1,"g_Client2->SetOutputCallbacks failed, 0x%X\n", Status);
            }
            char *HandArg = (char *) malloc(0x40);
            sprintf_s(HandArg,0x40,"%d %d %X",0,3,Ids[i]);
            if (( Status = g_Control->CallExtension(Handle,"handle",HandArg)) != S_OK)
            {
                Exit(1,"g_Control->CallExtension failed,0x%X\n",Status);
            }
            free(HandArg);
            if ((Status = g_Client2->SetOutputCallbacks    (0))    != S_OK)
            {
                Exit(1,"g_Client2->SetOutputCallbacks failed, 0x%X\n", Status);
            }
            continue;
        }
        if (( Status = g_Client2->AttachKernel(DEBUG_ATTACH_LOCAL_KERNEL,NULL )) != S_OK)
        {
            Exit(1,"g_Client2->AttachKernel 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("kdexts.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);
        }
        char *HandArg = (char *) malloc(0x40);
        sprintf_s(HandArg,0x40,"%d %d %x",0,3,Ids[i]);
        if (( Status = g_Control->CallExtension(Handle,"handle",HandArg)) != S_OK)
        {
            Exit(1,"g_Control->CallExtension failed,0x%X\n",Status);
        }
        free(HandArg);
        if ((Status = g_Client2->SetOutputCallbacks    (0))    != S_OK)
        {
            Exit(1,"g_Client2->SetOutputCallbacks failed, 0x%X\n", Status);
        }
        IsAttached = TRUE;
    }
    Exit(0, "Finished Debugging Quitting\n");
}

result as follows

Code:
No of Running Process is 0n32

SRNo    PID    ProcessName

01    0n0000    System Process
02    0n0004    System

Searching for Process with Cid == 4
PROCESS 86dc69c8  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 002f4000  ObjectTable: e1000d18  HandleCount: 2659.
    Image: System

Kernel handle table at e1cdd000 with 2659 entries in use

0004: Object: 86dc69c8  GrantedAccess: 001f0fff Entry: e1002008
Object: 86dc69c8  Type: (86dc6040) Process
    ObjectHeader: 86dc69b0 (old version)
        HandleCount: 2  PointerCount: 93

0008: Object: 86dc6308  GrantedAccess: 00000000 Entry: e1002010
Object: 86dc6308  Type: (86dc6e70) Thread
    ObjectHeader: 86dc62f0 (old version)
        HandleCount: 1  PointerCount: 1

000c: Object: e1797518  GrantedAccess: 000f003f Entry: e1002018
Object: e1797518  Type: (86dbf980) Key
    ObjectHeader: e1797500 (old version)
        HandleCount: 1  PointerCount: 1
        Directory Object: 00000000  Name: \REGISTRY\MACHINE\SYSTEM\CONTROLSET001\CONTROL\SESSION MANAGER\MEMORY MANAGEMENT\PREFETCHPARAMETERS

0010: Object: e1011490  GrantedAccess: 00000000 Entry: e1002020
Object: e1011490  Type: (86dbf980) Key
    ObjectHeader: e1011478 (old version)
        HandleCount: 1  PointerCount: 3
        Directory Object: 00000000  Name: \REGISTRY

0014: Object: e1789450  GrantedAccess: 0002001f Entry: e1002028
Object: e1789450  Type: (86dbf980) Key
    ObjectHeader: e1789438 (old version)
        HandleCount: 1  PointerCount: 2
        Directory Object: 00000000  Name: \REGISTRY\MACHINE\SYSTEM\SETUP
redirect the output to txt file from the binary

dbgengkdhandle.exe > sometext.txt

source and a compile binary attached