如何在 C#/Win32 api 中找到 Windows 应用程序执行别名的目标?

Ger*_*oli 6 c# symlink alias

Microsft Windows Terminal(通过 Microsoft Store 安装)创建一个 0 字节wt.exe文件,它是Windows 执行别名。AFAIK 它类似于符号链接,只不过它似乎是在CreateProcessApi 级别解析的,而不是在文件系统中翻译的符号链接。

\n\n

在 powershell 中:

\n\n
\xe2\x9d\xaf dir ~\\AppData\\Local\\Microsoft\\WindowsApps\\wt.exe\n\nMode    Name\n----    ----\nla---   wt.exe -> C:\\Program Files\\WindowsApps\\Microsoft.WindowsTerminal_1.0.1401.0_x64__8wekyb3d8bbwe\\WindowsTerminal.exe\n\n\xe2\x9d\xaf Get-Item .\\wt.exe | fl\n\nName           : wt.exe\nLength         : 0\nLinkType       : AppExeCLink\nTarget         : C:\\Program Files\\WindowsApps\\Microsoft.WindowsTerminal_1.0.1401.0_x64__8wekyb3d8bbwe\\WindowsTerminal.exe\n
Run Code Online (Sandbox Code Playgroud)\n\n

我无法找到这些“新”别名的正确文档。即使谷歌搜索 PSAppExeCLink值也不是很有用。

\n\n

我需要一种快速方法来解析 C# 应用程序中的执行别名(获取目标文件)。鉴于我的要求,我更喜欢非托管(Win32 Api)方式,而不是添加对慢速 WMI 或外部 300kb nuget 包的引用。

\n\n

谢谢!

\n

Jea*_*ire 14

我在我的系统工具库中遇到了同样的问题,它被这些新型链接阻塞了。该库用 C 语言编写,并使用 WIN32 API。

\n

这是我到目前为止发现的:

