返回列表 发帖

[转帖]WinDbg插件编写——基础篇

本文只是简略的描述了一下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 –cZMg 四.加载 把编译出的含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 #include "simple.h" #define KDEXT_64BIT #include #include // // 全局变量 // 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
// DECLARE_API( edit ) { ULONG cb; ULONG64 Address; ULONG Value; if (GetExpressionEx(args, &Address, &args)) { Value = (ULONG) GetExpression( args); } else { dprintf("Usage: !edit
\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 - It reads and dumps 4 dwords at\n" "edit - It modifies a dword value to at \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 #include #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,这一点是其他调试器所不具备的吧。

返回列表 回复 发帖