首页
社区
课程
招聘
[原创]wdf驱动蓝屏调试定位全过程, 请指导
发表于: 2016-8-4 17:41 11072

[原创]wdf驱动蓝屏调试定位全过程, 请指导

2016-8-4 17:41
11072
/*****************************************************************************
      代码架构
*****************************************************************************/
1、 用户通过deviceuicontrol发送请求到驱动
2、 驱动收到用户的request(WDFREQUEST)后, 为该请求设置取消例程,同时创建子请求subrequest,为子请求设置完成例程
3、 驱动的requst的取消例程中,我首先结束subrequest,然后以STATUS_CANCELLED状态结束主request
4、 在subrequest的完成例程中,我代码大致如下
    VOID EvtXFerCompletionRoutine (...)
    {
        if ( WdfRequestUnmarkCancelable(pParentRequest) != STATUS_CANCELLED )    // 此处在开启vierifier后,系统睡眠,触发int3中断
        {
            完成主请求 request
        }
   
        // reuse subrequest
    }

/*****************************************************************************
      问题出现
*****************************************************************************/
代码架构描述清楚了,出现步骤如下
1、 开启程序,使数据开始传输,意味着源源不断的request发送给驱动,驱动又源源不断的产生subrequest
2、 此时,点击使设备睡眠(非长时间不操作后设备休眠)
3、 系统蓝屏

/*****************************************************************************
      windbg分析
*****************************************************************************/

KERNEL_MODE_EXCEPTION_NOT_HANDLED_M (1000008e)
This is a very common bugcheck.  Usually the exception address pinpoints
the driver/function that caused the problem.  Always note this address
as well as the link date of the driver/image that contains this address.
Some common problems are exception code 0x80000003.  This means a hard
coded breakpoint or assertion was hit, but this system was booted
/NODEBUG.  This is not supposed to happen as developers should never have
hardcoded breakpoints in retail code, but ...
If this happens, make sure a debugger gets connected, and the
system is booted /DEBUG.  This will let us see why this breakpoint is
happening.
Arguments:
Arg1: 80000003, The exception code that was not handled
Arg2: 83eab4bc, The address that the exception occurred at
Arg3: 807e5ca8, Trap Frame
Arg4: 00000000

STACK_TEXT:  
807e5d18 8603737f 8ceb97fc 8cec4eb0 00000000 nt!DbgBreakPoint+0x1
807e5d2c 9bd0117a 8cecceb0 00000000 73133148 Wdf01000!imp_WdfRequestUnmarkCancelable+0xa5
807e5d44 86047317 7313b148 796adfb0 8ceb97fc XXXXXXXX!EvtBulkRWURBCompletionRoutine+0x32 [f:\010_driver\cyioctl.c @ 1862]
807e5d70 8602bc36 a7cd8ed8 86952048 00000000 Wdf01000!FxRequestBase::CompleteSubmitted+0xf6
807e5d8c 8602bcde 01ec4eb0 8ca589b0 807e5dc4 Wdf01000!FxIoTarget::RequestCompletionRoutine+0x12d
807e5d9c 83ec99be 00000000 a7cd8ed8 8cec4eb0 Wdf01000!FxIoTarget::_RequestCompletionRoutine+0x35
807e5dc4 8416fcd4 00000000 a7cd8ed8 8ca589b0 nt!IopUnloadSafeCompletion+0x45
807e5df4 83ea8c53 00000000 a7cd8ed8 807e5e68 nt!IovpLocalCompletionRoutine+0x14b
807e5e38 8416fb64 8ea890f0 8cf2c008 8ea89028 nt!IopfCompleteRequest+0x128
807e5ea0 8ed15868 83e80314 8cf2c008 00000000 nt!IovCompleteRequest+0x133
807e5ed0 8ed16178 98f031d0 a7cd8ed8 8ceb9844 USBPORT!USBPORT_Core_iCompleteDoneTransfer+0x6e0
807e5efc 8ed199af 8ea89028 8ea890f0 8ea89a98 USBPORT!USBPORT_Core_iIrpCsqCompleteDoneTransfer+0x33b
807e5f24 8ed13d18 8ea89028 8ea89a98 8ea89002 USBPORT!USBPORT_Core_UsbIocDpc_Worker+0xbc
807e5f48 83ea84f5 8ea89aa4 8ea89002 00000000 USBPORT!USBPORT_Xdpc_Worker+0x173
807e5fa4 83ea8358 807c5120 8cbd3020 00000000 nt!KiExecuteAllDpcs+0xf9
807e5ff4 83ea7b1c 9e9b18fc 00000000 00000000 nt!KiRetireDpcList+0xd5
807e5ff8 9e9b18fc 00000000 00000000 00000000 nt!KiDispatchInterrupt+0x2c

