定制 winpe

WinPE是一个小型操作系统,用于安装、部署和修复 Windows。

前期准备

ADK

第一步先安装 ADK 和加载项。

从 Win10 1809 开始,官方 WinPE 包含在ADK加载项里。

导出 WinPE

以管理员身份启动部署和映像工具环境(在开始菜单的程序栏 Windows Kits 下)运行以下脚本,之后的脚本也都是使用这个环境。
这个环境是 cmd,所以本文所有的脚本都使用 cmd 而非 powershell。

1
copype amd64 C:\WinPE_amd64

生成映像文件

1
MakeWinPEMedia /ISO /F C:\WinPE_amd64 C:\WinPE_amd64\WinPE_amd64.iso

基本操作

查看映像信息

1
2
3
4
5
6
7
8
9
10
11
12
> Dism /Get-ImageInfo /ImageFile:C:\WinPE_amd64\media\sources\boot.wim
部署映像服务和管理工具
版本: 10.0.26100.1

映像详细信息: C:\WinPE_amd64\media\sources\boot.wim

索引: 1
名称: Microsoft Windows PE (amd64)
描述: Microsoft Windows PE (amd64)
大小: 2,009,251,937 字节

操作成功完成。

挂载

1
Dism /Mount-Image /ImageFile:"C:\WinPE_amd64\media\sources\boot.wim" /index:1 /MountDir:"C:\WinPE_amd64\mount"

完成挂载后,在C:\WinPE_amd64\mount的修改就对应着 WinPE 中的X:\

避免忘记挂载的目标目录在哪,可以使用下面的命令查看已经挂载的映像

1
Dism /Get-MountedWimInfo

查看已安装的包

使用Dism /Get-Packages /Image:"C:\WinPE_amd64\mount"可以查看已经安装的包。

卸载

卸载时可以选择提交(/commit)或丢弃修改(/discard)。

1
Dism /Unmount-Image /MountDir:"C:\WinPE_amd64\mount" /commit

初试 physdiskwrite

拷贝文件

1
2
3
4
5
6
7
Dism /Mount-Image /ImageFile:"C:\WinPE_amd64\media\sources\boot.wim" /index:1 /MountDir:"C:\WinPE_amd64\mount"

copy %USERPROFILE%\Downloads\physdiskwrite-0.5.3\physdiskwrite.exe C:\WinPE_amd64\mount\Windows\System32

Dism /Unmount-Image /MountDir:"C:\WinPE_amd64\mount" /commit

MakeWinPEMedia /ISO /F C:\WinPE_amd64 C:\WinPE_amd64\WinPE_amd64.iso

验证

验证 iso 可以使用 Hyper-V 虚拟机加载启动。

1
2
X:\Windows\System32>physdiskwrite
The application has failed to start because its side-by-side configuration is incorrect. Please see the appl,ication event log or use command-line sxstrace.exe tool for more detail.

通常出现这个提示是缺少运行依赖库。

依赖库检查

下载Dependencies工具,查看到physdiskwrite依赖为C:\Windows\SysWOW64\kernel32.dll

WOW64

SysWOW64 是 WOW64 的一部分,WOW64 的全写是 Windows 32-bit on Windows 64-bit,用于在 Windows 64 位操作系统上支持运行 32 位程序。

而 Windows 在 WinPE 的限制提到:

Windows PE 不支持以下任一操作:

  • 在不同的体系结构上运行针对某一种体系结构编译的应用程序,例如,在 64 位版本的 Windows PE 上运行 32 位应用程序,或者在 Arm64 版本的 WinPE 上运行 Amd64 应用程序。

支持 WOW64

现在我们的问题就变成了:如何在 WinPE 上支持 WOW64。

搜索了下,有不少文章指向 reboot.pro 这个网站,比如msfn 上的这篇,和superuser 上的这篇。但 reboot.pro 这个网站不能访问。

后来在国内的无忧论坛上看到[分享] (更新支持虚拟化程序)Win10X64 中运行 32 位程序的临时办法,但也没讲原理。

