探索 dotnet core 为何在 Windows7 系统需要补丁的原因

在一些 Windows 7 系统上,根据 dotnet 官方文档,需要安装上 KB2533623 补丁,才能运行 dotnet core 或 .NET 5 等应用。尽管非所有的设备都需要安装此,但这也让应用的分发不便,安装包上都需要带上补丁给用户安装。此补丁同时也要求安装完成之后重启系统,这对用户端来说,也是较不方便。本文来聊聊为什么 dotnet core 一系的框架依赖于此补丁

特别感谢 lsj 给我讲解 Win32 调用部分的知识和帮我调查具体的原因,我只是记录的工具人

补丁

开始之前,先来理一下所需补丁的情况,不想看补丁细节还请跳到下文主题这章。准确来说,在当前 2021.12.25 官方推荐 Win7 系统打上的补丁是 KB3063858 补丁

KB3063858: MS15-063:Windows 内核中的漏洞可能允许特权提升:2015 年 6 月 9 日 此安全更新可解决 Windows 中的一个漏洞。如果用户访问包含特殊设计的文件的网络共享(或指向网络共享的网站)时,此漏洞可能允许特权提升。但是在所有情况下,攻击者都无法强制用户访问此类网络共享或网站。

也有伙伴推荐给我的是安装 KB4457144 补丁。但是 KB4457144 补丁太大了,包含太多内容,带上这个补丁没什么优势

KB4457144: 2018 年 9 月 11 日 - KB4457144(月度汇总)

在 GitHub 上的 Security update KB2533623 no longer available · Issue #20459 · dotnet/docs 讨论上,有大佬表示 KB3063858 或 KB4457144 包含了 KB2533623 补丁内容:

The thread claims that KB2533623 is superseded by KB3063858 or KB4457144. https://github.com/dotnet/docs/issues/20459#issuecomment-689513876

值得一说的是对需要安装 KB3063858 补丁的系统来说,大多数都需要额外加上证书,参阅 https://www.microsoft.com/pkiops/Docs/Repository.htm 因此我认为对于客户端分发来说,打上 KB2533623 补丁似乎更好。但是 KB2533623 当前被微软下架了,请看 Security update KB2533623 no longer available · Issue #20459 · dotnet/docs

这是 KB2533623 的下载地址: http://www.microsoft.com/download/details.aspx?familyid=c79c41b0-fbfb-4d61-b5d8-cadbe184b9fc

另外,在刚推送 dotnet core 3.0 的预览版本时,有伙伴在 WPF 官方仓库反馈说需要加上 KB2999226 补丁。此 KB2999226 补丁是 Windows 中的 Universal C Runtime 更新 的内容,参阅 https://github.com/dotnet/wpf/issues/2009#issuecomment-543872453

也许可以使用 runtime.win7-x64.Microsoft.NETCore.Windows.ApiSets NuGet 库 代替 KB2999226 补丁内容,只需要将 api-xxxxx.dll 这些文件拷贝到输出路径即可。或者是解包 VC++ 2015 的分发包里的文件,将 api-xxxxx.dll 和 ucrtbase.dll 拷贝到输出路径即可

因此,对于客户端分发来说,似乎采用 KB2533623 最小补丁,然后在输出路径上拷贝好 api-xxxxx.dll 这些文件到输出路径是最佳方法

下载地址:

  • KB2533623 x86

    • MD5:EDF1D538C85F24EC0EF0991E6B27F0D7

    • SHA1:25BECC0815F3E47B0BA2AE84480E75438C119859

  • KB2533623 x64

    • MD5:0A894C59C245DAD32E6E48ECBDBC8921

    • SHA1:8A59EA3C7378895791E6CDCA38CC2AD9E83BEBFF

  • KB3063858 32-bit

  • KB3063858 64-bit

主题

清理好了各个补丁的关系之后,咱回到主题。为什么在 dotnet core 一系都有此要求?而且还不是对所有 Win7 系统都有此要求,这是为什么?回答这两个问题,可以从 dotnet core 的 dotnet host core run 开始聊起

在 Windows 下,咱双击运行的 dotnet core 的可执行 exe 文件,其实是一个 AppHost 文件。咱编写的 Main 函数,在非单文件模式下,是放在同名的 dll 里面。详细关于 AppHost 请参阅 dotnet core 应用是如何跑起来的 通过AppHost理解运行过程

在 dotnet host core run 里,对应代码是 src\coreclr\hosts\corerun\corerun.hpp 文件,在这里需要拉起 hostpolicy.dll 组件。加载此组件的代码如下,不过代码内容不重要哈

