当前位置: 首页 > news >正文

Chrome V49 SxS 加载问题分析与修复

Chrome V49 SxS 加载问题分析与修复

概述

本文详细记录了 Chrome V49(49.0.2623.112)在 ReactOS 上因 Side-by-Side (SxS) 程序集机制不完善导致加载失败的问题,从根因分析到代码修复的完整过程。

运行环境

项目说明
操作系统ReactOS (Debug 构建)
虚拟机VirtualBox (VCI 镜像:ReactOS-Test.vdi)
目标程序Chrome V49 (49.0.2623.112)
目录结构C:\Chrome_V49\— Chrome.exe、Chrome.exe.manifest
C:\Chrome_V49\49.0.2623.112\— chrome.dll、chrome_elf.dll、其他 DLL

问题现象

Chrome.exe 启动后立即崩溃,调试日志显示:

LoadLibraryExW(chrome.dll) failing with status c0000135

STATUS_DLL_NOT_FOUND— Chrome 无法加载其核心模块chrome.dll

随后发生 NULL 指针解引用(c0000005,地址0x00000000),进程崩溃。

第一阶段:SxS 清单分析

1.1 提取嵌入清单

使用 Windows API(LoadLibraryExW+FindResourceExW)从 Chrome.exe 中提取RT_MANIFEST资源。

Chrome.exe 嵌入清单(资源 ID 1):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><assemblyxmlns="urn:schemas-microsoft-com:asm.v1"manifestVersion="1.0"><!-- 依赖 1: Common Controls 6.0(有 publicKeyToken,走 WinSxS) --><dependency><dependentAssembly><assemblyIdentitytype="Win32"name="Microsoft.Windows.Common-Controls"version="6.0.0.0"processorArchitecture="*"publicKeyToken="6595b64144ccf1df"language="*"/></dependentAssembly></dependency><!-- 依赖 2: 49.0.2623.112 私有程序集(无 publicKeyToken,走私有路径) --><dependency><dependentAssembly><assemblyIdentitytype="win32"name="49.0.2623.112"version="49.0.2623.112"language="*"/></dependentAssembly></dependency><trustInfo>...</trustInfo><compatibility>...</compatibility></assembly>

外部Chrome.exe.manifest
与嵌入清单类似,但缺少49.0.2623.112的依赖声明。

49.0.2623.112.manifest(位于子目录中):

<assemblymanifestVersion="1.0"><assemblyIdentityname='49.0.2623.112'version='49.0.2623.112'type='win32'/><filename='chrome_elf.dll'/><filename='kasko.dll'/></assembly>

关键发现:chrome.dll不在 SxS 清单中。只有chrome_elf.dllkasko.dll在 SxS 的 DLL 重定向清单中。这意味着 SxS 的 DLL 重定向机制对chrome.dll无效。

1.2 其他模块清单

模块资源 ID依赖
chrome.dllRT_MANIFEST #2Common Controls 6.0
chrome_child.dllRT_MANIFEST #2仅有 trustInfo

1.3 SxS 安全项验证

分析 ReactOS 的 SxS 实现代码sdk/lib/rtl/actctx.c

潜在问题验证结果
type属性大小写敏感安全— 解析器原样存储不做比较
缺少publicKeyToken安全— 所有属性都是可选的,lookup_winsxs正确返回STATUS_NO_SUCH_FILE
私有程序集路径搜索安全lookup_assembly正确搜索appdir\name\name.manifest
DLL 重定向路径解析安全find_actctx_dll正确处理非 WinSxS 路径

第二阶段:调试日志分析

2.1 首次运行日志

LdrpInitializeProcessCompat: Found guid for winver 0x600 in manifest

→ 激活上下文创建成功,清单解析正常,兼容性垫片设置 Vista 模式。

LoadLibraryExW(chrome.dll) failing with status c0000135

搜索路径:

C:\Chrome_V49;C:\ReactOS\System32;C:\ReactOS\system;C:\ReactOS;.; C:\ReactOS\bin;C:\ReactOS\System32;C:\ReactOS;C:\ReactOS\System32\Wbem

49.0.2623.112\子目录不在搜索路径中!