最终通过这个帖子,摸到了wimbuilder2,里面有解决方案

拷贝文件

本文使用的 WinPE 的版本是10.0.26100.1,对于低于16299版本的 WinPE 除了拷贝文件外还需要额外的 hack,新版本则不需要。

在 WinPE 的X:\Windows\SysWOW64\下已经有wowreg32.exe,但运行后和运行 physdiskwrite 报相同的错。

需要复制的文件有点多,而且还有查找筛选动作,所以我们使用一个脚本函数filecopy.cmd来简化操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@echo off
setlocal enabledelayedexpansion

:: 定义源路径变量
set "SourcePath=%~1"
set "SourceFolder=%~dp1"

rem 查找满足条件的目录
for /f "tokens=*" %%i in ('dir /b "%SourcePath%"') do (
rem 输出满足条件的目录的全路径
set "Source=%SourceFolder%%%i"
set "Target=!Source:c:=c:\WinPE_amd64\mount!"
if exist "!source!\*" (
robocopy !Source! !Target! /E /W:0 /R:0
) else (
copy !Source! !Target! /y
)
)

复制文件

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
rem [WinSXS]
filecopy c:\Windows\WinSxS\x86_microsoft.windows.c..-controls.resources_*_en-US*
filecopy c:\Windows\WinSxS\x86_microsoft.windows.common-controls*
filecopy c:\Windows\WinSxS\wow64_microsoft.windows.gdiplus.systemcopy_*
filecopy c:\Windows\WinSxS\x86_microsoft.windows.gdiplus_*
filecopy c:\Windows\WinSxS\x86_microsoft.windows.isolationautomation_*
filecopy c:\Windows\WinSxS\x86_microsoft.windows.i..utomation.proxystub_*
filecopy c:\Windows\WinSxS\x86_microsoft-windows-servicingstack_*

filecopy c:\Windows\WinSxS\manifests\x86_microsoft.windows.c..-controls.resources_*_en-US*.manifest
filecopy c:\Windows\WinSxS\Manifests\x86_microsoft.windows.common-controls_*.manifest
filecopy c:\Windows\WinSxS\Manifests\wow64_microsoft.windows.gdiplus.systemcopy_*.manifest
filecopy c:\Windows\WinSxS\Manifests\x86_microsoft.windows.gdiplus_*.manifest
filecopy c:\Windows\WinSxS\Manifests\x86_microsoft.windows.isolationautomation_*.manifest
filecopy c:\Windows\WinSxS\Manifests\x86_microsoft.windows.i..utomation.proxystub_*.manifest
filecopy c:\Windows\WinSxS\Manifests\x86_microsoft.windows.systemcompatible_*.manifest
filecopy c:\Windows\WinSxS\Manifests\x86_microsoft-windows-servicingstack_*.manifest

rem [wow64]
filecopy c:\windows\system32\wow64.dll
filecopy c:\windows\system32\wow64cpu.dll
filecopy c:\windows\system32\wow64win.dll

rem added for 21H1 and later
filecopy c:\windows\system32\wow64base.dll
filecopy c:\windows\system32\wow64con.dll

filecopy c:\windows\SysWOW64\C_*.NLS
filecopy c:\windows\SysWOW64\KBD*.dll

filecopy c:\windows\SysWOW64\DXCore.dll
filecopy c:\windows\SysWOW64\umpdc.dll
filecopy c:\windows\SysWOW64\TextShaping.dll

rem 还有文件,没写未完

文件有点多,有时间再写完吧。

WinSXS 文件夹被特殊处理过,直接复制会无权限写入。需要先取得写入权限

1
2
takeown /F "C:\WinPE_amd64\mount\windows\winsxs" /A /R
icacls "C:\WinPE_amd64\mount\windows\winsxs" /grant Administrators:F /T

注册表

挂载和卸载注册表

