论坛: 编程破解 标题: [转帖]WinDbg插件编写――基础篇 复制本贴地址    
作者: yongmin [yongmin]    论坛用户   登录
本文只是简略的描述了一下WinDbg扩展命令的编写步骤及方法,更详细的请看他的帮助文档,起到一个抛砖引玉的作用就行了。
WinDbg是老盖自己家出的调试器,功能很强大。即可调试用户态,也可以调试核心态程序。本文主要介绍他插件(准确讲应该是扩展命令)的编写方法。WinDbg的扩展命令和OD一样是通过DLL文件导出的。
一.插件的类型
他有两种不同类型的DLL文件:
1.DbgEng类型DLL。这种类型的DLL都已“dbgeng.h” 头文件为基础。扩展命令的功能比较强大,可以用Debugger Engine API(这种调试API不依赖WinDbg,可以用来编写自己的调试器),也可以用WdbgExts API。
2.WdbgExts类型DLL。这种类型的DLL以“Wdbgexts.h” 头文件为基础,它只能用WdbgExts API.
二.两种插件的编写方法。
一般来说编写一个扩展命令需要四个文件:.c/c++文件,.def文件,sources文件和makefile文件,和写一般DLL文件一样。下面主要讲c/c++文件和def文件,应为他们在两种类型的DLL中差异比较大。
1.DbgEng类型。
(1) c/c++文件,可以用dbgeng.h标准的C++代码调试接口也可以用wdbgexts.h中的c代码接口。如果在这个类型中用wdbgexts API,需要用到wdbgexts.h和KDEXT_64BIT宏,如:
  #define KDEXT_64BIT
  #include wdbgexts.h
  #include dbgeng.h
这个文件主要依据dbgeng.h和wdbgexts.h中的调试接口函数实现特定功能的函数代码。第一行主要是编译64位的,两个头文件中的函数都有32和64位,如ReadIoSpace64和ReadIoSpace,你可以在这种类型的扩展中完全用64位的函数,既可以在64位cpu也可以在32为cpu 运行。
(2)def文件,定义导出函数和自己的扩展命令
DebugExtensionInitialize函数必须导出,当DLL被加载时用来初始化全局变量。其他的根据实际情况而定。
2.WdbgExts类型
这种类型扩展的功能比上一种来说差一些,但一般情况下也能完成很多任务。
(1)C文件。
  I.只能用wdbgexts.h中的c接口,如果用64位,简单的包含
#define KDEXT_64BIT
#include wdbgexts.h
只是编译32位的话,就无需包含第一句。
  II.必须用DECLARE_API宏
这个宏定义在wdbgexts.h中,
#define DECLARE_API(s)                            \
    CPPMOD VOID                                    \
    s(                                            \
        HANDLE                hCurrentProcess,    \
        HANDLE                hCurrentThread,    \
        ULONG64                dwCurrentPc,        \
        ULONG                  dwProcessor,        \
        PCSTR                  args                \
    )
如果是32位dwCurrentPc的类型就要换成ULONG.
(2)def文件
必须输出WinDbgExtensionDllInit.和ExtensionApiVersion两个函数。
三.编译
1.需要Windows Driver Kit(WDK),必须在windows 2003 server build environment环境下。
2.设置DBGSDK_INC_PATH和DBGSDK_LIB_PATH环境变量。
3.切换到你的原文件目录下
4.执行build �CcZMg
四.加载
把编译出的含DLL的文件夹放到WinDbg安装目录下,运行WinDbg后用.load dllname 就可以了。然后就尽情的享受你自己编写的命令把。

*********************************************************************
实例:
下来用一个主要是以wdbgexts.h API调试接口的例子。这个dll文件主要是自己实现read(读指定地址值),
edit(编辑指定地址的值),stack(取得堆栈值),help(显示以上三个命令的帮助信息).
(1)编写simple.c文件
(2)编写simple.def文件
(3)编写sources文件
(4)编写makefile文件
(5)编写rc资源文件
(6)编译并产生simple.dll
(7)加载并执行自己的扩展命令
**********************************************************************



CODE:[Copy to clipboard](1)c文件
//
//头文件和宏定义
#include <windows.h>
#include "simple.h"

#define KDEXT_64BIT 
#include <wdbgexts.h>
#include <ntverp.h>
//
// 全局变量
//
EXT_API_VERSION        ApiVersion = { (VER_PRODUCTVERSION_W >> 8), (VER_PRODUCTVERSION_W & 0xff), EXT_API_VERSION_NUMBER64, 0 };
WINDBG_EXTENSION_APIS  ExtensionApis;
ULONG SavedMajorVersion;
ULONG SavedMinorVersion;
//
//主程序
//

DllInit(
    HANDLE hModule,
    DWORD  dwReason,
    DWORD  dwReserved
    )
{
    switch (dwReason) {
        case DLL_THREAD_ATTACH:
            break;

        case DLL_THREAD_DETACH:
            break;

        case DLL_PROCESS_DETACH:
            break;

        case DLL_PROCESS_ATTACH:
            break;
    }

    return TRUE;
}


VOID
WinDbgExtensionDllInit(
    PWINDBG_EXTENSION_APIS lpExtensionApis,
    USHORT MajorVersion,
    USHORT MinorVersion
    )
{
    ExtensionApis = *lpExtensionApis;

    SavedMajorVersion = MajorVersion;
    SavedMinorVersion = MinorVersion;

    return;
}

LPEXT_API_VERSION
ExtensionApiVersion(
    VOID
    )
{
 
    return &ApiVersion;
}


