前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >英特尔驱动导致Qt程序必定崩溃

英特尔驱动导致Qt程序必定崩溃

原创
作者头像
lealc
发布2024-08-14 20:36:48
发布2024-08-14 20:36:48
3290
举报

背景

用户反馈Qt程序启动即必现崩溃,用户环境为Dell笔记本电脑,具有英特尔&英伟达双显卡,win10 64位

分析

首先崩溃后,需要对用户提供的dmp文件进行分析

dmp分析

打开用户提供的dmp文件,发现栈帧被破坏导致堆栈无法正常显示

栈帧被破坏
栈帧被破坏

这里需要手动还原堆栈,首先输出!teb拿到线程环境块,然后dps  StackLimit   StackBase拿到栈上所有信息,输出到文件中

代码语言:shell
复制
> .logopen ${path}\stack.txt
> !teb
> dps StackLimit StackBase
> .logclose

一般进程启动都是从ntdll!__RtlUserThreadStart这里开始,我们从这里进行栈底还原

代码语言:shell
复制
029ff790  029ff7ec
029ff794  773280ce ntdll!__RtlUserThreadStart+0x2f

029ff5ec  029ff634
029ff5f0  00b73c7c YOUR_RPOGRAM_NAME!main+0x2fc

***

029ff1d0  00000000
029ff1d4  7a43d8ec Qt5Gui!QWindow::create+0xc [C:\Users\qt\work\qt\qtbase\src\gui\kernel\qwindow.cpp @ 651]

029ff184  02bd6718
029ff188  7a43d948 Qt5Gui!QWindowPrivate::create+0x58 [C:\Users\qt\work\qt\qtbase\src\gui\kernel\qwindow.cpp @ 527]

上面还原问题隐藏了业务敏感信息,不过问题大同小异

还原到这里基本上可以确定出问题的代码是在创建第一个窗口,同时也符合我们现网一直观测到的一个问题

代码语言:shell
复制
0f 0260d810 56f5552b     0260d824 0260d900 047ba960 atiumdag+0x2c77
10 0260d84c 56f5391f     047ba960 00000000 042807d0 atiu9pag+0x552b
*** WARNING: Unable to verify timestamp for aticfx32.dll
11 0260d868 77ae698c     0260d900 00000000 c0000001 atiu9pag+0x391f
12 0260d87c 77ae57e1     0260d900 0260dbe8 613fb634 aticfx32+0x3698c
*** WARNING: Unable to verify checksum for d3d9.dll
13 0260d888 613fb634     0260d900 082656b8 082656d8 aticfx32+0x357e1
14 0260dbe8 613fb431     e701114a 082656d8 082656b0 d3d9!CreateDeviceLHDDI+0x2dc
15 0260e440 613fa2cc     e701114a 08265678 00000000 d3d9!D3D9CreateDirectDrawObject+0x1ae
16 0260e8f0 613fb146     08265380 00000000 00000000 d3d9!FetchDirectDrawData+0xc9
17 0260e924 613fc6d7     082651c0 08260810 00000001 d3d9!InternalDirectDrawCreate+0x22e
18 0260eb2c 613fc46f     00000020 00000000 0260ecd0 d3d9!CEnum::CEnum+0x479
19 0260ec74 61450a93     00000020 00000000 0260ec88 d3d9!Direct3DCreate9Impl+0x19d
*** WARNING: Unable to verify checksum for qwindows.dll
1a 0260ec8c 56fd7fe2     00000020 0260f4c4 047a7c68 d3d9!Direct3DCreate9+0x31
1b 0260eca0 56fd859c     ffffffff 0260f5b0 00000000 qwindows!QDirect3D9Handle::QDirect3D9Handle+0x72 [C:\Users\qt\work\qt\qtbase\src\plugins\platforms\windows\qwindowsopengltester.cpp @ 108] 
1c 0260f498 56fa4367     0260f4c4 0260f6f8 0260f5b0 qwindows!GpuDescription::detect+0x6c [C:\Users\qt\work\qt\qtbase\src\plugins\platforms\windows\qwindowsopengltester.cpp @ 128] 
1d 0260f4e0 56fa2ae0     047a7c68 ffffffff 047a7c68 qwindows!QWindowsWindow::forcedScreenForGLWindow+0x47 [C:\Users\qt\work\qt\qtbase\src\plugins\platforms\windows\qwindowswindow.cpp @ 1519] 
1e 0260f588 56fa393f     0260f5e4 047a7c68 0260f5b0 qwindows!calcPosition+0x60 [C:\Users\qt\work\qt\qtbase\src\plugins\platforms\windows\qwindowswindow.cpp @ 576] 
1f 0260f6d0 56fa33a1     0260f850 047a7c68 0260f784 qwindows!WindowCreationData::create+0x46f [C:\Users\qt\work\qt\qtbase\src\plugins\platforms\windows\qwindowswindow.cpp @ 800] 
20 0260f710 56fab880     0260f850 047a7c68 0260f784 qwindows!QWindowsWindowData::create+0x71 [C:\Users\qt\work\qt\qtbase\src\plugins\platforms\windows\qwindowswindow.cpp @ 1557] 
*** WARNING: Unable to verify checksum for Qt5Gui.dll
21 0260f898 5780d948     047a7c68 02a54a40 047a7c68 qwindows!QWindowsIntegration::createPlatformWindow+0x300 [C:\Users\qt\work\qt\qtbase\src\plugins\platforms\windows\qwindowsintegration.cpp @ 348] 
22 0260f8e4 5780d8ec     00000000 00000000 0082b377 Qt5Gui!QWindowPrivate::create+0x58 [C:\Users\qt\work\qt\qtbase\src\gui\kernel\qwindow.cpp @ 527] 
23 0260f8f0 0082b377     f4642ecd 047733f0 047733f0 Qt5Gui!QWindow::create+0xc [C:\Users\qt\work\qt\qtbase\src\gui\kernel\qwindow.cpp @ 651] 