2.2 关键发现:SetDllDirectory未被调用

LdrpDllDirectory.Length = 0, Buffer = 'NULL'

Chrome 在 ReactOS 上没有调用SetDllDirectory,导致版本子目录未被加入 DLL 搜索路径。而在 Windows 7 上,Chrome 会通过此机制将49.0.2623.112\添加到搜索路径。

2.3 Chrome 的两次尝试

尝试调用结果
1LoadLibraryExW("chrome.dll")❌ Length=0,找不到
2LoadLibraryExW("49.0.2623.112/chrome.dll")✅ Length=76,找到
3LoadLibraryExW("chrome.dll")❌ 再次失败,随后崩溃

第二次使用的相对路径49.0.2623.112/chrome.dll通过RtlDosSearchPath_U相对于 CWD 解析成功,但 Chrome 继续尝试第三次裸名调用并最终崩溃。

第三阶段:根因分析

3.1 搜索路径计算代码

BaseComputeProcessDllPathdll/win32/kernel32/client/path.c)构建搜索路径:

SetDllDirectory已被调用BaseDllDirectory.Buffer != NULL):

AppDir → SetDllDirectory → System32 → Windows → PATH

SetDllDirectory未被调用

AppDir → System32 → Windows → CWD → PATH (安全模式) AppDir → CWD → System32 → Windows → PATH (非安全模式)

Chrome 的情况属于后者,搜索路径只有C:\Chrome_V49,不包含子目录。

3.2 LdrpBuildSearchPath 双重路径

LdrpBuildSearchPathdll/ntdll/ldr/ldrutils.c)会在 kernel32 传来的搜索路径前额外添加LdrpDllDirectory。但由于SetDllDirectory未被调用,LdrpDllDirectory.Length = 0,不产生任何效果。

3.3 核心结论

ReactOS 缺少 Windows 7 的行为:当进程激活上下文有私有程序集依赖时,程序集子目录应被隐式添加到 DLL 搜索路径。

在 Windows 7 上,LoadLibrary("chrome.dll")的搜索顺序包括 DLL 搜索顺序:

  1. DLL 重定向
  2. API Sets
  3. SxS 清单重定向← ReactOS 缺少此步骤的目录扩展
  4. 已加载模块列表
  5. Known DLLs
  6. 文件系统搜索

第四阶段:修复实现

4.1 修复策略

LdrpResolveDllName(ntdll)中添加 Windows 7 风格的 fallback:当标准 DLL 搜索失败时,查询激活上下文中的私有程序集清单路径,提取其目录并加入搜索路径重新搜索。

4.2 修改代码

文件:dll/ntdll/ldr/ldrutils.c
函数:LdrpResolveDllName