VOID
CheckVersion(
    VOID
    )
{
    return;
}
//
// 读目标双字值
//
DECLARE_API( read )
{
    ULONG cb;
    ULONG64 Address;
    ULONG  Buffer[4];

    Address = GetExpression(args);

   
    if (ReadMemory(Address, &Buffer, sizeof(Buffer), &cb) && cb == sizeof(Buffer)) {
        dprintf("%I64lx: %08lx %08lx %08lx %08lx\n\n", Address,
                Buffer[0], Buffer[1], Buffer[2], Buffer[3]);
    }
}

//
// 编辑目标的双字值
// 
//    !edit <address> <value>
//
DECLARE_API( edit )
{
    ULONG cb;
    ULONG64 Address;
    ULONG  Value;

    if (GetExpressionEx(args, &Address, &args)) {
        Value = (ULONG) GetExpression( args);
    } else {
        dprintf("Usage:  !edit <address> <value>\n");
        return;
    }

   
    if (WriteMemory(Address, &Value, sizeof(Value), &cb) && cb == sizeof(Value)) {
        dprintf("%I64lx: %08lx\n", Address, Value);
    }
}


//
// 提取堆栈值
//
DECLARE_API ( stack )
{
    EXTSTACKTRACE64 stk[20];
    ULONG frames, i;
    CHAR Buffer[256];
    ULONG64 displacement;


    // 在当前线程中获得堆栈祯值
    frames = StackTrace( 0, 0, 0, stk, 20 );

    if (!frames) {
        dprintf("Stacktrace failed\n");
    }

    for (i=0; i<frames; i++) {

        if (i==0) {
            dprintf( "ChildEBP RetAddr  Args to Child\n" );
        }

        Buffer[0] = '!';
        GetSymbol(stk.ProgramCounter, (PUCHAR)Buffer, &displacement);
       
        dprintf( "%08p %08p %08p %08p %08p %s",
                stk.FramePointer,
                stk.ReturnAddress,
                stk.Args[0],
                stk.Args[1],
                stk.Args[2],
                Buffer
                );

        if (displacement) {
            dprintf( "+0x%p", displacement );
        }

        dprintf( "\n" );
    }
}

/*
  编写help扩展命令
*/

DECLARE_API ( help )
{
    dprintf("Help for extension dll simple.dll\n"
"read  <addr>  - It reads and dumps 4 dwords at<addr>\n"
"edit  <addr> <val> - It modifies a dword value to <val> at <addr>\n"
"stack              - Printd current stack trace\n"
"help              - Shows this help\n"
            );

}

**********************************************************************
(2)def文件
;--------------------------------------------------------------------

;
; Module:
;    simple.def
;--------------------------------------------------------------------

EXPORTS

;--------------------------------------------------------------------
; These are the extensions exported by dll
;--------------------------------------------------------------------
    read
    edit
    help
    stack

;--------------------------------------------------------------------
;
; these are the extension service functions provided for the debugger
;
;--------------------------------------------------------------------


    CheckVersion
    WinDbgExtensionDllInit
    ExtensionApiVersion
**********************************************************************
(3)source文件
TARGETNAME=simple
TARGETPATH=obj
TARGETTYPE=DYNLINK

DLLENTRY=_DllMainCRTStartup

!if "$(DBGSDK_INC_PATH)" != ""
INCLUDES = $(DBGSDK_INC_PATH);$(INCLUDES)
!endif
!if "$(DBGSDK_LIB_PATH)" == ""
DBGSDK_LIB_PATH = $(SDK_LIB_PATH)
!else
DBGSDK_LIB_PATH = $(DBGSDK_LIB_PATH)\$(TARGET_DIRECTORY)
!endif

TARGETLIBS=$(SDK_LIB_PATH)\kernel32.lib

USE_MSVCRT=1

UMTYPE=windows

SOURCES= simple.c  \
        simple.rc
**********************************************************************
(4)makefile文件
#
# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
# file to this component.  This file merely indirects to the real make file
# that is shared by all the components of Windows
#
!INCLUDE $(NTMAKEENV)\makefile.def
**********************************************************************
(5)rc文件
#include <windows.h>
#include <ntverp.h>

#define VER_FILETYPE                VFT_DLL
#define VER_FILESUBTYPE            VFT2_UNKNOWN
#define VER_FILEDESCRIPTION_STR    "Sample Debugger Extensions"

#define VER_INTERNALNAME_STR        "simple.DLL"
#define VER_ORIGINALFILENAME_STR    "simple.DLL"

#include "common.ver"
**********************************************************************
(6)编译并产生simple.dll
i.切换到windows server 2003 ddk编译环境
ii.设置windbg sdk环境变量
  set DBGSDK_INC_PATH=%debuggers%\sdk\inc
  set DBGSDK_LIB_PATH=%debuggers%\sdk\lib
  %debuggers%要换成你自己的目录
iii.切换到包含源文件的文件夹,并执行build -cZMg
**********************************************************************
(7)加载并执行
.load %debuggers%\simple
然后就可以执行我们的扩展命令。

后记:最新版的windbg 6.6.00007.5的安装时,要选择Custom,然后手工把SDK选中才会把SDK安装上。而且关于扩展命令编写的详细方法也集成到了帮助文档中。用Windbg还可以写.net调试命令扩展,如sos.dll,这一点是其他调试器所不具备的吧。

地主 发表时间: 07-02-05 10:13

回复: jhkdiy [jhkdiy]   版主   登录
这篇不错

B1层 发表时间: 07-02-07 20:11

论坛: 编程破解

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号