首页 -> 安全研究
安全研究
绿盟月刊
绿盟安全月刊->第48期->技术专题
作者:scz <scz@nsfocus.com>
日期:2004-06-03
--------------------------------------------------------------------------
目录:
☆ 背景
☆ 最终可用的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 <security@nsfocus.com>
* : http://www.nsfocus.net
* Maintain : scz <scz@nsfocus.com>
* 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 <windows.h>
#include <wdbgexts.h>
/************************************************************************
* *
* 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 <addr> - Dumps struct _CONTEXT at <addr>\n"
"\n"
);
return;
} /* end of help */
DECLARE_API ( showcontext )
{
ULONG Address;
PCONTEXT context = NULL;
ULONG BytesRead = 0;
if ( !args || !args[0] )
{
dprintf
(
"Usage: showcontext <addr>\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 <stdio.h>
#include <stdlib.h>
#include <windows.h>
#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 <addr> - Dumps struct _CONTEXT at <addr>
: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弹出,KeDebugCheck()来了!回安全模式吧。
尤其那些下载了最新版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] <<The Windows 2000 Device Driver Book, Second Edition>> - 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文件)
版权所有,未经许可,不得转载