原文:Extracting and Diffing Windows Patches in 2020
我已经有一段时间没有在这里发布任何东西了!毕竟,个人博客除了多年来被忽视之外还有什么用;)
不管怎样,我在教授 SANS SEC760 时一直在运行这个演示,我想我应该把它写下来,以便研究人员稍后在需要时可以回来查看它。将所有这些内容记录在一个地方也很有用,因为有关它的信息似乎分散在整个 Internet 上,就像许多 Windows 主题一样。
那么为什么要关心提取和分析 Windows 补丁呢?补丁不是说修复的bug现在就没用了吗?
要开始思考如何回答这些问题,请考虑一下,即使是一个运行良好且具有适当补丁管理的组织也需要多长时间才能向设备推出补丁。如果您,安全研究人员,可以在补丁发布后的几周内将错误武器化,那么您就可以出售它或在活动中使用它。查找 bug 很困难,但是经过 n 天的研究可以告诉您几乎确切的 bug 位置!这是个好消息。查看补丁的实施方式以及错误的修复位置对于发现 0day 也很有用。多年来,微软不得不在多个地方修复相同(或非常相似)的错误。一个典型的例子是旧的 MS07-017 动画光标错误,它实际上是两年前 (MS05-002 ) 中相同错误的重复,只是一个函数交叉引用。此外,微软可能根本不会修复该漏洞,或者修复可能不完整,就像今年发现的打印后台处理程序错误一样,该错误被 Ionescu 和 Shafir 称为 PrintDemon 。原始 CVE 为 CVE-2020-1048 ,归功于 SafeBreach 实验室 的 Peleg Hadar 和 Tomer Bar。修复后,Ionescu 被认定为 CVE-2020-1337,该漏洞仍然允许通过检查时间使用时间 (TOC/TOU) 错误创建恶意端口,详细信息请参见此处 。所有这些只是想说:是的,值得一看补丁。查看补丁还可以帮助您找到尚未被研究人员彻底分解的新功能,这些新功能是漏洞研究的主要目标 。
如何获取补丁以及Windows补丁包格式 为了能够分解补丁,您首先需要了解补丁的格式以及如何获取它们。您实际上可能对用于打包补丁的文件格式有些熟悉:.MSU
(Microsoft 独立更新)和 .CAB
(Cabinet)。所有补丁均作为 Windows Update 的一部分分发到您的设备上,但您仍然可以从 Microsoft Update Catolog 下载独立补丁。在这篇文章中,我将拆解 Windows 10 1903 x64 的补丁。很久以前,微软将每个月的第二个星期二定为“补丁星期二” ,这样补丁管理员就可以随时知道何时需要修复。在大多数情况下,他们坚持在补丁星期二发布更新,偶尔会针对非常严重 的错误发布紧急补丁。Microsoft 过去提供必须按顺序安装的连续更新包。如今,更新以累积方式提供,这意味着基础版本 (.1) 所需的所有更新都包含在软件包中。这可以进行一些相当大的更新!许多更新都以增量
形式分发,这让事情变得更复杂一些。我们将在本文后面深入讨论这一点。
有效浏览 Microsoft 更新目录 幸运的是,Microsoft 更新目录具有非常好的搜索功能。搜索所需更新的最有效方法是按以下格式搜索:
1 YYYY-MM release -number (x 86 |x 64 |ARM64 ) cumulative
例如,如果我正在寻找 Windows 10 1903 x64 的 2020 年 7 月补丁集,我将搜索 2020-07 1903 x64 累积,并且最热门的点击之一应该是我正在寻找的结果。
如您所见,返回了几个不同版本号(1903、1909 和 2004)以及 Windows 10 和 Windows Server 的结果。敏锐的观察者应该注意到,Windows Server 和 Windows 10 更新的大小完全相同。事实上,如果您单击下载,两个链接都会定向到同一个地方。此外,1903和1909的更新也是相同的。后一种情况的原因在操作系统构建页面 上进行了解释:
Windows 10 版本 1903 和 1909 共享一个通用的核心操作系统和一组相同的系统文件。因此,Windows 10 版本 1909 中的新功能包含在最近的 Windows 10 版本 1903 每月质量更新(2019 年 10 月 8 日发布)中,但目前处于休眠状态。这些新功能将保持休眠状态,直到使用启用包打开它们,启用包是一个小型、快速安装的“主开关”,只需激活 Windows 10 版本 1909 功能即可。
动态和服务堆栈更新 Microsoft 还通过 Microsoft 更新目录分发一些其他类型的更新。如果您在上面的搜索中省略“cumulative(累积)
”一词,那么您会得到更多结果,包括比累积更新小得多的 Dynamic(动态)
和 Servicing Stack(服务堆栈)
更新。
根据 Microsoft 文档 ,服务堆栈更新是对 Windows 更新过程本身的更新。服务堆栈更新像累积更新一样打包,并且仅包含与 Windows Update 相关的组件。
Microsoft 文档 再次为动态更新节省了时间,这显然还可以更新 Windows 更新组件,以及安装介质、Windows 恢复环境 (WinRE) 和一些驱动程序等安装组件。 动态更新的打包方式与累积更新和服务堆栈更新略有不同;它们可以作为单个 CAB 文件下载,并具有各种语言包和其他安装组件 。
提取补丁 补丁被紧密地打包到一个 MSU 文件中,该文件可以包含数以万计的文件,其中只有一些文件对我们作为安全研究人员来说很重要。我想首先完成手动提取,然后提供对现有脚本 (PatchExtract.ps1
) 的更新,以自动提取和排序给定的补丁。
手动提取 首先,您需要从更新目录下载累积更新 MSU 文件。在本示例中,我使用 Windows 10 1903 x64 2020 年 8 月累积更新包。我通常在开始之前创建几个文件夹:我用补丁年份和月份命名顶级文件夹,然后创建两个子文件夹,分别称为 patch
和 ext
。嵌套 CAB 文件内的实际补丁文件将放入 patch 文件夹中,解压的 MSU 的内容将放入 ext 文件夹中。
1 2 3 4 5 mkdir 2020 -08 mv ".\windows10.0-kb4565351-x64_e4f46f54ab78b4dd2dcef193ed573737661e5a10.msu" .\2020 -08 \cd .\2020 -08 \ mkdir ext mkdir patch
接下来,我将使用 Expand.exe
命令提取 MSU
。 Expand 的参数可以使用 /?
选项获取详细说明。出于我们的目的,我们将提取每个文件,因此我们将使用 -F:*
。如果您只需要某些类型的文件(CAB、DLL、EXE 等),那么您可以使用 -F
标志来实现。接下来的两个参数是要提取的 MSU,然后是扩展文件的目标文件夹。
1 expand.exe -F :* ".\windows10.0-kb4565351-x64_e4f46f54ab78b4dd2dcef193ed573737661e5a10.msu" .\ext\
最后,我将再次使用 expand
命令从PSFX cab文件中提取补丁文件,这次扩展到 patch
目录。
1 expand.exe -F :* ".\ext\Windows10.0-KB4565351-x64_PSFX.cab" .\patch\ | Out-Null
此时我建议走开,开始洗一堆衣服,买一个三明治,然后抚摸猫,因为这部分需要一段时间(10-20 分钟)。Out-Null
是可选的,我只使用它,因为我不关心它打印要提取的每个文件。这种特殊的提取大约需要 15 分钟(通过 Measure-Command
),并在 patch
文件夹下总共产生了 78898
个文件和文件夹!
如果你在家也跟着做: 提取完成后,给自己鼓掌,然后收回它,因为不幸的是,这是最容易的部分!
接下来,您必须理解提取的文件并找到您正在寻找的修补文件。
理解提取的文件 要找到您要查找的内容,了解补丁的结构以及您将遇到的文件类型会有所帮助。
要开始了解这些细节,请看一下从 MSU 开始的补丁的层次结构视图(输出缩写以节省空间):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 windows10.0 -kb4565351-x64_e4f46f54ab78b4dd2dcef193ed573737661e5a10.msu ├── WSUSSCAN.cab ├── Windows10.0 -KB4565351-x64-pkgProperties_PSFX.txt ├── Windows10.0 -KB4565351-x64_PSFX.xml └── Windows10.0 -KB4565351-x64_PSFX.cab ├── amd64_microsoft.windows .gdiplus_6595b64144ccf1df_1 .0.18362 .1016 _none_e013babca5ee7b0b │ └── gdiplus.dll ├── amd64_microsoft-windows-os-kernel_31bf3856ad364e35_10.0.18362 .1016 _none_79ea293316ee3bad │ ├── f │ │ └── ntoskrnl.exe │ └── r │ └── ntoskrnl.exe ├── msil_microsoft.hyperv .powershell .cmdlets_31bf3856ad364e35_10 .0.18362 .959 _none_a7668eee2055cacf │ ├── f │ │ └── microsoft.hyperv .powershell .cmdlets .dll │ └── r │ └── microsoft.hyperv .powershell .cmdlets .dll ├── wow64_microsoft-windows-p ..ting-spooler-client_31bf3856ad364e35_10 .0.18362 .693 _none_f3229700ded2ae02 │ ├── f │ │ └── winspool.drv │ └── r │ └── winspool.drv ├── x86_microsoft-windows-win32calc.resources_31bf3856ad364e35_10 .0.18362 .387 _ar-sa_38566bf3d86fbe5c │ ├── f │ │ └── win32calc.exe .mui │ └── r │ └── win32calc.exe .mui ├── amd64_windows-shield-provider_31bf3856ad364e35_10.0.18362 .900 _none_fbf40d7d5ed8b490 │ ├── f │ │ ├── featuretoastbulldogimg.png │ │ ├── securityhealthagent.dll │ │ ├── securityhealthhost.exe │ │ ├── securityhealthproxystub.dll │ │ ├── securityhealthservice.exe │ │ ├── windowsdefendersecuritycenter.admx │ │ └── windowssecurityicon.png │ ├── n │ │ └── featuretoastdlpimg.png │ └── r │ ├── featuretoastbulldogimg.png │ ├── securityhealthagent.dll │ ├── securityhealthhost.exe │ ├── securityhealthproxystub.dll │ ├── securityhealthservice.exe │ ├── windowsdefendersecuritycenter.admx │ └── windowssecurityicon.png ├── microsoft-windows-kernel-feature-package~31 bf3856ad364e35~amd64~~10.0 .18362.1016 .cat ├── microsoft-windows-kernel-feature-package~31 bf3856ad364e35~amd64~~10.0 .18362.1016 .mum ├── amd64_microsoft-windows-os-kernel_31bf3856ad364e35_10.0.18362 .1016 _none_79ea293316ee3bad.manifest ├── amd64_microsoft.windows .gdiplus_6595b64144ccf1df_1 .0.18362 .1016 _none_e013babca5ee7b0b.manifest ├── msil_microsoft.hyperv .powershell .cmdlets_31bf3856ad364e35_10 .0.18362 .959 _none_a7668eee2055cacf.manifest ├── wow64_microsoft-windows-p ..ting-spooler-client_31bf3856ad364e35_10 .0.18362 .693 _none_f3229700ded2ae02.manifest ├── amd64_windows-shield-provider_31bf3856ad364e35_10.0.18362 .900 _none_fbf40d7d5ed8b490.manifest └── x86_microsoft-windows-win32calc.resources_31bf3856ad364e35_10 .0.18362 .387 _ar-sa_38566bf3d86fbe5c.manifest
正如您在上面看到的,有许多不同的文件格式和文件夹类型:
文件夹类型
平台 - 更新中的所有文件夹都将以其中之一为前缀
amd64
- 64-bit x86
x86
- 32-bit x86
wow64
- Windows (32-bit) On Windows 64-bit
msil
- Microsoft Intermediate Language (.NET)
差异文件夹
n
- Null differentials(无差异)
r
- Reverse differentials(向后差异)
f
- Forward differentials(向前差异)
文件类型
manifest
-(几乎)1-1 与平台文件夹配对, 这些是 Windows Side-by-Side (WinSxS) 清单
cat
- security catalog
mum
- 1-1 paired with a .cat file and conatins metadata about the part of the update package that the security catalog applies to(1-1 与 .cat 文件配对,包含有关安全目录适用的更新包部分的元数据)
平台文件夹和清单实际上与 WinSxS 有关,因为系统可能在 C:\Windows\WinSxS
文件夹中存储二进制文件的多个版本以及差异文件。请注意,这些文件夹中不仅仅有 EXE 和 DLL。还有 PNG 和 MUI 文件。任何类型的文件都可以通过 Windows Update 和 WinSxS 进行更新。一些文件夹名称已被截断;看起来最大文件夹名称长度是100个字符,中间多余的字符被替换为..
出于本文的目的,我将保留 .mum 和 .cat 文件,因为它们本质上只是元数据和签名验证信息。
WinSxS Manifests 补丁中的 .manifest
文件描述了如何应用补丁、补丁中包含的文件、文件哈希形式的补丁的预期结果、结果文件的权限、要设置的注册表项以及更多的 。它们定义了除了替换正在更新的文件之外对系统产生的影响。
以下是 Windows-Gaming-XboxLive-Storage-Service-Component
(无论是什么)的示例清单。
▼ amd64_windows-gaming-xbox..e-service-component_31bf3856ad364e35_10.0.18362.836_none_a949879e457dbcd4.manifest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <assembly xmlns ="urn:schemas-microsoft-com:asm.v3" manifestVersion ="1.0" copyright ="Copyright (c) Microsoft Corporation. All Rights Reserved." > <assemblyIdentity name ="Windows-Gaming-XboxLive-Storage-Service-Component" version ="10.0.18362.836" processorArchitecture ="amd64" language ="neutral" buildType ="release" publicKeyToken ="31bf3856ad364e35" versionScope ="nonSxS" /> <dependency discoverable ="no" resourceType ="resources" > <dependentAssembly > <assemblyIdentity name ="Windows-Gaming-XboxLive-Storage-Service-Component.Resources" version ="10.0.18362.836" processorArchitecture ="amd64" language ="*" buildType ="release" publicKeyToken ="31bf3856ad364e35" /> </dependentAssembly > </dependency > <file name ="XblGameSave.dll" destinationPath ="$(runtime.system32)\" sourceName ="XblGameSave.dll" importPath ="$(build.nttree)\" sourcePath =".\" > <securityDescriptor name ="WRP_FILE_DEFAULT_SDDL" /> <asmv2:hash xmlns:asmv2 ="urn:schemas-microsoft-com:asm.v2" xmlns:dsig ="http://www.w3.org/2000/09/xmldsig#" > <dsig:Transforms > <dsig:Transform Algorithm ="urn:schemas-microsoft-com:HashTransforms.Identity" /> </dsig:Transforms > <dsig:DigestMethod Algorithm ="http://www.w3.org/2000/09/xmldsig#sha256" /> <dsig:DigestValue > VjbzeELS2YXIwIhHo5f2hQm+pWTzHY8wo7dFxzfkbtA=</dsig:DigestValue > </asmv2:hash > </file > <file name ="XblGameSaveTask.exe" destinationPath ="$(runtime.system32)\" sourceName ="" importPath ="$(build.nttree)\" > <securityDescriptor name ="WRP_FILE_DEFAULT_SDDL" /> <asmv2:hash xmlns:asmv2 ="urn:schemas-microsoft-com:asm.v2" xmlns:dsig ="http://www.w3.org/2000/09/xmldsig#" > <dsig:Transforms > <dsig:Transform Algorithm ="urn:schemas-microsoft-com:HashTransforms.Identity" /> </dsig:Transforms > <dsig:DigestMethod Algorithm ="http://www.w3.org/2000/09/xmldsig#sha256" /> <dsig:DigestValue > Ez9Rg7QMg26whoQcakH4i15oeH1NOZgbybxRdPMoi8Q=</dsig:DigestValue > </asmv2:hash > </file > <memberships > <categoryMembership > <id name ="Microsoft.Windows.Categories.Services" version ="10.0.18362.836" publicKeyToken ="31bf3856ad364e35" typeName ="Service" /> <categoryInstance subcategory ="XblGameSave" > <serviceData name ="XblGameSave" displayName ="@%systemroot%\system32\XblGameSave.dll,-100" errorControl ="normal" start ="demand" type ="win32ShareProcess" description ="@%systemroot%\system32\XblGameSave.dll,-101" dependOnService ="UserManager,XblAuthManager" imagePath ="%SystemRoot%\system32\svchost.exe -k netsvcs -p" objectName ="LocalSystem" > <failureActions resetPeriod ="86400" > <actions > <action delay ="10000" type ="restartService" /> <action delay ="10000" type ="restartService" /> <action delay ="10000" type ="restartService" /> <action delay ="0" type ="none" /> </actions > </failureActions > <serviceTrigger action ="start" subtype ="RPC_INTERFACE_EVENT" type ="NetworkEndpointEvent" > <triggerData type ="string" value ="F6C98708-C7B8-4919-887C-2CE66E78B9A0" /> </serviceTrigger > </serviceData > </categoryInstance > </categoryMembership > <categoryMembership > <id name ="Microsoft.Windows.Categories" version ="1.0.0.0" publicKeyToken ="365143bb27e7ac8b" typeName ="BootRecovery" /> </categoryMembership > <categoryMembership > <id name ="Microsoft.Windows.Categories" version ="1.0.0.0" publicKeyToken ="365143bb27e7ac8b" typeName ="SvcHost" /> <categoryInstance subcategory ="netsvcs" > <serviceGroup position ="last" serviceName ="XblGameSave" /> </categoryInstance > </categoryMembership > </memberships > <taskScheduler > <Task xmlns ="http://schemas.microsoft.com/windows/2004/02/mit/task" > <RegistrationInfo > <Author > Microsoft</Author > <Description > XblGameSave Standby Task</Description > <URI > \Microsoft\XblGameSave\XblGameSaveTask</URI > </RegistrationInfo > <Principals > <Principal id ="LocalSystem" > <UserId > S-1-5-18</UserId > </Principal > </Principals > <Triggers > <IdleTrigger id ="XblGameSave Check on CS Entry" > <Enabled > false</Enabled > </IdleTrigger > </Triggers > <Settings > <MultipleInstancesPolicy > IgnoreNew</MultipleInstancesPolicy > <DisallowStartIfOnBatteries > true</DisallowStartIfOnBatteries > <StopIfGoingOnBatteries > false</StopIfGoingOnBatteries > <AllowHardTerminate > true</AllowHardTerminate > <StartWhenAvailable > false</StartWhenAvailable > <RunOnlyIfNetworkAvailable > true</RunOnlyIfNetworkAvailable > <AllowStartOnDemand > true</AllowStartOnDemand > <Enabled > true</Enabled > <Hidden > false</Hidden > <RunOnlyIfIdle > true</RunOnlyIfIdle > <WakeToRun > false</WakeToRun > <ExecutionTimeLimit > PT2H</ExecutionTimeLimit > <Priority > 7</Priority > </Settings > <Actions Context ="LocalSystem" > <Exec > <Command > %windir%\System32\XblGameSaveTask.exe</Command > <Arguments > standby</Arguments > </Exec > </Actions > </Task > </taskScheduler > <registryKeys > <registryKey keyName ="HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Ubpm" > <registryValue name ="CriticalTask_XblGameSaveTask" valueType ="REG_SZ" value ="NT TASK\Microsoft\XblGameSave\XblGameSaveTask" /> <registryValue name ="CriticalTask_XblGameSaveTaskLogon" valueType ="REG_SZ" value ="NT TASK\Microsoft\XblGameSave\XblGameSaveTaskLogon" /> <securityDescriptor name ="WRP_REGKEY_DEFAULT_SDDL" /> </registryKey > <registryKey keyName ="HKEY_CLASSES_ROOT\AppId\{C5D3C0E1-DC41-4F83-8BA8-CC0D46BCCDE3}" > <registryValue name ="" valueType ="REG_SZ" value ="Xbox Live Game Saves" /> <registryValue name ="LocalService" valueType ="REG_SZ" value ="XblGameSave" /> <registryValue name ="AccessPermission" valueType ="REG_BINARY" value ="010014806400000070000000140000003000000002001c000100000011001400040000000101000000000010001000000200340002000000000018001f000000010200000000000f0200000001000000000014001f00000001010000000000010000000001010000000000050a00000001020000000000052000000021020000" /> <registryValue name ="LaunchPermission" valueType ="REG_BINARY" value ="010014806400000070000000140000003000000002001c000100000011001400040000000101000000000010001000000200340002000000000018001f000000010200000000000f0200000001000000000014001f00000001010000000000010000000001010000000000050a00000001020000000000052000000021020000" /> <securityDescriptor name ="WRP_REGKEY_DEFAULT_SDDL" /> </registryKey > <registryKey keyName ="HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\XblGameSave\Parameters" > <registryValue name ="ServiceDll" valueType ="REG_EXPAND_SZ" value ="%SystemRoot%\System32\XblGameSave.dll" /> <registryValue name ="ServiceDllUnloadOnStop" valueType ="REG_DWORD" value ="0x00000001" /> <registryValue name ="ServiceIdleTimeout" valueType ="REG_DWORD" value ="0x00000258" /> </registryKey > <registryKey keyName ="HKEY_CLASSES_ROOT\CLSID\{F7FD3FD6-9994-452D-8DA7-9A8FD87AEEF4}\" > <registryValue name ="AppId" valueType ="REG_SZ" value ="{C5D3C0E1-DC41-4F83-8BA8-CC0D46BCCDE3}" /> <securityDescriptor name ="WRP_REGKEY_DEFAULT_SDDL" /> </registryKey > <registryKey keyName ="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsRuntime\AllowedCOMCLSIDs\{F7FD3FD6-9994-452D-8DA7-9A8FD87AEEF4}\" /> <registryKey keyName ="HKEY_CLASSES_ROOT\CLSID\{5B3E6773-3A99-4A3D-8096-7765DD11785C}\" > <registryValue name ="AppId" valueType ="REG_SZ" value ="{C5D3C0E1-DC41-4F83-8BA8-CC0D46BCCDE3}" /> <securityDescriptor name ="WRP_REGKEY_DEFAULT_SDDL" /> </registryKey > <registryKey keyName ="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsRuntime\AllowedCOMCLSIDs\{5B3E6773-3A99-4A3D-8096-7765DD11785C}\" /> </registryKeys > <localization > <resources culture ="en-US" > <stringTable > <string id ="displayName" value ="XblGameSave" /> <string id ="description" value ="XblGameSave service" /> </stringTable > </resources > </localization > <trustInfo > <security > <accessControl > <securityDescriptorDefinitions > <securityDescriptorDefinition name ="WRP_REGKEY_DEFAULT_SDDL" sddl ="O:S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464G:S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464D:P(A;CI;GA;;;S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464)(A;CI;GR;;;SY)(A;CI;GR;;;BA)(A;CI;GR;;;BU)(A;CI;GR;;;S-1-15-2-1)(A;CI;GR;;;S-1-15-3-1024-1065365936-1281604716-3511738428-1654721687-432734479-3232135806-4053264122-3456934681)" operationHint ="replace" /> <securityDescriptorDefinition name ="WRP_FILE_DEFAULT_SDDL" sddl ="O:S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464G:S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464D:P(A;;FA;;;S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464)(A;;GRGX;;;BA)(A;;GRGX;;;SY)(A;;GRGX;;;BU)(A;;GRGX;;;S-1-15-2-1)(A;;GRGX;;;S-1-15-2-2)S:(AU;FASA;0x000D0116;;;WD)" operationHint ="replace" /> </securityDescriptorDefinitions > </accessControl > </security > </trustInfo > </assembly >
注意所有不同的字段。有一些字段可以修改注册表项、更改文件权限、要修补的文件及其生成的哈希值、要修改或更改状态的服务、要添加或更改的计划任务等等!
如果您查看此清单描述的相应平台文件夹,您将找到它所引用的文件,可以是完整文件,也可以是(在本例中)差异文件:
1 PS > ls -Recurse amd64_windows-gaming-xbox ..e-service-component_31bf3856ad364e35_10 .0.18362 .836 _none_a949879e457dbcd4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 Directory: C:\Users\wumb0\Desktop\patches\2020 -08 \patch\amd64_windows-gaming-xbox ..e-service-component_31bf3856ad36 4 e35_10.0.18362 .836 _none_a949879e457dbcd4 Mode LastWriteTime Length Name---- ------------- ------ ---- d----- 8 /23 /2020 6 :50 PM f d----- 8 /23 /2020 6 :50 PM r Directory: C:\Users\wumb0\Desktop\patches\2020 -08 \patch\amd64_windows-gaming-xbox ..e-service-component_31bf3856ad36 4 e35_10.0.18362 .836 _none_a949879e457dbcd4\f Mode LastWriteTime Length Name---- ------------- ------ ---- -a---- 8 /6 /2020 5 :10 AM 35111 xblgamesave.dll-a---- 8 /6 /2020 5 :10 AM 237 xblgamesavetask.exe Directory: C:\Users\wumb0\Desktop\patches\2020 -08 \patch\amd64_windows-gaming-xbox ..e-service-component_31bf3856ad36 4 e35_10.0.18362 .836 _none_a949879e457dbcd4\r Mode LastWriteTime Length Name---- ------------- ------ ---- -a---- 8 /6 /2020 5 :10 AM 35200 xblgamesave.dll-a---- 8 /6 /2020 5 :10 AM 237 xblgamesavetask.exe
注:ls -Recurse
递归显示目录内容
自动补丁提取 现在您已经了解了补丁的结构以及如何从中提取文件,现在是时候在混合中引入一些自动化了。Greg Linares (@laughing_mantis) 是 Patch Extract 的作者,一个自动提取和组织 Microsoft 补丁的工具。他还创建了一个名为 Patch Clean 的工具,但我不确定它是否仍然适用于现代补丁,所以使用后果自负!我稍微修改了 PatchExtract 以修复一些 powershell 问题并安静脚本的输出。请注意,它现在在用户输入字符串上使用 IEX
,所以要小心:)。
PatchExtract.ps1:
要使用,请指定 PATCH
的路径和结果文件的输出 PATH
。 PatchClean
将提取 MSU,找到 PSFX
CAB
,提取其内容,并将提取的补丁分类到各个文件夹中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 PS > ls X:\Patches\x64\1903 \2019 \9 Directory: X:\Patches\x64\1903 \2019 \9 Mode LastWriteTime Length Name---- ------------- ------ ---- da---- 11 /9 /2019 6 :30 PM JUNK da---- 11 /9 /2019 6 :30 PM MSIL da---- 11 /9 /2019 6 :32 PM PATCH da---- 11 /9 /2019 6 :31 PM WOW64 da---- 11 /9 /2019 7 :06 PM x64 da---- 11 /9 /2019 6 :31 PM x86-a---- 9 /8 /2019 12 :28 PM 517 Windows10.0 -KB4515384-x64-pkgProperties_PSFX .txt
MSIL、WOW64、x86 和 x64 文件夹将包含所有不同平台文件夹,并删除其前缀。 PATCH 文件夹将包含补丁 MSU 及其内容,但补丁 PSFX 元数据文本文件除外,该文件保留在顶级文件夹的根目录中。最后,JUNK 文件夹中填充了 .manifest 文件以及我们并不真正关心的 .mum 和 .cat 文件。使用此工具可以加快补丁提取过程!
处理提取的补丁 提取补丁时请注意:始终在本地计算机上进行,压缩结果,然后传输到另一台计算机进行存储。未压缩的解压补丁大约为 1.5 GB,压缩的解压补丁大约为 1 GB。这可以快速填满您的磁盘空间!由于每个补丁中有数万个文件,未压缩的目录结构的传输将需要很长时间。如果您需要搜索压缩补丁,您只需使用 unzip -l 列出内容,然后仅提取您需要的文件。
补丁文件类型 完整文件 不含 n
、f
或 r
目录的平台文件夹包含要安装的完整文件。修补过程非常简单,只需将该文件夹中的文件复制到相应 .manifest
文件中指定的位置即可。
您如何获得该文件的另一个副本来进行比较?这可能很困难,但您也许可以查看以前的补丁以获取不同的版本。事实证明,差速器实际上是更方便的情况!
补丁增量 当平台文件夹中包含 n
、f
或 r
目录时,补丁是一个增量,它要么应用于现有文件 (r/f)
,要么应用于空缓冲区以创建新文件 (n)
。微软在今年(2020)年初发布了关于差异化的白皮书 。
增量类型 如前所述,增量分为三种类型:
Forward differentials (f)
- 将基本二进制文件 (.1) 提升到特定补丁级别
Reverse differentials (r)
- 将应用的补丁恢复为基本二进制文件 (.1)
Null differentials (n)
- 一个全新的文件,刚刚压缩;应用于空缓冲区以获取完整文件
您将始终在补丁内看到 r 和 f 文件夹,因为您需要能够稍后恢复补丁以应用较新的更新。
Delta APIs 在我开始深入研究 Delta 格式并将其应用于文件之前,值得注意的是 Microsoft 提供了有关 Delta Compression API 的开发人员文档(稍微过时,但仍然相关)。实际上有两个完全不同的 API 用于创建和应用补丁增量:PatchAPI 和 MSDELTA 。在这篇文章中,我将重点关注 MSDELTA API,因为它较新,并且仅在正在发布的新补丁中使用。此外,如果您调用 MSDELTA API 并提供 PatchAPI 修补程序文件,它会识别该文件并通过调用 mspatcha.dll
来应用修补程序。
MSDELTA API 中的函数包含在 msdelta.dll 内。
CreateDelta(A|W|B)
- 从文件 (A|W) 或缓冲区 (B) 创建增量
ApplyDelta(A|W|B)
- 将增量从文件应用到文件 (A|W) 或从缓冲区 (B) 应用到缓冲区 (B)
ApplyDeltaProvidedB
- 将缓冲区中的增量应用到被调用者分配的提供的缓冲区(无需调用 DeltaFree
)
GetDeltaInfo(A|W|B)
- 获取有关补丁的元数据并计算增量文件 (A|W) 或缓冲区 (B) 的签名
GetDeltaSignature(A|W|B)
- 计算增量文件 (A|W) 或缓冲区 (B) 的签名。
DeltaNormalizeProvidedB
- 将增量缓冲区置于标准状态,以便通过 MSDELTA 不支持的算法进行哈希处理
DeltaFree
- 释放由 CreateDeltaB
或 ApplyDeltaB
创建的增量缓冲区
我将使用 ApplyDeltaB
将多个补丁增量文件应用到文件缓冲区,然后使用 DeltaFree
释放生成的缓冲区。更仔细地查看 GetDeltaInfo*
和 DeltaNormalizeProvidedB
都在我的 TODO 列表中,但对于本文的目的来说并不是那么重要。
MSDELTA API 的其他有趣功能是能够通过文件类型集将增量应用到特定的二进制部分 。这些背后还有更多的研究要做!
乍一看,您会确信补丁内的增量文件夹中的文件是完整的二进制文件,因为它们的扩展名。第一个线索是它们的大小,因为它们比您预期的完整二进制文件要小得多。另一个是文件格式完全不同!在十六进制编辑器中打开一些提取的文件很快就会显示这一点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 wumb0 in patches$ xxd 2020-08/patch/amd64_microsoft-windows-os-kernel_31bf3856ad364e35_10.0.18362.1016_none_79ea293316ee3bad/f/ntoskrnl.exe | head 00000000: e45a 9bd5 5041 3330 6e2b 8720 fa6a d601 .Z..PA30n+. .j.. 00000010: b05e 10d0 c7c4 0cc4 69bc c401 4021 00b4 .^......i...@!.. 00000020: ab4f 2159 0f6a 2ab4 7848 f5df d9cd 2fb8 .O!Y.j*.xH..../. 00000030: b30b 0400 0000 0a00 0000 0000 0000 9836 ...............6 00000040: 86a9 cb02 f05b dddd dddd dddd dddd dddd .....[.......... 00000050: dd2d 4dd2 333d d143 3dd4 ddd3 0128 c6c4 .-M.3=.C=....(.. 00000060: cccc cccc cccc cccc c31c 22c2 cccc 3c2c .........."...<, 00000070: cccc ccc3 7280 3000 d07f 0700 a8ff 1700 ....r.0......... 00000080: fc7f 00a0 ff03 80fc 5f00 90ff 0c00 ecfc ........_....... 00000090: 8701 60e5 ff19 1100 7cff 5f00 f8ff 0080 ..`.....|._..... wumb0 in patches$ xxd 2020-08/patch/amd64_microsoft-onecore-reverseforwarders_31bf3856ad364e35_10.0.18362.997_none_f7e8eb88fe7a4f39/r/gdi32.dll | head 00000000: db07 a73a 5041 3330 f494 3566 d8dd d401 ...:PA30..5f.... 00000010: b05e 10d0 c7c4 0c02 6006 0e00 0a01 5d41 .^......`.....]A 00000020: 1606 6042 f2b4 03a7 1295 36ee fbe7 2e01 ..`B......6..... 00000030: 0100 0000 0c00 0000 0000 0000 b0b4 5e9e ..............^. 00000040: 0802 402d aaaa aaaa aaaa aaaa aaaa aa0a ..@-............ 00000050: aaaa 2aa2 0117 dba2 aaaa aaaa aaaa aaaa ..*............. 00000060: a2a2 111a c900 f87f 03c0 fd17 00e4 ff00 ................ 00000070: f8ff 00d0 3f00 fa1f 00ff 0fd6 00b3 0340 ....?..........@ 00000080: 20ee ea69 7500 00d8 1069 a703 f54e 5d0f ..iu....i...N]. 00000090: d301 2557 07ec 681d 9a0f caa7 03b5 c81a ..%W..h......... wumb0 in patches$ xxd 2020-08/patch/amd64_microsoft-windows-f..ysafety-refreshtask_31bf3856ad364e35_10.0.18362.997_none_b453df19f80f8d5b/f/wpcmon.png | head 00000000: 400b 0a1a 5041 3330 008b e980 ac49 d601 @...PA30.....I.. 00000010: b07e 4000 00c3 2709 1c00 1402 c30c 6217 .~@...'.......b. 00000020: 48c6 6ce7 51b1 9b27 8855 9a3e 010b b103 H.l.Q..'.U.>.... 00000030: 003c 12
这些不是 PE 或 PNG 文件,并且出现了一种清晰的模式!PA30
在每个文件中从偏移量 4
开始,无论类型是什么。但是前四个字节是什么?在我最初尝试使用 delta 时,我感到很沮丧,因为使用 msdelta.dll
中的任何 ApplyDelta*
函数都会导致错误。对文件格式(PA30)的研究最终使我获得了该技术的专利 ,如果您想看一下,这很有趣,但没有为我的问题提供答案。在真正的 FILDI 时刻,我只是切断了前四个字节,因为文件magic通常位于文件的开头(对吗?),令我惊讶的是,增量应用了!太棒了,那 4 个字节是多少?该格式是否记录在任何地方?在思考了我之前遇到的文件中看似无用的字节之后,我想到了一个校验和,特别是我能想到的最常见的 4 字节校验和:CRC32!
所以我跳进 ipython
来尝试一下:
1 2 3 4 5 6 7 8 9 10 In [1 ]: import zlib In [2 ]: data = open ("2020-08/patch/amd64_microsoft-windows-f..ysafety-refreshtask_31bf3856ad364e35_10.0.18362.997_none_ ...: b453df19f80f8d5b/f/wpcmon.png" , "rb" ).read() In [3 ]: hex (zlib.crc32(data[4 :])) Out[3 ]: '0x1a0a0b40' In [4 ]: hex (int .from_bytes(data[:4 ], 'little' )) Out[4 ]: '0x1a0a0b40'
我的怀疑得到了证实!完全是一个幸运的猜测,而且我能找到的任何地方都没有记录它。
在经历了这个发现之后,我认为这将是一个有趣的 CTF 挑战。所以我为一年一度的 RITSEC CTF 设计了一个 CTF 挑战赛。它应该被称为 patch-tuesday
,但我不小心上传了带有该标志的原始 .sys
文件。该挑战最终被称为 patch-2sday,涉及调用 MSDELTA API 在剥离前置的 CRC32 后修补文件。感谢莱尔 和元娜是仅有的两个解决了这个问题的人!您可以在 RITSEC Github 上找到该挑战的解决方案的文章;如果您对此感兴趣,该存储库还包含我用来创建增量的脚本 。
从 Delta 中生成有用的二进制文件 假设我有一台 Windows 10 1903 x64 计算机,我想查看 2020 年 7 月至 8 月 ntoskrnl.exe 之间的差异。该机器当前安装了 2019 年 10 月 的补丁。我将从 C:\windows\system32
中复制 ntoskrnl.exe 二进制文件,并使用 MSDELTA API 将增量应用于二进制文件以获得我想要的版本。
后退,然后前进 我拥有的内核二进制文件的版本是 10.0.18362.388。在开始修补之前,我需要此特定版本的反向差分将其回滚到版本 10.0.18362.1。我可以下载并提取 2019 年 10 月更新,但这需要很长时间。回想一下,安装补丁后,Windows Update 会将二进制文件和差异文件放置在 C:\Windows\WinSxS
目录中。您可以运行一些 powershell 来查找系统上已有的增量:
1 PS > Get-ChildItem -Recurse C:\windows\WinSxS\ | ? {$_ .Name -eq "ntoskrnl.exe" }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Directory: C:\windows\WinSxS\amd64_microsoft-windows-os-kernel_31bf3856ad364e35_10 .0.18362 .388 _none_c1e023dc45da9936 Mode LastWriteTime Length Name---- ------------- ------ ---- -a---l 10 /4 /2019 6 :06 AM 9928720 ntoskrnl.exe Directory: C:\windows\WinSxS\amd64_microsoft-windows-os-kernel_31bf3856ad364e35_10 .0.18362 .388 _none_c1e023dc45da9936\f Mode LastWriteTime Length Name---- ------------- ------ ---- -a---- 9 /30 /2019 6 :39 PM 479646 ntoskrnl.exe Directory: C:\windows\WinSxS\amd64_microsoft-windows-os-kernel_31bf3856ad364e35_10 .0.18362 .388 _none_c1e023dc45da9936\r Mode LastWriteTime Length Name---- ------------- ------ ---- -a---- 9 /30 /2019 6 :39 PM 476929 ntoskrnl.exe
完整版本以及前进和后退差速器都存在。现在我拥有执行增量所需的所有文件并获取我想要比较的两个版本的内核!
使用 MSDELTA API 应用补丁增量 我决定编写一个 python 程序来与 msdelta.dll
交互并调用 ApplyDelta
系列函数。如果您以前从未使用过 python ctypes
,那么该脚本一开始可能看起来有点奇怪,但我保证它是您实用工具带中的一个非常强大的工具。除此之外,ctypes 可以充当 C 的外部函数 接口;它允许您调用 DLL 内部的函数、创建结构和联合、原始缓冲区,并实现了许多基本类型,例如 c_uint64
、c_char_p
,以及 Windows 类型,例如 DWORD
、HANDLE
和 LPVOID
。
如果您对 ctypes 的更多用途感兴趣,请查看我关于有效使用 ctypes 结构的文章 ,但请记住它是为 python 2.7 编写的,并且可能需要更改示例以支持 python 3。
下面是为 python 3 编写的最终补丁增量应用脚本(单击文件名展开)。它使用所有 python 内置函数,您需要在 Windows 系统上运行它,因为它导入 msdelta.dll
并使用 ApplyDeltaB
来应用补丁。它甚至支持旧版 PatchAPI 补丁 (PA19
)。
delta_patch.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 from ctypes import (windll, wintypes, c_uint64, cast, POINTER, Union , c_ubyte, LittleEndianStructure, byref, c_size_t)import zlib DELTA_FLAG_TYPE = c_uint64 DELTA_FLAG_NONE = 0x00000000 DELTA_APPLY_FLAG_ALLOW_PA19 = 0x00000001 class DELTA_INPUT (LittleEndianStructure ): class U1 (Union ): _fields_ = [('lpcStart' , wintypes.LPVOID), ('lpStart' , wintypes.LPVOID)] _anonymous_ = ('u1' ,) _fields_ = [('u1' , U1), ('uSize' , c_size_t), ('Editable' , wintypes.BOOL)]class DELTA_OUTPUT (LittleEndianStructure ): _fields_ = [('lpStart' , wintypes.LPVOID), ('uSize' , c_size_t)] ApplyDeltaB = windll.msdelta.ApplyDeltaB ApplyDeltaB.argtypes = [DELTA_FLAG_TYPE, DELTA_INPUT, DELTA_INPUT, POINTER(DELTA_OUTPUT)] ApplyDeltaB.rettype = wintypes.BOOL DeltaFree = windll.msdelta.DeltaFree DeltaFree.argtypes = [wintypes.LPVOID] DeltaFree.rettype = wintypes.BOOL gle = windll.kernel32.GetLastErrordef apply_patchfile_to_buffer (buf, buflen, patchpath, legacy ): with open (patchpath, 'rb' ) as patch: patch_contents = patch.read() magic = [b"PA30" ] if legacy: magic.append(b"PA19" ) if patch_contents[:4 ] in magic and patch_contents[4 :][:4 ] in magic: crc = int .from_bytes(patch_contents[:4 ], 'little' ) if zlib.crc32(patch_contents[4 :]) == crc: patch_contents = patch_contents[4 :] elif patch_contents[4 :][:4 ] in magic: patch_contents = patch_contents[4 :] elif patch_contents[:4 ] not in magic: raise Exception("Patch file is invalid" ) applyflags = DELTA_APPLY_FLAG_ALLOW_PA19 if legacy else DELTA_FLAG_NONE dd = DELTA_INPUT() ds = DELTA_INPUT() dout = DELTA_OUTPUT() ds.lpcStart = buf ds.uSize = buflen ds.Editable = False dd.lpcStart = cast(patch_contents, wintypes.LPVOID) dd.uSize = len (patch_contents) dd.Editable = False status = ApplyDeltaB(applyflags, ds, dd, byref(dout)) if status == 0 : raise Exception("Patch {} failed with error {}" .format (patchpath, gle())) return (dout.lpStart, dout.uSize)if __name__ == '__main__' : import sys import base64 import hashlib import argparse ap = argparse.ArgumentParser() mode = ap.add_mutually_exclusive_group(required=True ) output = ap.add_mutually_exclusive_group(required=True ) mode.add_argument("-i" , "--input-file" , help ="File to patch (forward or reverse)" ) mode.add_argument("-n" , "--null" , action="store_true" , default=False , help ="Create the output file from a null diff " "(null diff must be the first one specified)" ) output.add_argument("-o" , "--output-file" , help ="Destination to write patched file to" ) output.add_argument("-d" , "--dry-run" , action="store_true" , help ="Don't write patch, just see if it would patch" "correctly and get the resulting hash" ) ap.add_argument("-l" , "--legacy" , action='store_true' , default=False , help ="Let the API use the PA19 legacy API (if required)" ) ap.add_argument("patches" , nargs='+' , help ="Patches to apply" ) args = ap.parse_args() if not args.dry_run and not args.output_file: print ("Either specify -d or -o" , file=sys.stderr) ap.print_help() sys.exit(1 ) if args.null: inbuf = b"" else : with open (args.input_file, 'rb' ) as r: inbuf = r.read() buf = cast(inbuf, wintypes.LPVOID) n = len (inbuf) to_free = [] try : for patch in args.patches: buf, n = apply_patchfile_to_buffer(buf, n, patch, args.legacy) to_free.append(buf) outbuf = bytes ((c_ubyte*n).from_address(buf)) if not args.dry_run: with open (args.output_file, 'wb' ) as w: w.write(outbuf) finally : for buf in to_free: DeltaFree(buf) finalhash = hashlib.sha256(outbuf) print ("Applied {} patch{} successfully" .format (len (args.patches), "es" if len (args.patches) > 1 else "" )) print ("Final hash: {}" .format (base64.b64encode(finalhash.digest()).decode()))
这是该程序的用法的打印输出,因此您可以了解它提供的功能以及如何使用它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 PS > python X:\Patches\tools\delta_patch.py -h usage: delta_patch.py [-h ] (-i INPUT_FILE | -n ) (-o OUTPUT_FILE | -d ) [-l ] patches [patches ... ] positional arguments: patches Patches to apply optional arguments: -h , --help show this help message and exit -i INPUT_FILE, --input-file INPUT_FILE File to patch (forward or reverse) -n , --null Create the output file from a null diff (null diff must be the first one specified) -o OUTPUT_FILE, --output-file OUTPUT_FILE Destination to write patched file to -d , --dry-run Don't write patch, just see if it would patchcorrectly and get the resulting hash -l, --legacy Let the API use the PA19 legacy API (if required)
为了生成我想要的二进制文件,我将应用反向增量,然后应用每个正向增量,创建两个输出文件:
1 2 3 4 PS > python X:\Patches\tools\delta_patch.py -i ntoskrnl.exe -o ntoskrnl.2020 -07 .exe .\r\ntoskrnl.exe X:\Patches\x64\1903 \2020 \2020 -07 \x64\os-kernel_10 .0.18362 .959 \f\ntoskrnl.exe Applied 2 patches successfully Final hash: zZC/JZ+y5ZLrqTvhRVNf1/79 C4ZYwXgmZ+DZBMoq8ek=
1 2 3 4 PS > python X:\Patches\tools\delta_patch.py -i ntoskrnl.exe -o ntoskrnl.2020 -08 .exe .\r\ntoskrnl.exe X:\Patches\x64\1903 \2020 \2020 -08 \x64\os-kernel_10 .0.18362 .1016 \f\ntoskrnl.exe Applied 2 patches successfully Final hash: UZw7bE231NL2R0S4yBNT1nmDW8PQ83u9rjp91AiCrUQ=
补丁已成功应用,现在我有两个完整的二进制文件,一个来自 2020 年 8 月的补丁集,另一个来自 2020 年 7 月。生成的哈希值应与相应清单文件中的哈希值匹配!
空差异怎么样? 在继续比较两个内核版本之前,我想解释如何使用 delta_patch 工具从 null (n) 差异中生成完整文件。有一个内置选项!使用 -n
标志并指定输出文件(但没有输入文件),并且 delta_patch 会将增量应用到空缓冲区。结果是完整的文件!
例如:
1 2 3 4 5 PS > python X:\Patches\tools\delta_patch.py -n -o vmcomputeagent.exe 2020 -08 \patch\amd64_hyperv-compute-guestcomputeservice_31bf3856ad364e35_10 .0.18362 .329 _none_e3769ae1a46d95f1\n\vmcomputeagent.exe Applied 1 patch successfully Final hash: B5mZQ8i4OU22UQXOaDhLHNtLNhos6exfTHlsPzTmXGo=PS > wsl -e file vmcomputeagent.exe vmcomputeagent.exe: PE32+ executable (GUI) x86-64 , for MS Windows
从文件的输出中可以看到,零差异已扩展为完整的可执行文件。当然,您还可以应用前向差分,但只能在空差分之后应用,否则您将没有文件可以修补!
补丁比较 有大量关于二进制比较和比较工具 的资源1 ,2 ,3 ,4 ,5 , 6 ,7 ,因此我不会深入研究如何使用它们,但为了完整起见,我将比较我刚刚创建的两个内核!
我将在 IDA Pro 7.5 中打开两个版本的 ntoskrnl.exe,接受符号下载提示,然后让自动分析完成。然后,我将关闭两个版本中较新的版本 (2020-08) 并调用 BinDiff 将新版本(次要版本)与旧版本(主要版本)进行比较。
我将查看 MmDuplicateMemory
,因为与内存相关的函数的变化总是引起我的注意!下面是 BinDiff 中组合调用图的概述。绿色块没有变化,黄色块有差异,红色块被补丁删除,灰色块被补丁添加。
有很多变化,但我想突出显示一个块,特别是靠近函数顶部的块(由红色箭头表示):
看起来未修补的版本中未检查函数 KeWaitForSingleObject
的返回值,并且修补程序添加了一项检查以确保该函数返回值 0 (WAIT_OBJECT_0
)。在判断这个bug的严重性方面,需要做更多的工作来调查什么可等待对象被传递给KeWaitForSingleObject(cs:[0x1404681D0])
,是否有任何方法可以让等待可靠地失败,以及该失败会导致什么行为。这是留给读者的练习。
Wrap Up 感谢您坚持到最后。我希望你学到了一两件事。如果您有疑问、意见、疑虑、投诉或更正,请随时与我联系。我的推特账号是@jgeigerm 。如果脚本损坏,也要联系他们,他们不应该这样做。以后我会尝试发布更多Windows相关内容,敬请期待。我希望有一天能在 SEC760 见到你!我最近重写了内核开发日,教学非常精彩!
Tags: patch-diff VR bindiff patch-delta