(可能是全球首发?)在Windows 11 26H2上运行旧版Edge!

详细内容一会再更新,先看截图

2 个赞

AI写的:

这是一份针对 Edge Legacy(代号 Spartan,EdgeHTML 18 内核)在 Windows 11 24H2 / 26H2(Build 26100 及以上) 上的底层崩溃机理全景总结与100% 可复现的实操教程。


第一部分:老版 Edge 无法在 Win11 上直接运行的底层原因剖析

旧版 Edge 无法直接在 Windows 11 上启动,全网此前之所以公认其为“物理级死路”,是因为它面临着两道互为因果的代码级“隐形死锁”,以及一道系统级安全机制屏障:

1. 致命关卡一:用户级 AppContainer 沙箱环境断层(导致 eModel.dll 闪退)

  • 崩溃现象:双击 Edge 瞬间闪退,事件查看器记录 eModel.dll 崩溃,异常代码 0xc0000409(Fail-Fast)。
  • 根本死因:
    • Edge Legacy 属于特殊的系统级 UWP(SystemApp)。通过传统三步法脚本安装时,系统仅在全局注册了应用清单(Manifest),但 Windows 11 的包管理器已经不再自动为老旧 SystemApp 初始化“每用户独立沙箱运行环境(Per-User AppContainer Profile)”。
    • 当主进程启动走到 eModel!LCIEStartAsFrame 时,Edge 会调用 EnsureAccessToAppContainerRegistry 校验沙箱目录与注册表。由于物理路径 %LOCALAPPDATA%\Packages\microsoft.microsoftedge_8wekyb3d8bbwe\AC 以及 HKCU\...\AppContainer\Storage\... 根本不存在,API 抛出 0x80070002 (ERROR_FILE_NOT_FOUND)。
    • 微软在代码中使用了 WIL 错误处理库,检测到底层沙箱缺失后判定为不可恢复错误,直接主动调用 RaiseFailFastException 终止进程。

2. 致命关卡二:WinRT 输入接口 GUID(IID)代际更迭(导致 Windows.UI.Xaml.dll 闪退)

  • 崩溃现象:在修复沙箱后,Edge 能短暂画出空白窗口框架,随后 1 秒内闪退;事件查看器报 Windows.UI.Xaml.dll,可靠性监视器报 combase.dll,错误代码为 0xc000027b(Stowed Exception 暂存异常)。
  • 根本死因:
    • 窗口外框创建后,XAML 引擎触发页面加载完成事件:SpartanXAML::MainPage::OnRootLoaded。
    • 旧版 Edge 为了接管触控、鼠标和手势总线,调用了未公开的内部输入类:Windows.UI.Internal.Input.InputSite::GetForVisual。
    • 在函数内部,旧 Edge 硬编码请求获取工厂接口,传入的旧版 IID 为:
      {8CA0442D-AE80-47B0-AF23-813FC1DA9CD0}
    • 在 Windows 11 中,微软重构了输入托管子系统(InputHost.dll),将该接口的 IID 升级为了:
      {73F80911-7A51-5B0F-906B-F6402EA6C3CB}
    • 当旧 Edge 拿着老 IID 去找系统索要接口时,系统的 COM 运行时(combase.dll)直接返回 0x80004002 (E_NOINTERFACE,不支持此接口)。
    • C++/CX 运行时(wincorlib.dll)接住该错误后,抛出了未捕获的 Platform::InvalidCastException。由于 Spartan 外壳代码对此未做容错,异常击穿至 XAML 根部,触发系统强制 Fail-Fast。
  • 破局的关键事实:
    • 微软虽然更改了接口 IID,但底层 InputHost!InputSiteWinRTStatics 的虚函数表(vtable)布局完全没有变!第 7 个槽位(+0x30)依然是 GetForVisual,参数与调用约定完全兼容。

3. 系统级安全屏障:AppX 包完整性签名校验(为什么不能直接改 EXE 磁盘文件)

  • 错误现象:若直接用十六进制编辑器修改磁盘上的 MicrosoftEdge.exe 二进制代码,系统弹窗报“无法打开这个应用 - Windows 出现问题并阻止打开 Microsoft Edge”。
  • 根本原因:
    • Windows 对部署在 C:\Windows\SystemApps 目录下的正规包实施了数字签名和目录块哈希(AppxBlockMap.xml / AppxSignature.p7x)校验。
    • 篡改磁盘二进制会使微软签名失效,包管理器在拉起进程前即刻拦截;
    • 因此,内存动态热补丁(In-Memory Patching)是唯一既不破坏微软原版签名、又能绕过 IID 代沟的完美路径。