/* * Windows 7 behavior: if the DLL was not found in the standard search path, * try searching in private assembly subdirectories of the application directory. * The activation context stores assembly manifest paths; we extract their * directories and retry the search with those directories prepended. */if(DllName&&!wcschr(DllName,L'\\')&&!wcschr(DllName,L'/')){NTSTATUS ActCtxStatus;SIZE_T RetLen;ACTIVATION_CONTEXT_DETAILED_INFORMATION DetInfo;DWORD AsmIdx;/* 查询激活上下文详细信息,获取程序集数量 */RtlZeroMemory(&DetInfo,sizeof(DetInfo));ActCtxStatus=RtlQueryInformationActivationContext(0,NULL,NULL,ActivationContextDetailedInformation,&DetInfo,sizeof(DetInfo),&RetLen);/* 处理缓冲区过小的情况 */if(ActCtxStatus==STATUS_BUFFER_TOO_SMALL&&RetLen>sizeof(DetInfo)){PACTIVATION_CONTEXT_DETAILED_INFORMATION pDet;pDet=RtlAllocateHeap(LdrpHeap,0,RetLen);if(pDet){RtlZeroMemory(pDet,RetLen);ActCtxStatus=RtlQueryInformationActivationContext(0,NULL,NULL,ActivationContextDetailedInformation,pDet,(ULONG)RetLen,&RetLen);if(NT_SUCCESS(ActCtxStatus))DetInfo=*pDet;RtlFreeHeap(LdrpHeap,0,pDet);}}if(NT_SUCCESS(ActCtxStatus)&&DetInfo.ulAssemblyCount>1){/* 跳过索引 0(主程序),检查依赖程序集 */for(AsmIdx=1;AsmIdx<=DetInfo.ulAssemblyCount;AsmIdx++){BYTE AsmBuf[4096];PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION AsmInfo=(PVOID)AsmBuf;WCHAR*LastSlash,NewSearchPath[MAX_PATH];RtlZeroMemory(AsmBuf,sizeof(AsmBuf));ActCtxStatus=RtlQueryInformationActivationContext(0,NULL,&AsmIdx,AssemblyDetailedInformationInActivationContext,AsmInfo,sizeof(AsmBuf),&RetLen);if(!NT_SUCCESS(ActCtxStatus))continue;if(!AsmInfo->lpAssemblyManifestPath)continue;/* 从清单路径中提取目录部分 */LastSlash=wcsrchr(AsmInfo->lpAssemblyManifestPath,L'\\');if(!LastSlash)continue;/* 构建: "manifest_dir;original_search_path" */RtlCopyMemory(NewSearchPath,AsmInfo->lpAssemblyManifestPath,(LastSlash-AsmInfo->lpAssemblyManifestPath+1)*sizeof(WCHAR));NewSearchPath[LastSlash-AsmInfo->lpAssemblyManifestPath+1]=L'\0';wcscat(NewSearchPath,L";");wcscat(NewSearchPath,DefaultPath);/* 用增强后的搜索路径重试 */Length=RtlDosSearchPath_U(NewSearchPath,DllName,NULL,BufSize,FullDllName->Buffer,&BaseDllName->Buffer);if(Length&&Length<=BufSize){DPRINT1("LDR: Found %ws in assembly dir %ws\n",DllName,NewSearchPath);break;}}}}

4.3 关键 API

API用途所在文件
RtlQueryInformationActivationContext查询激活上下文信息sdk/lib/rtl/actctx.c
ActivationContextDetailedInformation获取程序集数量和 app 目录sdk/include/xdk/winnt_old.h
AssemblyDetailedInformationInActivationContext获取单个程序集的清单路径同上
RtlDosSearchPath_U按搜索路径搜索文件sdk/lib/rtl/path.c

4.4 数据结构

