blabberer
January 29th, 2013, 21:15
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?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?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?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?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 attachedDbgEngKDHandle.zip (10.3 KB)