第二部分:完整复现教程(从零复活指南)


步骤 0:基础系统包部署

  1. 准备一套社区通用的旧版 Edge 恢复包(基于 21301 脚本清理现代 Edge / 注入原版 Windows 10 Build 19041 官方签名的 Microsoft.MicrosoftEdge_44.19041.1.0_neutral__8wekyb3d8bbwe 包)。
  2. 在 PowerShell 中验证包状态:
    Get-AppxPackage -Name Microsoft.MicrosoftEdge
    
    确保显示 Status : Ok。
  3. 确保你的 C:\Windows\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\MicrosoftEdge.exe 处于微软原版有效签名状态。

步骤 1:补全 AppContainer 容器环境(消灭 eModel.dll 闪退)

打开系统自带的 Windows PowerShell 5.1(在运行中输入 powershell 回车,不要使用 Store 下载的 PowerShell 7),完整复制并运行以下脚本:

Add-Type @'
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;

public static class EdgeProfileBuilder
{
    [DllImport("userenv.dll", CharSet = CharSet.Unicode)]
    private static extern int CreateAppContainerProfile(
        string appContainerName,
        string displayName,
        string description,
        IntPtr capabilities,
        uint capabilityCount,
        out IntPtr appContainerSid);

    [DllImport("kernel32.dll")]
    private static extern IntPtr LocalFree(IntPtr hMem);

    public static string Create(string name)
    {
        IntPtr sid = IntPtr.Zero;
        int hr = CreateAppContainerProfile(
            name,
            name,
            "Edge Legacy Profile",
            IntPtr.Zero,
            0,
            out sid);

        try
        {
            string sidText = null;
            if (sid != IntPtr.Zero)
                sidText = new SecurityIdentifier(sid).Value;

            return String.Format("HRESULT=0x{0:X8}; SID={1}", hr, sidText);
        }
        finally
        {
            if (sid != IntPtr.Zero)
                LocalFree(sid);
        }
    }
}
'@

$result = [EdgeProfileBuilder]::Create('Microsoft.MicrosoftEdge_8wekyb3d8bbwe')
$result
  • 验证标准:返回 HRESULT=0x00000000(或 0x800700B7 表示已创建)。
  • 执行 Test-Path "$env:LOCALAPPDATA\Packages\microsoft.microsoftedge_8wekyb3d8bbwe\AC" 应当返回 True。

步骤 2:使用 WinDbg 注入 IID 热补丁并放行

  1. 安装 WinDbg(若未安装,在终端执行 winget install Microsoft.WinDbg)。
  2. 打开 WinDbg,点击菜单:
    File → Start debugging → Launch App Package。
  3. 列表选中:
    Microsoft.MicrosoftEdge_44.19041.1.0_neutral__8wekyb3d8bbwe,点击 Launch。
  4. 程序会暂停在初始加载断点(ntdll!LdrpDoDebuggerBreak)。在下方命令框中,直接粘贴并执行这一行复合断点指令:
bp MicrosoftEdge!Windows::UI::Internal::Input::InputSite::GetForVisual+0x57 "ed @rbp-20 73f80911; ed @rbp-1c 5b0f7a51; ed @rbp-18 40f66b90; ed @rbp-14 cbc3a62e; g"

(指令机理:每当 Edge 走到调用工厂的前一瞬间,调试器自动把栈上的旧 IID 改写为 Win11 识别的新 IID,并立刻毫秒级自动放行)

  1. 紧接着执行以下过滤屏蔽指令,并全速放行:
sxd epr; sxd cpr; sxd ibp; sxd ld; sxd ud; g

(指令机理:禁用对子进程退出 epr、进程创建 cpr、初始中断 ibp 以及模块加载的暂停拦截,防止切换窗口或调用输入法时 Edge 发生假死)


步骤 3:最终成果验证