typedefstruct_ACTIVATION_CONTEXT_DETAILED_INFORMATION{DWORD dwFlags;DWORD ulFormatVersion;DWORD ulAssemblyCount;// 程序集总数(含主程序)DWORD ulRootManifestPathType;DWORD ulRootManifestPathChars;// ... 更多字段PCWSTR lpRootManifestPath;PCWSTR lpAppDirPath;}ACTIVATION_CONTEXT_DETAILED_INFORMATION;typedefstruct_ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION{DWORD ulFlags;DWORD ulEncodedAssemblyIdentityLength;DWORD ulManifestPathType;DWORD ulManifestPathLength;// ...PCWSTR lpAssemblyEncodedAssemblyIdentity;PCWSTR lpAssemblyManifestPath;// 清单文件的完整路径PCWSTR lpAssemblyDirectoryName;// WinSxS 风格目录名DWORD ulFileCount;}ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION;

第五阶段:测试结果

5.1 修复后日志

LDR: Found chrome.dll in assembly dir C:\Chrome_V49\49.0.2623.112\;

修复成功!chrome.dll通过 SxS 程序集目录回退机制被正确找到。

5.2 修复后的问题

chrome.dll加载成功后,Chrome 继续执行并触发了另一个独立的问题:

Assertion failed at ../ntoskrnl/fsrtl/filelock.c(1190): Result == NT_SUCCESS(IoStatusBlock.Status)

调用链:

Chrome.exe → NtLockFile → FatCommonLockControl → FsRtlProcessFileLock

这是ReactOS FAT32 文件系统驱动(fastfat.sys)的文件锁(NtLockFile)实现存在缺陷,属于独立的内核层问题,不影响 SxS 修复本身的有效性。

附录

A. 涉及的 ReactOS 源代码文件

文件修改状态说明
dll/ntdll/ldr/ldrutils.c✅ 已修改添加 SxS 程序集目录回退搜索
dll/win32/kernel32/client/loader.c✅ 已修改添加调试日志(可移除)
sdk/lib/rtl/actctx.c❌ 未修改SxS 基础设施(分析用)
dll/ntdll/rtl/libsupp.c❌ 未修改现有find_actctx_dll函数(分析用)
dll/win32/kernel32/client/path.c❌ 未修改BaseComputeProcessDllPath(分析用)

B. SxS 清单提取脚本

使用 Python + ctypes 调用 Windows APIFindResourceExWLoadResource从 PE 文件中提取RT_MANIFEST资源。

C. 参考文档

  • Windows DLL 搜索顺序
  • SxS 程序集搜索顺序
  • 私有程序集
  • ReactOS CORE-10843 — SxS 激活上下文相关 bug
http://www.jsqmd.com/news/1222655/

相关文章:

  • 2026指南:沈阳老旧小区防水改造有实力的服务公司专业解析 - 甄选服务推荐
  • 雷池 SafeLine:一条命令装好的开源 WAF,让黑客“越不过雷池半步“
  • Structurae核心组件详解:BitField与BigBitField实战教程
  • 2026 园区屋顶外墙防水排名 TOP3,高层渗水、楼顶漏水正规商家测评 - 苏易房屋修缮
  • 2026年07月防爆伺服电机专业制造厂家与供应商综合解析 - 企业推荐官【官方】
  • 2026 相城地下室防水排名 TOP3,别墅 / 车库返潮渗水正规商家测评 - 苏易房屋修缮
  • TMS320F2838x USB控制器寄存器详解与Bulk传输实战
  • Kickstarter上线后复盘不乱:海外众筹UTM字段怎么设计
  • 2026年7月最新劳力士唐山吾悦广场维修保养服务电话 - 劳力士官方服务中心
  • QCNet源码深度解读:理解DETR-like两阶段解码器的实现原理
  • 2026年7月宝珀香港官方售后维修网点地址:服务热线权威核验 - 宝珀官方售后服务中心
  • 跨境电商海外仓费用无国内发票,如何合规入账、税前扣除?
  • iNiR性能优化指南:10个技巧让你的桌面Shell运行更流畅
  • NitroStack认证系统详解:JWT、OAuth 2.1和API密钥的完整实现
  • docker-compose.yaml 是“开发/测试环境”的利器,而 Kubernetes 配置是“生产环境”的标准。
  • 2026 年新发布:邯山比较好的钢边采光瓦制造厂有哪些,打破传统瓦片:这才是高采光秘密 - 企业信息推荐【官方】
  • 九江停车方便的火锅怎么选?3个核心维度避坑,附实测推荐 - 品牌2026推荐
  • 解决Home Assistant Roborock集成常见问题:端口设置与设备连接排查
  • 2026敦煌活动策划执行高口碑服务商排行全盘点 - 互联网科技品牌测评
  • 深圳大空间火锅怎么选?避坑指南+品牌推荐,新手不踩雷! - 品牌2026推荐
  • 三步搞定国家中小学智慧教育平台电子课本PDF下载:完整教程指南
  • 【苍穹外卖】(截至day2)所使用到的IDEA使用技巧和测试流程
  • 于 KES MCP 的终端数据库 Agent 实践
  • Priceline Design System 无障碍访问性实践:构建符合 WCAG 标准的现代应用
  • 2026甄选:沈阳消防池防水服务公司专业施工与长效防渗实力之选 - 甄选服务推荐
  • 2026年凉亭品牌挑选攻略:津泉门业厅及头部品牌实测梳理 - 每天一杯纯牛奶
  • 大庆商家宣传获客成本复盘:传统推广失效,AI精细化营销成高性价比选择
  • 2026年07月本溪全屋定制与实木板式家具行业深度解析及优质服务商推荐 - 甄选服务推荐
  • 深圳手工底料火锅怎么选?避坑指南+品牌推荐,新手不踩雷 - 品牌2026推荐
  • java语法基础_双色球小练习