суббота, 28 мая 2011 г.

DbgEng in Windows Debugging tools

DbgEng In Windows Debugging tools
dbgeng.dll
Export 2 functions.
DebugCreate
DebugConnect


This is note about DebugCreate
I use 2 general interface: IDebugClient(5 version) and IDebugControl(4 version).

IDebugClient work with Process, remote machines, servers and dump. Also, IDebugClient provide get\set callbacks, output and some masks.

IDebugControl managment debug engine: Debug statuts, assembler\disassembler, options, execute debug commands , logs and etc.
Creating dbgeng objects:
IDebugClient5  * g_lpDebugClient  = NULL;
IDebugControl4 * g_lpDebugControl = NULL;

Creating dbgeng objects:
    HRESULT hr;
    hr = DebugCreate(
        __uuidof(IDebugClient5),
        (LPVOID*)&g_lpDebugClient
        );

    if (FAILED(hr))
    {
        printf("Failed DebugCreate hr = 0x%08X\n", hr);
        return FALSE;
    }

    hr = g_lpDebugClient->QueryInterface(
        __uuidof(IDebugControl4),
        (LPVOID*)&g_lpDebugControl
        );
    if (FAILED(hr))
    {
        printf("Failed DebugControl::QueryInterface(__uuidof(IDebugControl4)) 0x%08X\n", hr);
        DestroyDbgEng();
        return FALSE;
    }

Set output calbacks(Debug outputs)
class StdioOutputCallbacks : public IDebugOutputCallbacks
{
public:
    // IUnknown.
    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_(ULONG)
StdioOutputCallbacks::AddRef(
    THIS
    )
{ return 1; }

STDMETHODIMP_(ULONG)
StdioOutputCallbacks::Release(
    THIS
    )
{ return 0; }

STDMETHODIMP
StdioOutputCallbacks::Output(
    THIS_
    IN ULONG Mask,
    IN PCSTR Text
    )
{ printf("%s", Text); return S_OK; }
//Set
hr = g_lpDebugClient->SetOutputCallbacks(&g_OutputCallback);
if (FAILED(hr))
{
    printf("Failed DebugControl->SetOutputCallbacks 0x%08X\n", hr);
    return FALSE;
}
//Set
hr = g_lpDebugClient->SetOutputCallbacks(&g_OutputCallback);
if (FAILED(hr))
{
    printf("Failed DebugControl->SetOutputCallbacks 0x%08X\n", hr);
    return FALSE;
}
Set Event Callbacks (Debug Events)
class EventCallbacks : public DebugBaseEventCallbacks
{
public:
    STDMETHOD_(ULONG, AddRef)(
        THIS
        );
    STDMETHOD_(ULONG, Release)(
        THIS
        );
    STDMETHOD(GetInterestMask)(
        THIS_
        OUT PULONG Mask
        );
    STDMETHOD(CreateProcess)(
        THIS_
        IN ULONG64 ImageFileHandle,
        IN ULONG64 Handle,
        IN ULONG64 BaseOffset,
        IN ULONG ModuleSize,
        IN PCSTR ModuleName,
        IN PCSTR ImageName,
        IN ULONG CheckSum,
        IN ULONG TimeDateStamp,
        IN ULONG64 InitialThreadHandle,
        IN ULONG64 ThreadDataOffset,
        IN ULONG64 StartOffset
        );
    STDMETHOD(LoadModule)(
        THIS_
        IN ULONG64 ImageFileHandle,
        IN ULONG64 BaseOffset,
        IN ULONG ModuleSize,
        IN PCSTR ModuleName,
        IN PCSTR ImageName,
        IN ULONG CheckSum,
        IN ULONG TimeDateStamp
        );
};
STDMETHODIMP_(ULONG)
EventCallbacks::AddRef(
    THIS
    )
{ return 1; }

STDMETHODIMP_(ULONG)
EventCallbacks::Release(
    THIS
    )
{ return 0; }

STDMETHODIMP
EventCallbacks::GetInterestMask(
    THIS_
    OUT PULONG Mask
    )
{
    *Mask = (DEBUG_EVENT_CREATE_PROCESS|DEBUG_EVENT_LOAD_MODULE);
    return S_OK;
}

STDMETHODIMP
EventCallbacks::CreateProcess(
    THIS_
    IN ULONG64 ImageFileHandle,
    IN ULONG64 Handle,
    IN ULONG64 BaseOffset,
    IN ULONG ModuleSize,
    IN PCSTR ModuleName,
    IN PCSTR ImageName,
    IN ULONG CheckSum,
    IN ULONG TimeDateStamp,
    IN ULONG64 InitialThreadHandle,
    IN ULONG64 ThreadDataOffset,
    IN ULONG64 StartOffset
    )
{
    printf("Create new process!(%s)\n", ModuleName);
    return DEBUG_STATUS_GO;
}

STDMETHODIMP
EventCallbacks::LoadModule(
    THIS_
    IN ULONG64 ImageFileHandle,
    IN ULONG64 BaseOffset,
    IN ULONG ModuleSize,
    IN PCSTR ModuleName,
    IN PCSTR ImageName,
    IN ULONG CheckSum,
    IN ULONG TimeDateStamp
    )
{
    printf("LoadModule!(%s)\n", ModuleName);
    return DEBUG_STATUS_GO;
}


Debugger loop
void DbgEventLoop(void)
{
    HRESULT hr;
    ULONG ExecStatus;

    while ( true )
    {
//Wait event
    hr = g_lpDebugControl->WaitForEvent(
            DEBUG_WAIT_DEFAULT,
            INFINITE
            );

    if ( hr != S_OK )
    {
        if (g_lpDebugControl->GetExecutionStatus(
            &ExecStatus
            ) == S_OK
            && ExecStatus == DEBUG_STATUS_NO_DEBUGGEE
            ) {
                break;
            }
        printf("WaitForEvent failed, 0x%X\n", hr);
    }
//Check debug status
    if (g_lpDebugControl->GetExecutionStatus(
        &ExecStatus
        ) == S_OK )
    {       
        printf("Exec status = %X\n", ExecStatus);
    }

    g_lpDebugControl->Execute(
        DEBUG_OUTCTL_ALL_CLIENTS, "kb",
        DEBUG_EXECUTE_DEFAULT);

    g_lpDebugControl->Execute(
        DEBUG_OUTCTL_ALL_CLIENTS, "g",
        DEBUG_EXECUTE_DEFAULT);
//Check debug status, after exec 'g' debug go!
    if (g_lpDebugControl->GetExecutionStatus(
            &ExecStatus
            ) == S_OK )
    {   
        printf("Exec status = %X\n", ExecStatus);
    }
    }
}

Destroy dbgeng Objects
BOOL DestroyDbgEng()
{
    if ( g_lpDebugControl ) {
        g_lpDebugControl->Release();
        g_lpDebugControl = NULL;
    }
    if ( g_lpDebugClient )
    {
        g_lpDebugClient->EndSession(DEBUG_END_PASSIVE);
        g_lpDebugClient->Release();
        g_lpDebugClient = NULL;
    }

    return TRUE;
}

Test create process   
hr = g_lpDebugClient->CreateProcess(
    NULL,
    "C:\\Windows\\system32\\notepad.exe",
    DEBUG_ONLY_THIS_PROCESS
    );
if (FAILED(hr))
{
    printf("Failed create debug process(0x%08X)\n", hr);
    DestroyDbgEng();
    return 2;
}