微软电脑管家的背后猫腻

一. 前言

事情是这样的, 在看完火绒手撕三鹿零系的木马软件, " 捉迷藏" 式收割: 撕开鲁大师为首系列企业流量劫持黑幕! -技术文章-火绒安全

在点击菜单栏的时候, 赫然发现电脑多了个PC Manager...

oh, shit!

什么时候塞进来的?

img

(组策略 - 禁止自动下载补丁)

由于在安装好系统后就禁止系统自动更新补丁, 显然不是通过补丁通道捆绑的.

这个软件从何而来?

答案: Edge浏览器更新时捆绑安装, 无需用户确认.

有趣的是, edge在诸般恶行之下居然还获得各类所谓的科技博主的推广, 而不是被喷成狗, 也就洋人公司出品能够享受的待遇, 当然这个垃圾软件也是国产货, 据悉是微软苏州出品, 几乎三鹿零之类的垃圾行径, edge基本复刻了一遍.

电脑管家-微软电脑管家官方网站

微软通过Microsoft Edge批量向中国用户推送微软电脑管家(特供版) – 蓝点网

当年吹爆Edge浏览器的我, 现在像个小丑_澎湃号- 湃客_澎湃新闻-The Paper

img

(反反复复的诱导弹窗)

1.1 管家为何物

这个软件大概率和edge浏览器一样都是中国区公司出品, 就是将国产管家关键那套东西移植过来.

实际上, 假如好好搞, 还是有那么一丝的用途...

img

光看首页, 还有模有样的, 但免不了要塞点广告进来.

img

img

这个软件的启动速度和微软另一个软件类似, 启动速度感人, PowerToys Microsoft - Windows 高级用户的实用程序 | Microsoft Learn

img

假死这个优良传统也是要继承的.

1.2 问题

微软签名的微软电脑管家( Windows Master) 离线版免费下载来啦! 电脑体检, 病毒查杀, 垃圾清理和优化加速 - 知乎

这管家软件早期貌似是可以通过exe安装, 现在改成了uwp应用.

注意这个Get-AppxPackage需要Windows powershell才支持, powershell不支持这个命令.

PS C:\Users\Lian> Get-AppxPackage -AllUsers -Name *microsoftpcmanager*
Get-AppxPackage : Access is denied.
Access is denied.
At line:1 char:1
+ Get-AppxPackage -AllUsers -Name *microsoftpcmanager*
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-AppxPackage], UnauthorizedAccessException
    + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.Windows.Appx.PackageManager.Commands.GetApp
   xPackageCommand

需要在管理员权限下才能有权限读取到内容

PS C:\Windows\system32> Get-AppxPackage -AllUsers -Name *microsoftpcmanager*

Name                   : Microsoft.MicrosoftPCManager
Publisher              : CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
Architecture           : X64
ResourceId             :
Version                : 3.17.14.0
PackageFullName        : Microsoft.MicrosoftPCManager_3.17.14.0_x64__8wekyb3d8bbwe
InstallLocation        : C:\Program Files\WindowsApps\Microsoft.MicrosoftPCManager_3.17.14.0_x64__8wekyb3d8bbwe
IsFramework            : False
PackageFamilyName      : Microsoft.MicrosoftPCManager_8wekyb3d8bbwe
PublisherId            : 8wekyb3d8bbwe
PackageUserInformation : {S-1-5-21-651656311-2711192680-3112360126-1001 [Lian]: Installed}
IsResourcePackage      : False
IsBundle               : False
IsDevelopmentMode      : False
NonRemovable           : False # 对于系统组件这个回事True, 不可移除
Dependencies           : {Microsoft.WindowsAppRuntime.1.5_5001.373.1736.0_x64__8wekyb3d8bbwe}
IsPartiallyStaged      : False
SignatureKind          : Store
Status                 : Ok

上述内容看似没什么奇怪的.

但, 通过菜单选项, 卸载掉程序会发现.

img

img

卸载前

img

