115 lines
9.2 KiB
Markdown
115 lines
9.2 KiB
Markdown
### Here's a list of the Windows updates that I will be talking about in this paper:
|
|
|
|
Title | Products | Classification | Last Updated | Version | Size
|
|
----- | -------- | -------------- | ------------ | ------- | ----
|
|
March, 2017 Preview of Monthly Quality Rollup for Windows 7 ([KB4012218]) | Windows 7 | Updates | 3/16/2017 | n/a | 93.4 MB
|
|
March, 2017 Preview of Monthly Quality Rollup for Windows 7 for x64-based Systems ([KB4012218]) | Windows 7 | Updates | 3/16/2017 | n/a | 153.9 MB
|
|
March, 2017 Preview of Monthly Quality Rollup for Windows Server 2008 R2 x64 Edition ([KB4012218]) | Windows Server 2008 R2 | Updates | 3/16/2017 | n/a | 153.9 MB
|
|
March, 2017 Preview of Monthly Quality Rollup for Windows 8.1 ([KB4012219]) | Windows 8.1 | Updates | 3/16/2017 | n/a | 121.2 MB
|
|
March, 2017 Preview of Monthly Quality Rollup for Windows 8.1 for x64-based Systems ([KB4012219]) | Windows 8.1 | Updates | 3/16/2017 | n/a | 218.0 MB
|
|
March, 2017 Preview of Monthly Quality Rollup for Windows Server 2012 R2 ([KB4012219]) | Windows Server 2012 R2 | Updates | 3/16/2017 | n/a | 218.0 MB
|
|
|
|
## About
|
|
|
|
After reading [this article](https://www.ghacks.net/2017/03/22/kb4012218-kb4012219-windows-update-processor-generation-detection/) on gHacks, I was inspired to look into these new rollup updates that Microsoft released on March 16. Among other things included in these updates, the changelog mentions the following:
|
|
|
|
> Enabled detection of processor generation and hardware support when PC tries to scan or download updates through Windows Update.
|
|
|
|
Which is really just Microsoft's nice way of telling you to fuck yourself if you want to keep using Windows 7 or 8.1. There even have been people with AMD and Intel systems from 2015 who have reportedly been locked out of Windows Update because of this!
|
|
|
|
## Bad Microsoft!
|
|
|
|
Well then, time figure out how to fix this garbage.
|
|
|
|
I started by downloading the `.msu` package for my system (in my case, it was `windows6.1-kb4012218-x64_590943c04550a47c1ed02d3a040d325456f03663.msu`)
|
|
|
|
I extracted it using the command line `expand` tool, like this:
|
|
|
|
```bat
|
|
md "windows6.1-kb4012218-x64"
|
|
expand -f:* ".\windows6.1-kb4012218-x64_590943c04550a47c1ed02d3a040d325456f03663.msu" ".\windows6.1-kb4012218-x64"
|
|
cd ".\windows6.1-kb4012218-x64"
|
|
md "Windows6.1-KB4012218-x64"
|
|
expand -f:* ".\Windows6.1-KB4012218-x64.cab" ".\Windows6.1-KB4012218-x64"
|
|
```
|
|
|
|
Great, now there's thousands of `.exe` and `.dll` files to sort through! Just kidding. Sort of. Maybe. :thinking:
|
|
|
|
I ended up using PowerShell to sort through all the binaries, like so:
|
|
|
|
```powershell
|
|
Get-ChildItem -Filter "wu*" -Exclude "*.mui" -Recurse | ForEach-Object { $_.FullName }
|
|
```
|
|
|
|
That's narrowed it down quite a bit! This is now what we're looking at:
|
|
|
|
- `wu.upgrade.ps.dll`
|
|
- `wuapi.dll`
|
|
- `wudriver.dll`
|
|
- `wups.dll`
|
|
- `wuapp.exe`
|
|
- `wuwebv.dll`
|
|
- `wuauclt.exe`
|
|
- `wuaueng.dll`
|
|
- `wups2.dll`
|
|
- `wucltux.dll`
|
|
- `wuapi.dll`
|
|
- `wudriver.dll`
|
|
- `wups.dll`
|
|
- `wuapp.exe`
|
|
- `wuwebv.dll`
|
|
|
|
Next, I started comparing these binaries with the ones already on my system with [BinDiff] and [Diaphora], starting with `wuauclt.exe`. After turning up empty with that (the two binaries were nearly identical), I decided to take a look at `wuaueng.dll`, which turned up quite a few relevant new functions:
|
|
|
|
EA | Name | Basicblock | Instructions | Edges
|
|
-- | ---- | ---------- | ------------ | -----
|
|
`00000600001DCB9C` | ``CWUTelemetryDownloadCanceledEvent::FireAsimovEvent(void)`` | 36 | 446 | 53
|
|
`00000600001D8F98` | ``CWUTelemetryDownloadCanceledEvent::`scalar deleting destructor'(uint)`` | 3 | 15 | 3
|
|
`00000600001D8FD0` | ``CWUTelemetryDownloadEvent::CWUTelemetryDownloadEvent(void)`` | 1 | 58 | 0
|
|
`00000600001DAEDC` | ``CWUTelemetryDownloadEvent::Init(CReporter *,long,long,ushort const *,long,_GUID,_GUID,CReportingOptionalValues &,AsimovDataInAddition *)`` | 6 | 50 | 8
|
|
`00000600001DAFB8` | ``CWUTelemetryDownloadEvent::InitializeMemebersFromOptionalData(tagOptionalData *)`` | 27 | 91 | 40
|
|
`00000600001D9100` | ``CWUTelemetryDownloadEvent::~CWUTelemetryDownloadEvent(void)`` | 2 | 60 | 1
|
|
`00000600001DC2C4` | ``CWUTelemetryDownloadFailedEvent::FireAsimovEvent(void)`` | 36 | 446 | 53
|
|
`00000600001DB114` | ``CWUTelemetryDownloadStartedEvent::FireAsimovEvent(void)`` | 36 | 446 | 53
|
|
`00000600001DB9EC` | ``CWUTelemetryDownloadSucceededEvent::FireAsimovEvent(void)`` | 36 | 446 | 53
|
|
`00000600001D8C48` | ``CWUTelemetryEventFactory::FireTelemetryEvent(CReporter *,long,long,ushort const *,long,_GUID,_GUID,CReportingOptionalValues &,AsimovDataInAddition *)`` | 11 | 76 | 17
|
|
`00000600001D8574` | ``CWUTelemetryEventFactory::GetTelemetryEvent(CReporter *,long,long,ushort const *,long,_GUID,_GUID,CReportingOptionalValues &,AsimovDataInAddition *,CWUTelemetryEvent * *)`` | 77 | 395 | 127
|
|
`00000600001DEE7C` | ``CWUTelemetryInstallCanceledEvent::FireAsimovEvent(void)`` | 34 | 409 | 50
|
|
`00000600001D8DD4` | ``CWUTelemetryInstallEvent::CWUTelemetryInstallEvent(void)`` | 1 | 57 | 0
|
|
`00000600001DD474` | ``CWUTelemetryInstallEvent::Init(CReporter *,long,long,ushort const *,long,_GUID,_GUID,CReportingOptionalValues &,AsimovDataInAddition *)`` | 6 | 50 | 8
|
|
`00000600001DD550` | ``CWUTelemetryInstallEvent::InitializeMemebersFromOptionalData(tagOptionalData *)`` | 23 | 81 | 34
|
|
`00000600001D8EFC` | ``CWUTelemetryInstallEvent::~CWUTelemetryInstallEvent(void)`` | 2 | 66 | 1
|
|
`00000600001DE67C` | ``CWUTelemetryInstallFailedEvent::FireAsimovEvent(void)`` | 34 | 409 | 50
|
|
`00000600001DF67C` | ``CWUTelemetryInstallRebootPendingEvent::FireAsimovEvent(void)`` | 34 | 409 | 50
|
|
`00000600001D8D9C` | ``CWUTelemetryInstallRebootPendingEvent::`scalar deleting destructor'(uint)`` | 3 | 15 | 3
|
|
`00000600001DD67C` | ``CWUTelemetryInstallStartedEvent::FireAsimovEvent(void)`` | 34 | 409 | 50
|
|
`00000600001DDE7C` | ``CWUTelemetryInstallSucceededEvent::FireAsimovEvent(void)`` | 34 | 409 | 50
|
|
`00000600001CAE68` | ``CWUTelemetryScanFailedEvent::FireAsimovEvent(void)`` | 31 | 416 | 46
|
|
`00000600001CA100` | ``CWUTelemetryScanRetryEvent::FireAsimovEvent(void)`` | 9 | 108 | 13
|
|
`00000600001CA588` | ``CWUTelemetryScanSucceededEvent::FireAsimovEvent(void)`` | 47 | 459 | 73
|
|
`00000600001CB790` | ``CWUTelemetryUnsupportedSystemClickSupportEvent::FireAsimovEvent(void)`` | 5 | 22 | 7
|
|
`00000600001CB9B0` | ``CWUTelemetryUnsupportedSystemClickSupportEvent::`scalar deleting destructor'(uint)`` | 3 | 17 | 3
|
|
`00000600001CB7FC` | ``CWUTelemetryUnsupportedSystemDetectionEvent::FireAsimovEvent(void)`` | 5 | 22 | 7
|
|
`00000600001CB970` | ``CWUTelemetryUnsupportedSystemDetectionEvent::`scalar deleting destructor'(uint)`` | 3 | 17 | 3
|
|
`00000600001CB724` | ``CWUTelemetryUnsupportedSystemNotificationDismissEvent::FireAsimovEvent(void)`` | 5 | 22 | 7
|
|
`00000600001CB9F0` | ``CWUTelemetryUnsupportedSystemNotificationDismissEvent::`scalar deleting destructor'(uint)`` | 3 | 17 | 3
|
|
`00000600001CB6B8` | ``CWUTelemetryUnsupportedSystemNotificationShowEvent::FireAsimovEvent(void)`` | 5 | 22 | 7
|
|
`00000600001CBA30` | ``CWUTelemetryUnsupportedSystemNotificationShowEvent::`scalar deleting destructor'(uint)`` | 3 | 17 | 3
|
|
**`0000060000102F08`** | **``IsCPUSupported(void)``** | **20** | **157** | **31**
|
|
**`00000600000AF3C0`** | **``IsDeviceServiceable(void)``** | **7** | **31** | **8**
|
|
`00000600000832CC` | ``TraceLoggingEnableForTelemetry(_TlgProvider_t const *)`` | 16 | 86 | 23
|
|
`0000060000083210` | ``TraceLoggingSetInformation(_TlgProvider_t const *,_EVENT_INFO_CLASS,void *,ulong)`` | 6 | 50 | 8
|
|
|
|
We have found culprits, [`IsDeviceServiceable(void)`](https://gist.github.com/zeffy/e5ec266952932bc905eb0cbc6ed72185) and [`IsCPUSupported(void)`](https://gist.github.com/zeffy/1a8f8984d2bec97ae24af63a76278694)!
|
|
|
|
`IsCPUSupported(void)` is only ever called by `IsDeviceServiceable(void)`, which is called by four other functions. As you may be able to tell, there are a few potential ways to kill this CPU check.
|
|
|
|
1. Patch `wuaueng.dll` and change `dword_600002EE948` (see [this line](https://gist.github.com/zeffy/e5ec266952932bc905eb0cbc6ed72185#file-isdeviceserviceable-c-L7)) which is at file offset `0x26C948`, from `0x01` to `0x00`, which makes `IsDeviceServiceable(void)` jump over its entire body and return 1 (supported CPU) immediately. This is my preferred method, because it is the least intrusive and doesn't require any runtime memory patching. **These offsets are only for the Windows 7 x64 version, I will upload `.xdelta` files for all of the other versions eventually.** The only downside of this method is you have to re-apply the patch whenever `wuaueng.dll` gets updated.
|
|
2. `nop` all the instructions out highlighted [here](https://gist.github.com/zeffy/e5ec266952932bc905eb0cbc6ed72185#file-isdeviceserviceable-asm-L24-L26) in `IsDeviceServiceable(void)`, this will enable the usage of the `ForceUnsupportedCPU` of type `REG_DWORD` under the registry key `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Test\Scan` (create it if it doesn't exist, if you want to use this method). Set this value to `0x00000001` to force unsupported CPUs, and back to `0x00000000` to change the behaviour back to default.
|
|
3. I guess you could do runtime memory patching with Windows APIs too, but that's ugly.
|
|
|
|
[KB4012218]: https://www.catalog.update.microsoft.com/search.aspx?q=kb4012218
|
|
[KB4012219]: https://www.catalog.update.microsoft.com/search.aspx?q=kb4012219
|
|
[BinDiff]: https://www.zynamics.com/software.html
|
|
[Diaphora]: http://diaphora.re
|