【逆向知识】开发WinDBG扩展DLL

如何开发WinDbg扩展DLL

WinDbg扩展DLL是一组导出的回调函数,用于实现用户定义的命令。以便从内存转储中提取特定的信息。扩展dll由调试器引擎加载,可以在执行用户模式或内核模式调试时提供自动化任务的扩展功能。扩展DLL可以导出任意数量用于执行扩展命令的函数。每个函数都被显式地声明为DLL定义文件中的导出函数,.def文件和函数名必须是小写字母。

​ WinDbg(DbgEng)扩展DLL必须导出DebugExtensionInitialize。 这将在DLL加载时调用,以便于初始化DLL。 它可能被DLL用来初始化全局变量。

​ 扩展DLL导出的可选函数DebugExtensionUninitialize。如果导出这个函数,那么卸载扩展时将调用这个DebugExtensionUninitialize 函数。

​ 扩展DLL导出的DebugExtensionNotify函数。如果导出这个函数将会在会话开始或结束时调用,当目标开始或停止执行时。这些通知还提供给在客户端注册的IDebugEventCallbacks对象。

​ 扩展DLL可以导出KnownStructOutput。如果导出这个函数将会在加载DLL时调用它。该函数返回在一行上打印的结构列表。稍后可以调用它来格式化这些结构的实例以便打印。

​ 开发自己的Windbg扩展DLL,可以按照以下步骤:

  • 1.下载并安装Windows的调试工具

http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx

  • 2.使用VS 2008创建“Win32 Console Application”
  • 3.选择应用程序类型为“DLL”,然后单击“完成”

图1

  • 4.在项目中添加一个名为“wdbrowser”的“Module-Definition File (.def) ”。 导出扩展功能的一种方法是在.def文件的EXPORTS部分中指定函数名称。 也可以使用其他方式导出函数,如__dllexport

图2

  • 5.将“Additional include Directories”配置为指向Windbg附带的头文件的目录。 x86的默认文件夹路径是“C:\Program Files\Debugging Tools for Windows (x86)\sdk\inc”

    注:include Directories指include 目录

  • 6.将“Additional Library Directories” 配置为指向Windbg附带库文件的目录。x86库文件的默认文件夹路径是:"C:\Program Files\Debugging Tools for Windows (x86)\sdk\lib\i386″

    注:Library Directories指Library 目录

  • 7.“dbgeng.lib ” & “dbgeng.dll” 具有实现调试引擎输出的功能。所以需要添加“dbgeng.lib ”到附加依赖项里

  • 8.添加在步骤#3中创建的模块定义文件名称“wdbrowser.def”

  • 9.在“stdafx.h”中包含以下所需的头文件

    #include <windows.h>
    #include <imagehlp.h>
    #include <wdbgexts.h>
    #include <dbgeng.h>
    #include <extsfns.h>
    
  • 10.声明以下两个全局变量

//Version.
EXT_API_VERSION g_ExtApiVersion = {1,1,EXT_API_VERSION_NUMBER,0} ;
WINDBG_EXTENSION_APIS ExtensionApis = {0};
  • 11.声明以下调试引擎COM接口指针。
IDebugAdvanced2*  gAdvancedDebug2=NULL;
IDebugControl4*   gDebugControl4=NULL;
IDebugControl*    gExecuteCmd=NULL;
IDebugClient*                 gDebugClient=NULL;
  • 12.下一步是在DLL Main实现源文件中声明和实现WinDbgExtensionDllInit函数。 在这个例子中是“wdbrowser.cpp”。 WinDbgExntensionDllInit是第一个将被windbg调用的函数。 所以这个函数是空闲的,用于实现任何扩展特定的初始化或相关功能。

    有关此功能的更多详细信息,请参阅http://msdn.microsoft.com/en-us/library/cc267872.aspx。

VOID WDBGAPI WinDbgExtensionDllInit (PWINDBG_EXTENSION_APIS lpExtensionApis, USHORT usMajorVersion, USHORT usMinorVersion)
{
                  ExtensionApis = *lpExtensionApis;
                  HRESULT hResult = S_FALSE;
                        if (hResult = DebugCreate(__uuidof(IDebugClient), (void**) &gDebugClient) != S_OK)
                         {
                                                dprintf(“Acuqiring IDebugClient* Failled\n\n”);
                                                return;
                         }
                         if (hResult = gDebugClient->QueryInterface(__uuidof(IDebugControl), (void**) &gExecuteCmd) != S_OK)
                         {
                                        dprintf(“Acuqiring IDebugControl* Failled\n\n”);
                                                return;
                         }
                         if (hResult = gDebugClient->QueryInterface(__uuidof(IDebugAdvanced2), (void**) &gAdvancedDebug2) != S_OK)
                         {
                                              dprintf(“Acuqiring IDebugAdvanced2* Failled\n\n”);
                                                return;
                         }
                         if (hResult = gDebugClient->QueryInterface(__uuidof(IDebugControl4), (void**) &gDebugControl4) != S_OK)
                         {
                            dprintf(“Acuqiring IDebugControl4* Failled\n\n”);
                                                return;
                         }
}

  • 13.声明另一个导出的函数ExtensionApiVersion,向windbg报告扩展版本。

    有关此函数的详细信息,请参见http://msdn.microsoft.com/en-us/library/cc267873.aspx。

LPEXT_API_VERSION WDBGAPI ExtensionApiVersion (void)
{
    return &g_ExtApiVersion;
}
  • 14.定义调试引擎的接口指针,以便扩展模块可以与调试引擎交互。更多信息请参考
