internal static bool IsDotNetCoreAppHost(string filename, [NotNullWhen(true)] out string?dllFilename) { // We detect the apphost.exe like so: // - must have an exe extension // - must be a PE file and an EXE (DLL bit cleared) // - must not have .NET metadata // - must have a file with the same name but a dll extension // - this dll file must be a PE file and have .NET metadata // .NET Core 1.x: the apphost is a renamed dotnet.exe and it assumes (unless overridden // on the command line) that the managed dll is apphostname with a dll extension. // .NET Core 2.x-3.x: the relative path of the managed dll is part of the exe, patched // by an MSBuild task. Max utf8 string length is 1024 bytes. It's currently not possible // to override this path so it should be identical to apphostname with a dll extension, // unless someone patched the apphost exe (eg. dnSpy). // Windows apphosts have an .exe extension. Don't call Path.ChangeExtension() unless it's guaranteed // to have an .exe extension, eg. 'some.file' => 'some.file.dll', not 'some.dll' if (filename.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)) { dllFilename = Path.ChangeExtension(filename, ".dll"); } else if (!filename.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) { dllFilename = filename + ".dll"; } else { dllFilename = null; return(false); } if (!File.Exists(dllFilename)) { return(false); } if (PortableExecutableFileHelpers.IsPE(filename, out bool isExe, out bool hasDotNetMetadata) && (!isExe || hasDotNetMetadata)) { return(false); } if (!PortableExecutableFileHelpers.IsPE(dllFilename, out _, out hasDotNetMetadata) || !hasDotNetMetadata) { return(false); } return(true); }
internal static bool TryGetAppHostEmbeddedDotNetDllPath(string apphostFilename, out bool couldBeAppHost, [NotNullWhen(true)] out string?dotNetDllPath) { dotNetDllPath = null; couldBeAppHost = false; if (!File.Exists(apphostFilename)) { return(false); } if (PortableExecutableFileHelpers.IsPE(apphostFilename, out _, out var hasDotNetMetadata) && hasDotNetMetadata) { return(false); } try { var data = ReadBytes(apphostFilename, MaxAppHostExeSize); if (GetOffset(data, AppHostExeUnpatchedSignature) >= 0) { couldBeAppHost = true; return(false); } if (GetOffset(data, AppHostExeSignature) < 0) { return(false); } couldBeAppHost = true; if (!ExeUtils.TryGetTextSectionInfo(new BinaryReader(new MemoryStream(data)), out _, out _)) { return(false); } var basePath = Path.GetDirectoryName(apphostFilename) !; foreach (var info in GetAppHostInfos(data)) { if (!TryGetUtf8StringZ(data, (int)info.RelPathOffset, AppHostInfo.MaxAppHostRelPathLength, out var relPath)) { continue; } if (relPath == AppHostExeUnpatched) { continue; } string dotnetFile; try { dotnetFile = Path.Combine(basePath, relPath); } catch (ArgumentException) { continue; } if (!PortableExecutableFileHelpers.IsPE(dotnetFile, out _, out hasDotNetMetadata)) { continue; } if (!hasDotNetMetadata) { continue; } dotNetDllPath = dotnetFile; return(true); } } catch (IOException) { } return(false); }