<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

文章分类

导航

订阅

调试笔记之侦查广告插件

朋友的电脑出了一个“怪”毛病,当使用资源管理器的时候,冷不丁会跳出一个非法访问对话框(其实就是应用程序错误对话框,也称GPF对话框),点击确定按钮关闭后,Explorer进程便会退出,然后重启,导致开始菜单和任务栏也消失片刻后再出现。

在把WinDBG设置为JIT调试器后,重现问题,于是WinDBG被自动唤起。崩溃现场的信息如下:

(680.c4c): Access violation - code c0000005 (first/second chance not available)
eax=00000000 ebx=00000000 ecx=00000003 edx=00000000 esi=01f1ad28 edi=00000000
eip=769c6239 esp=01f1a764 ebp=01f1a7cc iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ole32!CServerContextActivator::GetClassObject+0x11c:
769c6239 8b08            mov     ecx,dword ptr [eax]  ds:0023:00000000=????????

看来是典型的访问空指针,第一现场在ole32模块的CServerContextActivator::GetClassObject方法中。ole32是支撑COM技术的核心模块,像CoInitializeEx,CoCreateInstanceEx等重要的COM函数都是这个模块导出的。

从上面这个发生问题的函数下手来追查问题原因不是不可以,但是效率太低了,因为这个模块本身有问题的概率很小,所以还是先看一下栈回溯:

0:011> kn 100
 # ChildEBP RetAddr 
