// 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); }
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 void DumpSxsEntries(PE Application) { SxsEntries SxsDependencies = SxsManifest.GetSxsEntries(Application); VerboseWriteLine("[-] sxs dependencies for executable : {0}", Application.Filepath); foreach (var entry in SxsDependencies) { if (entry.Path.Contains("???")) { Console.WriteLine(" [x] {0:s} : {1:s}", entry.Name, entry.Path); } else { Console.WriteLine(" [+] {0:s} : {1:s}", entry.Name, Path.GetFullPath(entry.Path)); } } }
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); }
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); } }