基于Sfilter框架Demo的缓冲区溢出BUG分析

来源:互联网 发布:linux系统怎么安装软件 编辑:程序博客网 时间:2024/05/16 11:57

实验了好几次, 才找到能崩溃的那个demoDrv.sys

做个应用层的启动程序, 只负责安装这个驱动指定该驱动随着系统启动.

(备注如果直接安装运行驱动, 有可能崩溃后, 调用栈链中没有我们的驱动)

安装驱动完成后, 重新启动计算机.

WinDbg链接计算机进行调试当计算机启动起来后,被WinDbg断下.

设置合适的符号路径源文件路径映像路径

demoDrv.sysDriverEntry中下断点然后全速运行

当demoDrv.sys启动后, 被WinDbg断下, 证实我们正在调试该驱动.

kd> gBreakpoint 0 hitdemoDrv!DriverEntry+0x12:ee859b22 8b450c          mov     eax,dword ptr [ebp+0Ch]

再全速运行就看到驱动挂掉了还没来的及在目标计算机里点击个目录~, 效果很理想

kd> gAccess violation - code c0000005 (!!! second chance !!!)nt!ExDeferredFreePool+0xfd:80545603 8913            mov     dword ptr [ebx],edx

用 !analyze -v 命令分析报错信息

kd> !analyze -vConnected to Windows XP 2600 x86 compatible target at (Mon Jun 10 20:40:58.066 2013 (UTC + 8:00)), ptr64 FALSELoading Kernel Symbols..................................................................................................Loading User Symbols...Loading unloaded module list..*** ERROR: Symbol file could not be found.  Defaulted to export symbols for sfcfiles.dll - *** ERROR: Module load completed but symbols could not be loaded for ipnat.sys*** ERROR: Module load completed but symbols could not be loaded for vmhgfs.sys*** ERROR: Module load completed but symbols could not be loaded for ipsec.sys*** ERROR: Module load completed but symbols could not be loaded for vmx_svga.sys*** ERROR: Module load completed but symbols could not be loaded for isapnp.sys*** ERROR: Symbol file could not be found.  Defaulted to export symbols for vmci.sys - *** ERROR: Symbol file could not be found.  Defaulted to export symbols for vsock.sys - *** ERROR: Symbol file could not be found.  Defaulted to export symbols for drmk.sys - *** ERROR: Module load completed but symbols could not be loaded for intelppm.sys********************************************************************************                                                                             **                        Bugcheck Analysis                                    **                                                                             ********************************************************************************Unknown bugcheck code (0)Unknown bugcheck descriptionArguments:Arg1: 00000000Arg2: 00000000Arg3: 00000000Arg4: 00000000Debugging Details:------------------PROCESS_NAME:  smss.exeFAULTING_IP: nt!ExDeferredFreePool+fd80545603 8913            mov     dword ptr [ebx],edxEXCEPTION_RECORD:  ffffffff -- (.exr 0xffffffffffffffff)ExceptionAddress: 80545603 (nt!ExDeferredFreePool+0x000000fd)   ExceptionCode: c0000005 (Access violation)  ExceptionFlags: 00000000NumberParameters: 2   Parameter[0]: 00000001   Parameter[1]: 00000000Attempt to write to address 00000000ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%08lxEXCEPTION_CODE: (NTSTATUS) 0xc0000005 - 0x%08lxEXCEPTION_PARAMETER1:  00000001EXCEPTION_PARAMETER2:  00000000WRITE_ADDRESS:  00000000 FOLLOWUP_IP: nt!ExDeferredFreePool+fd80545603 8913            mov     dword ptr [ebx],edxBUGCHECK_STR:  ACCESS_VIOLATIONDEFAULT_BUCKET_ID:  NULL_DEREFERENCELAST_CONTROL_TRANSFER:  from 80545c6f to 80545603STACK_TEXT:  f71f92b4 80545c6f e12fd558 85fbf018 86174f38 nt!ExDeferredFreePool+0xfdf71f92f4 f780082f e14aac00 00000000 00000018 nt!ExFreePoolWithTag+0x489f71f9350 f78008c0 e14aa008 e14aa066 e13f79e8 demoDrv!QueryDirectoryForLongName+0x29f [d:\myworkdir\sfilterdebug\demo\driver\misc.c @ 499]f71f9378 f7800c8b e14aa008 e13f79e8 00000208 demoDrv!QueryLongName+0x80 [d:\myworkdir\sfilterdebug\demo\driver\misc.c @ 527]f71f93bc f77fe8ad f71f93f0 e16eb7a8 00000208 demoDrv!ConverShortToLongName+0x39b [d:\myworkdir\sfilterdebug\demo\driver\misc.c @ 640]f71f9a60 804ef119 85e5eef8 85fbf008 85fbf008 demoDrv!sfCreate+0x3bd [d:\myworkdir\sfilterdebug\demo\driver\sfilter.c @ 2530]f71f9a70 80579616 861ad8e8 85f51264 f71f9c18 nt!IopfCallDriver+0x31f71f9b50 805b5cbc 861ad900 00000000 85f511c0 nt!IopParseDevice+0xa12f71f9bd8 805b2065 00000000 f71f9c18 00000040 nt!ObpLookupObjectName+0x56af71f9c2c 8056c223 00000000 00000000 1b4e7001 nt!ObOpenObjectByName+0xebf71f9ca8 8056cb9a 0015fe50 00110000 0015fde8 nt!IopCreateFile+0x407f71f9d04 805703c1 0015fe50 00110000 0015fde8 nt!IoCreateFile+0x8ef71f9d44 8053e638 0015fe50 00110000 0015fde8 nt!NtOpenFile+0x27f71f9d44 7c92e4f4 0015fe50 00110000 0015fde8 nt!KiFastCallEntry+0xf80015fd74 7c92d58c 48587b32 0015fe50 00110000 ntdll!KiFastSystemCallRet0015fd78 48587b32 0015fe50 00110000 0015fde8 ntdll!NtOpenFile+0xc0015fe58 48588c79 00000000 7c921295 00000000 smss!SmpProcessFileRenames+0x2e10015fecc 48588f27 0015ff6c 00000005 00000000 smss!SmpLoadDataFromRegistry+0x31c0015ff18 48589bfc 0015ff6c 0015ff64 00000005 smss!SmpInit+0x1bd0015ffa8 4858ad97 00000001 00162340 00162348 smss!main+0x680015fff4 00000000 7ffdd000 000000c8 0000017c smss!NtProcessStartup+0x1d2STACK_COMMAND:  kbSYMBOL_STACK_INDEX:  0SYMBOL_NAME:  nt!ExDeferredFreePool+fdFOLLOWUP_NAME:  Pool_corruptionIMAGE_NAME:  Pool_CorruptionDEBUG_FLR_IMAGE_TIMESTAMP:  0MODULE_NAME: Pool_CorruptionFAILURE_BUCKET_ID:  ACCESS_VIOLATION_nt!ExDeferredFreePool+fdBUCKET_ID:  ACCESS_VIOLATION_nt!ExDeferredFreePool+fdFollowup: Pool_corruption---------