\n
    \n
  • 在 Windows 中引入三年后,cmd.exe 和 PowerShell 5.1 仍然不知道 App Exec 链接,并将它们报告为 0 字节文件。

    \n

    但 PowerShell Core 7 了解它们:

    \n
    PS C:\\Temp> dir $env:LOCALAPPDATA\\Microsoft\\WindowsApps | ?{$_.LinkType} | select Name,LinkType,Target\n\nName                        LinkType    Target\n----                        --------    ------\nGameBarElevatedFT_Alias.exe AppExeCLink C:\\Program Files\\WindowsApps\\Microsoft.XboxGamingOverlay_5.420.11102.0_x64__8w...\nMicrosoftEdge.exe           AppExeCLink C:\\WINDOWS\\system32\\SystemUWPLauncher.exe\npython.exe                  AppExeCLink C:\\Program Files\\WindowsApps\\Microsoft.DesktopAppInstaller_1.11.3162.0_x64__8w...\npython3.exe                 AppExeCLink C:\\Program Files\\WindowsApps\\Microsoft.DesktopAppInstaller_1.11.3162.0_x64__8w...\nubuntu.exe                  AppExeCLink C:\\Program Files\\WindowsApps\\CanonicalGroupLimited.UbuntuonWindows_2004.2020.8...\nubuntu1804.exe              AppExeCLink C:\\Program Files\\WindowsApps\\CanonicalGroupLimited.Ubuntu18.04onWindows_2020.1...\nWinFR.exe                   AppExeCLink C:\\Program Files\\WindowsApps\\Microsoft.WindowsFileRecovery_0.1.13492.0_x64__8w...\nwinget.exe                  AppExeCLink C:\\Program Files\\WindowsApps\\Microsoft.DesktopAppInstaller_1.11.3162.0_x64__8w...\nwt.exe                      AppExeCLink C:\\Program Files\\WindowsApps\\Microsoft.WindowsTerminal_1.4.3243.0_x64__8wekyb3...\n\nPS C:\\Temp>\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • 这些应用程序执行链接是 NTFS 重新分析点,标记为
    \nIO_REPARSE_TAG_APPEXECLINK = 0x8000001b。

    \n

    DeviceIoControl()您可以使用 WIN32 API和控制代码在 C/C++/C# 程序中读取它们 FSCTL_GET_REPARSE_POINT

    \n

    我的readlink.c模块包含一个ReadReparsePointW()演示这一点的例程。

    \n
  • \n
  • 您可以通过运行以下命令转储此类链接的内容:

    \n
    fsutil reparsepoint query <REPARSE_POINT_PATHNAME>\n
    Run Code Online (Sandbox Code Playgroud)\n

    前任:

    \n
    C:\\Temp>fsutil reparsepoint query "%LOCALAPPDATA%\\Microsoft\\WindowsApps\\wt.exe"\nReparse Tag Value : 0x8000001b\nTag value: Microsoft\n\nReparse Data Length: 0x168\nReparse Data:\n0000:  03 00 00 00 4d 00 69 00  63 00 72 00 6f 00 73 00  ....M.i.c.r.o.s.\n0010:  6f 00 66 00 74 00 2e 00  57 00 69 00 6e 00 64 00  o.f.t...W.i.n.d.\n0020:  6f 00 77 00 73 00 54 00  65 00 72 00 6d 00 69 00  o.w.s.T.e.r.m.i.\n0030:  6e 00 61 00 6c 00 5f 00  38 00 77 00 65 00 6b 00  n.a.l._.8.w.e.k.\n0040:  79 00 62 00 33 00 64 00  38 00 62 00 62 00 77 00  y.b.3.d.8.b.b.w.\n0050:  65 00 00 00 4d 00 69 00  63 00 72 00 6f 00 73 00  e...M.i.c.r.o.s.\n0060:  6f 00 66 00 74 00 2e 00  57 00 69 00 6e 00 64 00  o.f.t...W.i.n.d.\n0070:  6f 00 77 00 73 00 54 00  65 00 72 00 6d 00 69 00  o.w.s.T.e.r.m.i.\n0080:  6e 00 61 00 6c 00 5f 00  38 00 77 00 65 00 6b 00  n.a.l._.8.w.e.k.\n0090:  79 00 62 00 33 00 64 00  38 00 62 00 62 00 77 00  y.b.3.d.8.b.b.w.\n00a0:  65 00 21 00 41 00 70 00  70 00 00 00 43 00 3a 00  e.!.A.p.p...C.:.\n00b0:  5c 00 50 00 72 00 6f 00  67 00 72 00 61 00 6d 00  \\.P.r.o.g.r.a.m.\n00c0:  20 00 46 00 69 00 6c 00  65 00 73 00 5c 00 57 00   .F.i.l.e.s.\\.W.\n00d0:  69 00 6e 00 64 00 6f 00  77 00 73 00 41 00 70 00  i.n.d.o.w.s.A.p.\n00e0:  70 00 73 00 5c 00 4d 00  69 00 63 00 72 00 6f 00  p.s.\\.M.i.c.r.o.\n00f0:  73 00 6f 00 66 00 74 00  2e 00 57 00 69 00 6e 00  s.o.f.t...W.i.n.\n0100:  64 00 6f 00 77 00 73 00  54 00 65 00 72 00 6d 00  d.o.w.s.T.e.r.m.\n0110:  69 00 6e 00 61 00 6c 00  5f 00 31 00 2e 00 34 00  i.n.a.l._.1...4.\n0120:  2e 00 33 00 32 00 34 00  33 00 2e 00 30 00 5f 00  ..3.2.4.3...0._.\n0130:  78 00 36 00 34 00 5f 00  5f 00 38 00 77 00 65 00  x.6.4._._.8.w.e.\n0140:  6b 00 79 00 62 00 33 00  64 00 38 00 62 00 62 00  k.y.b.3.d.8.b.b.\n0150:  77 00 65 00 5c 00 77 00  74 00 2e 00 65 00 78 00  w.e.\\.w.t...e.x.\n0160:  65 00 00 00 30 00 00 00                           e...0...\n\nC:\\Temp>\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • 重新解析数据有一个包含四个宽字符串的结构,如下所示:

    \n
    typedef struct _REPARSE_APPEXECLINK_READ_BUFFER { // For tag IO_REPARSE_TAG_APPEXECLINK\n  DWORD  ReparseTag;\n  WORD   ReparseDataLength;\n  WORD   Reserved;\n  ULONG  Version;    // Currently version 3\n  WCHAR  StringList[1];  // Multistring (Consecutive UTF-16 strings each ending with a NUL)\n  /* There are normally 4 strings here. Ex:\n    Package ID:  L"Microsoft.WindowsTerminal_8wekyb3d8bbwe"\n    Entry Point: L"Microsoft.WindowsTerminal_8wekyb3d8bbwe!App"\n    Executable:  L"C:\\Program Files\\WindowsApps\\Microsoft.WindowsTerminal_1.4.3243.0_x64__8wekyb3d8bbwe\\wt.exe"\n    Applic. Type: L"0"   // Integer as ASCII. "0" = Desktop bridge application; Else sandboxed UWP application\n  */     \n} APPEXECLINK_READ_BUFFER, *PAPPEXECLINK_READ_BUFFER;\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • 正在运行 wt.exe 的 App Exec Link 目标...

    \n
    "C:\\Program Files\\WindowsApps\\Microsoft.WindowsTerminal_1.4.3243.0_x64__8wekyb3d8bbwe\\wt.exe"\n
    Run Code Online (Sandbox Code Playgroud)\n

    ...工作,并启动 Windows 终端。

    \n

    但是运行 MicrosoftEdge.exe 的 App Exec Link 目标...

    \n
    "C:\\WINDOWS\\system32\\SystemUWPLauncher.exe"\n
    Run Code Online (Sandbox Code Playgroud)\n

    ... 什么也没做。

    \n

    \xe2\x87\x92 重解析数据中的其他参数在某种程度上很重要。(但我不知道如何使用它们。)

    \n
  • \n
  • 跑步

    \n
    "%LOCALAPPDATA%\\Microsoft\\WindowsApps\\MicrosoftEdge.exe"\n
    Run Code Online (Sandbox Code Playgroud)\n

    然后在任务管理器中查看,我发现 MS Edge 运行的真正可执行文件是

    \n
    "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"\n
    Run Code Online (Sandbox Code Playgroud)\n

    \xe2\x87\x92 这证明App Exec Link目标程序并不总是真正的程序。

    \n
  • \n
  • 可以使用重解析数据中的入口点字符串而不是目标路径名来启动目标应用程序,方法是:

    \n
    explorer.exe shell:appsFolder\\<REPARSE_POINT_ENTRY_POINT_NAME>\n
    Run Code Online (Sandbox Code Playgroud)\n

    例如,这将启动 Microsoft Edge:

    \n
    explorer.exe shell:appsFolder\\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge\n
    Run Code Online (Sandbox Code Playgroud)\n

    但这不是我想要的。我真的很想找到如何使用目标应用程序路径名和其他两个参数来启动应用程序。

    \n
  • \n
\n

无论如何,我已经更新了MsvcLibX 库中的 readlink() 例程以返回 App Exec Links 的目标。\n我的系统工具库中可以处理符号链接的所有工具现在都显示该目标。
\n但由于这个目标显然不是完整的答案,我认为当前版本充其量只是一个临时实现。

\n

如果有人找到有关此主题的更多信息,我非常感兴趣!

\n

  • 判断它是否是 AppExecLink 的最佳方法是首先运行 GetFileAttributesW() 来检查它是否是重解析点;如果是,则执行“DeviceIoControl(FSCTL_GET_REPARSE_POINT)”来检查重解析点标记是否为 IO_REPARSE_TAG_APPEXECLINK。 (3认同)
  • 这非常有帮助!我了解到,当您执行 AppExecLink 时,CreateProcess 函数[行为不同](https://www.tiraniddo.dev/2019/09/overview-of-windows-execution-aliases.html),例如添加安全令牌的“WIN:SYSAPPID”属性。因此,直接启动链接目标永远不会得到相同的结果。我使用“cmd /c wt.exe”作为解决方法。我仍然需要重新阅读您的信息并找到判断它是否是 AppExecLink 的最佳方法。 (2认同)
  • 您还给了我检查 PowerShell 中 Get-ChildItem 实现的想法,在 [FileSystemProvider.cs](https://github.com/PowerShell/PowerShell/blob/v7.1.0/src/System 中发现了有趣的 WinInternalGetTarget 和 WinInternalGetLinkType 函数.管理.自动化/命名空间/FileSystemProvider.cs#L8377) (2认同)