分析 : BSOD案例 2013-0821
发布日期:2021-06-30 22:01:42 浏览次数:2 分类:技术文章

本文共 9831 字,大约阅读时间需要 32 分钟。

今天帮人解决了一个BSOD,  根据参考他提供的DUMP文件 和 他自己调试时发现的出错前后的一段驱动代码.

没有接触他的R3和R0实体文件~

问题描述

测试一个入门的驱动程序:在ring3 通过DeviceIoControl 与驱动通信,驱动将一个进程的部分信息(ID、进程名等)写进缓冲区,通过双机调试在 win7 home basic 虚拟机上可以运行,但在外面主机(win7 旗舰版)中,运行蓝屏.

这是 DispatchDeviceControl 例程,用windbg 看了dump文件,指出貌似是在最后一句,return 是出错。。。

出错函数代码

NTSTATUS DispatchDeviceControl(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp){  NTSTATUS status = STATUS_SUCCESS;  ULONG dwPIdOffset;  ULONG dwPLinkOffset;  ULONG dwPNameOffset;  ULONG dwPCreateTimeOffset;  ULONG ulEprocess;  ULONG ulFirstProcess, ulNextProcess;  LIST_ENTRY*        ActiveProcessLinks;    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(pIrp);  PVOID    pInBuffer      = pIrp->AssociatedIrp.SystemBuffer;  PCHAR    pOutBuffer    = pIrp->AssociatedIrp.SystemBuffer;  ULONG   inBufLength    = irpStack->Parameters.DeviceIoControl.InputBufferLength;  ULONG  outBufLength  = irpStack->Parameters.DeviceIoControl.OutputBufferLength;  ULONG  ioControlCode  = irpStack->Parameters.DeviceIoControl.IoControlCode;  switch (ioControlCode)  {  case IOCTL_PROCESSLIST:    {      ulFirstProcess = (ULONG)IoGetCurrentProcess();      ulNextProcess = ulFirstProcess;      dwPCreateTimeOffset = GetPlantformDependentInfo(CREATE_TIME_OFFSET);      dwPIdOffset = GetPlantformDependentInfo(PROCESS_ID_OFFSET);      dwPNameOffset = GetPlantformDependentInfo(FILE_NAME_OFFSET);      dwPLinkOffset = GetPlantformDependentInfo(PROCESS_LINK_OFFSET);      do       {        memcpy(pOutBuffer, (void*)(ulNextProcess+dwPIdOffset), sizeof(ULONG));        pOutBuffer += sizeof(ULONG);        memcpy(pOutBuffer, (void*)(ulNextProcess+dwPCreateTimeOffset), sizeof(ULONG));        pOutBuffer += sizeof(ULONG);        memcpy(pOutBuffer, (void*)(ulNextProcess+dwPNameOffset), 15);        pOutBuffer += 15;        ActiveProcessLinks = (LIST_ENTRY*)*(ULONG*)(ulNextProcess + dwPLinkOffset);        ulEprocess = (ULONG)ActiveProcessLinks->Flink;        ulEprocess -=dwPLinkOffset;        ulNextProcess = ulEprocess;      } while (ulNextProcess != ulFirstProcess);    }    break;  default:    break;  }  pIrp->IoStatus.Status = STATUS_SUCCESS;  pIrp->IoStatus.Information = (ULONG)pOutBuffer-(ULONG)pInBuffer;  IoCompleteRequest(pIrp, IO_NO_INCREMENT);  return pIrp->IoStatus.Status;}

