前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子2

DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子2

作者头像
方亮
发布2019-01-16 10:27:26
7150
发布2019-01-16 10:27:26
举报
文章被收录于专栏:方亮

        本文介绍使用Windbg去验证《DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子》中的结论,调试对象是文中刚开始那个例子。(转载请指明出于breaksoftware的csdn博客)

        1 g 让程序运行起来

        2 ctrl+break 中断程序

        3 ~ 查看线程数

        其实该程序自己运行起来的线程只有ID为0、TID为afc的线程。18c4线程是我们在windbg中输入ctrl+break,导致windbg在我们调试的进程中插入的一个中断线程。以后我们看到是这个线程的操作,就可以忽略。

        4 dd fs:[0] 寻找主线程TEB起始地址(7ffde000)

      5 dt _TEB 7ffde000 查看主线程中PEB结构指针(0x7ffdc000)

        6 dt _PEB 0x7ffdc000 寻找LoaderLock的指针(0x7c99e0174)

        7  dt_RTL_CRITICAL_SECTION 0x7c99e174 查看临界区状态,我们看到看到LockCount值为-1,那么我们通过给它设置“写”断点,从而在每次“关键”时刻予以监控。

        8 baw2 0x7c99e178 对LockCount设置写断点

        9 g 

        10kb 我们看到线程号是1,即Windbg插入的线程导致的断点,我们忽略之(我们看到关闭线程时也会进入临界区)

        11 g

        12 kb 同上,忽略之

        13 g

        14 kb 这次是主线程(0)触发了断点,断点原因是LdrLoadDll中要加锁。

        我们使用IDA反编译LdrLoadDll,可以看到调用的位置

代码语言:javascript
复制
 v4 = RtlDosApplyFileIsolationRedirection_Ustr(1, a3, &unk_7C99E214, &v11, &v14, &v17, 0, 0, 0);
  v5 = v4;
  if ( v4 >= 0 )
  {
    v9 = 1;
  }
  else
  {
    if ( v4 != -1072365560 )
      goto LABEL_6;
  }
  LdrLockLoaderLock(1, 0, &v10);
  ms_exc.disabled = 0;

        15 g

        16 kb 还是主线程(0)触发了断点,原因是LdrLoadDll中调用了LdrpLoadDll,该函数中需要进入临界区,这是第二次进临界区了。在《Best Practices for Creating DLLs》中有对这种现象允许的说明

代码语言:javascript
复制
The loader lock is recursive, which means that it can be acquired again by the same thread.  

        在LdrLoadDll中我们看到

代码语言:javascript
复制
LdrLockLoaderLock(1, 0, &v10);
  ms_exc.disabled = 0;
  if ( LdrpTopLevelDllBeingLoaded )
  {
    if ( ShowSnaps || LdrpShowRecursiveDllLoads || LdrpBreakOnRecursiveDllLoads )
    {
      DbgPrint("[%lx,%lx] LDR: Recursive DLL load\n");
      DbgPrint("[%lx,%lx]   Previous DLL being loaded: \"%wZ\"\n");
      DbgPrint("[%lx,%lx]   DLL being requested: \"%wZ\"\n");
      if ( LdrpCurrentDllInitializer )
        DbgPrint("[%lx,%lx]   DLL whose initializer was currently running: \"%wZ\"\n");
      else
        DbgPrint("[%lx,%lx]   No DLL initializer was running\n");
    }
  }
  LdrpTopLevelDllBeingLoaded = v17;
  v6 = LdrpLoadDll(v9, a1, a2, v17, a4, 1);

        在LdrpLoadDll中我们看到

        17 g

        18 kb 第三次进入临界区

        19 g 主线程第一次退出临界区

        20 kb 主线程第四次进入临界区

        21 g 主线程第二次退出临界区

        22 g 有线程要进入临界区

        23 kb 这次是我们在代码中启动的工作线程(1)要尝试进入临界区

        24 ~ 查看线程 确定有两个线程了

        25 g 

        26 kb 工作线程(1)要进入临界区,可是它不会进去的,因为它会被挂起

        27 g 死锁了

        28 control+break windbg要启动一个中断线程,中断线程触发了断点

        29 ~ 查看线程,ID为2的就是windbg插入的线程

       30 ~0s 切换到主线程(0),发现主线程在内核态中出不来了

        31 kb 查看主线程调用堆栈,确实是在等工作线程结束

        32 ~1s 切换到工作线程,发现它也在内核态中出不来了

        33 kb 查看工作线程调用堆栈

        34 dt _RTL_CRITICAL_SECTION 0x7c99e174  查看临界区所有权,从线程TID中我们可以看到,临界区的确是被主线程占着。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2012年11月05日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档