报错分析

可以看到最新的6条堆栈调用是引起报错的有效信息都是demoDrv.sys引起的

f71f92b4 80545c6f e12fd558 85fbf018 86174f38 nt!ExDeferredFreePool+0xfdf71f92f4 f780082f e14aac00 00000000 00000018 nt!ExFreePoolWithTag+0x489f71f9350 f78008c0 e14aa008 e14aa066 e13f79e8 demoDrv!QueryDirectoryForLongName+0x29f [d:\myworkdir\sfilterdebug\demo\driver\misc.c @ 499]f71f9378 f7800c8b e14aa008 e13f79e8 00000208 demoDrv!QueryLongName+0x80 [d:\myworkdir\sfilterdebug\demo\driver\misc.c @ 527]f71f93bc f77fe8ad f71f93f0 e16eb7a8 00000208 demoDrv!ConverShortToLongName+0x39b [d:\myworkdir\sfilterdebug\demo\driver\misc.c @ 640]f71f9a60 804ef119 85e5eef8 85fbf008 85fbf008 demoDrv!sfCreate+0x3bd [d:\myworkdir\sfilterdebug\demo\driver\sfilter.c @ 2530]f71f9a70 80579616 861ad8e8 85f51264 f71f9c18 nt!IopfCallDriver+0x31

下面直接对着调用栈,看着代码可以分析到最终引起报错的原因, 没有再分析WinDbg调试信息.

demoDrv.sys调用链的最开始处分析代码如果不能找到错误,逐渐向报错处的函数分析.

分析顺序为 sfilter.c @ 2530 => misc.c @ 640 => misc.c @ 527 => misc.c @ 499


