// find dll with same name as sxs assembly in target directory public static SxsEntries SxsFindTargetDll(string AssemblyName, string Folder) { SxsEntries EntriesFromElement = new SxsEntries(); string TargetFilePath = Path.Combine(Folder, AssemblyName); if (File.Exists(TargetFilePath)) { var Name = System.IO.Path.GetFileName(TargetFilePath); var Path = TargetFilePath; EntriesFromElement.Add(new SxsEntry(Name, Path)); return(EntriesFromElement); } string TargetDllPath = Path.Combine(Folder, String.Format("{0:s}.dll", AssemblyName)); if (File.Exists(TargetDllPath)) { var Name = System.IO.Path.GetFileName(TargetDllPath); var Path = TargetDllPath; EntriesFromElement.Add(new SxsEntry(Name, Path)); return(EntriesFromElement); } return(EntriesFromElement); }
/// <summary> /// Initialize the class from a PE file /// </summary> /// <param name="file"></param> public void Init(string file) { if (!File.Exists(file)) { throw new FileNotFoundException(); } filename = file; localPE = new PE(file); SxsEntriesCache = SxsManifest.GetSxsEntries(localPE); ApiSetmapCache = Phlib.GetApiSetSchema(); }
public static SxsEntries FromSxsAssembly(XElement SxsAssembly, XNamespace Namespace, string Folder) { SxsEntries Entries = new SxsEntries(); XElement SxsAssemblyIdentity = SxsAssembly.Element(Namespace + "assemblyIdentity"); foreach (XElement SxsFile in SxsAssembly.Elements(Namespace + "file")) { Entries.Add(new SxsEntry(SxsAssemblyIdentity, SxsFile, Folder)); } return(Entries); }
public static SxsEntries ExtractDependenciesFromSxsManifest(System.IO.Stream ManifestStream, string Folder, string ExecutableName = "", bool Wow64Pe = false) { SxsEntries AdditionnalDependencies = new SxsEntries(); XDocument XmlManifest = ParseSxsManifest(ManifestStream); XNamespace Namespace = XmlManifest.Root.GetDefaultNamespace(); // Find any declared dll //< assembly xmlns = 'urn:schemas-microsoft-com:asm.v1' manifestVersion = '1.0' > // < assemblyIdentity name = 'additional_dll' version = 'XXX.YY.ZZ' type = 'win32' /> // < file name = 'additional_dll.dll' /> //</ assembly > foreach (XElement SxsAssembly in XmlManifest.Descendants(Namespace + "assembly")) { AdditionnalDependencies.AddRange(SxsEntries.FromSxsAssembly(SxsAssembly, Namespace, Folder)); } // Find any dependencies : // <dependency> // <dependentAssembly> // <assemblyIdentity // type="win32" // name="Microsoft.Windows.Common-Controls" // version="6.0.0.0" // processorArchitecture="amd64" // publicKeyToken="6595b64144ccf1df" // language="*" // /> // </dependentAssembly> // </dependency> foreach (XElement SxsAssembly in XmlManifest.Descendants(Namespace + "dependency") .Elements(Namespace + "dependentAssembly") .Elements(Namespace + "assemblyIdentity") ) { // find target PE AdditionnalDependencies.AddRange(ExtractDependenciesFromSxsElement(SxsAssembly, Folder, ExecutableName, Wow64Pe)); } return(AdditionnalDependencies); }
public static SxsEntries GetSxsEntries(PE Pe) { SxsEntries Entries = new SxsEntries(); string RootPeFolder = Path.GetDirectoryName(Pe.Filepath); string RootPeFilename = Path.GetFileName(Pe.Filepath); // Look for overriding manifest file (named "{$name}.manifest) string OverridingManifest = String.Format("{0:s}.manifest", Pe.Filepath); if (File.Exists(OverridingManifest)) { return(ExtractDependenciesFromSxsManifestFile( OverridingManifest, RootPeFolder, RootPeFilename, Pe.IsWow64Dll() )); } // Retrieve embedded manifest string PeManifest = Pe.GetManifest(); if (PeManifest.Length == 0) { return(Entries); } byte[] RawManifest = System.Text.Encoding.UTF8.GetBytes(PeManifest); System.IO.Stream ManifestStream = new System.IO.MemoryStream(RawManifest); Entries = ExtractDependenciesFromSxsManifest( ManifestStream, RootPeFolder, RootPeFilename, Pe.IsWow64Dll() ); return(Entries); }
// default search order : // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682586(v=vs.85).aspx // // if (SafeDllSearchMode) { // -1. Sxs manifests // 0. KnownDlls list // 1. Loaded PE folder // 2. C:\Windows\(System32 | SysWow64 ) // 3. 16-bit system directory <-- ignored // 4. C:\Windows // 5. %pwd% // 6. AppDatas // } public static Tuple <ModuleSearchStrategy, string> FindPeFromDefault(PE RootPe, string ModuleName, SxsEntries SxsCache) { bool Wow64Dll = RootPe.IsWow64Dll(); string RootPeFolder = Path.GetDirectoryName(RootPe.Filepath); string FoundPePath = null; Environment.SpecialFolder WindowsSystemFolder = (Wow64Dll) ? Environment.SpecialFolder.SystemX86 : Environment.SpecialFolder.System; String WindowsSystemFolderPath = Environment.GetFolderPath(WindowsSystemFolder); // -1. Look in Sxs manifest (copious reversing needed) // TODO : find dll search order if (SxsCache.Count != 0) { SxsEntry Entry = SxsCache.Find(SxsItem => string.Equals(SxsItem.Name, ModuleName, StringComparison.OrdinalIgnoreCase) ); if (Entry != null) { return(new Tuple <ModuleSearchStrategy, string>(ModuleSearchStrategy.SxS, Entry.Path)); } } // 0. Look in well-known dlls list // HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\KnownDLLs // https://blogs.msdn.microsoft.com/larryosterman/2004/07/19/what-are-known-dlls-anyway/ String KnownDll = Phlib.GetKnownDlls(Wow64Dll).Find(x => string.Equals(x, ModuleName, StringComparison.OrdinalIgnoreCase)); if (KnownDll != null) { return(new Tuple <ModuleSearchStrategy, string>( ModuleSearchStrategy.WellKnownDlls, Path.Combine(WindowsSystemFolderPath, KnownDll) )); } // 1. Look in application folder FoundPePath = FindPeFromPath(ModuleName, new List <string>(new string[] { RootPeFolder }), Wow64Dll); if (FoundPePath != null) { return(new Tuple <ModuleSearchStrategy, string>( ModuleSearchStrategy.ApplicationDirectory, FoundPePath )); } // {2-3-4}. Look in system folders List <String> SystemFolders = new List <string>(new string[] { WindowsSystemFolderPath, Environment.GetFolderPath(Environment.SpecialFolder.Windows) } ); FoundPePath = FindPeFromPath(ModuleName, SystemFolders, Wow64Dll); if (FoundPePath != null) { return(new Tuple <ModuleSearchStrategy, string>( ModuleSearchStrategy.WindowsFolder, FoundPePath )); } // 5. Look in current directory // Ignored for the time being since we can't know from // where the exe is run // TODO : Add a user supplied path emulating %cwd% // 6. Look in local app data (check for python for exemple) // 7. Find in PATH string PATH = Environment.GetEnvironmentVariable("PATH"); List <String> PATHFolders = new List <string>(PATH.Split(';')); FoundPePath = FindPeFromPath(ModuleName, PATHFolders, Wow64Dll); if (FoundPePath != null) { return(new Tuple <ModuleSearchStrategy, string>( ModuleSearchStrategy.Environment, FoundPePath )); } // 8. Check if it's an absolute import if (File.Exists(ModuleName)) { return(new Tuple <ModuleSearchStrategy, string>( ModuleSearchStrategy.Fullpath, ModuleName )); } return(new Tuple <ModuleSearchStrategy, string>( ModuleSearchStrategy.NOT_FOUND, null )); }
public static SxsEntries ExtractDependenciesFromSxsElement(XElement SxsAssembly, string Folder, string ExecutableName = "", bool Wow64Pe = false) { // Private assembly search sequence : https://msdn.microsoft.com/en-us/library/windows/desktop/aa374224(v=vs.85).aspx // // * In the application's folder. Typically, this is the folder containing the application's executable file. // * In a subfolder in the application's folder. The subfolder must have the same name as the assembly. // * In a language-specific subfolder in the application's folder. // -> The name of the subfolder is a string of DHTML language codes indicating a language-culture or language. // * In a subfolder of a language-specific subfolder in the application's folder. // -> The name of the higher subfolder is a string of DHTML language codes indicating a language-culture or language. The deeper subfolder has the same name as the assembly. // // // 0. Side-by-side searches the WinSxS folder. // 1. \\<appdir>\<assemblyname>.DLL // 2. \\<appdir>\<assemblyname>.manifest // 3. \\<appdir>\<assemblyname>\<assemblyname>.DLL // 4. \\<appdir>\<assemblyname>\<assemblyname>.manifest string TargetSxsManifestPath; string SxsManifestName = SxsAssembly.Attribute("name").Value.ToString(); string SxsManifestDir = Path.Combine(Folder, SxsManifestName); // 0. find publisher manifest in %WINDIR%/WinSxs/Manifest if (SxsAssembly.Attribute("publicKeyToken") != null) { string WinSxsDir = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.Windows), "WinSxs" ); string WinSxsManifestDir = Path.Combine(WinSxsDir, "Manifests"); var RegisteredManifests = Directory.EnumerateFiles( WinSxsManifestDir, "*.manifest" ); string PublicKeyToken = SxsAssembly.Attribute("publicKeyToken").Value; string Name = SxsAssembly.Attribute("name").Value.ToLower(); string ProcessArch = SxsAssembly.Attribute("processorArchitecture") != null?SxsAssembly.Attribute("processorArchitecture").Value : "*"; string Version = SxsAssembly.Attribute("version").Value; string Langage = SxsAssembly.Attribute("langage") != null?SxsAssembly.Attribute("langage").Value : "none"; // TODO : support localized sxs redirection switch (ProcessArch.ToLower()) { case "$(build.arch)": case "*": ProcessArch = (Wow64Pe) ? "x86" : "amd64"; break; case "amd64": case "x86": case "wow64": case "msil": break; // nothing to do default: ProcessArch = ".*"; break; } Regex MajorVersionRegex = new Regex(@"([0-9]+)\.(.*)", RegexOptions.IgnoreCase); Match MajorVersionMatch = MajorVersionRegex.Match(Version); string MajorVersion = (MajorVersionMatch.Success) ? MajorVersionMatch.Groups[1].Value.ToString() : ".*"; // Manifest filename : {ProcArch}_{Name}_{PublicKeyToken}_{FuzzyVersion}_{Langage}_{some_hash}.manifest Regex ManifestFileNameRegex = new Regex( String.Format(@"({0:s}_{1:s}_{2:s}_({3:s}\.[\.0-9]*)_none_([a-fA-F0-9]+))\.manifest", ProcessArch, Name, PublicKeyToken, MajorVersion //Langage, // some hash ), RegexOptions.IgnoreCase ); foreach (var FileName in RegisteredManifests) { Match MatchingSxsFile = ManifestFileNameRegex.Match(FileName); if (MatchingSxsFile.Success) { TargetSxsManifestPath = Path.Combine(WinSxsManifestDir, FileName); SxsManifestDir = Path.Combine(WinSxsDir, MatchingSxsFile.Groups[1].Value); // "{name}.local" local sxs directory hijack ( really used for UAC bypasses ) if (ExecutableName != "") { string LocalSxsDir = Path.Combine(Folder, String.Format("{0:s}.local", ExecutableName)); string MatchingLocalSxsDir = Path.Combine(LocalSxsDir, MatchingSxsFile.Groups[1].Value); if (Directory.Exists(LocalSxsDir) && Directory.Exists(MatchingLocalSxsDir)) { SxsManifestDir = MatchingLocalSxsDir; } } return(ExtractDependenciesFromSxsManifestFile(TargetSxsManifestPath, SxsManifestDir, ExecutableName, Wow64Pe)); } } } // 1. \\<appdir>\<assemblyname>.DLL // find dll with same assembly name in same directory SxsEntries EntriesFromMatchingDll = SxsFindTargetDll(SxsManifestName, Folder); if (EntriesFromMatchingDll.Count > 0) { return(EntriesFromMatchingDll); } // 2. \\<appdir>\<assemblyname>.manifest // find manifest with same assembly name in same directory TargetSxsManifestPath = Path.Combine(Folder, String.Format("{0:s}.manifest", SxsManifestName)); if (File.Exists(TargetSxsManifestPath)) { return(ExtractDependenciesFromSxsManifestFile(TargetSxsManifestPath, Folder, ExecutableName, Wow64Pe)); } // 3. \\<appdir>\<assemblyname>\<assemblyname>.DLL // find matching dll in sub directory SxsEntries EntriesFromMatchingDllSub = SxsFindTargetDll(SxsManifestName, SxsManifestDir); if (EntriesFromMatchingDllSub.Count > 0) { return(EntriesFromMatchingDllSub); } // 4. \<appdir>\<assemblyname>\<assemblyname>.manifest // find manifest in sub directory TargetSxsManifestPath = Path.Combine(SxsManifestDir, String.Format("{0:s}.manifest", SxsManifestName)); if (Directory.Exists(SxsManifestDir) && File.Exists(TargetSxsManifestPath)) { return(ExtractDependenciesFromSxsManifestFile(TargetSxsManifestPath, SxsManifestDir, ExecutableName, Wow64Pe)); } // TODO : do the same thing for localization // // 0. Side-by-side searches the WinSxS folder. // 1. \\<appdir>\<language-culture>\<assemblyname>.DLL // 2. \\<appdir>\<language-culture>\<assemblyname>.manifest // 3. \\<appdir>\<language-culture>\<assemblyname>\<assemblyname>.DLL // 4. \\<appdir>\<language-culture>\<assemblyname>\<assemblyname>.manifest // TODO : also take into account Multilanguage User Interface (MUI) when // scanning manifests and WinSxs dll. God this is horrendously complicated. // Could not find the dependency { SxsEntries EntriesFromElement = new SxsEntries(); EntriesFromElement.Add(new SxsEntry(SxsManifestName, "file ???")); return(EntriesFromElement); } }
public static Tuple <ModuleSearchStrategy, PE> ResolveModule(PE RootPe, string ModuleName, SxsEntries SxsCache) { Tuple <ModuleSearchStrategy, string> ResolvedFilepath; // if no extension is used, assume a .dll if (Path.GetExtension(ModuleName) == String.Empty) { ModuleName = String.Format("{0:s}.dll", ModuleName); } string ApiSetName = LookupApiSetLibrary(ModuleName); if (ApiSetName != null) { ModuleName = ApiSetName; } ResolvedFilepath = FindPe.FindPeFromDefault(RootPe, ModuleName, SxsCache); // ApiSet override the underneath search location if found ModuleSearchStrategy ModuleLocation = ResolvedFilepath.Item1; if ((ApiSetName != null) && (ResolvedFilepath.Item2 != null)) { ModuleLocation = ModuleSearchStrategy.ApiSetSchema; } // PE ResolvedModule = null; if (ResolvedFilepath.Item2 != null) { ResolvedModule = LoadPe(ResolvedFilepath.Item2); } return(new Tuple <ModuleSearchStrategy, PE>(ModuleLocation, ResolvedModule)); }