分析 : BSOD案例 2013-0821
看调用链, 是 IoCompleteRequest 内部会释放一些空间, 应该和pIrp有关, 但是因为我们代码中拷贝多了,覆盖了pIrp的未知空间, 使IoCompleteRequest 内部释放空间的操作失败了,引起报错。
发布日期:2021-06-30 22:01:42
浏览次数:3
分类:技术文章
本文共 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); ///< 这里记录一个数目,看看向缓冲区一共拷贝了多少内容?
*/
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提供的缓冲区到底有多大,就一股脑的往里面写,所以引起报错。
{
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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
不错!
[***.144.177.141]2024年05月04日 01时36分02秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
北大数学系“扫地僧”韦东奕爆红!拒绝哈佛 offer,留任北大,却因长相引热议...
2019-05-01
Python中文速查表来了!精心整理52张思维导图!
2019-05-01
别再问我Python打包成exe了!(终极版)
2019-05-01
当铛噹!Python字符串速查表来啦~
2019-05-01
收费的 XShell,我改用国产良心工具!
2019-05-01
想象中的论文答辩和真实的论文答辩!哈哈哈哈哈哈……
2019-05-01
基于 Python 的 11 种经典数据降维算法
2019-05-01
PyPy为什么能让Python原地起飞,速度比C还快!
2019-05-01
同样是技术出身,深夜看完王兴饭否的190条思考,越想越后怕!
2019-05-01
详尽实用的 PyCharm 教程,这篇文章值得一看
2019-05-01
Pyfolio一行代码实现专业量化回测图表
2019-05-01
Python正则表达式,这一篇就够了!
2019-05-01
学会这7个绘图工具包,Matplotlib可视化也没那么难
2019-05-01
用Python制作有声小说
2019-05-01
下一代Windows系统,Win11来了
2019-05-01
我不建议你抄大厂的用户画像。为什么?
2019-05-01
Python实现导弹自动追踪
2019-05-01
来了!Python 官方发布整套中文PDF文档(共27本)
2019-05-01
7个Python实战项目代码,让你分分钟晋级大神!
2019-05-01
GitHub 这份程序员强者生涯指南,成功斩获 4 万星!
2019-05-01