DUMP文件分析

Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64Copyright (c) Microsoft Corporation. All rights reserved.Loading Dump File [D:\Download\Dumpfile\082013-18345-01.dmp]Mini Kernel Dump File: Only registers and stack trace are availableSymbol search path is: SRV*D:\WinDbgSysSymbolsWin7X86*http://msdl.microsoft.com/download/symbols/Executable search path is: Windows 7 Kernel Version 7600 MP (2 procs) Free x86 compatibleProduct: WinNt, suite: TerminalServer SingleUserTSBuilt by: 7600.17207.x86fre.win7_gdr.130104-1435Machine Name:Kernel base = 0x8401c000 PsLoadedModuleList = 0x84164810Debug session time: Tue Aug 20 12:02:18.338 2013 (UTC + 8:00)System Uptime: 0 days 3:02:29.336Loading Kernel Symbols....................................................................................................................................................................................Loading User SymbolsLoading unloaded module list.........********************************************************************************                                                                             **                        Bugcheck Analysis                                    **                                                                             ********************************************************************************Use !analyze -v to get detailed debugging information.BugCheck 1000008E, {c0000005, 840d3f8d, b0891a3c, 0}*** WARNING: Unable to verify timestamp for AthenyDriver.sys*** ERROR: Module load completed but symbols could not be loaded for AthenyDriver.sysProbably caused by : AthenyDriver.sys ( AthenyDriver+14fe )Followup: MachineOwner---------
1: kd> !analyze -v********************************************************************************                                                                             **                        Bugcheck Analysis                                    **                                                                             ********************************************************************************KERNEL_MODE_EXCEPTION_NOT_HANDLED_M (1000008e)This is a very common bugcheck.  Usually the exception address pinpointsthe driver/function that caused the problem.  Always note this addressas well as the link date of the driver/image that contains this address.Some common problems are exception code 0x80000003.  This means a hardcoded breakpoint or assertion was hit, but this system was booted/NODEBUG.  This is not supposed to happen as developers should never havehardcoded breakpoints in retail code, but ...If this happens, make sure a debugger gets connected, and thesystem is booted /DEBUG.  This will let us see why this breakpoint ishappening.Arguments:Arg1: c0000005, The exception code that was not handledArg2: 840d3f8d, The address that the exception occurred atArg3: b0891a3c, Trap FrameArg4: 00000000Debugging Details:------------------EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - 0x%08lxFAULTING_IP: nt!ExpReleasePoolQuota+21840d3f8d 8a07            mov     al,byte ptr [edi]TRAP_FRAME:  b0891a3c -- (.trap 0xffffffffb0891a3c)ErrCode = 00000000eax=00000088 ebx=20206f49 ecx=000001ff edx=000f72e6 esi=8704abc0 edi=5f74656eeip=840d3f8d esp=b0891ab0 ebp=b0891b18 iopl=0         nv up ei pl nz na po nccs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010202nt!ExpReleasePoolQuota+0x21:840d3f8d 8a07            mov     al,byte ptr [edi]          ds:0023:5f74656e=??Resetting default scopeCUSTOMER_CRASH_COUNT:  1DEFAULT_BUCKET_ID:  VISTA_DRIVER_FAULTBUGCHECK_STR:  0x8EPROCESS_NAME:  Atheny.exeCURRENT_IRQL:  1IRP_ADDRESS:  017bd4c8LAST_CONTROL_TRANSFER:  from 8413b77f to 840d3f8dSTACK_TEXT:  b0891ab8 8413b77f 00000000 877bd4c8 8b04b5e0 nt!ExpReleasePoolQuota+0x21b0891b18 840bd555 8704abc8 00000000 9a1f90e1 nt!ExFreePoolWithTag+0x779b0891b64 8408417f 017bd508 b0891bac b0891ba4 nt!IopCompleteRequest+0xe6b0891bb4 aa9f14fe 00222000 000003e8 00000000 nt!IopfCompleteRequest+0x3b4WARNING: Stack unwind information not available. Following frames may be wrong.b0891bfc 8405779c 8a7c1a08 877bd4c8 877bd4c8 AthenyDriver+0x14feb0891c14 8425a4ce 8b04b5e0 877bd4c8 877bd538 nt!IofCallDriver+0x63b0891c34 842772fa 8a7c1a08 8b04b5e0 00000000 nt!IopSynchronousServiceTail+0x1f8b0891cd0 84279ad6 8a7c1a08 877bd4c8 00000000 nt!IopXxxControlFile+0x6aab0891d04 8405e78a 000000fc 00000000 00000000 nt!NtDeviceIoControlFile+0x2ab0891d04 77d96194 000000fc 00000000 00000000 nt!KiFastCallEntry+0x12a001ce08c 00000000 00000000 00000000 00000000 0x77d96194STACK_COMMAND:  kbFOLLOWUP_IP: AthenyDriver+14feaa9f14fe ??              ???SYMBOL_STACK_INDEX:  4SYMBOL_NAME:  AthenyDriver+14feFOLLOWUP_NAME:  MachineOwnerMODULE_NAME: AthenyDriverIMAGE_NAME:  AthenyDriver.sysDEBUG_FLR_IMAGE_TIMESTAMP:  5212e848FAILURE_BUCKET_ID:  0x8E_AthenyDriver+14feBUCKET_ID:  0x8E_AthenyDriver+14feFollowup: MachineOwner---------
BugCheckCode : KERNEL_MODE_EXCEPTION_NOT_HANDLED_M (1000008e)
这是一个未被捕获的异常.
Arg1: c0000005, The exception code that was not handled
异常记录的参数也证明了这点, 此错误没被MS明确定义
从栈调用链看到, 最后一次报错代码为: b0891ab8 8413b77f 00000000 877bd4c8 8b04b5e0
nt!ExpReleasePoolQuota+0x21
看起来是缓冲区溢出后,释放时引起的错误.
根据给出的出错函数看, 有缓冲区写动作的,是R0向R3提供的缓冲区写得到的进程信息.
分析写缓冲区的逻辑发现,  写缓冲区动作没有考虑缓冲区是否够大.