卸载后

是的, 卸载后, 该软件的文件依然完好无损的躺在磁盘上.

也就是这个卸载是假的.

二. 问题分析

UWP is one of many ways to create client applications for Windows.

If you are starting to develop Windows apps, we recommend you consider using the Windows App SDK, and WinUI rather than UWP. Although still supported, UWP is not under active development. Please see Start developing Windows apps for more information.

这种通过微软商店安装的app(现在商店也可以安装其他类型的软件了), 之前叫uwp app, 现在改成了 Windows app?(微软改名部)

What's a Universal Windows Platform (UWP) app? - UWP applications | Microsoft Learn

这个问题隐藏的有点深, 不管是安装过程还是卸载都是不可见的, 一般的用户根本不会意识到微软玩了这一手, 检索内容只有寥寥无几的内容提及了这个问题.

Do UWP apps leave residuals after uninstall? - Microsoft Q&A

【求助】卸载UWP后残留清理-百度贴吧

How to clean up WindowsApps folder? Solved - Windows 10 Forums

为什么Windows商店应用卸载之后, WindowsApps文件夹里仍然保留有应用的文件, 而且很占空间 - Microsoft Q&A

列出所有的安装包

Get-AppxPackage -All

不管是早就卸载的weather应用, 还是微软管家, 这些应用依然在列表中.

Name                   : Microsoft.BingWeather(安装好系统, 就卸载)
Publisher              : CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
Architecture           : X64
ResourceId             :
Version                : 4.25.20211.0
PackageFullName        : Microsoft.BingWeather_4.25.20211.0_x64__8wekyb3d8bbwe
InstallLocation        : C:\Program Files\WindowsApps\Microsoft.BingWeather_4.25.20211.0_x64__8wekyb3d8bbwe
IsFramework            : False
PackageFamilyName      : Microsoft.BingWeather_8wekyb3d8bbwe
PublisherId            : 8wekyb3d8bbwe
PackageUserInformation : {S-1-5-18 [S-1-5-18]: Staged}
IsResourcePackage      : False
IsBundle               : False
IsDevelopmentMode      : False
NonRemovable           : False
IsPartiallyStaged      : False
SignatureKind          : Store
Status                 : Ok

Name                   : Microsoft.MicrosoftPCManager
Publisher              : CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
Architecture           : X64
ResourceId             :
Version                : 3.17.14.0
PackageFullName        : Microsoft.MicrosoftPCManager_3.17.14.0_x64__8wekyb3d8bbwe
InstallLocation        : C:\Program Files\WindowsApps\Microsoft.MicrosoftPCManager_3.17.14.0_x64__8wekyb3d8bbwe
IsFramework            : False
PackageFamilyName      : Microsoft.MicrosoftPCManager_8wekyb3d8bbwe
PublisherId            : 8wekyb3d8bbwe
PackageUserInformation : {S-1-5-18 [S-1-5-18]: Staged}
IsResourcePackage      : False
IsBundle               : False
IsDevelopmentMode      : False
NonRemovable           : False
IsPartiallyStaged      : False
SignatureKind          : Store
Status                 : Ok

这个目录的权限较高无法直接访问, 这进一步限制了用户对于安装软件的干预.

img

PS C:\Windows\system32> (Get-ChildItem "C:\Program Files\WindowsApps\" -force -Recurse -ErrorAction SilentlyContinue| measure Length -sum).sum / 1Gb

2.86252080835402

PowerShell: Get Folder Size on Windows | Windows OS Hub

但是可以通过命令行获取到文件的大小.

PS C:\Windows\system32> Get-AppxPackage -AllUsers -Name microsoft.microsoftpcmanager | Remove-AppxPackage -AllUsers
Remove-AppxPackage : Removal failed. Please contact your software vendor.
Deployment Remove operation with target volume C: on Package Microsoft.MicrosoftPCManager_3.17.14.0_x64__8wekyb3d8bbwe
from:   failed with error 0x80070002. See http://go.microsoft.com/fwlink/?LinkId=235160 for help diagnosing app
deployment issues.
At line:1 char:64
+ ... ers -Name microsoft.microsoftpcmanager | Remove-AppxPackage -AllUsers
+                                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Remove-AppxPackage], COMException
    + FullyQualifiedErrorId : System.Runtime.InteropServices.COMException,Microsoft.Windows.Appx.PackageManager.Comman
   ds.RemoveAppxPackageCommand

