Windows升级安装失败之0xC1900101排查
最近遇到Windows升级安装的时候出现0xC1900101错误失败,大致是在升级并安装新版本Windows进度到70%左右的时候出现错误,重启回滚。
查看Windows的升级记录,发现0xC1900101错误,如下:
这个问题非常有意思,本文我们记录一下整个排查过程。
1. 升级日志
首先我们看一下升级时候的一些日志,日志目录为:
C:\$Windows.~BT\Sources\Panther
C:\Windows\Logs\Setup
C:\Windows\Panther
在这些目录中,有如下关键日志文件:
setupact.log
:安装过程的操作记录。setuperr.log
:安装过程中的错误汇总。SetupCompat.log
:兼容性检查结果。Rollback.log
:回滚操作记录(如果升级失败后回退)。
针对这些日志文件进行查看,但是并没有发现有用的任何线索。
难道我们的排查无法进行下去了吗,就在这个时候发现了一个重要文件setupmem.dmp,看后缀名我们知道是一个内存dump文件,这个文件是非常可疑的,一般来说如下两种情况会产生dmp文件:
- 我们的应用程序崩溃,系统会有机制记录程序崩溃的内存情况。
- 系统出现蓝屏死机,系统会记录死机的状态。
使用WINDBG分析一下这个文件,发现如下堆栈:
0: kd> kb
# RetAddr : Args to Child : Call Site
00 fffff802`4464f1d3 : ffff8600`bf8ed500 00000000`00000000 00000000`00000001 00000000`00000300 : nt!KeBugCheck
01 fffff802`4464ff3c : 00000000`00000000 fffff802`b15bbb3e ffffe203`4a7ae0f8 ffff8600`bf8ed5b0 : WinSetupMon!HandleOperation+0x97f
02 fffff802`42dec7a1 : ffffe203`00000001 ffffe203`4bd13050 ffffe203`4a7ae220 ffffe203`4a7ae010 : WinSetupMon!WinSetupMonPreSetInformation+0x6c
03 fffff802`42debe31 : ffff8600`bf8ed840 00000000`00000000 ffffe203`4bb29000 fffff802`42de5606 : FLTMGR!FltpPerformPreCallbacksWorker+0x631
04 fffff802`42dead88 : ffff8600`bf8e8000 ffff8600`bf8ed779 ffffe203`50da4d10 ffffe203`50887b10 : FLTMGR!FltpPassThroughInternal+0xf1
05 fffff802`42dea93d : 00000000`00000000 00000000`00000000 00000000`00000000 ffff8600`bf8edb60 : FLTMGR!FltpPassThrough+0x218
06 fffff802`b14bffde : 00000000`42536f49 ffffe203`50da4d10 ffffe203`50da4d10 00000000`00000000 : FLTMGR!FltpDispatch+0xed
07 fffff802`b14bfd16 : ffffe203`50da4d10 ffffe203`50da4d10 00000000`00000020 ffffffff`ffffffff : nt!IofCallDriver+0xbe
08 fffff802`b15ad19d : 00000000`00000004 ffff8600`bf8edb60 ffffe203`50887b10 0000004b`42536f49 : nt!IopCallDriverReference+0xe6
09 fffff802`b188ef55 : 00000000`00000de4 0000004b`415ff3e8 0000004b`415ff4b0 00000000`00000004 : nt!NtSetInformationFile+0x83d
0a 00007ffb`0721c4a4 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x25
0b 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : 0x00007ffb`0721c4a4
查看BUGCHECK的信息,如下:
0: kd> .bugcheck
Bugcheck code 00000004
Arguments 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000
蓝屏码INVALID_DATA_ACCESS_TRAP (4)
没有任何有用信息。
但是我们仔细观察堆栈,发现几个重要信息:
NtSetInformationFile
表示我们是在设置文件的一些信息(例如删除,重命名等)。WinSetupMon!HandleOperation
表示有一个文件过滤驱动WinSetupMon用来监控Windows升级时候的一些文件信息。
看来应该是WinSetupMon
引起的蓝屏导致升级失败,我们详细分析一下WinSetupMon
。
2. WinSetupMon
我们从WinSetupMonPreSetInformation
函数出发,分析一下WinSetupMon
做了什么,是否有第三方驱动引起的蓝屏。
WinSetupMonPreSetInformation
函数实现如下:
从上面我们发现WinSetupMonPreSetInformation
主要针对删除和重命名做一些操作。联动WinSetupMon
这个名字,我们大致可以得出结论:
WinSetupMon
主要是记录在升级过程中重命名的文件和删除的文件。
我们继续进一步分析,发现蓝屏的代码如下:
FileStatus2 = FileStatus - 3;
if ( FileStatus2 )
{
if ( FileStatus2 == 1 )
{
KeWaitForSingleObject(&stru_FFFFF80540239A20, 0, 0, 0, 0i64);
StopLoggingToFile(0i64);
KeBugCheck(4i64);
}
}
主要是确认FileStatus
这个状态的来源,接着我们还能看到代码:
这个是一个非常重要的线索,说明对于每个状态的信息,这里我们的状态是ProtectBugcheck,所以这里猜测是文件被保护,删除或者重命名的时候主动出现蓝屏了。
因此我们最终的目的是确定文件状态是哪里确定的,接着我们分析可以发现代码:
v20 = IsPathTracked(&v50, v19, (enum _TRACKING_MODE *)&v56);
FileStatus = v56;
IsPathTracked
这个函数,用来判断当前删除(或者重命名)的文件是否是被跟踪的文件,返回被跟踪的类型;判断的被跟踪的规则是注册表的策略信息,注册表路径如下:
计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\WinSetupMon
读取策略的代码如下:
这里我们得到了两个重要信息:
LogConfig
表示WinSetupMon
日志路径信息。TrackingConfig
表示跟踪文件的配置信息。
我们可以解析TrackingConfig
配置,得到如下路径:
\\?\Volume{43021D03-B482-4DE4-A952-B5B69A3751C7}\ProgramData\Microsoft\Windows\Start Menu\Programs
\\?\Volume{43021D03-B482-4DE4-A952-B5B69A3751C7}\Windows.old\ProgramData\Microsoft\Windows\Start Menu\Programs
\\?\Volume{43021D03-B482-4DE4-A952-B5B69A3751C7}\ProgramData\Microsoft\Windows\Start Menu
\\?\Volume{43021D03-B482-4DE4-A952-B5B69A3751C7}\Windows.old\ProgramData\Microsoft\Windows\Start Menu
\\?\Volume{43021D03-B482-4DE4-A952-B5B69A3751C7}\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
\\?\Volume{43021D03-B482-4DE4-A952-B5B69A3751C7}\Windows.old\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
\\?\Volume{43021D03-B482-4DE4-A952-B5B69A3751C7}\ProgramData
\\?\Volume{43021D03-B482-4DE4-A952-B5B69A3751C7}\Windows.old\ProgramData
\\?\Volume{43021D03-B482-4DE4-A952-B5B69A3751C7}\Users\Public\Downloads
\\?\Volume{43021D03-B482-4DE4-A952-B5B69A3751C7}\Windows.old\Users\Public\Downloads
\\?\Volume{43021D03-B482-4DE4-A952-B5B69A3751C7}\Users\Public\Desktop
\\?\Volume{43021D03-B482-4DE4-A952-B5B69A3751C7}\WINDOWS\System32\drvinst.exe
//...
从这里看,我们可以发现是一些用户使用比较重要的路径信息。也就是说在升级的时候会对这些文件进行监控,如果我们有改动这些监控的文件,那么根据策略就会禁用或者蓝屏等反馈。
我们还可以通过LogConfig
查看日志信息,如下:
2025-04-14 16:04:31, DELTRACK PATH: C:\ProgramData\TrackTest.doc, PROCESS: \Device\HarddiskVolume4\CppServiceDemo.exe
2025-04-14 16:04:31, DENY PATH: C:\Users\test\Favorites\TrackTest.doc, PROCESS: \Device\HarddiskVolume4\CppServiceDemo.exe
2025-04-14 16:04:31, INFO Logging process tree for bugcheck
2025-04-14 16:04:31, INFO |- \Device\HarddiskVolume4\CppServiceDemo.exe
2025-04-14 16:04:31, INFO |- \Device\HarddiskVolume4\Windows\System32\services.exe
2025-04-14 16:04:31, INFO |- \Device\HarddiskVolume4\Windows\System32\wininit.exe
2025-04-14 16:04:32, INFO Flushed log volume; took 328 ms
2025-04-14 16:04:32, INFO **** SESSION STOP: New OS ****
2025-04-14 16:04:32, INFO Logging stopped to : \Device\HarddiskVolume4\Windows\Panther\WinSetupMon.log
从这里我们发现了两种消息:
- DELTRACK表示删除的跟踪。
- DENY表示文件操作被拒绝。
从这里我们也发现了,失败的原因是出现了DENY,并且进程树关系也给出了,我们可以明确得知是哪个进程导致的问题。
3. 问题重现
通过上面分析我们知道,只要在Windows升级安装的时候,如果有删除或者重命名重要目录的文件,那么就会导致升级失败。
那么我们可以写一个自动启动的服务,在服务启动的时候尝试删除文件来重现该过程,如下:
void CSampleService::ServiceWorkerThread(void)
{
// Periodically check if the service is stopping.
#define WIN_SETUP_FILE_PATHW L"C:\\Users\\test\\Favorites\\TestTrack.doc"
if (!DeleteFileW(WIN_SETUP_FILE_PATHW))
{
WCHAR wszLog[MAX_PATH] = { 0 };
StringCchPrintfW(wszLog, _countof(wszLog), L"Failed to delete file %s with error %d", WIN_SETUP_FILE_PATHW, GetLastError());
WriteEventLogEntry(wszLog,
EVENTLOG_ERROR_TYPE);
}
else
{
WriteEventLogEntry(L"Success to delete file " WIN_SETUP_FILE_PATHW,
EVENTLOG_INFORMATION_TYPE);
}
while (!m_fStopping)
{
// Perform main service function here...
::Sleep(2000); // Simulate some lengthy operations.
}
// Signal the stopped event.
SetEvent(m_hStoppedEvent);
}
将这个服务安装为自启动之后,我们升级Windows系统;我们在升级的时候发现蓝屏导致升级安装失败,蓝屏时候的堆栈如下:
0: kd> kb
# RetAddr : Args to Child : Call Site
00 fffff800`ccf6d9c2 : fffffb8d`909f6ae8 00000000`00000001 00000000`00000100 fffff800`cd095401 : nt!DbgBreakPointWithStatus
01 fffff800`ccf6ceec : 00000000`00000003 fffffb8d`909f6bd0 fffff800`cd095570 00000000`00000004 : nt!KiBugCheckDebugBreak+0x12
02 fffff800`cceb563e : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!KeBugCheck2+0xb2c
03 fffff800`cceb5509 : 00000000`00000004 00000000`00000000 00000000`00000001 00000000`00000001 : nt!KeBugCheckEx+0x11e
04 fffff800`5fedf1d3 : fffffb8d`909f7500 00000000`00000000 00000000`00000001 00000000`00000000 : nt!KiBugCheckReturn+0x5
05 fffff800`5fedff3c : 00000000`00000000 fffff800`ccdbbb3e ffff9e07`cb6730f8 fffffb8d`909f75b0 : WinSetupMon!HandleOperation+0x97f
06 fffff800`5e67c7a1 : ffff9e07`00000001 ffff9e07`c7a9e520 ffff9e07`cb673220 ffff9e07`cb673010 : WinSetupMon!WinSetupMonPreSetInformation+0x6c
07 fffff800`5e67be31 : fffffb8d`909f7840 00000000`00000000 ffff9e07`c7446100 fffff800`5e675606 : FLTMGR!FltpPerformPreCallbacksWorker+0x631
08 fffff800`5e67ad88 : fffffb8d`909f2000 fffffb8d`909f7779 ffff9e07`cb98ee90 ffff9e07`cb6df4e0 : FLTMGR!FltpPassThroughInternal+0xf1
09 fffff800`5e67a93d : 00000000`00000000 00000000`00000000 00000000`00000000 fffffb8d`909f7b60 : FLTMGR!FltpPassThrough+0x218
0a fffff800`cccbffde : 00000000`42536f49 ffff9e07`cb98ee90 ffff9e07`cb98ee90 00000000`00000000 : FLTMGR!FltpDispatch+0xed
0b fffff800`cccbfd16 : ffff9e07`cb98ee90 ffff9e07`cb98ee90 00000000`00000020 00000000`002df360 : nt!IofCallDriver+0xbe
0c fffff800`ccdad19d : 00000000`00000004 fffffb8d`909f7b60 ffff9e07`cb6df4e0 00000055`42536f49 : nt!IopCallDriverReference+0xe6
0d fffff800`cd08ef55 : 00000000`00000164 00000055`40aff188 00000055`40aff250 00000000`00000004 : nt!NtSetInformationFile+0x83d
0e 00007fff`65bbc4a4 : 00007fff`6326b172 00000249`579e0000 00000055`00000000 00000249`57a0faf0 : nt!KiSystemServiceCopyEnd+0x25
0f 00007fff`6326b172 : 00000249`579e0000 00000055`00000000 00000249`57a0faf0 00000000`00000001 : ntdll!NtSetInformationFile+0x14
10 00007fff`6326adeb : 00000055`403ffc50 00000002`00000000 00000000`00000003 00000000`00000164 : KERNELBASE!InternalDeleteFileW+0x35a
11 00007ff6`01f517c0 : 00000000`00000000 00000055`403ffc50 00000000`00000000 00007ff6`00000000 : KERNELBASE!DeleteFileW+0xb
我们可以发现是调用DeleteFileW
导致WinSetupMon
检测到了,出现蓝屏升级失败,我们看看这个文件路径,如下:
0: kd> !fileobj ffff9e07cb98ee90
\Users\test\Favorites\TestTrack.doc
Device Object: 0xffff9e07c763a060 \Driver\volmgr
Vpb: 0xffff9e07c7a2b4f0
Access: Delete SharedRead SharedWrite SharedDelete
Flags: 0x40040
Cache Supported
Handle Created
FsContext: 0xffffb4037c444170 FsContext2: 0xffffb4037c4443f0
CurrentByteOffset: 0
Cache Data:
Section Object Pointers: ffff9e07cb8c6c28
Shared Cache Map: 00000000
4. 总结
当我们在进行Windows升级的时候(Windows10 较新的版本),如果在升级安装的途中有删除(或者重命名)了一些文档,图片(C:\Users\xxx\Documents
,C:\Users\xxx\Pictures
)路径中的文件的时候,就会导致升级安装失败,错误码为0xC1900101。
因此我们把有删除这些目录文件的服务关闭掉,升级安装就成功了。