http://msdn.microsoft.com/en-us/library/cc265976.aspx  – IDebugClient, http://msdn.microsoft.com/en-us/library/cc266102.aspx – IDebugControl
http://msdn.microsoft.com/en-us/library/cc265957.aspx – IDebugAdvanced
IDebugAdvanced2* gAdvancedDebug2=NULL;
IDebugControl4* gDebugControl4=NULL;
IDebugControl* gExecuteCmd=NULL;
IDebugClient*               gDebugClient=NULL;
    1. 下一步是实现调试引擎的回调接口IDebugOutputCallbacks。调试引擎回调IDebugOutCallbacks::Output()的实现,输出扩展函数执行命令后的结果。
有关idebugoutput回调的详细信息,请参见http://msdn.microsoft.com/en-us/library/cc265716.aspx::Output()
  • 16.在继承idebugoutputcallback接口的头文件中添加以下新类。
#ifndef __OUT_HPP__
#define __OUT_HPP__
#include <string>
#include <sstream>
class StdioOutputCallbacks : public IDebugOutputCallbacks
{
private:
                        std::string m_OutputBuffer;
                        //
                        //This buffer holds the output from the command execution.
                        //
                        CHAR m_OutPutBuffer[4096];
public:
                        void InitOutPutBuffer();
                        std::string GetOutputBuffer()
                        {
                                                return m_OutputBuffer;
                        };
                        void ClearOutPutBuffer()              
                        {
                                                m_OutputBuffer = “”;
                        };
    STDMETHOD(QueryInterface)(
        THIS_
        IN REFIID InterfaceId,
        OUT PVOID* Interface
        );
    STDMETHOD_(ULONG, AddRef)(
        THIS
        );
    STDMETHOD_(ULONG, Release)(
        THIS
        );
    // IDebugOutputCallbacks.
    STDMETHOD(Output)(
        THIS_
        IN ULONG Mask,
        IN PCSTR Text
        );
};
extern StdioOutputCallbacks g_OutputCb;
#endif // #ifndef __OUT_HPP__
  • 17.添加实现IDebugOutputCallbacks接口方法的代码,特别是Output()
#include “stdafx.h”
#include <stdio.h>
#include <windows.h>
#include <dbgeng.h>
#include “OutputCallBack.h”
StdioOutputCallbacks g_OutputCb;
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
    )
{
    // This class is designed to be static so
    // there’s no true refcount.
    return 1;
}
STDMETHODIMP_(ULONG)
StdioOutputCallbacks::Release(
    THIS
    )
{
    // This class is designed to be static so
    // there’s no true refcount.
    return 0;
}
STDMETHODIMP
StdioOutputCallbacks::Output(
    THIS_
    IN ULONG Mask,
    IN PCSTR Text
    )
{
    UNREFERENCED_PARAMETER(Mask);
                        m_OutputBuffer += Text;
    return S_OK;
}
void StdioOutputCallbacks::InitOutPutBuffer()
{
                        m_OutputBuffer.erase();
}
  • 18.添加扩展函数的实现。在本例我们实现了一个扩展,该扩展显示当前线程第2帧中的变量名和类型。实现代码:
DECLARE_API (dvf3)
{
//
// Install output callbacks.
//
if ((gDebugClient->SetOutputCallbacks((PDEBUG_OUTPUT_CALLBACKS) &g_OutputCb))!= S_OK)
{
dprintf(“*****Error while installing Outputcallback.*****\n\n”);
return;
}
//
// Since frame count starts from 0 index, we have to pass 2 as parameter for .frame command for the frame# 2
//
//Execute command to extrac 2nd frame.
if (gExecuteCmd->Execute(DEBUG_OUTCTL_THIS_CLIENT | //Send output to only outputcallbacks
DEBUG_OUTCTL_OVERRIDE_MASK |
DEBUG_OUTCTL_NOT_LOGGED,
“.frame 2”,
DEBUG_EXECUTE_DEFAULT ) != S_OK)
{
dprintf(“Executing .frame 2 failled\n”);
return;
}
//Execute command to extrac 2nd frame.
if (gExecuteCmd->Execute(DEBUG_OUTCTL_THIS_CLIENT | //Send output to only outputcallbacks
DEBUG_OUTCTL_OVERRIDE_MASK |
DEBUG_OUTCTL_NOT_LOGGED,
“dv /i /t /v”,
DEBUG_EXECUTE_DEFAULT ) != S_OK)
{
dprintf(“Executing dv /i /t /v failled\n”);
return;
}
dprintf(“***** Extracting locals & formal params from frame 2 *****”);
dprintf(“\n%s\n”, g_OutputCb.GetOutputBuffer().c_str());
}

  • 19.重建项目。将. dll从发布文件夹中复制到Windbg查找扩展dll的文件夹中。
在x86机器上,默认目录为“<Drive letter>\Program Files\ debug Tools for Windows (x86)\winext”。
  • 20.扩展已经准备好用于使用或测试。
  • 21.启动windbg并打开一个完整的用户模式转储。输入.load myextension和hit enter,将扩展DLL加载到Windbg进程空间中。

  • 22.运行.chain命令来验证是否由WinDbg加载扩展。如果扩展被加载,将看到类似于下面输出的内容。

  • 23.输入!dvf3以运行扩展函数,用于从框架2中提取和显示变量名。

posted @ 2018-06-21 16:45  17bdw  阅读(684)  评论(0编辑  收藏  举报