分析 : BSOD案例 2013-0821
看调用链, 是 IoCompleteRequest 内部会释放一些空间, 应该和pIrp有关, 但是因为我们代码中拷贝多了,覆盖了pIrp的未知空间, 使IoCompleteRequest 内部释放空间的操作失败了,引起报错。
发布日期: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); ///< 这里记录一个数目,看看向缓冲区一共拷贝了多少内容?
*/
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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月10日 15时58分39秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
上线三天获 22w 浏览量!2021 最新一线大厂 Java 高级架构师面试题总结~
2019-05-01
电信物联网平台SOTA升级(软件升级)的全流程说明
2019-05-01
电信物联网平台插件开发相关总结
2019-05-01
ARM之一 分散加载文件(scatter)详述
2019-05-01
centos6 python3.6 安装配置jupyer
2019-05-01
CDH5.14 spark2.4.0配置python3 以及读取hive表
2019-05-01
VMware安装centos7.2后配置网络并设置固定ip
2019-05-01
在 centos7.2安装docker 并设置阿里云源
2019-05-01
centos7.2 将mysql添加到服务中
2019-05-01
【linux用户模块】/etc/passwd的字段含义
2019-05-01
【linux用户模块】用户/用户组的管理
2019-05-01
【大数据】【调度】Airflow 和 Azkaban的选型
2019-05-01
用zabbix监控nginx
2019-05-01
计算机网络 —— 数据链路层 3.
2019-05-01
计算机网络 —— 网络层 1.
2019-05-01
29. 两数相除
2019-05-01
1833. 雪糕的最大数量
2019-05-01