可以发现创建第一个窗口,qt会去加载d3d9的模块,然后加载到了显卡驱动,为什么要做这件事情呢?

review一下这里的代码,创建第一个窗口时,qt需要确认这个窗口需要出现在显示器的哪里,调用到了calcPosition

calcPosition
calcPosition

然后因为顶层窗口的原因,这里一定会走到forcedScreenForGLWindow,这里是要去推测是否有多屏场景,需要出现在主屏,主要是为了解决多屏多显卡场景下的崩溃问题:QTBUG-50371

forcedScreenForGLWindow
forcedScreenForGLWindow

接着往下就会去遍历每个显示器,利用d3d的接口来实现,需要加载d3d9.dll

加载d3d9.dll
加载d3d9.dll

创建d3d9.dll!Direct3DCreate9函数创建句柄时就会加载英特尔驱动模块

加载显卡驱动模块
加载显卡驱动模块

创建句柄会最终调用到d3d9!CreateDeviceLHDDI上来创建设备驱动相关句柄,然后调用到显卡驱动模块内部

问题分析

用户出问题的模块在于Dell电脑上装了笔记本厂提供的定制英特尔显卡驱动(27版本)模块,导致的崩溃问题,类似问题也有大量的反馈:

英特尔-WPF应用崩溃英特尔-QT崩溃英特尔-D3d崩溃

基本上回复都是升级驱动版本,回滚驱动版本等操作修复问题,但是现网观测不仅仅英特尔驱动会导致我们崩溃,英伟达、AMD显卡模块同样会有问题,所以这里考虑屏蔽驱动模块的加载来解决问题,主要因为我们不会用到Opengl,去除风险较低

解决

因为这里d3d9.dll是显式调用LoadLibrary来实现加载,而我们防注入模块是Hook这个系统API来实现防注入,正好比较合适,增加d3d9.dll到我们防注入黑名单即可解决,后续考虑动态防注入名单配置来实现灰度。

参考

1、WinDbg手动修复堆栈_windbg 堆栈修复-CSDN博客

2、编程技术-Windbg调试栈溢出_游戏逆向|游戏安全|yxfzedu.com

3、手动遍历堆栈 - Windows drivers | Microsoft Learn

4、x64 手动堆栈重建和堆栈遍历 |Microsoft 学习

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 分析
    • dmp分析
      • 问题分析
      • 解决
      • 参考
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档