标题: MSDN系列(11)--给SoftICE写插件 创建: 2004-03-30 20:17 更新: 2004-04-05 15:10 链接: https://scz.617.cn/windows/200406031438.txt -------------------------------------------------------------------------- 目录: ☆ 背景 ☆ 最终可用的SoftICE插件 1) 编写PrivateExt.c文件 2) 编写PrivateExt.def文件 3) 编写sources文件 4) 编写makefile文件 5) 编译产生PrivateExt.dll文件 6) 测试windbg插件PrivateExt.dll 7) 转换并测试SoftICE插件PrivateExt.sys ☆ windbg插件转SoftICE插件友情提示 ☆ 参考资源 -------------------------------------------------------------------------- ☆ 背景 一般打开faults on,触发异常时可以用stack命令查看调用栈回溯。可是在异常处理 过程中再次触发异常,faults on就无能为力了。此时设置如下断点: bpx ntdll!KiUserExceptionDispatcher do "dd (*esp)+c L10;dd (*(esp+4))+8c L40" 对照CONTEXT结构: +0x08c SegGs +0x090 SegFs +0x094 SegEs +0x098 SegDs +0x09c Edi +0x0a0 Esi +0x0a4 Ebx +0x0a8 Edx +0x0ac Ecx +0x0b0 Eax +0x0b4 Ebp +0x0b8 Eip +0x0bc SegCs +0x0c0 EFlags +0x0c4 Esp +0x0c8 SegSs 用命令"stack SS:EBP"查看调用栈回溯即可。但每次都要对照CONTEXT结构,很不爽, 而SoftICE又没有windbg的"dt -v nt!_CONTEXT"命令可用,因此想写一个SoftICE的 插件。 官方解决办法只有将windbg插件转成SoftICE插件这一条路可走,毕竟KD2SYS是自带 工具。非官方解决办法估计得参考IceExt的源代码([7]),暂时没精力做这件事。 ☆ 最终可用的SoftICE插件 1) 编写PrivateExt.c文件 hume同学成功地实现了SoftICE插件,区别在于编写PrivateExt.c时不要考虑64-bit 可移植性。 wdbgexts.h中PWINDBG_CHECK_VERSION的函数原型与CheckVersion不相符,但几乎所 有的(官方的、非官方的)例子中返回值都是VOID,所以我也采用之。由于该函数可选, 如果有顾虑,可以不实现CheckVersion()。 6.3版windbg开始携带debugext.chm文件,开始介绍WINDBG_EXTENSION_APIS的用法。 -------------------------------------------------------------------------- /* * Copyright (C) 2002, 2012 * The NSFOCUS INFORMATION TECHNOLOGY CO.,LTD. * ----------------------------------------------------------------------- * Author : NSFocus Security Team * : http://www.nsfocus.net * Maintain : scz * Version : 1.10 * Compile : For x86/EWindows XP SP1 * : VC 7 * : Windows DDK 2600.1106 * : Windows Debugger Version 6.2.0007.4 * : build -cZMg -x86 * : * Create : 2004-03-31 15:02 * Modify : 2004-04-05 13:31 * ----------------------------------------------------------------------- * The only thing they can't take from us are our minds. !H */ /* * 这次为了成功转换成SoftICE插件,不要考虑64-bit可移植性。 */ /************************************************************************ * * * Head File * * * ************************************************************************/ #include #include /************************************************************************ * * * Macro * * * ************************************************************************/ #define VERSION "1.10" #define OFFSETOF(TYPE, MEMBER) ((size_t)&((TYPE)0)->MEMBER) /************************************************************************ * * * Function Prototype * * * ************************************************************************/ /************************************************************************ * * * Static Global Var * * * ************************************************************************/ EXT_API_VERSION ApiVersion = { 5, 0, EXT_API_VERSION_NUMBER, 0 }; WINDBG_EXTENSION_APIS ExtensionApis; ULONG SavedMajorVersion; ULONG SavedMinorVersion; /************************************************************************/ DECLARE_API ( help ) { dprintf ( "\n" "Help for extension dll PrivateExt.dll\n" "\n" " help - Shows this help\n" " showcontext - Dumps struct _CONTEXT at \n" "\n" ); return; } /* end of help */ DECLARE_API ( showcontext ) { ULONG Address; PCONTEXT context = NULL; ULONG BytesRead = 0; if ( !args || !args[0] ) { dprintf ( "Usage: showcontext \n" ); goto showcontext_exit; } Address = GetExpression( args ); context = LocalAlloc ( LPTR, OFFSETOF( PCONTEXT, ExtendedRegisters ) ); if ( NULL == context ) { dprintf ( "Failed to allocate memory for context.\n" ); goto showcontext_exit; } ReadMemory ( Address, context, OFFSETOF( PCONTEXT, ExtendedRegisters ), &BytesRead ); if ( OFFSETOF( PCONTEXT, ExtendedRegisters ) == BytesRead ) { dprintf ( "EAX=%08X EBX=%08X ECX=%08X EDX=%08X ESI=%08X\n" "EDI=%08X EBP=%08X ESP=%08X EIP=%08X EFLAGS=%08X\n" "CS=%04X DS=%04X SS=%04X ES=%04X FS=%04X GS=%04X\n", context->Eax, context->Ebx, context->Ecx, context->Edx, context->Esi, context->Edi, context->Ebp, context->Esp, context->Eip, context->EFlags, ( WORD )context->SegCs, ( WORD )context->SegDs, ( WORD )context->SegSs, ( WORD )context->SegEs, ( WORD )context->SegFs, ( WORD )context->SegGs ); } else { dprintf ( "OFFSETOF( PCONTEXT, ExtendedRegisters ) != BytesRead\n" ); } showcontext_exit: if ( NULL != context ) { LocalFree( context ); context = NULL; } return; } /* end of showcontext */ VOID WinDbgExtensionDllInit ( PWINDBG_EXTENSION_APIS lpExtensionApis, USHORT MajorVersion, USHORT MinorVersion ) { ExtensionApis = *lpExtensionApis; SavedMajorVersion = MajorVersion; SavedMinorVersion = MinorVersion; return; } /* end of WinDbgExtensionDllInit */ LPEXT_API_VERSION ExtensionApiVersion ( VOID ) { return( &ApiVersion ); } /* end of ExtensionApiVersion */ VOID CheckVersion ( VOID ) { return; } /* end of CheckVersion */ BOOL WINAPI DllMain ( HINSTANCE hinstDll, DWORD fdwReason, PVOID fImpLoad ) { switch ( fdwReason ) { case DLL_PROCESS_ATTACH: /* * The DLL is being mapped into the process's address space. * * We don't need thread start/stop notifications, so disable them. */ DisableThreadLibraryCalls( hinstDll ); break; case DLL_THREAD_ATTACH: /* * A thread is being created. */ break; case DLL_THREAD_DETACH: /* * A thread is exiting cleanly. */ break; case DLL_PROCESS_DETACH: /* * The DLL is being unmapped from the process's address space. */ break; } /* end of switch */ /* * Used only for DLL_PROCESS_ATTACH */ return( TRUE ); } /* end of DllMain */ /************************************************************************/ -------------------------------------------------------------------------- 2) 编写PrivateExt.def文件 -------------------------------------------------------------------------- LIBRARY "PrivateExt.dll" EXPORTS WinDbgExtensionDllInit ExtensionApiVersion CheckVersion help showcontext -------------------------------------------------------------------------- 3) 编写sources文件 -------------------------------------------------------------------------- TARGETNAME=PrivateExt TARGETPATH=obj TARGETTYPE=DYNLINK TARGETLIBS=J:\WINDDK\2600.1106\lib\wxp\i386\kernel32.lib DLLENTRY=_DllMainCRTStartup USE_PDB=1 USE_MSVCRT=1 UMTYPE=windows INCLUDES= MSC_WARNING_LEVEL=-W3 -WX SOURCES=PrivateExt.c -------------------------------------------------------------------------- 假设进入了"Win XP Free Build Environment": > set BUILD_ALT_DIR= 此时PrivateExt/下执行build -cZMg -x86,产生的目录/文件布局如下: PrivateExt> build -cZMg -x86 PrivateExt> tree /F /A . PRIVATEEXT | build.log | makefile | PrivateExt.c | PrivateExt.def | sources | \---obj | _objects.mac | \---i386 PrivateExt.dll PrivateExt.exp PrivateExt.lib privateext.obj PrivateExt.pdb 4) 编写makefile文件 -------------------------------------------------------------------------- !INCLUDE $(NTMAKEENV)\makefile.def -------------------------------------------------------------------------- PrivateExt> set NTMAKEENV NTMAKEENV=J:\WINDDK\2600~1.110\bin 5) 编译产生PrivateExt.dll文件 PrivateExt> set BUILD_ALT_DIR= PrivateExt> build -cZMg -x86 BUILD: Adding /Y to COPYCMD so xcopy ops won't hang. BUILD: Compile and Link for i386 BUILD: Examining privateext directory for files to compile. BUILD: Compiling privateext directory Compiling - privateext.c for i386 Building Library - obj\i386\privateext.lib for i386 BUILD: Linking privateext directory Linking Executable - obj\i386\privateext.dll for i386 BUILD: Done 2 files compiled 1 library built 1 executable built PrivateExt> dumpbin /imports PrivateExt.dll msvcrt.dll B6 _adjust_fdiv 2D7 malloc 13A _initterm 2A4 free KERNEL32.dll 240 LocalAlloc 244 LocalFree 84 DisableThreadLibraryCalls PrivateExt> dumpbin /exports PrivateExt.dll 1 0 00001398 CheckVersion 2 1 00001392 ExtensionApiVersion 3 2 00001369 WinDbgExtensionDllInit 4 3 00001260 help 5 4 0000126F showcontext 6) 测试windbg插件PrivateExt.dll -------------------------------------------------------------------------- /* * Matt Pietrek 1997 * ----------------------------------------------------------------------- * For x86/EWindows XP SP1 & VC 7 * cl SEHDEMO_1.c /nologo /Os /G6 /W3 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /link /RELEASE */ #include #include #include #pragma comment( linker, "/INCREMENTAL:NO" ) #pragma comment( linker, "/subsystem:console" ) static DWORD writable = 0xFFFFFFFF; static EXCEPTION_DISPOSITION __cdecl seh_func ( struct _EXCEPTION_RECORD *ExceptionRecord, void *EstablisherFrame, struct _CONTEXT *ContextRecord, void *DispatcherContext ) { printf( "Hello from seh_func()\n" ); ContextRecord->Eax = ( DWORD )&writable; return( ExceptionContinueExecution ); } /* end of seh_func */ int __cdecl main ( int argc, char * argv[] ) { __asm { push seh_func push FS:[0] mov FS:[0],ESP } printf( "writable = 0x%08X\n", writable ); __asm { mov EAX,0 mov DWORD PTR [EAX],0 } printf( "You should see this message\n" "writable = 0x%08X\n", writable ); __asm { mov EAX,[ESP] mov FS:[0],EAX add ESP,8 } return( EXIT_SUCCESS ); } /* end of main */ -------------------------------------------------------------------------- ntsd -s SEHDEMO_1.exe > bp ntdll!KiUserExceptionDispatcher "dd poi(esp)+c L1;dd (dwo(esp+4))+8c L10" > g writable = 0xFFFFFFFF (e54.a5c): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. 0040102d c70000000000 mov dword ptr [eax],0x0 ds:0023:00000000=???????? > g 0012fc00 0040102d 0012fc9c 00000000 00000038 00000023 00000023 0012fcac 00000000 00000a28 7ffdf000 00000001 0012fcbc ffffffff 00000000 0012fee4 0040102d 0012fccc 0000001b 00010212 0012fedc 00000023 eax=00000000 ebx=7ffdf000 ecx=ffffffff edx=00000001 esi=00000a28 edi=00000000 eip=77f75dac esp=0012fbec ebp=0012fee4 iopl=0 nv up ei pl nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212 ntdll!KiUserExceptionDispatcher: 77f75dac 8b4c2404 mov ecx,[esp+0x4] ss:0023:0012fbf0=0012fc10 > bc * > .restart > .load PrivateExt.dll > bp ntdll!KiUserExceptionDispatcher "dd poi(esp)+c L1;!showcontext dwo(esp+4)" > g > g 0012fc00 0040102d EAX=00000000 EBX=7FFDF000 ECX=FFFFFFFF EDX=00000001 ESI=00000A28 EDI=00000000 EBP=0012FEE4 ESP=0012FEDC EIP=0040102D EFLAGS=00010212 CS=001B DS=0023 SS=0023 ES=0023 FS=0038 GS=0000 > 7) 转换并测试SoftICE插件PrivateExt.sys 用KD2SYS转换: Copying X:\onlytemp\PrivateExt.dll to X:\WINDOWS\SYSTEM32\DRIVERS\PrivateExt.SYS Original checksum was 0000db01, new checksum is 00006131 Adding device to registry... Creating SYSTEM\CurrentControlSet\Services\PrivateExt Updating KDExtensions key for NTICE KDExtensions='' i=16384 j=212 New extension list='PrivateExt.SYS' len 15 net start PrivateExt :!help Help for extension dll PrivateExt.dll help - Shows this help showcontext - Dumps struct _CONTEXT at :bpx ntdll!KiUserExceptionDispatcher do "dd (*esp)+c L10;dd (*(esp+4))+8c L40" :g Break due to BP 00: BPX _KiUserExceptionDispatcher DO "dd (*esp)+c L10;dd (*(esp+4))+8c L40" _KiUserExceptionDispatcher 0023:0012FC00 0040102D 00000002 00000001 00000000 -.@............. 0023:0012FC9C 00000000 00000038 00000023 00000023 ....8...#...#... 0023:0012FCAC 00000000 00000A28 7FFDF000 00000001 ....(......?.... 0023:0012FCBC FFFFFFFF 00000000 0012FEE4 0040102D ............-.@. 0023:0012FCCC 0000001B 00000212 0012FEDC 00000023 ............#... :bc * :bpx ntdll!KiUserExceptionDispatcher do "!showcontext *(esp+4)" :g Break due to BP 00: BPX _KiUserExceptionDispatcher DO "!showcontext *(esp+4)" _KiUserExceptionDispatcher EAX=00000000 EBX=7FFDF000 ECX=FFFFFFFF EDX=00000001 ESI=00000A28 EDI=00000000 EBP=0012FEE4 ESP=0012FEDC EIP=0040102D EFLAGS=00000212 CS=001B DS=0023 SS=0023 ES=0023 FS=0038 GS=0000 :bc * :macro bpseh="bpx ntdll!KiUserExceptionDispatcher do \"!showcontext *(esp+4)\"" :bpseh :g ☆ windbg插件转SoftICE插件友情提示 写程序写久了,就不可避免地出现"保持高可移植性"的僻好。如果哪位兄弟写windbg 插件,进而转SoftICE插件,一定要注意一件事,不要保持32-bit与64-bit之间的可 移植性,应该写一个纯32-bit的windbg插件。否则有两种下场: a) SoftICE手动加载 此时用"net start"命令可以成功启动插件,driver命令也可以看到加载上来的插 件,但用!号看不到扩展命令。 b) SoftICE以其它方式加载 此时你会发现加载插件时SoftICE弹出,KeBugCheck()来了!回安全模式吧。 尤其那些下载了最新版windbg的兄弟要留心这个事。 当然,只写windbg插件,不打算转成SoftICE插件的话,就不存在这里所说的问题。 多谢hume的发现以及Immortal1015兄的蓝屏测试。 ☆ 参考资源 [ 1] Writing a kd/WinDbg Debugger Extension DLL - Myk Willis[1998-12] http://www.windevnet.com/documents/s=7293/wdj9812c/9812c.htm ftp://ftp.wdj.com/pub/1998/dec98.zip [ 2] Making WinDbg Your Friend - Creating Debugger Extensions http://www.osronline.com/article.cfm?id=52 http://www.osronline.com/custom.cfm?name=articlePrint.cfm&id=52 [ 3] Debug Tutorial Part 4: Writing WINDBG Extensions http://www.codeproject.com/useritems/cdbntsd4.asp http://www.codeproject.com/useritems/cdbntsd4/cdbntsd4_src.zip http://www.codeproject.com/useritems/cdbntsd4/cdbntsd4_demo.zip [ 4] Kernel Debug Extensions http://frontline.compuware.com/nashua/papers/kernel_debug.htm Error Translating Kernel Debugger Extention DLL [1999-08-19] http://frontline.compuware.com/nashua/kb/doc/612.asp [ 5] Writing Your Own WinDBG Extensions - John Robbins[2000-01] http://www.microsoft.com/msj/0100/bugslayer/bugslayer0100.aspx http://download.microsoft.com/download/0/6/7/0678184e-905e-4783-9511-d4dca1f492b4/Jan00Bugslayer.exe [ 6] <> - Art Baker, Jerry Lozano [ 7] IceExt official homepage - Sten http://stenri.pisem.net [ 8] Using the Debugger Engine and Extension API (6.3版windbg开始携带debugext.chm文件)