00 01f1a7cc 769c60fe ole32!CServerContextActivator::GetClassObject+0x11c
01 01f1a804 769c62e4 ole32!ActivationPropertiesIn::DelegateGetClassObject+0xf3
02 01f1a824 769c6290 ole32!CApartmentActivator::GetClassObject+0x4d
03 01f1a83c 769dddf4 ole32!CProcessActivator::GCOCallback+0x2b
04 01f1a85c 769dddab ole32!CProcessActivator::AttemptActivation+0x2c
05 01f1a894 769c6337 ole32!CProcessActivator::ActivateByContext+0x42
06 01f1a8bc 769c60fe ole32!CProcessActivator::GetClassObject+0x48
07 01f1a8f4 769c6118 ole32!ActivationPropertiesIn::DelegateGetClassObject+0xf3
08 01f1ab3c 769c60fe ole32!CClientContextActivator::GetClassObject+0x88
09 01f1ab74 769c5f92 ole32!ActivationPropertiesIn::DelegateGetClassObject+0xf3
0a 01f1b320 769c5e4b ole32!ICoGetClassObject+0x334
0b 01f1b34c 769c5dcd ole32!CComActivator::DoGetClassObject+0x93
0c 01f1b36c 75c77e99 ole32!CoGetClassObject+0x1b
0d 01f1b3d8 75c65433 urlmon!CProtMgr::FindFirstCF+0x11a
0e 01f1b3fc 75c655bb urlmon!COInetSession::FindFirstCF+0xb2
0f 01f1b488 75c6550d urlmon!COInetSession::CreateProtocolInfo+0x66
10 01f1b4a4 75c645fe urlmon!COInetSession::ParseUrl+0x1e
11 01f1b4ec 75c64ac0 urlmon!CoInternetGetSecurityUrl+0xad
12 01f1b9d4 75c64a36 urlmon!CSecurityManager::_MapUrlToZoneDirect+0x46
13 01f1ba0c 75c630de urlmon!CSecurityManager::MapUrlToZoneInternal+0xcf
14 01f1ba28 75f0c6b1 urlmon!CSecurityManager::MapUrlToZone+0x1a
15 01f1caac 75f141e6 browseui!CShellBrowser2::_GetTempZone+0x126
16 01f1cd24 75f1779c browseui!CShellBrowser2::_UpdateZonesPane+0x108
17 01f1cd84 77f52fb8 browseui!CShellBrowser2::Exec+0x132
18 01f1cda8 7e5693c2 shlwapi!IUnknown_Exec+0x3e
19 01f1cdcc 7e56bd4e shdocvw!CBaseBrowser2::_Exec_psbMixedZone+0x36
1a 01f1cde8 75ef860c shdocvw!CBaseBrowser2::_SwitchActivationNow+0x1c5
1b 01f1cdf4 75f0e58e browseui!CCommonBrowser::_SwitchActivationNow+0x14
1c 01f1ce08 7e56b9db browseui!CShellBrowser2::_SwitchActivationNow+0x10
1d 01f1de8c 75ef856f shdocvw!CBaseBrowser2::ActivatePendingView+0x17a
1e 01f1de98 75f14b30 browseui!CCommonBrowser::ActivatePendingView+0x14
1f 01f1dea8 7e56d4ee browseui!CShellBrowser2::ActivatePendingView+0x16
20 01f1dedc 7e56af14 shdocvw!CBaseBrowser2::_CreateNewShellView+0x27c
21 01f1df04 7e56ae80 shdocvw!CBaseBrowser2::_CreateNewShellViewPidl+0x46
22 01f1ef84 75ef85ef shdocvw!CBaseBrowser2::_NavigateToPidl+0x17c
23 01f1ef9c 75f0b894 browseui!CCommonBrowser::_NavigateToPidl+0x1d
24 01f1efc0 75f1331b browseui!CShellBrowser2::_NavigateToPidl+0x111
25 01f1f034 75f36d9f browseui!CShellBrowser2::OnCreate+0x49f
26 01f1f04c 7e56d337 browseui!CExplorerBrowser::OnCreate+0x13
27 01f1f068 75ef28c9 shdocvw!CBaseBrowser2::WndProcBS+0xf1
28 01f1f084 75f16d33 browseui!CCommonBrowser::WndProcBS+0x20
29 01f1f0c0 75f146a8 browseui!CShellBrowser2::WndProcBS+0x196
2a 01f1f0ec 77d18734 browseui!IEFrameWndProc+0xff
2b 01f1f118 77d1d05b user32!InternalCallWinProc+0x28
2c 01f1f180 77d1b4c0 user32!UserCallWinProcCheckWow+0xea
2d 01f1f1d4 77d1f9fe user32!DispatchClientMessage+0xa3
2e 01f1f204 7c92e473 user32!__fnINLPCREATESTRUCT+0x8b
2f 01f1f290 77d1fe13 ntdll!KiUserCallbackDispatcher+0x13
30 01f1f734 77d1fecc user32!NtUserCreateWindowEx+0xc
31 01f1f7e0 77d1fc58 user32!_CreateWindowEx+0x1ed
32 01f1f81c 77f5b2d1 user32!CreateWindowExW+0x33
33 01f1fc94 75f15073 shlwapi!CreateWindowExWrapW+0xc1
34 01f1ff20 75f15385 browseui!BrowserThreadProc+0x197
35 01f1ffb4 7c80b699 browseui!BrowserProtectedThreadProc+0x50
36 01f1ffec 00000000 kernel32!BaseThreadStart+0x37

这个栈回溯有五十多个栈帧,这样的深度在本地程序中不算浅了。首先应该看一下整个栈序列中有没有可疑的模块。如果想了解某个模块的详细信息,那么可以使用lmvm命令,比如:

0:011> lm vm urlmon
start    end        module name
75c60000 75cff000   urlmon     (pdb symbols)          d:\symbols\urlmon.pdb\9AE72F9177B7457E8FD6586279A7FF032\urlmon.pdb
    Loaded symbol image file: urlmon.dll
    Image path: C:\WINDOWS\system32\urlmon.dll
    Image name: urlmon.dll
    Timestamp:        Wed Apr 29 08:51:19 2009 (49F7DCC7)
    CheckSum:         0009A3C4
    ImageSize:        0009F000
    File version:     6.0.2900.3562
    Product version:  6.0.2900.3562
    File flags:       0 (Mask 3F)
    File OS:          40004 NT Win32
    File type:        2.0 Dll
    File date:        00000000.00000000
    Translations:     0804.04b0
    CompanyName:      Microsoft Corporation
    ProductName:      Microsoft(R) Windows(R) Operating System
    InternalName:     UrlMon.dll
    OriginalFilename: UrlMon.dll
    ProductVersion:   6.00.2900.3562
    FileVersion:      6.00.2900.3562 (xpsp_sp2_gdr.090427-1232)
    FileDescription:  OLE32 Extensions for Win32
    LegalCopyright:   (C) Microsoft Corporation. All rights reserved.