查离错误最远的一个函数 sfilter.c @ 2530

        if (IsShortNamePath(lpNameControl->Name.Buffer))        {ConverShortToLongName(wszLongName, lpNameControl->Name.Buffer, sizeof(WCHAR)*MAX_PATH);RtlCopyMemory(lpNameControl->Name.Buffer, wszLongName, sizeof(WCHAR)*MAX_PATH); ///< line 2530, 这里有Buffer操作        }

wszLongName 是在函数中定义的缓冲区宽字符 _MAX_PATH, 没问题

查看 lpNameControl->Name 怎么来的

lpNameControl 是由前面的 GetFileNameFromObject 产生

ntStatus = GetFileNameFromObject(&lpNameControl, LookupFlags, lpIrpStack->FileObject, lpDevice);

 GetFileNameFromObject 函数

NTSTATUSGetFileNameFromObject(   PNAME_CONTROL* lppNameControl,    ULONG ulFlag,    FILE_OBJECT* lpFileObject,    PDEVICE_OBJECT lpDevice){    BOOLEAN bCacheName = FALSE;    NTSTATUS Status = STATUS_SUCCESS;    PSFILTER_DEVICE_EXTENSION lpDevExt = (PSFILTER_DEVICE_EXTENSION)(lpDevice->DeviceExtension);  Status = NLAllocateNameControl( lppNameControl, &gSfNameBufferLookasideList );///< 可以看到 lppNameControl 是由 NLAllocateNameControl函数分配

NLAllocateNameControl函数

NTSTATUSNLAllocateNameControl (    __out PNAME_CONTROL *NameControl,    __in PPAGED_LOOKASIDE_LIST LookasideList    ){    PNAME_CONTROL nameCtrl = NULL;    nameCtrl = ExAllocateFromPagedLookasideList( LookasideList );    if (nameCtrl == NULL) {        *NameControl = NULL;        return STATUS_INSUFFICIENT_RESOURCES;    }    NLInitNameControl( nameCtrl );///< 空间是由NLInitNameControl函数初始化    *NameControl = nameCtrl;    return STATUS_SUCCESS;}

NLInitNameControl函数

VOIDNLInitNameControl (    __inout PNAME_CONTROL NameCtrl    ){    PAGED_CODE();    NameCtrl->AllocatedBuffer = NULL;    NameCtrl->BufferSize = sizeof( NameCtrl->SmallBuffer );///<  NameCtrl->SmallBuffer是真正的缓冲区, 供外部使用    RtlInitEmptyUnicodeString( &NameCtrl->Name,                               (PWCHAR)NameCtrl->SmallBuffer,                               (USHORT)NameCtrl->BufferSize );}

NameCtrl->SmallBuffer定义

ypedef struct _NAME_CONTROL {    UNICODE_STRING Name;    PUCHAR AllocatedBuffer;    ULONG BufferSize;    DECLSPEC_PTRALIGN UCHAR SmallBuffer[254];///< 问题找到了, 缓冲区太小, 拷贝时, 用的是(sizeof(wchar_t ) * _MAX_PATH), 这里是(sizeof(BYTE) * 254)} NAME_CONTROL, *PNAME_CONTROL;

问题已经定位

最直接的修改方案是将SmallBuffer定义改大改成 sizeof(wchar_t)* _MAX_PATH

// 原始工程中头文件少包含了, 从标准定义中, 抄一个宏过来#ifndef _MAX_PATH#define _MAX_PATH   260 /* max. length of full pathname */#endiftypedef struct _NAME_CONTROL {    //    //  UNICODE_STRING whos buffer is either SmallBuffer or AllocatedBuffer    //  if a larger buffer was needed.    //    UNICODE_STRING Name;    //    //  AllocatedBuffer is used when we need a buffer larger than SmallBuffer.    //    PUCHAR AllocatedBuffer;    //    //  The size of whatever buffer is currently being used (SmallBuffer or    //  AllocatedBuffer) in bytes.    //    ULONG BufferSize;    //    //  This is the buffer that we start out with.  The thinking is that this    //  should be large enough for most names.    //  /// original define => DECLSPEC_PTRALIGN UCHAR SmallBuffer[254];    DECLSPEC_PTRALIGN WCHAR SmallBuffer[_MAX_PATH];///< bigfix } NAME_CONTROL, *PNAME_CONTROL;