完成步骤 2 后,旧版 Edge 将在 Windows 11 上彻底苏醒:

  1. 核心 UI 完全体:经典扁平标签页、亚克力半透明深色设置抽屉、Hub 收藏夹面板均可正常交互操作。
  2. 现代网页浏览(EdgeHTML 18 + Chakra):
    • 在地址栏输入 https://www.baidu.com/,内容渲染沙箱(MicrosoftEdgeCP.exe)正常派生,TLS 安全锁亮起,DOM、CSS 样式与 JS 脚本完整渲染。
  3. 神级 PDF 墨迹阅读器:
    • 拖拽或通过 file:/// 协议打开本地任意 PDF 文件,原生平滑滚动、目录跳转、Surface 触控手写批注(增加备注)、以及微软自然语音朗读(Read Aloud)全功能满血可用。
  4. F12 开发者套件:
    • 按 F12 可正常唤起开发人员工具,实时 DOM 树检查、CSSOM 样式计算规则、脚本断点以及控制台错误捕获全部正常运作。
  5. 高 DPI 动态自适应:
    • 系统缩放比例在 100%、200%、300% 之间剧烈切换,界面与网页矢量内容重绘平滑,无任何崩溃。

步骤 4:收尾与系统清理(防止 C 盘被转储文件占满)

如果之前配置过系统错误转储(LocalDumps),调试期间子进程可能会吐出数百 MB 的 Dump。请在管理员 PowerShell 中运行以下命令彻底关闭转储并释放磁盘空间:

Remove-Item -Path 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MicrosoftEdge.exe' -Recurse -Force -ErrorAction SilentlyContinue
Remove-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps' -Name 'DumpFolder', 'DumpType', 'DumpCount' -Force -ErrorAction SilentlyContinue
Remove-Item -Path 'C:\Dumps\*', 'C:\CrashDumps\*' -Force -Recurse -ErrorAction SilentlyContinue
1 个赞

请问win10也可以吗?希望能有个一键包装包

Win10直接用这个呀

:thinking: 但是为什么啊

2楼是AI写的总结

打印功能无法使用,原因不明

我有点怀疑,毕竟我之前用过: 创造过去·当Win11上出现了旧版Edge浏览器_哔哩哔哩_bilibili(23年5月发布的)
但是功能完整度好像有点堪忧,我也是好奇试用一下就没继续用了~

b站这个是第三方(Gxap)的,不是原版Edge

是的

这个试过,好像装不上.

Win10哪个小版本

合影

$csc = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe"
if (!(Test-Path $csc)) {
    $csc = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe"
}

$source = @'
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