inline bool try_load_hostpolicy(pal::string_t mock_hostpolicy_value){const char_t* hostpolicyName = W("hostpolicy.dll");pal::mod_t hMod = (pal::mod_t)::GetModuleHandleW(hostpolicyName);if (hMod != nullptr)return true;// Check if a hostpolicy exists and if it does, load it.if (pal::does_file_exist(mock_hostpolicy_value))hMod = (pal::mod_t)::LoadLibraryExW(mock_hostpolicy_value.c_str(), nullptr, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);if (hMod == nullptr)pal::fprintf(stderr, W("Failed to load mock hostpolicy at path '%s'. Error: 0x%08x\n"), mock_hostpolicy_value.c_str(), ::GetLastError());return hMod != nullptr;}

以上最关键的只有这一行代码 LoadLibraryExW(mock_hostpolicy_value.c_str(), nullptr, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)

以上代码通过 LoadLibraryExW 函数进行加载库。调用时传入了 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 参数。根据官方文档的描述,调用此函数,如果加入了 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 参数,将要求 KB2533623 补丁

If this value is used, the directory that contains the DLL is temporarily added to the beginning of the list of directories that are searched for the DLL’s dependencies. Directories in the standard search path are not searched. The lpFileName parameter must specify a fully qualified path. This value cannot be combined with LOAD_WITH_ALTERED_SEARCH_PATH. For example, if Lib2.dll is a dependency of C:\Dir1\Lib1.dll, loading Lib1.dll with this value causes the system to search for Lib2.dll only in C:\Dir1. To search for Lib2.dll in C:\Dir1 and all of the directories in the DLL search path, combine this value with LOAD_LIBRARY_DEFAULT_DIRS.

Windows 7, Windows Server 2008 R2, Windows Vista and Windows Server 2008: This value requires KB2533623 to be installed. Windows Server 2003 and Windows XP: This value is not supported

除以上逻辑之外,在 dotnet 仓库里还可以找到其他的各个部分的 LoadLibraryExW 函数上,也都带上了 LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 参数,列表如下:

  • src\coreclr\dlls\dbgshim\dbgshim.cpp: CreateDebuggingInterfaceFromVersion2 函数

  • src\coreclr\hosts\corerun\corerun.hpp: try_load_hostpolicy 函数

  • src\coreclr\hosts\coreshim\CoreShim.cpp: TryLoadHostPolicy 函数

  • src\coreclr\vm\nativelibrary.cpp: DetermineLibNameVariations 函数

  • src\native\corehost\hostmisc\pal.windows.cpp: load_library 函数

看起来文件不多,就看哪个伙伴想不开就去改改挖坑吧

此 LoadLibraryExW 函数是放在 Kernel32.dll 的,相同的需求,在 dotnet core 里也间接依赖于 AddDllDirectory 和 SetDefaultDllDirectories 和 RemoveDllDirectory 等方法。如官方文档描述,刚好这些方法也都相同依赖 KB2533623 补丁

Windows 7, Windows Server 2008 R2, Windows Vista and Windows Server 2008: To use this function in an application, call GetProcAddress to retrieve the function’s address from Kernel32.dll. KB2533623 must be installed on the target platform.

通过如上描述,可以了解到,在 dotnet core 需要补丁的原因是调用了 Kernel32.dll 的新(大约10年前加的)函数,对于一些 Win7 旧设备上,没有更新 Kernel32.dll 加上函数

因此,判断 dotnet core 所依赖环境可以有两个方法,第一个方法是判断 KB2533623 补丁是否有安装,另一个方法是判断 Kernel32.dll 里是否存在 AddDllDirectory 函数。第一个方法判断是不靠谱的,因为不一定需要 KB2533623 补丁,如上文描述,换成其他几个补丁也可以。判断补丁安装可以使用下面命令行代码,更多请参阅 dotnet 通过 WMI 获取系统补丁 和 PowerShell 通过 WMI 获取补丁

BAT:wmic qfe GET hotfixid | findstr /C:"KB2533623"

另外,判断是否存在 KB2533623 补丁,不存在则安装的 bat 脚本代码如下

echo off
cd /d %~dp0
wmic qfe GET hotfixid | findstr /C:"KB2533623"
if %errorlevel% equ 0 (Echo Patch KB2533623 installed) else (
wusa Windows6.1-KB2533623-x64.msu /quiet /norestart
wusa Windows6.1-KB2533623-x86.msu /quiet /norestart
exit /b 1
)
exit /b 0

第二个方法我比较推荐,判断代码如下:

using PInvoke;
using System;namespace AddDllDirectoryDetectCs
{class Program{static void Main(string[] args){using (var hModule = Kernel32.LoadLibrary("Kernel32.dll")){if (!hModule.IsInvalid){IntPtr hFarProc = Kernel32.GetProcAddress(hModule, "AddDllDirectory");if (hFarProc != IntPtr.Zero){Console.WriteLine("Either running on Win8+, or KB2533623 is installed");}else{Console.Write("Likely running on Win7 or older OS, and KB2533623 is not installed");}}}// 以下是判断 Universal C Runtime 的逻辑,可以忽略using (var hModule = Kernel32.LoadLibraryEx("UCRTBASE.dll", IntPtr.Zero, Kernel32.LoadLibraryExFlags.LOAD_LIBRARY_SEARCH_SYSTEM32)){if (!hModule.IsInvalid){Console.WriteLine("UCRT is available - Either running on Win10+ or KB2999226 is installed");}else{Console.WriteLine("UCRT is not available - Likely running on OS older than Win10 and KB2999226 is not installed");}}}}
}

以上代码由 WPF 框架官方开发 Vatsan Madhavan 大佬提供,请看 vatsan-madhavan/checknetcoreprereqs: Helper utility to check .NET Core Prerequisites on Windows systems

d62d55211f231d29f88a5281ed46d62d.png

收到 Vatsan Madhavan 大佬赞

参考

LoadLibraryExW function (libloaderapi.h) - Win32 apps Microsoft Docs

LoadLibraryExA function (libloaderapi.h) - Win32 apps Microsoft Docs

LoadLibraryW function (libloaderapi.h) - Win32 apps Microsoft Docs

windows - SetDllDirectory does not cascade, so dependency DLLs cannot be loaded - Stack Overflow

SetDllDirectoryA function (winbase.h) - Win32 apps Microsoft Docs

AddDllDirectory function (libloaderapi.h) - Win32 apps Microsoft Docs

Windows installer should warn about missing required updated · Issue #2452 · dotnet/runtime

RemoveDllDirectory function (libloaderapi.h) - Win32 apps

Unable to load DLL ‘wpfgfx_cor3.dll’ or one of its dependencies · Issue #2009 · dotnet/wpf

SqlClient: Unable to load DLL ‘sni.dll’ · Issue #16905 · dotnet/runtime

Failed to bind to coreclr dotnet run failure on Windows 7 and Windows 2008 R2 · Issue #5590 · dotnet/sdk

API Set Usage Question · Issue #5075 · dotnet/runtime

Cannot load CoreCLR.dll · Issue #5076 · dotnet/runtime

vatsan-madhavan/checknetcoreprereqs: Helper utility to check .NET Core Prerequisites on Windows systems

使用 C# 判断指定的 Windows 更新是否已安装-码农很忙

Windows 7 安装 msu 系统更新时的常见报错及解决办法-码农很忙

Windows 7 安装 .NET 5 / .NET Core 3.1 环境的方法和依赖文件-码农很忙

Windows 7 SP 1 部署 .NET 6 Desktop Runtime 桌面运行时会遇到的问题-码农很忙

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/293464.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

oracle 性能优化--索引总结

索引是建立在表的一列或多个列上的辅助对象,目的是加快访问表中的数据; Oracle存储索引的数据结构是B*树,位图索引也是如此,只不过是叶子节点不同B*数索引; 索引由根节点、分支节点和叶子节点组成,上级索引…

Android之在ubuntu过滤日志以及ps总结

第一步:得到Pid 如果我们不知道TAG的情况下,先得到进程的PID adb shell ps | grep call 会显示出进程关于call的出来 比如得到pid 是1123 第二步:过滤Pid adb logcat | grep 1123 就可以看到过滤的日志了 常见的命令 杀死进程 adb shell kill pid adb shell am force-s…

Centos6.3下DRBD+HeartBeat+NFS配置笔记

--------------闲 扯------------------ 这里首先感谢酒哥的构建高可用的Linux服务器的这本书,看了这本书上并参考里面的配置让自己对DRBDHeartBeatNFS思路清晰了许多。drbd简单来说就是一个网络raid-1,一般有2到多个node节点,各个节点创建的磁盘块会…

解决centos ping不通外网

先确认三件事: 一。ip 二。网关 三。dns 一就不说了,设置好本地ip和掩码就行了,二网关 添加默认网关,命令:route add defaule gw 192.168.1.1 这是 你用route命令查看最下面会有一条默认路由,走192.168.1…

如何在单个测试中同时执行多个断言

前言虽然,推荐做法是每次测试只断言一件事,但是,在实际工作中,我们可能需要对同一个对象同时执行多个断言。例如,微软官方示例项目eShopOnContainers有一个测试用例的实现代码如下:[Fact] public async Tas…

jquery如何获取元素的滚动高度

获取浏览器显示区域(可视区域)的高度 : $(window).height(); 获取浏览器显示区域(可视区域)的宽度 : $(window).width(); 获取页面的文档高度 $(document).height(); 获取页面的文档宽度 &a…

TCP/IP模型的各层的作用

第一种总结: TCP/IP模型:以无缝方式实现各种网络之间互连的网络体系结构。 TCP/IP模型共分四层,分别为应用层、传输层、互联网层和主机到网络层。 各层实现特定的功能,提供特定的服务和访问接口,并具有相对的独立性。 …

JAVA解决山脉数组的峰顶索引问题

JAVA解决山脉数组的峰顶索引问题 01 题目 符合下列属性的数组 arr 称为 山峰数组&#xff08;山脉数组&#xff09; &#xff1a; arr.length > 3 存在 i&#xff08;0 < i < arr.length - 1&#xff09;使得&#xff1a;arr[0] < arr[1] < ... arr[i-1] <…

php设计模式之单例(多例),注册器,观察者模式

单例(Singleton)模式和不常见的多例(Multiton)模式控制着应用程序中类的数量。如模式名称&#xff0c;单例只能实例化一次&#xff0c;只有一个对象&#xff0c;多例模式可以多次实例化。 基于Singleton的特性&#xff0c;我们经常用Singleton配置应用程序并定义应用程序中可能…

Oracle小知识总结

1. 每天的8&#xff1a;00到23&#xff1a;00每隔5分钟执行一个sql语句的JOB --建立一个存储过程 CREATE OR REPLACE PROCEDURE p_jobtest IS v_hh VARCHAR2(2); BEGIN v_hh : to_char(SYSDATE, hh24); IF v_hh > 08 AND v_hh < 22 THEN --你的sql语句 NULL; END IF; EN…

使用ArcGIS Server发布我们的数据

原文:使用ArcGIS Server发布我们的数据引言 上一篇我们已经安装好了ArcGIS体系的服务软件&#xff0c;这一篇将介绍如何把我们自己的数据通过ArcGIS Server发布出去&#xff0c;并且能够通过Web页面进行显示和编辑。 发布数据服务 在进行WebGIS开发中&#xff0c;地图显示的内容…

网关的一些知识

什么是网关 &#xff1a; 顾名思义&#xff0c;网关&#xff08;Gateway&#xff09;就是一个网络连接到另一个网络的“关口”。 种类&#xff1a; 按照不同的分类标准&#xff0c;网关也有很多种。TCP/IP协议里的网关是最常用的&#xff0c;在这里我们所讲的“网关”均指TCP/…

ArrayBlockingQueue, LinkedBlockingQueue, ConcurrentLinkedQueue, RingBuffer

1. ArrayBlockingQueue, LinkedBlockingQueue, ConcurrentLinkedQueue ArrayBlockingQueue, LinkedBlockingQueue 继承自 BlockingQueue, 他们的特点就是 Blocking, Blocking 特有的方法就是 take() 和 put(), 这两个方法是阻塞方法, 每当队列容量满的时候, put() 方法就会进入…

ASP.NET Core 中是否有 PostAsJsonAsync() 方法?

咨询区 LP13在 Asp.NET 中我一般都用 PostAsJsonAsync() 做数据提交&#xff0c;在 Asp.NET Core 时代我貌似没有找到&#xff0c;按照程序集的命名规范&#xff0c;我觉得应该也是由 Microsoft.AspNet.WebApi.Client 迁移到 Microsoft.AspNetCore.WebApi.Client 中。回答区 Je…

OSI七层模型的作用

第七层&#xff1a;应用层 数据 用户接口&#xff0c;提供用户程序“接口”。 第六层&#xff1a;表示层 数据 数据的表现形式&#xff0c;特定功能的实现&#xff0c;如数据加密。 第五层&#xff1a;会话层 数据 允许不同机器上的用户之间建立会话关系&#xff0c;如WINDOW…

MyBatis学习总结(17)——Mybatis分页插件PageHelper

2019独角兽企业重金招聘Python工程师标准>>> 如果你也在用Mybatis&#xff0c;建议尝试该分页插件&#xff0c;这一定是最方便使用的分页插件。 分页插件支持任何复杂的单表、多表分页&#xff0c;部分特殊情况请看重要提示。 想要使用分页插件&#xff1f;请看如何…

微信发力了,一键部署网站后端!

大家好&#xff0c;我是鱼皮。还记得么&#xff1f;之前我全程直播带大家从 0 到 1 做了一个包含前端、后端的 表情包网站项目 &#xff0c;支持搜索表情、自由裁切下载、给表情包配字等功能。爸爸表情包网站在线编辑下载但由于各方面的原因&#xff0c;我暂时将该网站战术下线…