通过菜单卸载后, 再使用PowerShell(Remove-AppxPackage)移除将会报错.

2.1 解决

卸载微软电脑管家: 一次性彻底移除( 含 PowerShell 一键脚本) - ByteZoneX社区

<#
  Remove-PCManager.ps1
  What it does:
    1) Kill PC Manager related processes/services
    2) Uninstall via winget / registry (MSI/EXE) / Microsoft Store (Appx)
    3) Clean leftover files, shortcuts, startup entries, scheduled tasks
    4) (Optional) Set policies to reduce auto-reinstall

  Usage:
    - Run PowerShell as Administrator
    - (Temporary) bypass policy for this session:
        Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
    - Execute:
        .\Remove-PCManager.ps1
#>

function Ensure-Admin {
  $id = [Security.Principal.WindowsIdentity]::GetCurrent()
  $p  = New-Object Security.Principal.WindowsPrincipal($id)
  if (-not $p.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    Write-Host "Re-launching with admin rights..." -ForegroundColor Yellow
    $psi = New-Object System.Diagnostics.ProcessStartInfo
    $psi.FileName = "powershell.exe"
    $psi.Arguments = "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`""
    $psi.Verb = "runas"
    try { [Diagnostics.Process]::Start($psi) | Out-Null } catch { Write-Host "UAC cancelled. Exit." -ForegroundColor Red }
    exit
  }
}
Ensure-Admin

$ErrorActionPreference = "SilentlyContinue"

function Stop-Targets {
  Write-Host "`n[1/7] Stopping related processes/services..." -ForegroundColor Cyan
  $procNames = @("PCManager","PCMgr","MSPCManager","MicrosoftPCManager","pcmanager")
  foreach ($n in $procNames) {
    Get-Process -Name $n -ErrorAction SilentlyContinue | Stop-Process -Force
  }
  Get-Process | Where-Object { $_.Path -and ($_.Path -match "PC\s*Manager|PCManager") } | Stop-Process -Force

  Get-Service | Where-Object { $_.Name -match "PCManager|PCMgr" -or $_.DisplayName -match "PC Manager" } |
    ForEach-Object {
      if ($_.Status -ne 'Stopped') { Stop-Service $_ -Force }
      Set-Service $_ -StartupType Disabled
    }
}

function Try-Winget-Uninstall {
  Write-Host "`n[2/7] Trying winget uninstall..." -ForegroundColor Cyan
  $winget = Get-Command winget -ErrorAction SilentlyContinue
  if ($winget) {
    winget uninstall --silent --accept-source-agreements --accept-package-agreements --force --id Microsoft.PCManager 2>$null
    winget uninstall --silent --accept-source-agreements --accept-package-agreements --force --name "Microsoft PC Manager" 2>$null
    winget uninstall --silent --accept-source-agreements --accept-package-agreements --force --name "PC Manager" 2>$null
    winget uninstall --silent --accept-source-agreements --accept-package-agreements --force --name "微软电脑管家" 2>$null
  } else {
    Write-Host "winget not found, skip." -ForegroundColor DarkYellow
  }
}