分析BSOD原因

最后一句出错在 nt!ExpReleasePoolQuota,拷贝缓冲区时,超出缓冲区大小了吧? 


ULONG   inBufLength    = irpStack->Parameters.DeviceIoControl.InputBufferLength;

ULONG  outBufLength  = irpStack->Parameters.DeviceIoControl.OutputBufferLength;


inBufLength 和 outBufLength 具体值是多少?


您R3往下送的时候,怎么写的? 

请贴出来(缓冲区建立的代码, DEVICE_IO_CONTROL 发送时的代码)


您可以尝试少拷贝一些内容,应该就不报错了

/*

do 

      {

        memcpy(pOutBuffer, (void*)(ulNextProcess+dwPIdOffset), sizeof(ULONG));

        pOutBuffer += sizeof(ULONG);


        memcpy(pOutBuffer, (void*)(ulNextProcess+dwPCreateTimeOffset), sizeof(ULONG));

        pOutBuffer += sizeof(ULONG);


        memcpy(pOutBuffer, (void*)(ulNextProcess+dwPNameOffset), 15);

        pOutBuffer += 15;


        ActiveProcessLinks = (LIST_ENTRY*)*(ULONG*)(ulNextProcess + dwPLinkOffset);

        ulEprocess = (ULONG)ActiveProcessLinks->Flink;

        ulEprocess -=dwPLinkOffset;

        ulNextProcess = ulEprocess;


      } while (ulNextProcess != ulFirstProcess);  
///< 这里记录一个数目,看看向缓冲区一共拷贝了多少内容?

*/
真机上的进程列表很多,虚拟机里面可能较少


      {

        memcpy(pOutBuffer, (void*)(ulNextProcess+dwPIdOffset), sizeof(ULONG));

        pOutBuffer += sizeof(ULONG);


        memcpy(pOutBuffer, (void*)(ulNextProcess+dwPCreateTimeOffset), sizeof(ULONG));

        pOutBuffer += sizeof(ULONG);


        memcpy(pOutBuffer, (void*)(ulNextProcess+dwPNameOffset), 15);

        pOutBuffer += 15;


        ActiveProcessLinks = (LIST_ENTRY*)*(ULONG*)(ulNextProcess + dwPLinkOffset);

        ulEprocess = (ULONG)ActiveProcessLinks->Flink;

        ulEprocess -=dwPLinkOffset;

        ulNextProcess = ulEprocess;


      }  ///< 改成这样, 就拷贝一次, 驱动应该不会报错


得进程列表之前,应先发一个 IO_CTRL_CODE 给驱动,驱动报出,当前有多少个进程.


R3根据(进程数 * sizeof(进程结构)) 开辟Buffer.

再发 IO_CTRL_CODE 给驱动, (下发的缓冲区中包含Buffer的数量(sizeof(进程结构) * N))让驱动上报进程具体信息.

有可能进程数量有变化,  当缓冲区不够时,就不再往里面拷贝进程信息了.

这样靠谱些.


看了您的代码实现, 我觉得主要问题,在于没有判断R3提供的缓冲区到底有多大,就一股脑的往里面写,所以引起报错。

STACK_TEXT:  b0891ab8 8413b77f 00000000 877bd4c8 8b04b5e0 nt!ExpReleasePoolQuota+0x21b0891b18 840bd555 8704abc8 00000000 9a1f90e1 nt!ExFreePoolWithTag+0x779b0891b64 8408417f 017bd508 b0891bac b0891ba4 nt!IopCompleteRequest+0xe6b0891bb4 aa9f14fe 00222000 000003e8 00000000 nt!IopfCompleteRequest+0x3b4WARNING: Stack unwind information not available. Following frames may be wrong.b0891bfc 8405779c 8a7c1a08 877bd4c8 877bd4c8 AthenyDriver+0x14fe
您看Dump文件的堆栈调用, IoCompleteRequest之后,就是返回,您说可能在返回那错了.


看调用链, 是 IoCompleteRequest 内部会释放一些空间, 应该和pIrp有关, 但是因为我们代码中拷贝多了,覆盖了pIrp的未知空间, 使IoCompleteRequest 内部释放空间的操作失败了,引起报错。 

修复验证

对方试了一下,搞定~
确定是写缓冲区时, R3给的buffer size小了.

转载地址:https://lostspeed.blog.csdn.net/article/details/10162659 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:英文缩写含义
下一篇:STM32调试时打开assert_failed

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月10日 15时58分39秒