/*****************************************************************************
      调试过程
*****************************************************************************/
1、 定位WdfRequestUnmarkCancelable会触发dbgbreakpoint
2、 还原WdfRequestUnmarkCancelable代码大致如下: 其中主要由于积累不足,无法获知相关形参。猜测为主
int __stdcall imp_WdfRequestUnmarkCancelable_252DA(int WdfDriverGlobals, ULONG_PTR Request)
{
  ULONG_PTR v2; // edi@1
  int v3; // ST14_4@3
  int v4; // eax@3
  int v5; // esi@6
  int result; // eax@11

  v2 = Request;
  if ( !Request )
    FxVerifierBugCheck_50F7A(WdfDriverGlobals - 200, 5u, 0, 0x1008u);
  v3 = Request;
  Request = 0;

  v4 = FxObject::_GetObjectFromHandle_127F7(v3, (int)&Request);   // 内核知识浅薄,不明白为何如此转换。 该代码实现请参考最后部分
  // 此处省略我认为不关键代码

  v5 = *(_DWORD *)(v4 + 0xC); // 这个是_FX_DRIVER_GLOBALS地址,巧合下,dt wdf01000!FxRequest 发现该结构体地址偏移c可以得到_FX_DRIVER_GLOBALS

  // 根据V5的判断, v4可以理解为 dtwdf01000!FxRequest类型 发现如下代码可以翻译为如下
  // if(!Request.m_Completed && Request.m_ioQueue), 理解为该请求尚未完成,或者仍在队列中m_ioQueue不为空,则执行真正的取消取消例程
  // 由于休眠使得主请求request被以STATUS_CANCELLED方式完成,因此走else分支
  if ( !*(_BYTE *)(v4 + 0x6A) && *(_DWORD *)(v4 + 0x88) )  
  {
    result = FxIoQueue::RequestCancelable_4179F(v4, 0, 0, 0);
  }
  else
  {
    // 出现该bug正式由于开启了verifier
    if ( /* *(_BYTE *)(v5 + 150) */ request.m_Globals.FxVerifierDbgBreakOnError == true )
      DbgBreakPoint();
    else
      FxRequestOutputBuffer::Delete(
        "Turn on framework verifier for %.sys to automatically break into the debugger next time it happens.\n",
        v5 + 212);
    result = 0xC0000010;
  }

  return result;
}

出现问题的是在开启verifier后,正在传输数据时系统睡眠引起的蓝屏, 原因可能是上层传递的请求在休眠时调用了取消例程
但是在该取消例程中,我以取消状态完成了这个请求, 同时迫使子请求调用完成例程,在完成例程中,我调用了WdfRequestUnmarkCancelable尝试取消 取消例程,因此引发了breakpoint调用。

因此我认为这个是正常现象。 不用搭理这个错误, 不知道理解的对不对。 只期望不是隐患

//????? 为啥request句柄转对象要这么恶心的操作,不了解。 那位高手可以解答一下呢?
unsigned int __stdcall FxObject::_GetObjectFromHandle_127F7(int a1, int a2)
{
  unsigned int result; // eax@1
  unsigned __int16 v3; // cx@2

  result = ~a1 & 0xFFFFFFF8;
  if ( a1 & 1 )
  {
    v3 = *(_WORD *)result;
    *(_WORD *)a2 = *(_WORD *)result;
    result -= v3;
  }
  return result;
}

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (4)
雪    币: 2096
活跃值: (1872)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
If exception code 0x80000003 occurs, a hard-coded breakpoint or assertion was hit, but the computer was started with the /NODEBUG switch. This problem should rarely occur. If it occurs repeatedly, make sure that a kernel debugger is connected and that the computer is started with the /DEBUG switch.
2016-8-4 18:11
0
雪    币: 757
活跃值: (21)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
im看不懂,小白不懂
2016-8-4 20:06
0
雪    币: 53
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
按道理,所有的程序都应该经得起Verifier验证(之前的认识), 这验证就是程序可以出错,但绝对不可以蓝屏。 所以出现这种breakpoint之后,尽管我知道这个描述,但还是要搞清楚为何出现这么一个breakpoint。
2016-8-5 08:37
0
雪    币: 2096
活跃值: (1872)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
别深入,深入就入坑了。。
2016-8-5 15:59
0
游客
登录 | 注册 方可回帖
返回
//