public Tuple <ModuleSearchStrategy, PE> ResolveModule(string ModuleName) { return(BinaryCache.ResolveModule( RootPe, ModuleName /*DllImport.Name*/ )); }
public void LoadPe() { Action action = () => { if (Filepath != null) { PE Module = BinaryCache.LoadPe(Filepath); Imports = Module.GetImports().Select(i => ImportDll.From(i)).ToList(); try { var PeAssembly = AssemblyDefinition.ReadAssembly(Filepath); ModuleReferences = PeAssembly.Modules.SelectMany(m => m.ModuleReferences).Where(mr => mr.Name.Length > 0).Select(m => ImportDll.From(m)).ToList(); AssemblyReferences = PeAssembly.Modules.SelectMany(m => m.AssemblyReferences).ToList(); } catch (BadImageFormatException) { } } else { //Module = null; } }; SafeExecutor(action); }
/// <summary> /// Background processing of a single PE file. /// It can be lengthy since there are disk access (and misses). /// </summary> /// <param name="NewTreeContexts"> This variable is passed as reference to be updated since this function is run in a separate thread. </param> /// <param name="newPe"> Current PE file analyzed </param> private void ProcessPe(List <ImportContext> NewTreeContexts, PE newPe) { List <PeImportDll> PeImports = newPe.GetImports(); foreach (PeImportDll DllImport in PeImports) { ImportContext ImportModule = new ImportContext(); ImportModule.PeFilePath = null; ImportModule.PeProperties = null; ImportModule.ModuleName = DllImport.Name; ImportModule.ApiSetModuleName = null; ImportModule.IsDelayLoadImport = (DllImport.Flags & 0x01) == 0x01; // TODO : Use proper macros // Find Dll in "paths" Tuple <ModuleSearchStrategy, PE> ResolvedModule = BinaryCache.ResolveModule(this.Pe, DllImport.Name, this.SxsEntriesCache); ImportModule.ModuleLocation = ResolvedModule.Item1; if (ImportModule.ModuleLocation != ModuleSearchStrategy.NOT_FOUND) { ImportModule.PeProperties = ResolvedModule.Item2; ImportModule.PeFilePath = ResolvedModule.Item2.Filepath; } // special case for apiset schema ImportModule.IsApiSet = (ImportModule.ModuleLocation == ModuleSearchStrategy.ApiSetSchema); if (ImportModule.IsApiSet) { ImportModule.ApiSetModuleName = BinaryCache.LookupApiSetLibrary(DllImport.Name); } NewTreeContexts.Add(ImportModule); } }
static string FindPeFromPath(string ModuleName, List <string> CandidateFolders, string ProcessorArch) { string PeFilePath = null; // Filter out "problematic" search paths before it triggers an exception from Path.Combine // see https://github.com/lucasg/Dependencies/issues/49 var CuratedCandidateFolders = CandidateFolders.Where( path => !IsFilepathInvalid(path) ); foreach (String CandidatePath in CuratedCandidateFolders) { PeFilePath = Path.Combine(CandidatePath, ModuleName); PE TestPe = BinaryCache.LoadPe(PeFilePath); if (TestPe != null && TestPe.LoadSuccessful) { Debug.WriteLine("Attempt to load {0:s} {1:s} {2:s}", PeFilePath, TestPe.GetProcessor(), ProcessorArch); if (TestPe.GetProcessor() == ProcessorArch) { return(PeFilePath); } } } return(null); }
private ImportContext ResolveImport(PeImportDll DllImport) { ImportContext ImportModule = new ImportContext(); ImportModule.PeFilePath = null; ImportModule.PeProperties = null; ImportModule.ModuleName = DllImport.Name; ImportModule.ApiSetModuleName = null; ImportModule.Flags = 0; if (DllImport.IsDelayLoad()) { ImportModule.Flags |= ModuleFlag.DelayLoad; } Tuple <ModuleSearchStrategy, PE> ResolvedModule = BinaryCache.ResolveModule( this.Pe, DllImport.Name, this.SxsEntriesCache, this.CustomSearchFolders, this.WorkingDirectory ); ImportModule.ModuleLocation = ResolvedModule.Item1; if (ImportModule.ModuleLocation != ModuleSearchStrategy.NOT_FOUND) { ImportModule.PeProperties = ResolvedModule.Item2; if (ResolvedModule.Item2 != null) { ImportModule.PeFilePath = ResolvedModule.Item2.Filepath; foreach (var Import in BinaryCache.LookupImports(DllImport, ImportModule.PeFilePath)) { if (!Import.Item2) { ImportModule.Flags |= ModuleFlag.MissingImports; break; } } } } else { ImportModule.Flags |= ModuleFlag.NotFound; } // special case for apiset schema ImportModule.IsApiSet = (ImportModule.ModuleLocation == ModuleSearchStrategy.ApiSetSchema); if (ImportModule.IsApiSet) { ImportModule.Flags |= ModuleFlag.ApiSet; ImportModule.ApiSetModuleName = BinaryCache.LookupApiSetLibrary(DllImport.Name); if (DllImport.Name.StartsWith("ext-")) { ImportModule.Flags |= ModuleFlag.ApiSetExt; } } return(ImportModule); }
private void ConstructDependencyTree(ModuleTreeViewItem RootNode, string FilePath, int RecursionLevel = 0) { PE CurrentPE = BinaryCache.LoadPe(FilePath); if (null == CurrentPE) { return; } ConstructDependencyTree(RootNode, CurrentPE, RecursionLevel); }
public void SetImports(string ModuleFilepath, List <PeExport> Exports, List <PeImportDll> ParentImports, PhSymbolProvider SymPrv, DependencyWindow Dependencies) { this.Items.Clear(); foreach (PeImportDll DllImport in ParentImports) { foreach (var Import in BinaryCache.LookupImports(DllImport, Exports)) { this.Items.Add(new DisplayPeImport(Import.Item1, SymPrv, ModuleFilepath, Import.Item2)); } } }
public void LoadPe() { if (Filepath != null) { PE Module = BinaryCache.LoadPe(Filepath); Imports = Module.GetImports(); } else { //Module = null; } }
/// <summary> /// Background processing of a single PE file. /// It can be lengthy since there are disk access (and misses). /// </summary> /// <param name="NewTreeContexts"> This variable is passed as reference to be updated since this function is run in a separate thread. </param> /// <param name="newPe"> Current PE file analyzed </param> private void ProcessPe(List <ImportContext> NewTreeContexts, PE newPe) { List <PeImportDll> PeImports = newPe.GetImports(); foreach (PeImportDll DllImport in PeImports) { bool FoundApiSet = false; string ImportDllName = DllImport.Name; // Look for api set target if (ImportDllName.StartsWith("api-") || ImportDllName.StartsWith("ext-")) { // Strip the .dll extension and the last number (which is probably a build counter) string ImportDllNameWithoutExtension = Path.GetFileNameWithoutExtension(ImportDllName); string ImportDllHashKey = ImportDllNameWithoutExtension.Substring(0, ImportDllNameWithoutExtension.LastIndexOf("-")); if (this.ApiSetmapCache.ContainsKey(ImportDllHashKey)) { ApiSetTarget Targets = this.ApiSetmapCache[ImportDllHashKey]; if (Targets.Count > 0) { FoundApiSet = true; ImportDllName = Targets[0]; } } } ImportContext ImportModule = new ImportContext(); ImportModule.PeFilePath = null; ImportModule.PeProperties = null; ImportModule.ModuleName = DllImport.Name; ImportModule.IsApiSet = FoundApiSet; ImportModule.ApiSetModuleName = ImportDllName; ImportModule.IsDelayLoadImport = (DllImport.Flags & 0x01) == 0x01; // TODO : Use proper macros // Find Dll in "paths" Tuple <ModuleSearchStrategy, String> FoundPe = FindPe.FindPeFromDefault(this.Pe, ImportDllName, this.SxsEntriesCache); ImportModule.ModuleLocation = FoundPe.Item1; if (ImportModule.ModuleLocation != ModuleSearchStrategy.NOT_FOUND) { ImportModule.PeFilePath = FoundPe.Item2; ImportModule.PeProperties = BinaryCache.LoadPe(ImportModule.PeFilePath); } NewTreeContexts.Add(ImportModule); } }
public PE LoadImport(string ModuleName, DisplayModuleInfo CurrentModule = null, bool DelayLoad = false) { if (CurrentModule == null) { CurrentModule = this._SelectedModule; } Tuple <ModuleSearchStrategy, PE> ResolvedModule = BinaryCache.ResolveModule( this.Pe, ModuleName, this.SxsEntriesCache, this.CustomSearchFolders, this.WorkingDirectory ); string ModuleFilepath = (ResolvedModule.Item2 != null) ? ResolvedModule.Item2.Filepath : null; ModuleCacheKey ModuleKey = new ModuleCacheKey(ModuleName, ModuleFilepath); if ((ModuleFilepath != null) && !this.ProcessedModulesCache.ContainsKey(ModuleKey)) { ModuleFlag DelayLoadFlag = (DelayLoad) ? ModuleFlag.DelayLoad : 0; if (ResolvedModule.Item1 == ModuleSearchStrategy.ApiSetSchema) { var ApiSetContractModule = new DisplayModuleInfo( BinaryCache.LookupApiSetLibrary(ModuleName), ResolvedModule.Item2, ResolvedModule.Item1, DelayLoadFlag & ModuleFlag.ApiSet ); var NewModule = new ApiSetModuleInfo(ModuleName, ref ApiSetContractModule); this.ProcessedModulesCache[ModuleKey] = NewModule; } else { var NewModule = new DisplayModuleInfo( ModuleName, ResolvedModule.Item2, ResolvedModule.Item1, DelayLoadFlag ); this.ProcessedModulesCache[ModuleKey] = NewModule; } // add it to the module list this.ModulesList.AddModule(this.ProcessedModulesCache[ModuleKey]); } return(ResolvedModule.Item2); }
public DependencyWindow(String FileName) { InitializeComponent(); this.Filename = FileName; this.Pe = BinaryCache.LoadPe(FileName); if (!this.Pe.LoadSuccessful) { MessageBox.Show( String.Format("{0:s} is not a valid PE-COFF file", this.Filename), "Invalid PE", MessageBoxButton.OK ); return; } this.SymPrv = new PhSymbolProvider(); this.RootFolder = Path.GetDirectoryName(FileName); this.SxsEntriesCache = SxsManifest.GetSxsEntries(this.Pe); this.ProcessedModulesCache = new ModulesCache(); this.ApiSetmapCache = Phlib.GetApiSetSchema(); this._SelectedModule = null; this._DisplayWarning = false; // TODO : Find a way to properly bind commands instead of using this hack this.ModulesList.DoFindModuleInTreeCommand = DoFindModuleInTree; this.ModulesList.ConfigureSearchOrderCommand = ConfigureSearchOrderCommand; var RootFilename = Path.GetFileName(FileName); var RootModule = new DisplayModuleInfo(RootFilename, this.Pe, ModuleSearchStrategy.ROOT); this.ProcessedModulesCache.Add(new ModuleCacheKey(RootFilename, FileName), RootModule); ModuleTreeViewItem treeNode = new ModuleTreeViewItem(); DependencyNodeContext childTreeInfoContext = new DependencyNodeContext() { ModuleInfo = new WeakReference(RootModule), IsDummy = false }; treeNode.DataContext = childTreeInfoContext; treeNode.Header = treeNode.GetTreeNodeHeaderName(Dependencies.Properties.Settings.Default.FullPath); treeNode.IsExpanded = true; this.DllTreeView.Items.Add(treeNode); // Recursively construct tree of dll imports ConstructDependencyTree(treeNode, this.Pe); }
public void SetImports(List <PeImportDll> Imports, PhSymbolProvider SymPrv, DependencyWindow Dependencies) { this.Items.Clear(); foreach (PeImportDll DllImport in Imports) { PE ModuleImport = Dependencies.LoadImport(DllImport.Name, null, DllImport.IsDelayLoad()); string ModuleFilepath = (ModuleImport != null) ? ModuleImport.Filepath : null; foreach (var Import in BinaryCache.LookupImports(DllImport, ModuleFilepath)) { this.Items.Add(new DisplayPeImport(Import.Item1, SymPrv, ModuleFilepath, Import.Item2)); } } }
public PE LoadBinary(string path) { StatusBarMessage = String.Format("Loading module {0:s} ...", path); PE pe = BinaryCache.LoadPe(path); if (!pe.LoadSuccessful) { StatusBarMessage = String.Format("Loading module {0:s} failed.", path); } else { StatusBarMessage = String.Format("Loading PE file \"{0:s}\" successful.", pe.Filepath); } return(pe); }
static string FindPeFromPath(string ModuleName, List <string> CandidateFolders, bool Wow64Dll = false) { string PeFilePath = null; foreach (String CandidatePath in CandidateFolders) { PeFilePath = Path.Combine(CandidatePath, ModuleName); PE TestPe = BinaryCache.LoadPe(PeFilePath); if ((TestPe != null) && (TestPe.LoadSuccessful) && (TestPe.IsWow64Dll() == Wow64Dll)) { return(PeFilePath); } } return(null); }
public void LoadPe() { Action action = () => { if (Filepath != null) { PE Module = BinaryCache.LoadPe(Filepath); Imports = Module.GetImports(); } else { //Module = null; } }; SafeExecutor(action); }
public static void InitializeBinaryCache(bool UseCache) { if (UseCache) { string ApplicationLocalAppDataPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Dependencies" ); Instance = new BinaryCacheImpl(ApplicationLocalAppDataPath, 200); } else { Instance = new BinaryNoCacheImpl(); } Instance.Load(); }
private bool VerifyModuleImports() { // current module has issues if ((Flags & (ModuleFlag.NotFound | ModuleFlag.MissingImports | ModuleFlag.ChildrenError)) != 0) { return(true); } // no parent : it's probably the root item ModuleTreeViewItem ParentModule = this.ParentModule; if (ParentModule == null) { return(false); } // Check we have any imports issues foreach (PeImportDll DllImport in ParentModule.ModuleInfo.Imports) { if (DllImport.Name != ModuleInfo._Name) { continue; } List <Tuple <PeImport, bool> > resolvedImports = BinaryCache.LookupImports(DllImport, ModuleInfo.Filepath); if (resolvedImports.Count == 0) { return(true); } foreach (var Import in resolvedImports) { if (!Import.Item2) { return(true); } } } return(false); }
void App_Startup(object sender, StartupEventArgs e) { (Application.Current as App).PropertyChanged += App_PropertyChanged; Phlib.InitializePhLib(); // Load singleton for binary caching BinaryCache.InitializeBinaryCache(Dependencies.BinaryCacheOption.GetGlobalBehaviour() == Dependencies.BinaryCacheOption.BinaryCacheOptionValue.Yes); // https://www.red-gate.com/simple-talk/blogs/wpf-menu-displays-to-the-left-of-the-window/ SetDropDownMenuToBeRightAligned(); mainWindow = new MainWindow(); mainWindow.IsMaster = true; switch (Phlib.GetClrPhArch()) { case CLRPH_ARCH.x86: mainWindow.Title = "Dependencies (x86)"; break; case CLRPH_ARCH.x64: mainWindow.Title = "Dependencies (x64)"; break; case CLRPH_ARCH.WOW64: mainWindow.Title = "Dependencies (WoW64)"; break; } mainWindow.Show(); // Process command line args if (e.Args.Length > 0) { mainWindow.OpenNewDependencyWindow(e.Args[0]); } }
private void VerifyModuleImports() { // no parent : it's probably the root item ModuleTreeViewItem ParentModule = this.ParentModule; if (ParentModule == null) { ModuleInfo.HasErrors = false; return; } foreach (PeImportDll DllImport in ParentModule.ModuleInfo.Imports) { if (DllImport.Name != ModuleInfo._Name) { continue; } List <Tuple <PeImport, bool> > resolvedImports = BinaryCache.LookupImports(DllImport, ModuleInfo.Filepath); if (resolvedImports.Count == 0) { ModuleInfo.HasErrors = true; return; } foreach (var Import in resolvedImports) { if (!Import.Item2) { ModuleInfo.HasErrors = true; return; } } } ModuleInfo.HasErrors = false; }
public PeDependencyItem(PeDependencies _Root, string _ModuleName, string ModuleFilepath, ModuleSearchStrategy Strategy, int Level) { Root = _Root; ModuleName = _ModuleName; if (ModuleFilepath != null) { PE Module = BinaryCache.LoadPe(ModuleFilepath); Imports = Module.GetImports(); } else { //Module = null; Imports = new List <PeImportDll>(); } Filepath = ModuleFilepath; SearchStrategy = Strategy; RecursionLevel = Level; DependenciesResolved = false; }
public PE LoadBinary(string path) { StatusBarMessage = String.Format("Loading module {0:s} ...", path); if (!NativeFile.Exists(path)) { StatusBarMessage = String.Format("Loading PE file \"{0:s}\" failed : file not present on disk.", path); return(null); } PE pe = BinaryCache.LoadPe(path); if (pe == null || !pe.LoadSuccessful) { StatusBarMessage = String.Format("Loading module {0:s} failed.", path); } else { StatusBarMessage = String.Format("Loading PE file \"{0:s}\" successful.", pe.Filepath); } return(pe); }
static string FindPeFromPath(string ModuleName, List <string> CandidateFolders, bool Wow64Dll = false) { string PeFilePath = null; // Filter out "problematic" search paths before it triggers an exception from Path.Combine // see https://github.com/lucasg/Dependencies/issues/49 var CuratedCandidateFolders = CandidateFolders.Where( path => !IsFilepathInvalid(path) ); foreach (String CandidatePath in CuratedCandidateFolders) { PeFilePath = Path.Combine(CandidatePath, ModuleName); PE TestPe = BinaryCache.LoadPe(PeFilePath); if ((TestPe != null) && (TestPe.LoadSuccessful) && (TestPe.IsWow64Dll() == Wow64Dll)) { return(PeFilePath); } } return(null); }
private void ProcessAppInitDlls(Dictionary <string, ImportContext> NewTreeContexts, PE AnalyzedPe, ImportContext ImportModule) { List <PeImportDll> PeImports = AnalyzedPe.GetImports(); // only user32 triggers appinit dlls string User32Filepath = Path.Combine(FindPe.GetSystemPath(this.Pe), "user32.dll"); if (ImportModule.PeFilePath != User32Filepath) { return; } string AppInitRegistryKey = (this.Pe.IsArm32Dll()) ? "SOFTWARE\\WowAA32Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows" : (this.Pe.IsWow64Dll()) ? "SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows" : "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows"; // Opening registry values RegistryKey localKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64); localKey = localKey.OpenSubKey(AppInitRegistryKey); int LoadAppInitDlls = (int)localKey.GetValue("LoadAppInit_DLLs", 0); string AppInitDlls = (string)localKey.GetValue("AppInit_DLLs", ""); if (LoadAppInitDlls == 0 || String.IsNullOrEmpty(AppInitDlls)) { return; } // Extremely crude parser. TODO : Add support for quotes wrapped paths with spaces foreach (var AppInitDll in AppInitDlls.Split(' ')) { Debug.WriteLine("AppInit loading " + AppInitDll); // Do not process twice the same imported module if (null != PeImports.Find(module => module.Name == AppInitDll)) { continue; } if (NewTreeContexts.ContainsKey(AppInitDll)) { continue; } ImportContext AppInitImportModule = new ImportContext(); AppInitImportModule.PeFilePath = null; AppInitImportModule.PeProperties = null; AppInitImportModule.ModuleName = AppInitDll; AppInitImportModule.ApiSetModuleName = null; AppInitImportModule.Flags = 0; AppInitImportModule.ModuleLocation = ModuleSearchStrategy.AppInitDLL; Tuple <ModuleSearchStrategy, PE> ResolvedAppInitModule = BinaryCache.ResolveModule( this.Pe, AppInitDll, this.SxsEntriesCache, this.CustomSearchFolders, this.WorkingDirectory ); if (ResolvedAppInitModule.Item1 != ModuleSearchStrategy.NOT_FOUND) { AppInitImportModule.PeProperties = ResolvedAppInitModule.Item2; AppInitImportModule.PeFilePath = ResolvedAppInitModule.Item2.Filepath; } else { AppInitImportModule.Flags |= ModuleFlag.NotFound; } NewTreeContexts.Add(AppInitDll, AppInitImportModule); } }
/// <summary> /// Background processing of a single PE file. /// It can be lengthy since there are disk access (and misses). /// </summary> /// <param name="NewTreeContexts"> This variable is passed as reference to be updated since this function is run in a separate thread. </param> /// <param name="newPe"> Current PE file analyzed </param> private void ProcessPe(Dictionary <string, ImportContext> NewTreeContexts, PE newPe) { List <PeImportDll> PeImports = newPe.GetImports(); Environment.SpecialFolder WindowsSystemFolder = (this.Pe.IsWow64Dll()) ? Environment.SpecialFolder.SystemX86 : Environment.SpecialFolder.System; string User32Filepath = Path.Combine(Environment.GetFolderPath(WindowsSystemFolder), "user32.dll"); string MsCoreeFilepath = Path.Combine(Environment.GetFolderPath(WindowsSystemFolder), "mscoree.dll"); foreach (PeImportDll DllImport in PeImports) { ImportContext ImportModule = new ImportContext(); ImportModule.PeFilePath = null; ImportModule.PeProperties = null; ImportModule.ModuleName = DllImport.Name; ImportModule.ApiSetModuleName = null; ImportModule.Flags = 0; if (DllImport.IsDelayLoad()) { ImportModule.Flags |= ModuleFlag.DelayLoad; } if (NewTreeContexts.ContainsKey(DllImport.Name)) { continue; } // Find Dll in "paths" Tuple <ModuleSearchStrategy, PE> ResolvedModule = BinaryCache.ResolveModule(this.Pe, DllImport.Name, this.SxsEntriesCache); ImportModule.ModuleLocation = ResolvedModule.Item1; if (ImportModule.ModuleLocation != ModuleSearchStrategy.NOT_FOUND) { ImportModule.PeProperties = ResolvedModule.Item2; ImportModule.PeFilePath = ResolvedModule.Item2.Filepath; } // special case for apiset schema ImportModule.IsApiSet = (ImportModule.ModuleLocation == ModuleSearchStrategy.ApiSetSchema); if (ImportModule.IsApiSet) { ImportModule.ApiSetModuleName = BinaryCache.LookupApiSetLibrary(DllImport.Name); } // add warning for appv isv applications if (String.Compare(DllImport.Name, "AppvIsvSubsystems32.dll", StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(DllImport.Name, "AppvIsvSubsystems64.dll", StringComparison.OrdinalIgnoreCase) == 0) { if (!this._DisplayWarning) { MessageBoxResult result = MessageBox.Show( "This binary use the App-V containerization technology which fiddle with search directories and PATH env in ways Dependencies can't handle.\n\nFollowing results are probably not quite exact.", "App-V ISV disclaimer" ); this._DisplayWarning = true; // prevent the same warning window to popup several times } } NewTreeContexts.Add(DllImport.Name, ImportModule); // AppInitDlls are triggered by user32.dll, so if the binary does not import user32.dll they are not loaded. if (ImportModule.PeFilePath == User32Filepath) { string AppInitRegistryKey = (this.Pe.IsWow64Dll()) ? "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows" : "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows"; int LoadAppInitDlls = (int)Registry.GetValue(AppInitRegistryKey, "LoadAppInit_DLLs", 0); string AppInitDlls = (string)Registry.GetValue(AppInitRegistryKey, "AppInit_DLLs", ""); if ((LoadAppInitDlls != 0) && (AppInitDlls != "")) { // Extremely crude parser. TODO : Add support for quotes wrapped paths with spaces foreach (var AppInitDll in AppInitDlls.Split(' ')) { Debug.WriteLine("AppInit loading " + AppInitDll); // Do not process twice the same imported module if (null != PeImports.Find(module => module.Name == AppInitDll)) { continue; } if (NewTreeContexts.ContainsKey(AppInitDll)) { continue; } ImportContext AppInitImportModule = new ImportContext(); AppInitImportModule.PeFilePath = null; AppInitImportModule.PeProperties = null; AppInitImportModule.ModuleName = AppInitDll; AppInitImportModule.ApiSetModuleName = null; AppInitImportModule.Flags = 0; AppInitImportModule.ModuleLocation = ModuleSearchStrategy.AppInitDLL; Tuple <ModuleSearchStrategy, PE> ResolvedAppInitModule = BinaryCache.ResolveModule(this.Pe, AppInitDll, this.SxsEntriesCache); if (ResolvedAppInitModule.Item1 != ModuleSearchStrategy.NOT_FOUND) { AppInitImportModule.PeProperties = ResolvedAppInitModule.Item2; AppInitImportModule.PeFilePath = ResolvedAppInitModule.Item2.Filepath; } NewTreeContexts.Add(AppInitDll, AppInitImportModule); } } } // if mscoree.dll is imported, it means the module is a C# assembly, and we can use Mono.Cecil to enumerate its references if (ImportModule.PeFilePath == MsCoreeFilepath) { var resolver = new DefaultAssemblyResolver(); resolver.AddSearchDirectory(RootFolder); AssemblyDefinition PeAssembly = AssemblyDefinition.ReadAssembly(newPe.Filepath); foreach (var module in PeAssembly.Modules) { // Process CLR referenced assemblies foreach (var assembly in module.AssemblyReferences) { AssemblyDefinition definition = resolver.Resolve(assembly); foreach (var AssemblyModule in definition.Modules) { Debug.WriteLine("Referenced Assembling loading " + AssemblyModule.Name + " : " + AssemblyModule.FileName); // Do not process twice the same imported module if (null != PeImports.Find(mod => mod.Name == Path.GetFileName(AssemblyModule.FileName))) { continue; } ImportContext AppInitImportModule = new ImportContext(); AppInitImportModule.PeFilePath = null; AppInitImportModule.PeProperties = null; AppInitImportModule.ModuleName = Path.GetFileName(AssemblyModule.FileName); AppInitImportModule.ApiSetModuleName = null; AppInitImportModule.Flags = ModuleFlag.ClrReference; AppInitImportModule.ModuleLocation = ModuleSearchStrategy.ClrAssembly; Tuple <ModuleSearchStrategy, PE> ResolvedAppInitModule = BinaryCache.ResolveModule(this.Pe, AssemblyModule.FileName, this.SxsEntriesCache); if (ResolvedAppInitModule.Item1 != ModuleSearchStrategy.NOT_FOUND) { AppInitImportModule.PeProperties = ResolvedAppInitModule.Item2; AppInitImportModule.PeFilePath = ResolvedAppInitModule.Item2.Filepath; } if (!NewTreeContexts.ContainsKey(AppInitImportModule.ModuleName)) { NewTreeContexts.Add(AppInitImportModule.ModuleName, AppInitImportModule); } } } // Process unmanaged dlls for native calls foreach (var UnmanagedModule in module.ModuleReferences) { // some clr dll have a reference to an "empty" dll if (UnmanagedModule.Name.Length == 0) { continue; } Debug.WriteLine("Referenced module loading " + UnmanagedModule.Name); // Do not process twice the same imported module if (null != PeImports.Find(m => m.Name == UnmanagedModule.Name)) { continue; } ImportContext AppInitImportModule = new ImportContext(); AppInitImportModule.PeFilePath = null; AppInitImportModule.PeProperties = null; AppInitImportModule.ModuleName = UnmanagedModule.Name; AppInitImportModule.ApiSetModuleName = null; AppInitImportModule.Flags = ModuleFlag.ClrReference; AppInitImportModule.ModuleLocation = ModuleSearchStrategy.ClrAssembly; Tuple <ModuleSearchStrategy, PE> ResolvedAppInitModule = BinaryCache.ResolveModule(this.Pe, UnmanagedModule.Name, this.SxsEntriesCache); if (ResolvedAppInitModule.Item1 != ModuleSearchStrategy.NOT_FOUND) { AppInitImportModule.PeProperties = ResolvedAppInitModule.Item2; AppInitImportModule.PeFilePath = ResolvedAppInitModule.Item2.Filepath; } if (!NewTreeContexts.ContainsKey(AppInitImportModule.ModuleName)) { NewTreeContexts.Add(AppInitImportModule.ModuleName, AppInitImportModule); } } } } } }
private void ProcessClrImports(Dictionary <string, ImportContext> NewTreeContexts, PE AnalyzedPe, ImportContext ImportModule) { List <PeImportDll> PeImports = AnalyzedPe.GetImports(); // only mscorre triggers clr parsing string User32Filepath = Path.Combine(FindPe.GetSystemPath(this.Pe), "mscoree.dll"); if (ImportModule.PeFilePath != User32Filepath) { return; } var resolver = new DefaultAssemblyResolver(); resolver.AddSearchDirectory(RootFolder); // Parse it via cecil AssemblyDefinition PeAssembly = null; try { PeAssembly = AssemblyDefinition.ReadAssembly(AnalyzedPe.Filepath); } catch (BadImageFormatException) { MessageBoxResult result = MessageBox.Show( String.Format("Cecil could not correctly parse {0:s}, which can happens on .NET Core executables. CLR imports will be not shown", AnalyzedPe.Filepath), "CLR parsing fail" ); return; } foreach (var module in PeAssembly.Modules) { // Process CLR referenced assemblies foreach (var assembly in module.AssemblyReferences) { AssemblyDefinition definition; try { definition = resolver.Resolve(assembly); } catch (AssemblyResolutionException) { ImportContext AppInitImportModule = new ImportContext(); AppInitImportModule.PeFilePath = null; AppInitImportModule.PeProperties = null; AppInitImportModule.ModuleName = Path.GetFileName(assembly.Name); AppInitImportModule.ApiSetModuleName = null; AppInitImportModule.Flags = ModuleFlag.ClrReference; AppInitImportModule.ModuleLocation = ModuleSearchStrategy.ClrAssembly; AppInitImportModule.Flags |= ModuleFlag.NotFound; if (!NewTreeContexts.ContainsKey(AppInitImportModule.ModuleName)) { NewTreeContexts.Add(AppInitImportModule.ModuleName, AppInitImportModule); } continue; } foreach (var AssemblyModule in definition.Modules) { Debug.WriteLine("Referenced Assembling loading " + AssemblyModule.Name + " : " + AssemblyModule.FileName); // Do not process twice the same imported module if (null != PeImports.Find(mod => mod.Name == Path.GetFileName(AssemblyModule.FileName))) { continue; } ImportContext AppInitImportModule = new ImportContext(); AppInitImportModule.PeFilePath = null; AppInitImportModule.PeProperties = null; AppInitImportModule.ModuleName = Path.GetFileName(AssemblyModule.FileName); AppInitImportModule.ApiSetModuleName = null; AppInitImportModule.Flags = ModuleFlag.ClrReference; AppInitImportModule.ModuleLocation = ModuleSearchStrategy.ClrAssembly; Tuple <ModuleSearchStrategy, PE> ResolvedAppInitModule = BinaryCache.ResolveModule( this.Pe, AssemblyModule.FileName, this.SxsEntriesCache, this.CustomSearchFolders, this.WorkingDirectory ); if (ResolvedAppInitModule.Item1 != ModuleSearchStrategy.NOT_FOUND) { AppInitImportModule.PeProperties = ResolvedAppInitModule.Item2; AppInitImportModule.PeFilePath = ResolvedAppInitModule.Item2.Filepath; } else { AppInitImportModule.Flags |= ModuleFlag.NotFound; } if (!NewTreeContexts.ContainsKey(AppInitImportModule.ModuleName)) { NewTreeContexts.Add(AppInitImportModule.ModuleName, AppInitImportModule); } } } // Process unmanaged dlls for native calls foreach (var UnmanagedModule in module.ModuleReferences) { // some clr dll have a reference to an "empty" dll if (UnmanagedModule.Name.Length == 0) { continue; } Debug.WriteLine("Referenced module loading " + UnmanagedModule.Name); // Do not process twice the same imported module if (null != PeImports.Find(m => m.Name == UnmanagedModule.Name)) { continue; } ImportContext AppInitImportModule = new ImportContext(); AppInitImportModule.PeFilePath = null; AppInitImportModule.PeProperties = null; AppInitImportModule.ModuleName = UnmanagedModule.Name; AppInitImportModule.ApiSetModuleName = null; AppInitImportModule.Flags = ModuleFlag.ClrReference; AppInitImportModule.ModuleLocation = ModuleSearchStrategy.ClrAssembly; Tuple <ModuleSearchStrategy, PE> ResolvedAppInitModule = BinaryCache.ResolveModule( this.Pe, UnmanagedModule.Name, this.SxsEntriesCache, this.CustomSearchFolders, this.WorkingDirectory ); if (ResolvedAppInitModule.Item1 != ModuleSearchStrategy.NOT_FOUND) { AppInitImportModule.PeProperties = ResolvedAppInitModule.Item2; AppInitImportModule.PeFilePath = ResolvedAppInitModule.Item2.Filepath; } if (!NewTreeContexts.ContainsKey(AppInitImportModule.ModuleName)) { NewTreeContexts.Add(AppInitImportModule.ModuleName, AppInitImportModule); } } } }
static void Main(string[] args) { // always the first call to make Phlib.InitializePhLib(); int recursion_depth = 0; bool early_exit = false; bool show_help = false; bool export_as_json = false; bool use_bin_cache = false; DumpCommand command = null; OptionSet opts = new OptionSet() { { "h|help", "show this message and exit", v => show_help = v != null }, { "json", "Export results in json format", v => export_as_json = v != null }, { "cache", "load and use binary cache to prevent dll file locking", v => use_bin_cache = v != null }, { "d|depth=", "limit recursion depth when analysing loaded modules or dependency chain. Default value is infinite", (int v) => recursion_depth = v }, { "knowndll", "List all known dlls", v => { DumpKnownDlls(GetObjectPrinter(export_as_json)); early_exit = true; } }, { "apisets", "List apisets redirections", v => { DumpApiSets(GetObjectPrinter(export_as_json)); early_exit = true; } }, { "apisetsdll", "List apisets redirections from apisetschema <FILE>", v => command = DumpApiSets }, { "manifest", "show manifest information embedded in <FILE>", v => command = DumpManifest }, { "sxsentries", "dump all of <FILE>'s sxs dependencies", v => command = DumpSxsEntries }, { "imports", "dump <FILE> imports", v => command = DumpImports }, { "exports", "dump <FILE> exports", v => command = DumpExports }, { "assemblyrefs", "dump <FILE> assemblyrefs", v => command = DumpAssemblyReferences }, { "modulerefs", "dump <FILE> modulerefs", v => command = DumpModuleReferences }, { "chain", "dump <FILE> whole dependency chain", v => command = DumpDependencyChain }, { "modules", "dump <FILE> resolved modules", v => command = DumpModules }, }; List <string> eps = opts.Parse(args); if (early_exit) { return; } if ((show_help) || (args.Length == 0) || (command == null)) { DumpUsage(); return; } BinaryCache.InitializeBinaryCache(use_bin_cache); if (eps.Count == 0) { Console.Error.WriteLine("[x] Command {0:s} needs to have a PE <FILE> argument", command.Method.Name); Console.Error.WriteLine(""); DumpUsage(); return; } String FileName = eps[0]; if (!NativeFile.Exists(FileName)) { Console.Error.WriteLine("[x] Could not find file {0:s} on disk", FileName); return; } Debug.WriteLine("[-] Loading file {0:s} ", FileName); PE Pe = new PE(FileName); if (!Pe.Load()) { Console.Error.WriteLine("[x] Could not load file {0:s} as a PE", FileName); return; } command(Pe, GetObjectPrinter(export_as_json), recursion_depth); }
/// <summary> /// Background processing of a single PE file. /// It can be lengthy since there are disk access (and misses). /// </summary> /// <param name="NewTreeContexts"> This variable is passed as reference to be updated since this function is run in a separate thread. </param> /// <param name="newPe"> Current PE file analyzed </param> private void ProcessPe(List <ImportContext> NewTreeContexts, PE newPe) { List <PeImportDll> PeImports = newPe.GetImports(); Environment.SpecialFolder WindowsSystemFolder = (this.Pe.IsWow64Dll()) ? Environment.SpecialFolder.SystemX86 : Environment.SpecialFolder.System; string User32Filepath = Path.Combine(Environment.GetFolderPath(WindowsSystemFolder), "user32.dll"); foreach (PeImportDll DllImport in PeImports) { ImportContext ImportModule = new ImportContext(); ImportModule.PeFilePath = null; ImportModule.PeProperties = null; ImportModule.ModuleName = DllImport.Name; ImportModule.ApiSetModuleName = null; ImportModule.IsDelayLoadImport = DllImport.IsDelayLoad(); // Find Dll in "paths" Tuple <ModuleSearchStrategy, PE> ResolvedModule = BinaryCache.ResolveModule(this.Pe, DllImport.Name, this.SxsEntriesCache); ImportModule.ModuleLocation = ResolvedModule.Item1; if (ImportModule.ModuleLocation != ModuleSearchStrategy.NOT_FOUND) { ImportModule.PeProperties = ResolvedModule.Item2; ImportModule.PeFilePath = ResolvedModule.Item2.Filepath; } // special case for apiset schema ImportModule.IsApiSet = (ImportModule.ModuleLocation == ModuleSearchStrategy.ApiSetSchema); if (ImportModule.IsApiSet) { ImportModule.ApiSetModuleName = BinaryCache.LookupApiSetLibrary(DllImport.Name); } // add warning for appv isv applications if (String.Compare(DllImport.Name, "AppvIsvSubsystems32.dll", StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(DllImport.Name, "AppvIsvSubsystems64.dll", StringComparison.OrdinalIgnoreCase) == 0) { if (!this._DisplayWarning) { MessageBoxResult result = MessageBox.Show( "This binary use the App-V containerization technology which fiddle with search directories and PATH env in ways Dependencies can't handle.\n\nFollowing results are probably not quite exact.", "App-V ISV disclaimer" ); this._DisplayWarning = true; // prevent the same warning window to popup several times } } NewTreeContexts.Add(ImportModule); // AppInitDlls are triggered by user32.dll, so if the binary does not import user32.dll they are not loaded. if (ImportModule.PeFilePath == User32Filepath) { string AppInitRegistryKey = (this.Pe.IsWow64Dll()) ? "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows" : "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows"; int LoadAppInitDlls = (int)Registry.GetValue(AppInitRegistryKey, "LoadAppInit_DLLs", 0); string AppInitDlls = (string)Registry.GetValue(AppInitRegistryKey, "AppInit_DLLs", ""); if ((LoadAppInitDlls != 0) && (AppInitDlls != "")) { // Extremely crude parser. TODO : Add support for quotes wrapped paths with spaces foreach (var AppInitDll in AppInitDlls.Split(' ')) { Debug.WriteLine("AppInit loading " + AppInitDll); ImportContext AppInitImportModule = new ImportContext(); AppInitImportModule.PeFilePath = null; AppInitImportModule.PeProperties = null; AppInitImportModule.ModuleName = AppInitDll; AppInitImportModule.ApiSetModuleName = null; AppInitImportModule.IsDelayLoadImport = false; AppInitImportModule.ModuleLocation = ModuleSearchStrategy.AppInitDLL; Tuple <ModuleSearchStrategy, PE> ResolvedAppInitModule = BinaryCache.ResolveModule(this.Pe, AppInitDll, this.SxsEntriesCache); if (ResolvedAppInitModule.Item1 != ModuleSearchStrategy.NOT_FOUND) { AppInitImportModule.PeProperties = ResolvedAppInitModule.Item2; AppInitImportModule.PeFilePath = ResolvedAppInitModule.Item2.Filepath; } NewTreeContexts.Add(AppInitImportModule); } } } } }
private void ConstructDependencyTree(ModuleTreeViewItem RootNode, string FilePath, int RecursionLevel = 0) { ConstructDependencyTree(RootNode, BinaryCache.LoadPe(FilePath), RecursionLevel); }