class Program
{
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int processId);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, out IntPtr lpNumberOfBytesWritten);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool CloseHandle(IntPtr hObject);

    const uint PROCESS_ALL_ACCESS = 0x1F0FFF;
    const uint PAGE_EXECUTE_READWRITE = 0x40;

    static readonly byte[] OldPattern = new byte[] {
        0xC7, 0x45, 0xE0, 0x2D, 0x44, 0xA0, 0x8C,
        0xC7, 0x45, 0xE4, 0x80, 0xAE, 0xB0, 0x47,
        0xC7, 0x45, 0xE8, 0xAF, 0x23, 0x81, 0x3F,
        0xC7, 0x45, 0xEC, 0xC1, 0xDA, 0x9C, 0xD0
    };

    static readonly byte[] NewPattern = new byte[] {
        0xC7, 0x45, 0xE0, 0x11, 0x09, 0xF8, 0x73,
        0xC7, 0x45, 0xE4, 0x51, 0x7A, 0x0F, 0x5B,
        0xC7, 0x45, 0xE8, 0x90, 0x6B, 0xF6, 0x40,
        0xC7, 0x45, 0xEC, 0x2E, 0xA6, 0xC3, 0xCB
    };

    static void Main(string[] args)
    {
        HashSet<int> oldPids = new HashSet<int>();
        foreach (var p in Process.GetProcessesByName("MicrosoftEdge"))
        {
            oldPids.Add(p.Id);
        }

        string edgeAumid = "shell:AppsFolder\\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge";
        if (args.Length > 0 && !string.IsNullOrEmpty(args[0]))
        {
            Process.Start("explorer.exe", edgeAumid + " " + args[0]);
        }
        else
        {
            Process.Start("explorer.exe", edgeAumid);
        }

        // 极速闪电轮询 (最长等待 2 秒)
        for (int i = 0; i < 200; i++)
        {
            Process[] procs = Process.GetProcessesByName("MicrosoftEdge");
            foreach (Process p in procs)
            {
                if (!oldPids.Contains(p.Id))
                {
                    // 找到了新生的 Edge!
                    try
                    {
                        if (p.MainModule != null)
                        {
                            IntPtr baseAddr = p.MainModule.BaseAddress;
                            if (baseAddr != IntPtr.Zero && PatchMemory(p.Id, baseAddr))
                            {
                                return; // 15毫秒内完成替换,立即退出,零等待!
                            }
                        }
                    }
                    catch
                    {
                        // 进程刚启动尚未映射主模块,等待下一个 10ms 循环
                    }
                }
            }
            Thread.Sleep(10);
        }
    }

    static bool PatchMemory(int pid, IntPtr baseAddr)
    {
        IntPtr hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
        if (hProcess == IntPtr.Zero) return false;

        try
        {
            int scanSize = 0x50000; // 320 KB 宽域扫描
            IntPtr scanStart = new IntPtr(baseAddr.ToInt64() + 0x70000);
            byte[] buffer = new byte[scanSize];
            IntPtr bytesRead;

            if (!ReadProcessMemory(hProcess, scanStart, buffer, scanSize, out bytesRead))
                return false;

            int limit = (int)bytesRead.ToInt64() - OldPattern.Length;
            for (int i = 0; i < limit; i++)
            {
                if (buffer[i] == 0xC7 && buffer[i + 1] == 0x45 && buffer[i + 2] == 0xE0 && buffer[i + 3] == 0x2D)
                {
                    bool match = true;
                    for (int j = 0; j < OldPattern.Length; j++)
                    {
                        if (buffer[i + j] != OldPattern[j])
                        {
                            match = false;
                            break;
                        }
                    }
                    if (match)
                    {
                        IntPtr patchAddr = new IntPtr(scanStart.ToInt64() + i);
                        uint oldProtect;
                        VirtualProtectEx(hProcess, patchAddr, (UIntPtr)NewPattern.Length, PAGE_EXECUTE_READWRITE, out oldProtect);
                        IntPtr bytesWritten;
                        WriteProcessMemory(hProcess, patchAddr, NewPattern, NewPattern.Length, out bytesWritten);
                        VirtualProtectEx(hProcess, patchAddr, (UIntPtr)NewPattern.Length, oldProtect, out oldProtect);
                        return true;
                    }
                }
            }
            return false;
        }
        finally
        {
            CloseHandle(hProcess);
        }
    }
}
'@

$tempSrc = "$env:TEMP\SpartanLauncher2.cs"
$desktopExe = "$([Environment]::GetFolderPath('Desktop'))\SpartanEdge.exe"

[System.IO.File]::WriteAllText($tempSrc, $source, [System.Text.Encoding]::ASCII)
& $csc /target:winexe /optimize+ /out:$desktopExe $tempSrc

Write-Host "`n[+] 2.0 版极速启动器已生成在桌面: $desktopExe" -ForegroundColor Green

AI说有错误


Add-Type @'
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;

public static class EdgeProfileBuilder
{
    [DllImport("userenv.dll", CharSet = CharSet.Unicode)]
    private static extern int CreateAppContainerProfile(
        string appContainerName,
        string displayName,
        string description,
        IntPtr capabilities,
        uint capabilityCount,
        out IntPtr appContainerSid);

    [DllImport("advapi32.dll")]
    private static extern IntPtr FreeSid(IntPtr pSid);

    public static string Create(string name)
    {
        IntPtr sid = IntPtr.Zero;

        int hr = CreateAppContainerProfile(
            name,
            name,
            "Edge Legacy Profile",
            IntPtr.Zero,
            0,
            out sid);

        try
        {
            string sidText = null;

            if (sid != IntPtr.Zero)
                sidText = new SecurityIdentifier(sid).Value;

            return String.Format(
                "HRESULT=0x{0:X8}; SID={1}",
                hr,
                sidText);
        }
        finally
        {
            if (sid != IntPtr.Zero)
                FreeSid(sid);
        }
    }
}
'@

$result = [EdgeProfileBuilder]::Create(
    'Microsoft.MicrosoftEdge_8wekyb3d8bbwe'
)

$result

很久了,都忘了什么版本了.系统都重装了

装个浏览器扩展试试

好吧不行,扩展会崩

最新Canary平台,仍然可行