如何在 C#/Win32 api 中找到 Windows 应用程序执行别名的目标?
How do I find the target of a Windows App Execution Alias in C#/Win32 api?
Microsoft Windows 终端(通过 Microsoft Store 安装)创建一个 0 字节 wt.exe
文件,这是一个 Windows execution alias。据我所知,它类似于符号 link,除了它似乎在 CreateProcess
Api 级别解析,而不是在文件系统中转换的 symlink .
在 powershell 中:
❯ dir ~\AppData\Local\Microsoft\WindowsApps\wt.exe
Mode Name
---- ----
la--- wt.exe -> C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.0.1401.0_x64__8wekyb3d8bbwe\WindowsTerminal.exe
❯ Get-Item .\wt.exe | fl
Name : wt.exe
Length : 0
LinkType : AppExeCLink
Target : C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.0.1401.0_x64__8wekyb3d8bbwe\WindowsTerminal.exe
我无法为这些 "new" 类别名找到合适的文档。即使谷歌搜索 PS AppExeCLink
值也不是很有用。
我需要一种快速的方法来解析 C# 应用程序中的执行别名(获取目标文件)。鉴于我的要求,我更喜欢非托管 (Win32 Api) 方式,而不是添加对慢速 WMI 或外部 300kb nuget 包的引用。
谢谢!
您也可以尝试将 Microsoft.PowerShell.5.1.ReferenceAssemblies
nuget 包添加到您的项目中。
然后下面的代码有效:
using System.Linq;
using System.Management.Automation;
string wtPath =
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Microsoft",
"WindowsApps",
"wt.exe"
);
using (var ps = PowerShell.Create())
{
var psObject = ps.AddCommand("Get-Item").AddParameter("Path", wtPath).Invoke().Single();
var psPropInfo = psObject.Properties["Target"];
string[] targets = (psPropInfo.Value as List<string>).ToArray();
Console.WriteLine($"[{psPropInfo.Name}]=[{String.Join("; ", targets)}]");
}
我在我的 System Tools Library 中遇到了同样的问题,它因这些新型 link 而窒息。这个库是用C写的,使用WIN32 API.
这是我目前的发现:
在 Windows 中引入三年后,cmd.exe 和 PowerShell 5.1 仍然不知道 App Exec Links,并将它们报告为 0 字节文件。
但 PowerShell Core 7 知道它们:
PS C:\Temp> dir $env:LOCALAPPDATA\Microsoft\WindowsApps | ?{$_.LinkType} | select Name,LinkType,Target
Name LinkType Target
---- -------- ------
GameBarElevatedFT_Alias.exe AppExeCLink C:\Program Files\WindowsApps\Microsoft.XboxGamingOverlay_5.420.11102.0_x64__8w...
MicrosoftEdge.exe AppExeCLink C:\WINDOWS\system32\SystemUWPLauncher.exe
python.exe AppExeCLink C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.11.3162.0_x64__8w...
python3.exe AppExeCLink C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.11.3162.0_x64__8w...
ubuntu.exe AppExeCLink C:\Program Files\WindowsApps\CanonicalGroupLimited.UbuntuonWindows_2004.2020.8...
ubuntu1804.exe AppExeCLink C:\Program Files\WindowsApps\CanonicalGroupLimited.Ubuntu18.04onWindows_2020.1...
WinFR.exe AppExeCLink C:\Program Files\WindowsApps\Microsoft.WindowsFileRecovery_0.1.13492.0_x64__8w...
winget.exe AppExeCLink C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.11.3162.0_x64__8w...
wt.exe AppExeCLink C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.4.3243.0_x64__8wekyb3...
PS C:\Temp>
这些 App Exec Link 是 NTFS 重分析点,标记为
IO_REPARSE_TAG_APPEXECLINK = 0x8000001b.
您可以使用 WIN32 API DeviceIoControl()
和 FSCTL_GET_REPARSE_POINT
控制代码在 C/C++/C# 程序中读取它们。
我的 readlink.c 模块包含一个 ReadReparsePointW()
例程来演示这一点。
你可以转储这样一个link的内容,通过运行:
fsutil reparsepoint query <REPARSE_POINT_PATHNAME>
例如:
C:\Temp>fsutil reparsepoint query "%LOCALAPPDATA%\Microsoft\WindowsApps\wt.exe"
Reparse Tag Value : 0x8000001b
Tag value: Microsoft
Reparse Data Length: 0x168
Reparse Data:
0000: 03 00 00 00 4d 00 69 00 63 00 72 00 6f 00 73 00 ....M.i.c.r.o.s.
0010: 6f 00 66 00 74 00 2e 00 57 00 69 00 6e 00 64 00 o.f.t...W.i.n.d.
0020: 6f 00 77 00 73 00 54 00 65 00 72 00 6d 00 69 00 o.w.s.T.e.r.m.i.
0030: 6e 00 61 00 6c 00 5f 00 38 00 77 00 65 00 6b 00 n.a.l._.8.w.e.k.
0040: 79 00 62 00 33 00 64 00 38 00 62 00 62 00 77 00 y.b.3.d.8.b.b.w.
0050: 65 00 00 00 4d 00 69 00 63 00 72 00 6f 00 73 00 e...M.i.c.r.o.s.
0060: 6f 00 66 00 74 00 2e 00 57 00 69 00 6e 00 64 00 o.f.t...W.i.n.d.
0070: 6f 00 77 00 73 00 54 00 65 00 72 00 6d 00 69 00 o.w.s.T.e.r.m.i.
0080: 6e 00 61 00 6c 00 5f 00 38 00 77 00 65 00 6b 00 n.a.l._.8.w.e.k.
0090: 79 00 62 00 33 00 64 00 38 00 62 00 62 00 77 00 y.b.3.d.8.b.b.w.
00a0: 65 00 21 00 41 00 70 00 70 00 00 00 43 00 3a 00 e.!.A.p.p...C.:.
00b0: 5c 00 50 00 72 00 6f 00 67 00 72 00 61 00 6d 00 \.P.r.o.g.r.a.m.
00c0: 20 00 46 00 69 00 6c 00 65 00 73 00 5c 00 57 00 .F.i.l.e.s.\.W.
00d0: 69 00 6e 00 64 00 6f 00 77 00 73 00 41 00 70 00 i.n.d.o.w.s.A.p.
00e0: 70 00 73 00 5c 00 4d 00 69 00 63 00 72 00 6f 00 p.s.\.M.i.c.r.o.
00f0: 73 00 6f 00 66 00 74 00 2e 00 57 00 69 00 6e 00 s.o.f.t...W.i.n.
0100: 64 00 6f 00 77 00 73 00 54 00 65 00 72 00 6d 00 d.o.w.s.T.e.r.m.
0110: 69 00 6e 00 61 00 6c 00 5f 00 31 00 2e 00 34 00 i.n.a.l._.1...4.
0120: 2e 00 33 00 32 00 34 00 33 00 2e 00 30 00 5f 00 ..3.2.4.3...0._.
0130: 78 00 36 00 34 00 5f 00 5f 00 38 00 77 00 65 00 x.6.4._._.8.w.e.
0140: 6b 00 79 00 62 00 33 00 64 00 38 00 62 00 62 00 k.y.b.3.d.8.b.b.
0150: 77 00 65 00 5c 00 77 00 74 00 2e 00 65 00 78 00 w.e.\.w.t...e.x.
0160: 65 00 00 00 30 00 00 00 e...0...
C:\Temp>
重新解析的数据有一个结构,有四个宽字符串,看起来像:
typedef struct _REPARSE_APPEXECLINK_READ_BUFFER { // For tag IO_REPARSE_TAG_APPEXECLINK
DWORD ReparseTag;
WORD ReparseDataLength;
WORD Reserved;
ULONG Version; // Currently version 3
WCHAR StringList[1]; // Multistring (Consecutive UTF-16 strings each ending with a NUL)
/* There are normally 4 strings here. Ex:
Package ID: L"Microsoft.WindowsTerminal_8wekyb3d8bbwe"
Entry Point: L"Microsoft.WindowsTerminal_8wekyb3d8bbwe!App"
Executable: L"C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.4.3243.0_x64__8wekyb3d8bbwe\wt.exe"
Applic. Type: L"0" // Integer as ASCII. "0" = Desktop bridge application; Else sandboxed UWP application
*/
} APPEXECLINK_READ_BUFFER, *PAPPEXECLINK_READ_BUFFER;
运行 wt.exe...
的 App Exec Link 目标
"C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.4.3243.0_x64__8wekyb3d8bbwe\wt.exe"
... 工作,并启动 Windows 终端。
但是 运行 MicrosoftEdge.exe 的 App Exec Link 目标...
"C:\WINDOWS\system32\SystemUWPLauncher.exe"
...什么都不做。
⇒ 重解析数据中的其他参数在某种程度上很重要。 (但我不知道如何使用它们。)
运行
"%LOCALAPPDATA%\Microsoft\WindowsApps\MicrosoftEdge.exe"
然后查看任务管理器,我看到 MS Edge 的真正可执行文件 运行 是
"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
⇒ 这证明 App Exec Link 目标程序并不总是真正的程序。
可以使用重新分析数据中的入口点字符串而不是目标路径名来启动目标应用程序,使用:
explorer.exe shell:appsFolder\<REPARSE_POINT_ENTRY_POINT_NAME>
例如,这会启动 Microsoft Edge:
explorer.exe shell:appsFolder\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge
但这不是我想要的。我真的很想找到如何使用目标应用程序路径名和其他两个参数启动应用程序。
无论如何,我已经将 MsvcLibX library 中的 readlink() 例程更新为 return App Exec Link 的目标。
我的 System Tools Library 中所有可以处理符号 link 的工具现在都显示该目标。
但由于这个目标显然不是完整的答案,我认为当前版本充其量只是一个临时实现。
如果有人找到关于这个主题的更多信息,我非常感兴趣!
我想我还要添加 this related thread 关于 UWP exe 和 WindowsApp 商店如何使用 ReparsePoint link 类型。
tl;dr;
The ~\AppData\Local\Microsoft\WindowsApps\
directory has EXEs
that are using a special form of IO_REPARSE_TAG_APPEXECLINK
symlink
to reference the actual UWP pkg located in
C:/Program Files/WindowsApps/
.
Microsoft Windows 终端(通过 Microsoft Store 安装)创建一个 0 字节 wt.exe
文件,这是一个 Windows execution alias。据我所知,它类似于符号 link,除了它似乎在 CreateProcess
Api 级别解析,而不是在文件系统中转换的 symlink .
在 powershell 中:
❯ dir ~\AppData\Local\Microsoft\WindowsApps\wt.exe
Mode Name
---- ----
la--- wt.exe -> C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.0.1401.0_x64__8wekyb3d8bbwe\WindowsTerminal.exe
❯ Get-Item .\wt.exe | fl
Name : wt.exe
Length : 0
LinkType : AppExeCLink
Target : C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.0.1401.0_x64__8wekyb3d8bbwe\WindowsTerminal.exe
我无法为这些 "new" 类别名找到合适的文档。即使谷歌搜索 PS AppExeCLink
值也不是很有用。
我需要一种快速的方法来解析 C# 应用程序中的执行别名(获取目标文件)。鉴于我的要求,我更喜欢非托管 (Win32 Api) 方式,而不是添加对慢速 WMI 或外部 300kb nuget 包的引用。
谢谢!
您也可以尝试将 Microsoft.PowerShell.5.1.ReferenceAssemblies
nuget 包添加到您的项目中。
然后下面的代码有效:
using System.Linq;
using System.Management.Automation;
string wtPath =
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Microsoft",
"WindowsApps",
"wt.exe"
);
using (var ps = PowerShell.Create())
{
var psObject = ps.AddCommand("Get-Item").AddParameter("Path", wtPath).Invoke().Single();
var psPropInfo = psObject.Properties["Target"];
string[] targets = (psPropInfo.Value as List<string>).ToArray();
Console.WriteLine($"[{psPropInfo.Name}]=[{String.Join("; ", targets)}]");
}
我在我的 System Tools Library 中遇到了同样的问题,它因这些新型 link 而窒息。这个库是用C写的,使用WIN32 API.
这是我目前的发现:
在 Windows 中引入三年后,cmd.exe 和 PowerShell 5.1 仍然不知道 App Exec Links,并将它们报告为 0 字节文件。
但 PowerShell Core 7 知道它们:
PS C:\Temp> dir $env:LOCALAPPDATA\Microsoft\WindowsApps | ?{$_.LinkType} | select Name,LinkType,Target Name LinkType Target ---- -------- ------ GameBarElevatedFT_Alias.exe AppExeCLink C:\Program Files\WindowsApps\Microsoft.XboxGamingOverlay_5.420.11102.0_x64__8w... MicrosoftEdge.exe AppExeCLink C:\WINDOWS\system32\SystemUWPLauncher.exe python.exe AppExeCLink C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.11.3162.0_x64__8w... python3.exe AppExeCLink C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.11.3162.0_x64__8w... ubuntu.exe AppExeCLink C:\Program Files\WindowsApps\CanonicalGroupLimited.UbuntuonWindows_2004.2020.8... ubuntu1804.exe AppExeCLink C:\Program Files\WindowsApps\CanonicalGroupLimited.Ubuntu18.04onWindows_2020.1... WinFR.exe AppExeCLink C:\Program Files\WindowsApps\Microsoft.WindowsFileRecovery_0.1.13492.0_x64__8w... winget.exe AppExeCLink C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.11.3162.0_x64__8w... wt.exe AppExeCLink C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.4.3243.0_x64__8wekyb3... PS C:\Temp>
这些 App Exec Link 是 NTFS 重分析点,标记为
IO_REPARSE_TAG_APPEXECLINK = 0x8000001b.您可以使用 WIN32 API
DeviceIoControl()
和FSCTL_GET_REPARSE_POINT
控制代码在 C/C++/C# 程序中读取它们。我的 readlink.c 模块包含一个
ReadReparsePointW()
例程来演示这一点。你可以转储这样一个link的内容,通过运行:
fsutil reparsepoint query <REPARSE_POINT_PATHNAME>
例如:
C:\Temp>fsutil reparsepoint query "%LOCALAPPDATA%\Microsoft\WindowsApps\wt.exe" Reparse Tag Value : 0x8000001b Tag value: Microsoft Reparse Data Length: 0x168 Reparse Data: 0000: 03 00 00 00 4d 00 69 00 63 00 72 00 6f 00 73 00 ....M.i.c.r.o.s. 0010: 6f 00 66 00 74 00 2e 00 57 00 69 00 6e 00 64 00 o.f.t...W.i.n.d. 0020: 6f 00 77 00 73 00 54 00 65 00 72 00 6d 00 69 00 o.w.s.T.e.r.m.i. 0030: 6e 00 61 00 6c 00 5f 00 38 00 77 00 65 00 6b 00 n.a.l._.8.w.e.k. 0040: 79 00 62 00 33 00 64 00 38 00 62 00 62 00 77 00 y.b.3.d.8.b.b.w. 0050: 65 00 00 00 4d 00 69 00 63 00 72 00 6f 00 73 00 e...M.i.c.r.o.s. 0060: 6f 00 66 00 74 00 2e 00 57 00 69 00 6e 00 64 00 o.f.t...W.i.n.d. 0070: 6f 00 77 00 73 00 54 00 65 00 72 00 6d 00 69 00 o.w.s.T.e.r.m.i. 0080: 6e 00 61 00 6c 00 5f 00 38 00 77 00 65 00 6b 00 n.a.l._.8.w.e.k. 0090: 79 00 62 00 33 00 64 00 38 00 62 00 62 00 77 00 y.b.3.d.8.b.b.w. 00a0: 65 00 21 00 41 00 70 00 70 00 00 00 43 00 3a 00 e.!.A.p.p...C.:. 00b0: 5c 00 50 00 72 00 6f 00 67 00 72 00 61 00 6d 00 \.P.r.o.g.r.a.m. 00c0: 20 00 46 00 69 00 6c 00 65 00 73 00 5c 00 57 00 .F.i.l.e.s.\.W. 00d0: 69 00 6e 00 64 00 6f 00 77 00 73 00 41 00 70 00 i.n.d.o.w.s.A.p. 00e0: 70 00 73 00 5c 00 4d 00 69 00 63 00 72 00 6f 00 p.s.\.M.i.c.r.o. 00f0: 73 00 6f 00 66 00 74 00 2e 00 57 00 69 00 6e 00 s.o.f.t...W.i.n. 0100: 64 00 6f 00 77 00 73 00 54 00 65 00 72 00 6d 00 d.o.w.s.T.e.r.m. 0110: 69 00 6e 00 61 00 6c 00 5f 00 31 00 2e 00 34 00 i.n.a.l._.1...4. 0120: 2e 00 33 00 32 00 34 00 33 00 2e 00 30 00 5f 00 ..3.2.4.3...0._. 0130: 78 00 36 00 34 00 5f 00 5f 00 38 00 77 00 65 00 x.6.4._._.8.w.e. 0140: 6b 00 79 00 62 00 33 00 64 00 38 00 62 00 62 00 k.y.b.3.d.8.b.b. 0150: 77 00 65 00 5c 00 77 00 74 00 2e 00 65 00 78 00 w.e.\.w.t...e.x. 0160: 65 00 00 00 30 00 00 00 e...0... C:\Temp>
重新解析的数据有一个结构,有四个宽字符串,看起来像:
typedef struct _REPARSE_APPEXECLINK_READ_BUFFER { // For tag IO_REPARSE_TAG_APPEXECLINK DWORD ReparseTag; WORD ReparseDataLength; WORD Reserved; ULONG Version; // Currently version 3 WCHAR StringList[1]; // Multistring (Consecutive UTF-16 strings each ending with a NUL) /* There are normally 4 strings here. Ex: Package ID: L"Microsoft.WindowsTerminal_8wekyb3d8bbwe" Entry Point: L"Microsoft.WindowsTerminal_8wekyb3d8bbwe!App" Executable: L"C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.4.3243.0_x64__8wekyb3d8bbwe\wt.exe" Applic. Type: L"0" // Integer as ASCII. "0" = Desktop bridge application; Else sandboxed UWP application */ } APPEXECLINK_READ_BUFFER, *PAPPEXECLINK_READ_BUFFER;
运行 wt.exe...
的 App Exec Link 目标"C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.4.3243.0_x64__8wekyb3d8bbwe\wt.exe"
... 工作,并启动 Windows 终端。
但是 运行 MicrosoftEdge.exe 的 App Exec Link 目标...
"C:\WINDOWS\system32\SystemUWPLauncher.exe"
...什么都不做。
⇒ 重解析数据中的其他参数在某种程度上很重要。 (但我不知道如何使用它们。)
运行
"%LOCALAPPDATA%\Microsoft\WindowsApps\MicrosoftEdge.exe"
然后查看任务管理器,我看到 MS Edge 的真正可执行文件 运行 是
"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
⇒ 这证明 App Exec Link 目标程序并不总是真正的程序。
可以使用重新分析数据中的入口点字符串而不是目标路径名来启动目标应用程序,使用:
explorer.exe shell:appsFolder\<REPARSE_POINT_ENTRY_POINT_NAME>
例如,这会启动 Microsoft Edge:
explorer.exe shell:appsFolder\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge
但这不是我想要的。我真的很想找到如何使用目标应用程序路径名和其他两个参数启动应用程序。
无论如何,我已经将 MsvcLibX library 中的 readlink() 例程更新为 return App Exec Link 的目标。
我的 System Tools Library 中所有可以处理符号 link 的工具现在都显示该目标。
但由于这个目标显然不是完整的答案,我认为当前版本充其量只是一个临时实现。
如果有人找到关于这个主题的更多信息,我非常感兴趣!
我想我还要添加 this related thread 关于 UWP exe 和 WindowsApp 商店如何使用 ReparsePoint link 类型。
tl;dr;
The~\AppData\Local\Microsoft\WindowsApps\
directory has EXEs that are using a special form ofIO_REPARSE_TAG_APPEXECLINK
symlink to reference the actual UWP pkg located inC:/Program Files/WindowsApps/
.