function Uninstall-FromUninstallKey {
  Write-Host "`n[3/7] Trying registry uninstall (MSI/EXE)..." -ForegroundColor Cyan
  $roots = @(
    "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
    "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall",
    "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
  )
  foreach ($root in $roots) {
    Get-ChildItem $root -ErrorAction SilentlyContinue | ForEach-Object {
      $p = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue
      if ($p -and $p.DisplayName -match "PC\s*Manager|微软电脑管家") {
        $us = $p.UninstallString
        Write-Host " - Found: $($p.DisplayName)"
        if ($us) {
          if ($us -match "msiexec(\.exe)?") {
            $cmd = $us -replace "/I","/x"
            if ($cmd -notmatch "/x") { $cmd = "$cmd /x" }
            if ($cmd -notmatch "/qn") { $cmd = "$cmd /qn" }
            Start-Process -FilePath "cmd.exe" -ArgumentList "/c",$cmd -Wait -WindowStyle Hidden
          } else {
            Start-Process -FilePath "cmd.exe" -ArgumentList "/c","`"$us`"" -Wait
          }
        }
      }
    }
  }
}

function Remove-StoreApp {
  Write-Host "`n[4/7] Removing Microsoft Store app (if any)..." -ForegroundColor Cyan
  $pkgs = Get-AppxPackage -AllUsers | Where-Object {
    $_.Name -match "PCManager|MicrosoftPCManager" -or $_.PackageFamilyName -match "PCManager"
  }
  foreach ($p in $pkgs) {
    Write-Host " - Remove Appx: $($p.Name)"
    Remove-AppxPackage -Package $p.PackageFullName -AllUsers -ErrorAction SilentlyContinue
  }
  $prov = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -match "PCManager|MicrosoftPCManager" }
  foreach ($pp in $prov) {
    Write-Host " - Remove provisioned: $($pp.DisplayName)"
    Remove-AppxProvisionedPackage -Online -PackageName $pp.PackageName | Out-Null
  }
}

function Cleanup-Files {
  Write-Host "`n[5/7] Cleaning leftover files/shortcuts..." -ForegroundColor Cyan
  $paths = @(
    "$Env:ProgramFiles\Microsoft PC Manager",
    "$Env:ProgramFiles\PC Manager",
    "$Env:ProgramFiles(x86)\Microsoft PC Manager",
    "$Env:ProgramFiles(x86)\PC Manager",
    "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft PC Manager",
    "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\PC Manager",
    "$Env:AppData\PCManager",
    "$Env:LocalAppData\PCManager",
    "$Env:LocalAppData\Packages\*PCManager*"
  )
  foreach ($p in $paths) {
    if (Test-Path $p) {
      Write-Host " - Delete: $p"
      Remove-Item -Path $p -Recurse -Force -ErrorAction SilentlyContinue
    }
  }
}

function Cleanup-StartupAndTasks {
  Write-Host "`n[6/7] Cleaning startup entries, shortcuts and scheduled tasks..." -ForegroundColor Cyan
  $runKeys = @(
    "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run",
    "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run"
  )
  foreach ($rk in $runKeys) {
    if (Test-Path $rk) {
      $props = Get-ItemProperty -Path $rk
      foreach ($prop in $props.PSObject.Properties) {
        if ($prop.MemberType -eq "NoteProperty" -and ($prop.Value -is [string]) -and ($prop.Value -match "PC\s*Manager|PCManager|微软电脑管家")) {
          Write-Host " - Remove startup: $($prop.Name) ($rk)"
          Remove-ItemProperty -Path $rk -Name $prop.Name -ErrorAction SilentlyContinue
        }
      }
    }
  }

  Get-ChildItem "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\*.lnk" -ErrorAction SilentlyContinue |
    Where-Object { $_.Name -match "PC\s*Manager|微软电脑管家" } | Remove-Item -Force -ErrorAction SilentlyContinue
  Get-ChildItem "$Env:AppData\Microsoft\Windows\Start Menu\Programs\*.lnk" -ErrorAction SilentlyContinue |
    Where-Object { $_.Name -match "PC\s*Manager|微软电脑管家" } | Remove-Item -Force -ErrorAction SilentlyContinue

  Get-ScheduledTask -ErrorAction SilentlyContinue | Where-Object {
    $_.TaskName -match "PC\s*Manager|PCManager|微软电脑管家" -or $_.TaskPath -match "PCManager"
  } | ForEach-Object {
    Write-Host " - Remove scheduled task: $($_.TaskName)"
    Unregister-ScheduledTask -TaskName $_.TaskName -TaskPath $_.TaskPath -Confirm:$false -ErrorAction SilentlyContinue
  }
}

function Optional-Block-Reinstall {
  param([switch]$EnableBlock)
  if (-not $EnableBlock) { return }
  Write-Host "`n[7/7] Setting policies to reduce auto-reinstall..." -ForegroundColor Cyan
  New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\WindowsStore" -Force | Out-Null
  New-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\WindowsStore" -Name "AutoDownload" -Value 2 -PropertyType DWord -Force | Out-Null
  New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CloudContent" -Force | Out-Null
  New-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CloudContent" -Name "DisableConsumerFeatures" -Value 1 -PropertyType DWord -Force | Out-Null
  Write-Host " - Done. You can revert these in policy settings later."
}

# ---- Execute ----
Stop-Targets
Try-Winget-Uninstall
Uninstall-FromUninstallKey
Remove-StoreApp
Cleanup-Files
Cleanup-StartupAndTasks
# Turn this on if you keep seeing it come back from Store or consumer experience:
Optional-Block-Reinstall -EnableBlock:$false

Write-Host "`nAll done. Please reboot your PC." -ForegroundColor Green

脚本除了移除掉程序之外, 连同注册表, 文件夹等也做了移除的处理.

关键在于: Remove-AppxProvisionedPackage这个命令.

2.2 问题关键

关于移除预安装程序包, 其实很多人是错了的( 我就大言不惭狂妄的发一个贴了) - 远景论坛 - 前沿科技与智慧生态的极客社区

在远景论坛上, 少有提及了uwp卸载问题.

DISM 概述 | Microsoft Learn

处理一键删除Win10/Win11预装程序Appx - 知乎

其中的关键在于这两个命令的差异.

Get-AppxPackage (Appx) | Microsoft Learn

Gets a list of the app packages that are installed in a user profile. 获得所有安装包

Get-AppxProvisionedPackage (Dism) | Microsoft Learn

Gets information about app packages (.appx) in an image that will be installed for each new user. 获得映像文件预先为新用户安装的包

PS C:\Windows\system32> Remove-AppxProvisionedPackage -PackageName Microsoft.BingWeather_4.25.20211.0_neutral_~_8wekyb3d8bbwe -AllUsers -Online

Path          :
Online        : True
RestartNeeded : False

简单来说, 通过包管理命令只能移除用户手动安装的包, 对于系统预先捆绑的, 无法移除, 界面上提供的移除操作, 只是移除了图标, 文件依然完好无损, 理论上当创建一个新用户登录时, 这些包会自动出现在新用户的菜单栏上.

当然用户自己手动安装的包, 是可以通过操作界面上的卸载执行移除和删除文件的操作的.

除了命令行移除之外, 还有图形界面操作的: GitHub - Chuyu-Team/Dism-Multi-language: Dism++ Multi-language Support & BUG Report

img

但是这个软件并没有对安装进行细致的区别, 到底在哪个操作界面执行移除操作才会实际从磁盘上彻底删除掉文件, 所以只要看到需要卸载的软件名称, 就点击卸载.

三. 小结

综上, 简而言之,和普通exe程序通过安装到Program Files作为全局安装, 单独用户安装则安装在用户目录方式之下这种方式有所区别, uwp应用所有安装都是塞进windowsapp目录之下, 用户自己安装的可以正常卸载, 对于捆绑的, 则偷偷隐藏起来(甚至连个彻底卸载的选项都不给, 也不提示这个软件没有被卸载), 当新创建用户, 这些app又会阴魂不散出现在用户的菜单栏上.

微软这种设计? 所为何物?

难道就为了开后门方便塞垃圾到用户的设备?

不清楚这个机制会不会被流氓软件利用.