这样看下来,没有发现异常的模块,所有模块都是Windows自身的。

长话短说,因为是发生在ole32模块中的,所以应该看一下是怎么进入到这个模块的。顺着栈帧向下排查,自然看到了CoGetClassObject函数,熟悉COM的朋友都知道这是一个公开的COM函数,用来创建COM对象。

HRESULT CoGetClassObject(
  __in      REFCLSID rclsid,
  __in      DWORD dwClsContext,
  __in_opt  COSERVERINFO pServerInfo,
  __in      REFIID riid,
  __out     LPVOID *ppv
);

因为我们没有私有符号,看不到函数参数的类型;但公开的函数可以查到函数原型,所以从公开的函数下手常常是一个捷径。

使用.frame命令切换到CoGetClassObject函数的栈帧:

0:011> .frame /c c
0c 01f1b36c 75c77e99 ole32!CoGetClassObject+0x1b
eax=00000000 ebx=01f1ad28 ecx=00000003 edx=00000000 esi=01f1ad28 edi=00000000
eip=769c5dcd esp=01f1b354 ebp=01f1b36c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ole32!CoGetClassObject+0x1b:
769c5dcd 5d              pop     ebp

再执行kv命令显示包含参数的栈帧信息:
0:011> kv
  *** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr  Args to Child             
01f1b36c 75c77e99 01f1b434 00000001 00000000 ole32!CoGetClassObject+0x1b (FPO: [5,0,0])

第一个参数(01f1b434 )是REFCLSID类型的,这个类型没有导出,但是查一下头文件,就可以看到它是IID类型的引用:

#define REFCLSID const IID &

而IID类型是GUID的别名:

typedef GUID IID;

所以:

0:011> dt _GUID 01f1b434
msvcr71!_GUID
 {bbca9f81-8f4f-11d2-90ff-0080c83d3571}
   +0x000 Data1            : 0xbbca9f81
   +0x004 Data2            : 0x8f4f
   +0x006 Data3            : 0x11d2
   +0x008 Data4            : [8]  "???"

于是我们得到了出问题时要创建的COM对象的类ID。接下来可以通过注册表来查找这个类ID对应的模块和更多信息。

启动regedit,然后在如下注册表键下查找:

HKEY_CLASSES_ROOT\CLSID

于是便发现了这个CLSID的模块,名为wc98pp.dll,看看这个名字,便不是很善,看一下详细信息:

0:011> lmvm wc98pp
start    end        module name
02b50000 02b61000   wc98pp   C (export symbols)       wc98pp.dll
    Loaded symbol image file: wc98pp.dll
    Image path: C:\WINDOWS\wc98pp.dll
    Image name: wc98pp.dll
    Timestamp:        Sat Jun 20 02:22:17 1992 (2A425E19)
    CheckSum:         00000000
    ImageSize:        00011000
    File version:     0.0.0.0
    Product version:  0.0.0.0
    File flags:       0 (Mask 0)
    File OS:          0 Unknown Base
    File type:        0.0 Unknown
    File date:        00000000.00000000
    Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4

无版本,无厂家,无产品名称...

GOOGLE一下,果不其然!

删除它的注册表项,然后删除文件,问题消失了。

 

posted on 2009年6月30日 21:33 由 Raymond

# re: 调试笔记之侦查广告插件 @ 2009年7月3日 9:48

不错。。。

diyhack

# one question! @ 2009年7月10日 8:44

Dear Raymond, I'm reading your book-Software Debugging,and I have a question about the blue screen.when the blue screen is generated, why it can't save the dump file sometimes and stop at initializing disk? I have set the windows saving as miniDump file mode.

yicaolove

# re: 调试笔记之侦查广告插件 @ 2009年7月11日 16:52

To yicaolove, 转储是可能失败的,原因有几个,比较普遍的是磁盘驱动程序方面的问题,比如有编写不好的过滤驱动在驱动栈上。

Raymond

# re: 调试笔记之侦查广告插件 @ 2009年7月13日 13:44

Thanks Raymond!

yicaolove

Powered by Community Server Powered by CnForums.Net