首页 -> 安全研究

安全研究

绿盟月刊
绿盟安全月刊->第48期->技术专题
期刊号: 类型: 关键词:
MSDN系列(11)--给SoftICE写插件

作者: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文件)
版权所有,未经许可,不得转载