1
2
3
4
5
reg load HKLM\WinPE_SOFTWARE c:\WinPE_amd64\mount\Windows\System32\config\Software

rem 修改注册表

reg unload HKLM\WinPE_SOFTWARE

从 Windows 中复制

需要复制的注册表有点多,而且还有查找筛选动作,所以我们使用一个脚本函数regcopy.cmd来简化操作。

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
@echo off
setlocal

:: 检查参数
if "%~1"=="" (
echo Usage: regcopy ^<SourcePath^>
echo Example: regcopy HKLM\Software\Classes\Wow6432Node\CLSID
goto :EOF
)

:: 定义源路径变量
set "SourcePath=%~1"

:: 替换HKLM\SOFTWARE为HKLM\WinPE_SOFTWARE
set "TmpPath=%SourcePath:HKLM\SOFTWARE=HKLM\WinPE_SOFTWARE%"
set "DestPath=%TmpPath:HKEY_LOCAL_MACHINE\SOFTWARE=HKEY_LOCAL_MACHINE\WinPE_SOFTWARE%"

if "%~2"=="" goto :_SimpleCopy
set "FindKey=%~2"
for /f "delims=" %%A IN ('reg query "%SourcePath%" /s /f "%FindKey%"') Do Call :_RegCopy "%%A"

:: 调用reg copy命令
:_SimpleCopy
reg copy "%SourcePath%" "%DestPath%" /f /s
goto :EOF

:_RegCopy
Set "SourcePath=%~1"
set "TmpPath=%SourcePath:HKLM\SOFTWARE=HKLM\WinPE_SOFTWARE%"
set "DestPath=%TmpPath:HKEY_LOCAL_MACHINE\SOFTWARE=HKEY_LOCAL_MACHINE\WinPE_SOFTWARE%"
reg copy "%SourcePath%" "%DestPath%" /f /s
goto :EOF

开始复制

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
rem [Reg_WoW64]
regcopy HKLM\Software\Classes\Wow6432Node\CLSID

regcopy HKLM\Software\Classes\WOW6432Node\DirectShow
regcopy "HKLM\Software\Classes\WOW6432Node\Media Type"
regcopy HKLM\Software\Classes\WOW6432Node\MediaFoundation

regcopy HKLM\Software\Wow6432Node

regcopy HKLM\Software\Microsoft\Windows\CurrentVersion\SMI
regcopy HKLM\Software\Microsoft\Windows\CurrentVersion\SideBySide\Winners,x86_microsoft.windows.c..-controls.resources_*
regcopy HKLM\Software\Microsoft\Windows\CurrentVersion\SideBySide\Winners,x86_microsoft.windows.common-controls_*
regcopy HKLM\Software\Microsoft\Windows\CurrentVersion\SideBySide\Winners,wow64_microsoft.windows.gdiplus.systemcopy_*
regcopy HKLM\Software\Microsoft\Windows\CurrentVersion\SideBySide\Winners,x86_microsoft.windows.gdiplus_*
regcopy HKLM\Software\Microsoft\Windows\CurrentVersion\SideBySide\Winners,x86_microsoft.windows.i..utomation.proxystub_*
regcopy HKLM\Software\Microsoft\Windows\CurrentVersion\SideBySide\Winners,x86_microsoft.windows.isolationautomation_*
regcopy HKLM\Software\Microsoft\Windows\CurrentVersion\SideBySide\Winners,x86_microsoft.windows.systemcompatible_*
regcopy HKLM\Software\Microsoft\Windows\CurrentVersion\SideBySide\Winners,x86_microsoft-windows-m..tion-isolationlayer_*

rem [Reg_WoW64_Bigger_Classes]
regcopy HKLM\Software\Classes\Wow6432Node

rem [Reg_WoW64_Mini_Software]
regcopy HKLM\Software\Wow6432Node\Microsoft\CTF
regcopy HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Authentication
regcopy HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer
regcopy HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Themes
regcopy "HKLM\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Svchost"
regcopy "HKLM\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Winlogon"