Repository: lucasg/Dependencies Branch: master Commit: 1997a40000b7 Files: 410 Total size: 4.6 MB Directory structure: gitextract_hd4rd2bh/ ├── .gitignore ├── ClrPhlib/ │ ├── AssemblyInfo.cpp │ ├── ClrPhlib.cpp │ ├── ClrPhlib.manifest │ ├── ClrPhlib.vcxproj │ ├── ClrPhlib.vcxproj.filters │ ├── app.rc │ ├── include/ │ │ ├── ApiSet.h │ │ ├── ClrPhSymbolProvider.h │ │ ├── ClrPhlib.h │ │ ├── NativeFile.h │ │ ├── UnmanagedPh.h │ │ └── UnmanagedSymPrv.h │ ├── resource.h │ └── src/ │ ├── managed/ │ │ ├── NativeFile.cpp │ │ ├── PE.cpp │ │ ├── PeExport.cpp │ │ ├── PeImport.cpp │ │ ├── PhSymbolProvider.cpp │ │ └── Phlib.cpp │ └── unmanaged/ │ ├── UnmanagedPE.cpp │ ├── UnmanagedSymPrv.cpp │ └── demangle.cpp ├── Dependencies/ │ ├── App.config │ ├── Dependencies.csproj │ ├── Program.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ └── packages.config ├── Dependencies.sln ├── DependenciesGui/ │ ├── About.xaml │ ├── About.xaml.cs │ ├── App.config │ ├── App.xaml │ ├── App.xaml.cs │ ├── CustomHeaderViewModel.cs │ ├── Dependencies.manifest │ ├── DependenciesGui.csproj │ ├── DependencyCustomListView.xaml │ ├── DependencyCustomListView.xaml.cs │ ├── DependencyExportList.xaml │ ├── DependencyExportList.xaml.cs │ ├── DependencyImportList.xaml │ ├── DependencyImportList.xaml.cs │ ├── DependencyModuleList.xaml │ ├── DependencyModuleList.xaml.cs │ ├── DependencyWindow.xaml │ ├── DependencyWindow.xaml.cs │ ├── DragablzCustomHeader.cs │ ├── DragablzCustomHeader.xaml │ ├── FilterControl/ │ │ ├── FilterControl.cs │ │ └── FilterControl.generic.xaml │ ├── GridViewSort.cs │ ├── Helpers/ │ │ ├── RelayCommand.cs │ │ └── SettingBindingHandler.cs │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── Models/ │ │ ├── ModuleInfo.cs │ │ ├── PeExport.cs │ │ └── PeImport.cs │ ├── ModuleSearchOrder.xaml │ ├── ModuleSearchOrder.xaml.cs │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ ├── Resources.resx │ │ ├── Settings.Designer.cs │ │ └── Settings.settings │ ├── SearchFolder.xaml │ ├── SearchFolder.xaml.cs │ ├── Settings.cs │ ├── Shell32IconExtractor.cs │ ├── UserSettings.xaml │ ├── UserSettings.xaml.cs │ └── packages.config ├── DependenciesLib/ │ ├── BinaryCache.cs │ ├── DependenciesLib.csproj │ ├── FindPeModule.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ └── SxsManifest.cs ├── Deploy-Dependencies.ps1 ├── LICENSE ├── README.md ├── appveyor.yml ├── nuget.config ├── test/ │ ├── binarycache-test/ │ │ ├── App.config │ │ ├── Program.cs │ │ ├── Properties/ │ │ │ └── AssemblyInfo.cs │ │ ├── binarycache-test.csproj │ │ └── packages.config │ ├── demangler-test/ │ │ ├── App.config │ │ ├── Program.cs │ │ ├── Properties/ │ │ │ └── AssemblyInfo.cs │ │ ├── demangler-test.csproj │ │ └── packages.config │ └── manifest-regress/ │ ├── Test-ManifestRegress.ps1 │ └── schedsvc.dll.manifest └── third_party/ ├── Dragablz/ │ └── Dragablz/ │ ├── CanvasOrganiser.cs │ ├── ContainerCustomisations.cs │ ├── Converters/ │ │ ├── BooleanAndToVisibilityConverter.cs │ │ ├── EqualityToBooleanConverter.cs │ │ ├── EqualityToVisibilityConverter.cs │ │ └── ShowDefaultCloseButtonConverter.cs │ ├── Core/ │ │ ├── CollectionTeaser.cs │ │ ├── Extensions.cs │ │ ├── FuncComparer.cs │ │ ├── HitTest.cs │ │ ├── InterTabTransfer.cs │ │ ├── MultiComparer.cs │ │ ├── Native.cs │ │ ├── SystemCommand.cs │ │ ├── TabHeaderDragStartInformation.cs │ │ └── WindowMessage.cs │ ├── DefaultInterLayoutClient.cs │ ├── DefaultInterTabClient.cs │ ├── Dockablz/ │ │ ├── Branch.cs │ │ ├── BranchAccessor.cs │ │ ├── BranchItem.cs │ │ ├── BranchResult.cs │ │ ├── CouldBeHeaderedStyleSelector.cs │ │ ├── DropZone.cs │ │ ├── DropZoneLocation.cs │ │ ├── Extensions.cs │ │ ├── Finder.cs │ │ ├── FloatRequestedEvent.cs │ │ ├── FloatTransfer.cs │ │ ├── FloatingItemSnapShot.cs │ │ ├── Layout.cs │ │ ├── LayoutAccessor.cs │ │ ├── LocationReport.cs │ │ ├── LocationReportBuilder.cs │ │ ├── LocationReportException.cs │ │ ├── LocationSnapShot.cs │ │ ├── Tiler.cs │ │ └── TilerCalculator.cs │ ├── Dragablz.net40.csproj │ ├── Dragablz.net45.csproj │ ├── Dragablz.nuspec │ ├── DragablzColors.cs │ ├── DragablzDragCompletedEventArgs.cs │ ├── DragablzDragDeltaEventArgs.cs │ ├── DragablzDragStartedEventArgs.cs │ ├── DragablzIcon.cs │ ├── DragablzItem.cs │ ├── DragablzItemEventArgs.cs │ ├── DragablzItemsControl.cs │ ├── DragablzWindow.cs │ ├── EmptyHeaderSizingHint.cs │ ├── HeaderedDragablzItem.cs │ ├── HeaderedItemViewModel.cs │ ├── HorizontalOrganiser.cs │ ├── HorizontalPositionMonitor.cs │ ├── IInterLayoutClient.cs │ ├── IInterTabClient.cs │ ├── IItemsOrganiser.cs │ ├── IManualInterTabClient.cs │ ├── INewTabHost.cs │ ├── InterTabController.cs │ ├── ItemActionCallbackArgs.cs │ ├── LocationChangedEventArgs.cs │ ├── LocationHint.cs │ ├── MoveItemRequest.cs │ ├── NewTabHost.cs │ ├── OrderChangedEventArgs.cs │ ├── PositionMonitor.cs │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ ├── Resources.resx │ │ ├── Settings.Designer.cs │ │ └── Settings.settings │ ├── Referenceless/ │ │ ├── AnonymousDisposable.cs │ │ ├── DefaultDisposable.cs │ │ ├── Disposable.cs │ │ ├── ICancelable.cs │ │ └── SerialDisposable.cs │ ├── StackOrganiser.cs │ ├── StackPositionMonitor.cs │ ├── StoryboardCompletionListener.cs │ ├── TabEmptiedResponse.cs │ ├── TabablzControl.cs │ ├── TabablzHeaderSizeConverter.cs │ ├── TabablzItemStyleSelector.cs │ ├── Themes/ │ │ ├── BrushToRadialGradientBrushConverter.cs │ │ ├── Dockablz.xaml │ │ ├── Generic.xaml │ │ ├── MahApps.xaml │ │ ├── MaterialDesign.xaml │ │ ├── MaterialDesignAssist.cs │ │ ├── Ripple.cs │ │ ├── RippleAssist.cs │ │ └── SystemCommandIcon.cs │ ├── Trapezoid.cs │ ├── VerticalOrganiser.cs │ └── VerticalPositionMonitor.cs ├── Get-ProcessHackerSources.ps1 ├── Ph-d7342929f1426e597b95e0c20a9b9651d406f410-__acrt_fp_format-bug-and-specify-CLR-compilation.patch ├── Ph-dc6a8a94f7e4b381090b46eb8e1b9fd7de052dbe-__acrt_fp_format-bug-and-specify-CLR-compilation.patch ├── demumble/ │ ├── CMakeLists.txt │ ├── LICENSE │ ├── README.md │ ├── RELEASING │ ├── demumble.vcxproj │ ├── demumble.vcxproj.filters │ └── third_party/ │ ├── libcxxabi/ │ │ ├── LICENSE.txt │ │ └── cxa_demangle.cpp │ └── wine/ │ ├── LICENSE.txt │ └── undname.c ├── llvm-demangle/ │ ├── README.md │ ├── include/ │ │ └── llvm/ │ │ └── Demangle/ │ │ ├── Compiler.h │ │ ├── Demangle.h │ │ ├── ItaniumDemangle.h │ │ ├── StringView.h │ │ └── Utility.h │ ├── lib/ │ │ └── Demangle/ │ │ ├── CMakeLists.txt │ │ ├── ItaniumDemangle.cpp │ │ ├── LLVMBuild.txt │ │ ├── MicrosoftDemangle.cpp │ │ ├── MicrosoftDemangleNodes.cpp │ │ └── MicrosoftDemangleNodes.h │ ├── llvm-demangle.vcxproj │ └── llvm-demangle.vcxproj.filters ├── phlib/ │ ├── apiimport.c │ ├── appresolver.c │ ├── avltree.c │ ├── basesup.c │ ├── circbuf.c │ ├── circbuf_i.h │ ├── colorbox.c │ ├── cpysave.c │ ├── data.c │ ├── dspick.c │ ├── emenu.c │ ├── error.c │ ├── extlv.c │ ├── fastlock.c │ ├── filepool.c │ ├── filestream.c │ ├── format.c │ ├── format_i.h │ ├── global.c │ ├── graph.c │ ├── guisup.c │ ├── handle.c │ ├── hexedit.c │ ├── hndlinfo.c │ ├── icotobmp.c │ ├── include/ │ │ ├── apiimport.h │ │ ├── appresolver.h │ │ ├── appresolverp.h │ │ ├── circbuf.h │ │ ├── circbuf_h.h │ │ ├── colorbox.h │ │ ├── cpysave.h │ │ ├── dltmgr.h │ │ ├── dspick.h │ │ ├── emenu.h │ │ ├── exlf.h │ │ ├── fastlock.h │ │ ├── filepool.h │ │ ├── filepoolp.h │ │ ├── filestream.h │ │ ├── filestreamp.h │ │ ├── graph.h │ │ ├── guisup.h │ │ ├── guisupp.h │ │ ├── handle.h │ │ ├── handlep.h │ │ ├── hexedit.h │ │ ├── hexeditp.h │ │ ├── hndlinfo.h │ │ ├── json.h │ │ ├── kphapi.h │ │ ├── kphuser.h │ │ ├── kphuserp.h │ │ ├── lsasup.h │ │ ├── mapimg.h │ │ ├── ph.h │ │ ├── phbase.h │ │ ├── phbasesup.h │ │ ├── phconfig.h │ │ ├── phdata.h │ │ ├── phintrnl.h │ │ ├── phnative.h │ │ ├── phnativeinl.h │ │ ├── phnet.h │ │ ├── phsup.h │ │ ├── phutil.h │ │ ├── provider.h │ │ ├── queuedlock.h │ │ ├── ref.h │ │ ├── refp.h │ │ ├── secedit.h │ │ ├── seceditp.h │ │ ├── settings.h │ │ ├── svcsup.h │ │ ├── symprv.h │ │ ├── symprvp.h │ │ ├── templ.h │ │ ├── treenew.h │ │ ├── treenewp.h │ │ ├── verify.h │ │ ├── verifyp.h │ │ ├── workqueue.h │ │ └── workqueuep.h │ ├── json.c │ ├── jsonc/ │ │ ├── AUTHORS │ │ ├── COPYING │ │ ├── ChangeLog │ │ ├── arraylist.c │ │ ├── arraylist.h │ │ ├── bits.h │ │ ├── config.h │ │ ├── config.h.in │ │ ├── debug.c │ │ ├── debug.h │ │ ├── json.h │ │ ├── json_c_version.c │ │ ├── json_c_version.h │ │ ├── json_config.h │ │ ├── json_inttypes.h │ │ ├── json_object.c │ │ ├── json_object.h │ │ ├── json_object_iterator.c │ │ ├── json_object_iterator.h │ │ ├── json_object_private.h │ │ ├── json_tokener.c │ │ ├── json_tokener.h │ │ ├── json_util.c │ │ ├── json_util.h │ │ ├── libjson.c │ │ ├── linkhash.c │ │ ├── linkhash.h │ │ ├── math_compat.h │ │ ├── printbuf.c │ │ ├── printbuf.h │ │ ├── random_seed.c │ │ └── random_seed.h │ ├── kph.c │ ├── kphdata.c │ ├── lsasup.c │ ├── mapexlf.c │ ├── mapimg.c │ ├── maplib.c │ ├── md5.c │ ├── md5.h │ ├── mxml/ │ │ ├── COPYING │ │ ├── config.h │ │ ├── mxml-attr.c │ │ ├── mxml-entity.c │ │ ├── mxml-file.c │ │ ├── mxml-get.c │ │ ├── mxml-index.c │ │ ├── mxml-node.c │ │ ├── mxml-private.c │ │ ├── mxml-private.h │ │ ├── mxml-search.c │ │ ├── mxml-set.c │ │ ├── mxml-string.c │ │ └── mxml.h │ ├── native.c │ ├── phlib.vcxproj │ ├── phlib.vcxproj.filters │ ├── provider.c │ ├── queuedlock.c │ ├── ref.c │ ├── secdata.c │ ├── secedit.c │ ├── settings.c │ ├── sha.c │ ├── sha.h │ ├── sha256.c │ ├── sha256.h │ ├── svcsup.c │ ├── symprv.c │ ├── sync.c │ ├── treenew.c │ ├── util.c │ ├── verify.c │ └── workqueue.c └── phnt/ ├── README.md ├── include/ │ ├── ntdbg.h │ ├── ntexapi.h │ ├── ntgdi.h │ ├── ntioapi.h │ ├── ntkeapi.h │ ├── ntldr.h │ ├── ntlpcapi.h │ ├── ntmisc.h │ ├── ntmmapi.h │ ├── ntnls.h │ ├── ntobapi.h │ ├── ntpebteb.h │ ├── ntpfapi.h │ ├── ntpnpapi.h │ ├── ntpoapi.h │ ├── ntpsapi.h │ ├── ntregapi.h │ ├── ntrtl.h │ ├── ntsam.h │ ├── ntseapi.h │ ├── ntsmss.h │ ├── nttmapi.h │ ├── nttp.h │ ├── ntwow64.h │ ├── ntxcapi.h │ ├── ntzwapi.h │ ├── phnt.h │ ├── phnt_ntdef.h │ ├── phnt_windows.h │ ├── subprocesstag.h │ └── winsta.h └── zw_options.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .vs/ obj/ bin/ packages/ _packages/ tests/ *.obj *.log *.tlog *.VC.db *.cache *.pdb *.pch *.user _ReSharper.Caches/ /**/x64-Debug ================================================ FILE: ClrPhlib/AssemblyInfo.cpp ================================================ using namespace System; using namespace System::Reflection; using namespace System::Runtime::CompilerServices; using namespace System::Runtime::InteropServices; using namespace System::Security::Permissions; // // Les informations générales relatives à un assembly dépendent de // l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations // associées à un assembly. // [assembly:AssemblyTitleAttribute(L"ClrPhlib")]; [assembly:AssemblyDescriptionAttribute(L"")]; [assembly:AssemblyConfigurationAttribute(L"")]; [assembly:AssemblyCompanyAttribute(L"")]; [assembly:AssemblyProductAttribute(L"ClrPhlib")]; [assembly:AssemblyCopyrightAttribute(L"Copyright (c) 2017")]; [assembly:AssemblyTrademarkAttribute(L"")]; [assembly:AssemblyCultureAttribute(L"")]; // // Les informations de version pour un assembly se composent des quatre valeurs suivantes : // // Version principale // Version secondaire // Numéro de build // Révision // // Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de révision et de build par défaut // en utilisant '*', comme indiqué ci-dessous : [assembly:AssemblyVersionAttribute("1.10.*")]; [assembly:ComVisible(false)]; [assembly:CLSCompliantAttribute(true)]; ================================================ FILE: ClrPhlib/ClrPhlib.cpp ================================================ #include using namespace Dependencies; ClrPh::CLRPH_ARCH ClrPh::Phlib::GetClrPhArch() { #if _WIN64 return ClrPh::CLRPH_ARCH::x64; #else if (PhIsExecutingInWow64()) return ClrPh::CLRPH_ARCH::WOW64; return ClrPh::CLRPH_ARCH::x86; #endif // _WIN64 } ================================================ FILE: ClrPhlib/ClrPhlib.manifest ================================================ CLR Process Hacker library true true ================================================ FILE: ClrPhlib/ClrPhlib.vcxproj ================================================  Appx Win32 Appx x64 Debug Win32 Release Win32 Debug x64 Release x64 {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8} v4.6.1 ManagedCProj ClrPhlib 10.0 DynamicLibrary true v142 true Unicode false DynamicLibrary false v142 true Unicode false DynamicLibrary false v142 true Unicode false DynamicLibrary true v142 true Unicode false DynamicLibrary false v142 true Unicode false DynamicLibrary false v142 true Unicode false true $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(PlatformArchitecture)\ true $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(PlatformArchitecture)\ false $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(PlatformArchitecture)\ false $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(PlatformArchitecture)\ false $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(PlatformArchitecture)\ false $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\ $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(PlatformArchitecture)\ Level3 Disabled WIN32;_DEBUG;%(PreprocessorDefinitions) NotUsing $(SolutionDir)third_party\phnt\include;$(SolutionDir)third_party\phlib\include;$(ProjectDir)include;$(SolutionDir)third_party\llvm-demangle\include;%(AdditionalIncludeDirectories) MultiThreadedDebugDLL true $(OutputPath)\phlib.lib;$(OutputPath)\demumble.lib;$(OutputPath)\llvm-demangle.lib;bcrypt.lib;%(AdditionalDependencies) DebugFull Default Level3 Disabled _DEBUG;%(PreprocessorDefinitions) NotUsing $(SolutionDir)third_party\phnt\include;$(SolutionDir)third_party\phlib\include;$(ProjectDir)include;$(SolutionDir)third_party\llvm-demangle\include;%(AdditionalIncludeDirectories) MultiThreadedDebugDLL Default true $(OutputPath)\phlib.lib;$(OutputPath)\demumble.lib;$(OutputPath)\llvm-demangle.lib;bcrypt.lib;%(AdditionalDependencies) DebugFull Default Level3 WIN32;NDEBUG;%(PreprocessorDefinitions) NotUsing $(SolutionDir)third_party\phnt\include;$(SolutionDir)third_party\phlib\include;$(ProjectDir)include;$(SolutionDir)third_party\llvm-demangle\include;%(AdditionalIncludeDirectories) MultiThreadedDLL true $(OutputPath)\phlib.lib;$(OutputPath)\demumble.lib;$(OutputPath)\llvm-demangle.lib;bcrypt.lib;%(AdditionalDependencies) Default Level3 WIN32;NDEBUG;%(PreprocessorDefinitions) NotUsing $(SolutionDir)third_party\phnt\include;$(SolutionDir)third_party\phlib\include;$(ProjectDir)include;$(SolutionDir)third_party\llvm-demangle\include;%(AdditionalIncludeDirectories) MultiThreadedDLL true $(OutputPath)\phlib.lib;$(OutputPath)\demumble.lib;$(OutputPath)\llvm-demangle.lib;bcrypt.lib;%(AdditionalDependencies) Default Level3 NDEBUG;%(PreprocessorDefinitions) NotUsing $(SolutionDir)third_party\phnt\include;$(SolutionDir)third_party\phlib\include;$(ProjectDir)include;$(SolutionDir)third_party\llvm-demangle\include;%(AdditionalIncludeDirectories) MultiThreadedDLL true $(OutputPath)\phlib.lib;$(OutputPath)\demumble.lib;$(OutputPath)\llvm-demangle.lib;bcrypt.lib;%(AdditionalDependencies) Default Level3 NDEBUG;%(PreprocessorDefinitions) NotUsing $(SolutionDir)third_party\phnt\include;$(SolutionDir)third_party\phlib\include;$(ProjectDir)include;$(SolutionDir)third_party\llvm-demangle\include;%(AdditionalIncludeDirectories) MultiThreadedDLL true $(OutputPath)\phlib.lib;$(OutputPath)\demumble.lib;$(OutputPath)\llvm-demangle.lib;bcrypt.lib;%(AdditionalDependencies) Default ================================================ FILE: ClrPhlib/ClrPhlib.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms {e9536ddc-3c30-4ef3-99fa-0e7f44736ebb} {e79a5a25-1203-4753-8c5a-644629cfac1a} Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers d%27en-tête Fichiers sources Fichiers sources Fichiers sources\Unmanaged Fichiers sources\Unmanaged Fichiers sources\Managed Fichiers sources\Managed Fichiers sources\Managed Fichiers sources\Managed Fichiers sources\Managed Fichiers sources\Managed Fichiers sources\Unmanaged Fichiers de ressources Fichiers de ressources ================================================ FILE: ClrPhlib/include/ApiSet.h ================================================ #pragma once #include #ifdef __cplusplus extern "C" { #endif /////////////////////////////////////////////////////////////////////////////// // ApiSet v2 typedef struct _API_SET_VALUE_ENTRY_REDIRECTION_V2 { ULONG NameOffset; USHORT NameLength; ULONG ValueOffset; USHORT ValueLength; } API_SET_VALUE_ENTRY_REDIRECTION_V2, *PAPI_SET_VALUE_ENTRY_REDIRECTION_V2; typedef struct _API_SET_VALUE_ENTRY_V2 { ULONG NumberOfRedirections; API_SET_VALUE_ENTRY_REDIRECTION_V2 Redirections[ANYSIZE_ARRAY]; } API_SET_VALUE_ENTRY_V2, *PAPI_SET_VALUE_ENTRY_V2; typedef struct _API_SET_NAMESPACE_ENTRY_V2 { ULONG NameOffset; ULONG NameLength; ULONG DataOffset; // ===> _API_SET_VALUE_ENTRY_V2 } API_SET_NAMESPACE_ENTRY_V2, *PAPI_SET_NAMESPACE_ENTRY_V2; typedef struct _API_SET_NAMESPACE_V2 { ULONG Version; ULONG Count; API_SET_NAMESPACE_ENTRY_V2 Array[ANYSIZE_ARRAY]; } API_SET_NAMESPACE_V2, *PAPI_SET_NAMESPACE_V2; /////////////////////////////////////////////////////////////////////////////// // ApiSet v4 typedef struct _API_SET_VALUE_ENTRY_REDIRECTION_V4 { ULONG Flags; ULONG NameOffset; ULONG NameLength; ULONG ValueOffset; ULONG ValueLength; } API_SET_VALUE_ENTRY_REDIRECTION_V4, *PAPI_SET_VALUE_ENTRY_REDIRECTION_V4; typedef struct _API_SET_VALUE_ENTRY_V4 { ULONG Flags; ULONG NumberOfRedirections; API_SET_VALUE_ENTRY_REDIRECTION_V4 Redirections[ANYSIZE_ARRAY]; } API_SET_VALUE_ENTRY_V4, *PAPI_SET_VALUE_ENTRY_V4; typedef struct _API_SET_NAMESPACE_ENTRY_V4 { ULONG Flags; ULONG NameOffset; ULONG NameLength; ULONG AliasOffset; ULONG AliasLength; ULONG DataOffset; // ===> _API_SET_VALUE_ENTRY_V4 } API_SET_NAMESPACE_ENTRY_V4, *PAPI_SET_NAMESPACE_ENTRY_V4; typedef struct _API_SET_NAMESPACE_V4 { ULONG Version; ULONG Size; ULONG Flags; ULONG Count; API_SET_NAMESPACE_ENTRY_V4 Array[ANYSIZE_ARRAY]; } API_SET_NAMESPACE_V4, *PAPI_SET_NAMESPACE_V4; /////////////////////////////////////////////////////////////////////////////// // ApiSet v6 typedef struct _API_SET_HASH_ENTRY_V6 { ULONG Hash; ULONG Index; } API_SET_HASH_ENTRY_V6, *PAPI_SET_HASH_ENTRY_V6; typedef struct _API_SET_NAMESPACE_ENTRY_V6 { ULONG Flags; ULONG NameOffset; ULONG NameLength; ULONG HashedLength; ULONG ValueOffset; ULONG ValueCount; } API_SET_NAMESPACE_ENTRY_V6, *PAPI_SET_NAMESPACE_ENTRY_V6; typedef struct _API_SET_VALUE_ENTRY_V6 { ULONG Flags; ULONG NameOffset; ULONG NameLength; ULONG ValueOffset; ULONG ValueLength; } API_SET_VALUE_ENTRY_V6, *PAPI_SET_VALUE_ENTRY_V6; typedef struct _API_SET_NAMESPACE_V6 { ULONG Version; ULONG Size; ULONG Flags; ULONG Count; ULONG EntryOffset; ULONG HashOffset; ULONG HashFactor; } API_SET_NAMESPACE_V6, *PAPI_SET_NAMESPACE_V6; /////////////////////////////////////////////////////////////////////////////// typedef struct _API_SET_NAMESPACE { union { ULONG Version; API_SET_NAMESPACE_V2 ApiSetNameSpaceV2; API_SET_NAMESPACE_V4 ApiSetNameSpaceV4; API_SET_NAMESPACE_V6 ApiSetNameSpaceV6; }; } API_SET_NAMESPACE, *PAPI_SET_NAMESPACE; #ifdef __cplusplus } #endif ================================================ FILE: ClrPhlib/include/ClrPhSymbolProvider.h ================================================ #pragma once #include #include using namespace Dependencies::ClrPh; // Symbol resolution and undecoration utility class public ref class PhSymbolProvider { public: PhSymbolProvider(); ~PhSymbolProvider(); !PhSymbolProvider(); virtual Tuple^ UndecorateName(_In_ String ^DecoratedName); protected: String^ UndecorateNameDemumble(_In_ String ^DecoratedName); String^ UndecorateNameLLVMItanium(_In_ String ^DecoratedName); String^ UndecorateNameLLVMMicrosoft(_In_ String ^DecoratedName); String^ UndecorateNamePh(_In_ String ^DecoratedName); private: String ^ UndecorateNamePrv(_In_ String ^DecoratedName, _In_ DemangleNameFn Demangler); UnmanagedSymPrv *m_Impl; }; ================================================ FILE: ClrPhlib/include/ClrPhlib.h ================================================ // ClrPhlib.h #pragma once #include #using using namespace System; using namespace Collections::Generic; namespace Dependencies { namespace ClrPh { #pragma region ENUMS public enum class CLRPH_ARCH { x86, x64, WOW64 }; public enum class CLRPH_DEMANGLER { None, Demumble, LLVMItanium, LLVMMicrosoft, Microsoft, Default // Synthetic demangler using all the previous ones }; #pragma endregion ENUMS #pragma region TYPES public ref class ApiSetTarget : List {}; public ref class ApiSetSchema abstract { public: virtual List>^ GetAll() = 0; virtual ApiSetTarget^ Lookup(String^ name) = 0; }; #pragma endregion TYPES public ref class Phlib { public: // Return the arch is which ClrPhLib runs. static CLRPH_ARCH GetClrPhArch(); // Imitialize Process Hacker's phlib internal data // Must be called before any other API (kinda like OleInitialize). static bool InitializePhLib(); // Return the list of knwown dll for this system static List^ GetKnownDlls(_In_ bool Wow64Dlls); static List^ KnownDll64List; static List^ KnownDll32List; // Return the Api Set schema: // NB: Api set resolution rely on hash buckets who // can contains more entries than this schema. static ApiSetSchema^ GetApiSetSchema(); }; public ref struct PeImport { UInt16 Hint; UInt16 Ordinal; String ^ Name; String ^ ModuleName; Boolean ImportByOrdinal; Boolean DelayImport; PeImport(const PPH_MAPPED_IMAGE_IMPORT_DLL importDll, size_t Index); PeImport(const PeImport ^ other); ~PeImport(); }; public ref struct PeImportDll { public: Int64 Flags; String ^Name; Int64 NumberOfEntries; List^ ImportList; // constructors PeImportDll(const PPH_MAPPED_IMAGE_IMPORTS &PvMappedImports, size_t ImportDllIndex); PeImportDll(const PeImportDll ^ other); // destructors ~PeImportDll(); // getters bool IsDelayLoad(); protected: !PeImportDll(); private: PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll; }; public ref struct PeExport { UInt16 Ordinal; String ^ Name; // may be NULL. Boolean ExportByOrdinal; Int64 VirtualAddress; String ^ ForwardedName; PeExport(); PeExport(const PeExport ^ other); ~PeExport(); static PeExport^ FromMapimg(const UnmanagedPE& refPe, size_t Index); }; public ref struct PeProperties { Int16 Machine; DateTime ^ Time; Int16 Magic; Int64 ImageBase; Int32 SizeOfImage; Int64 EntryPoint; Int32 Checksum; Boolean CorrectChecksum; Int16 Subsystem; Tuple ^SubsystemVersion; Int16 Characteristics; Int16 DllCharacteristics; UInt64 FileSize; }; // C# visible class representing a parsed PE file public ref class PE { public: PE(_In_ String^ Filepath); ~PE(); // Mapped the PE in memory and init infos bool Load(); // Unmapped the PE from memory void Unload(); // Check if the PE is 32-bit bool IsWow64Dll(); // Check if the PE is 32-bit bool IsArm32Dll(); // return the processorArchiture of PE String^ GetProcessor(); // Return the ApiSetSchema ApiSetSchema^ GetApiSetSchema(); // Return the list of functions exported by the PE List^ GetExports(); // Return the list of functions imported by the PE, bundled by Dll name List^ GetImports(); // Retrieve the manifest embedded within the PE // Return an empty string if there is none. String^ GetManifest(); // PE properties parsed from the NT header PeProperties ^Properties; // Check if the specified file has been successfully parsed as a PE file. Boolean LoadSuccessful; // Path to PE file. String^ Filepath; protected: // Deallocate the native object on the finalizer just in case no destructor is called !PE(); // Initalize PeProperties struct once the PE has been loaded into memory bool InitProperties(); private: // C++ part interfacing with phlib UnmanagedPE * m_Impl; // local cache for imports and exports list List^ m_Imports; List^ m_Exports; bool m_ExportsInit; bool m_ImportsInit; }; } } ================================================ FILE: ClrPhlib/include/NativeFile.h ================================================ // Native.h #pragma once #include #include #using using namespace System; namespace Dependencies { namespace ClrPh { // Partial rewrite of System.IO.File in order to circumvent the wow64 system folder redirection // that is not properly handled in .Net Core. public ref class NativeFile { public: // @return true if the path actually points to a file on the disk static bool Exists(_In_ String^ Path); static bool Exists(_In_ String^ Path, bool IsFolder); // Copy a filename to a new location static void Copy(_In_ String^ sourceFileName, _In_ String^ destFileName); // Hash the first FileSize bytes of a file, using SHA256. static String^ GetPartialHashFile(_In_ String^ Path, _In_ size_t FileSize); private: // Hash buffer using bcrypt library static bool HashBuffer(_In_ uint8_t *Buffer, _In_ size_t BufferSize, _In_ wchar_t *HASH_ALGORITHM, _Outptr_ void **Hash, _Out_ size_t *HashSize); // @return a hex string representing the buffer values, kinda like Python's binascii.hexlify static String^ GetHexString(_In_ uint8_t *Buffer, _In_ size_t BufferSize); // Ignore system32 folder redirection since we may analyzing 64-bit binaries on a 32-bit Dependencies static bool DisableWow64FsRedirection(); // revert redirection since it may have unpredictible results further down the line static bool RevertWow64FsRedirection(); }; } /* namespace ClrPh */ } /* namespace System */ ================================================ FILE: ClrPhlib/include/UnmanagedPh.h ================================================ #pragma once #include #include // C++ part of the PE class interfacing with phlib. // Responsible for mapping/unmapping the PE file in memory and // parse the NT headers and Directory entries. class UnmanagedPE { public: UnmanagedPE(); ~UnmanagedPE(); // Try to load the PE pointed by Filepath in memmory bool LoadPE(LPWSTR Filepath); // Unload the memory mapped PE in order to release the FS lock void UnloadPE(); // Extract the manifest embedded within the mapped PE // // /param manifest variable pointing to the part of the mapped file holding the manifest (no allocations here) // /param manifestLen variable returning the length of the embedded binary manifest // /return false if there is none bool GetPeManifest( _Out_ BYTE* *manifest, _Out_ INT *manifestLen ); PH_MAPPED_IMAGE m_PvMappedImage; PH_MAPPED_IMAGE_EXPORTS m_PvExports; PH_MAPPED_IMAGE_IMPORTS m_PvImports; PH_MAPPED_IMAGE_IMPORTS m_PvDelayImports; union { PIMAGE_LOAD_CONFIG_DIRECTORY32 m_PvConfig32; PIMAGE_LOAD_CONFIG_DIRECTORY64 m_PvCconfig64; }; private: bool m_bImageLoaded; }; ================================================ FILE: ClrPhlib/include/UnmanagedSymPrv.h ================================================ #pragma once #include #include #include #include // Native Symbol Provider class. // Allow the application to unmangle C and C++ mangled names. class UnmanagedSymPrv { public: // Initialize a new provider. static UnmanagedSymPrv* Create(); // Attempt to demangle a C/C++ name. Return false if the name is not mangled. bool DemangleName( _In_ wchar_t* DecoratedName, _In_ size_t DecoratedNameLen, _Out_ wchar_t** UndecoratedName, _Out_ size_t* UndecoratedNameLen, _Out_ Dependencies::ClrPh::CLRPH_DEMANGLER *Demangler ); public: PPH_SYMBOL_PROVIDER m_SymbolProvider; }; typedef bool(__cdecl *DemangleNameFn) (UnmanagedSymPrv*, wchar_t*, size_t, wchar_t**, size_t*); bool DemumbleDemangleName( _In_ UnmanagedSymPrv* obj, _In_ wchar_t* DecoratedName, _In_ size_t DecoratedNameLen, _Out_ wchar_t** UndecoratedName, _Out_ size_t* UndecoratedNameLen ); bool LLVMItaniumDemangleName( _In_ UnmanagedSymPrv* obj, _In_ wchar_t* DecoratedName, _In_ size_t DecoratedNameLen, _Out_ wchar_t** UndecoratedName, _Out_ size_t* UndecoratedNameLen ); bool LLVMMicrosoftDemangleName( _In_ UnmanagedSymPrv* obj, _In_ wchar_t* DecoratedName, _In_ size_t DecoratedNameLen, _Out_ wchar_t** UndecoratedName, _Out_ size_t* UndecoratedNameLen ); bool UndecorateSymbolDemangleName( _In_ UnmanagedSymPrv* obj, _In_ wchar_t* DecoratedName, _In_ size_t DecoratedNameLen, _Out_ wchar_t** UndecoratedName, _Out_ size_t* UndecoratedNameLen ); const DemangleNameFn Demanglers[] = { DemumbleDemangleName, // Undecorate name using demumble library LLVMItaniumDemangleName, // Undecorate name using llvm::itaniumDemangle library LLVMMicrosoftDemangleName, // Undecorate name using llvm::microsoftDemangle library UndecorateSymbolDemangleName // Undecorate name using UnDecorateSymbolNameW library }; ================================================ FILE: ClrPhlib/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by app.rc ================================================ FILE: ClrPhlib/src/managed/NativeFile.cpp ================================================ #include #include #include #include #include using namespace Dependencies; using namespace ClrPh; using namespace System::Text; static bool isCurrentProcessWow64 = CLRPH_ARCH::WOW64 == Phlib::GetClrPhArch(); static PVOID FsRedirectionValue = NULL; #define WITH_WOW64_FS_REDIRECTION_DISABLED(action) do { \ DisableWow64FsRedirection(); \ action \ RevertWow64FsRedirection(); \ } while (false) bool NativeFile::DisableWow64FsRedirection() { if (!isCurrentProcessWow64) return true; BOOL bWow64RedirectionDisabled = Wow64DisableWow64FsRedirection( &FsRedirectionValue ); return (bWow64RedirectionDisabled == TRUE); } bool NativeFile::RevertWow64FsRedirection() { if (!isCurrentProcessWow64) return true; BOOL bWow64RedirectionReverted = Wow64RevertWow64FsRedirection( FsRedirectionValue ); return (bWow64RedirectionReverted == TRUE); } bool NativeFile::Exists(_In_ String^ Path) { return NativeFile::Exists(Path, false); } bool NativeFile::Exists(_In_ String^ Path, bool IsFolder) { bool bFileExists = false; pin_ptr RawPath = PtrToStringChars(Path); WITH_WOW64_FS_REDIRECTION_DISABLED({ DWORD FileAttributes = GetFileAttributes(RawPath); //Console::WriteLine("FileAttributes: {0:x}", FileAttributes); bFileExists = (FileAttributes != INVALID_FILE_ATTRIBUTES); if (!IsFolder) { bFileExists &= !(FileAttributes & FILE_ATTRIBUTE_DIRECTORY); } }); return bFileExists; } void NativeFile::Copy(_In_ String^ sourceFileName, _In_ String^ destFileName) { bool bFileExists = false; PVOID OldRedirectionValue = NULL; BOOLEAN isWow64 = PhIsExecutingInWow64(); pin_ptr RawSourceFilepath = PtrToStringChars(sourceFileName); pin_ptr RawDestFilepath = PtrToStringChars(destFileName); WITH_WOW64_FS_REDIRECTION_DISABLED({ CopyFile( RawSourceFilepath, RawDestFilepath, false ); }); } String^ NativeFile::GetPartialHashFile(_In_ String^ Path, _In_ size_t FileSize) { bool read_success = false; bool success = false; void* hash = NULL; size_t hash_size = 0; HANDLE fileHandle = INVALID_HANDLE_VALUE; PVOID fileBuffer = NULL; ULONG FileSizeRead = 0; String^ PartialHash; pin_ptr RawPath = PtrToStringChars(Path); WITH_WOW64_FS_REDIRECTION_DISABLED({ fileHandle = CreateFile( RawPath, FILE_GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); }); if ((INVALID_HANDLE_VALUE == fileHandle)) goto CleanupExit; if (!(fileBuffer = malloc(FileSize))) goto CleanupExit; if (!ReadFile( fileHandle, fileBuffer, (DWORD) FileSize, &FileSizeRead, NULL )) goto CleanupExit; if (FileSizeRead != FileSize) goto CleanupExit; // hash it if (!HashBuffer((uint8_t *)fileBuffer, FileSize, BCRYPT_SHA256_ALGORITHM, &hash, &hash_size)) goto CleanupExit; // Convert to hex string PartialHash = GetHexString((uint8_t *)hash, hash_size); success = TRUE; CleanupExit: if (fileBuffer) free(fileBuffer); if (fileHandle) CloseHandle(fileHandle); if (hash) free(hash); if (!success) { return gcnew String(""); } return PartialHash; } bool NativeFile::HashBuffer(_In_ uint8_t *Buffer, _In_ size_t BufferSize, _In_ wchar_t *HASH_ALGORITHM, _Outptr_ void **Hash, _Out_ size_t *HashSize) { NTSTATUS status; BCRYPT_ALG_HANDLE hashAlgHandle = NULL; BCRYPT_HASH_HANDLE hashHandle = NULL; PVOID hash = NULL; PVOID hashObject = NULL; ULONG hashObjectSize = 0; ULONG hashSize = 0; ULONG querySize = 0; *Hash = NULL; *HashSize = 0; bool success = false; if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hashAlgHandle, HASH_ALGORITHM, NULL, 0))) goto CleanupExit; if (!NT_SUCCESS(status = BCryptGetProperty(hashAlgHandle, BCRYPT_OBJECT_LENGTH, (PUCHAR)&hashObjectSize, sizeof(ULONG), &querySize, 0))) goto CleanupExit; if (!NT_SUCCESS(status = BCryptGetProperty(hashAlgHandle, BCRYPT_HASH_LENGTH, (PUCHAR)&hashSize, sizeof(ULONG), &querySize, 0))) goto CleanupExit; if (!(hashObject = malloc(hashObjectSize))) goto CleanupExit; if (!(hash = malloc(hashSize))) goto CleanupExit; if (!NT_SUCCESS(status = BCryptCreateHash( hashAlgHandle, &hashHandle, (PUCHAR)hashObject, hashObjectSize, NULL, 0, 0 ))) goto CleanupExit; if (!NT_SUCCESS(status = BCryptHashData(hashHandle, (PUCHAR)Buffer, (ULONG)BufferSize, 0))) goto CleanupExit; if (!NT_SUCCESS(status = BCryptFinishHash(hashHandle, (PUCHAR)hash, hashSize, 0))) goto CleanupExit; *Hash = hash; *HashSize = hashSize; success = true; CleanupExit: if (!success) { if (hash) free(hash); } if (hashHandle) BCryptDestroyHash(hashHandle); if (hashAlgHandle) BCryptCloseAlgorithmProvider(hashAlgHandle, 0); if (hashObject) free(hashObject); return success; } String^ NativeFile::GetHexString(_In_ uint8_t *Buffer, _In_ size_t BufferSize) { ASCIIEncoding AsciiDecoder; array ^hexBuffer = gcnew array(2 * (int)BufferSize); for (ULONG i = 0; i < BufferSize; i++) { char hexNumber[2] = {0}; sprintf(hexNumber, "%02X", ((unsigned char*)Buffer)[i]); hexBuffer[2*i] = hexNumber[0]; hexBuffer[2*i + 1] = hexNumber[1]; } return AsciiDecoder.GetString(hexBuffer, 0, 2 * (int)BufferSize); } ================================================ FILE: ClrPhlib/src/managed/PE.cpp ================================================ #include #include using namespace Dependencies; using namespace System::Text; using namespace ClrPh; using namespace Runtime::InteropServices; PE::PE( _In_ String ^ Filepath ) { this->m_Impl = new UnmanagedPE(); this->Filepath = gcnew String(Filepath); this->LoadSuccessful = false; this->m_ExportsInit = false; this->m_ImportsInit = false; } PE::~PE() { Unload(); delete m_Impl; } PE::!PE() { Unload(); delete m_Impl; } bool PE::Load() { // Load PE as mapped section wchar_t* PvFilepath = (wchar_t*)(Marshal::StringToHGlobalUni(Filepath)).ToPointer(); this->LoadSuccessful = m_Impl->LoadPE(PvFilepath); Marshal::FreeHGlobal(IntPtr((void*)PvFilepath)); if (!LoadSuccessful) { return false; } // Parse PE LoadSuccessful &= InitProperties(); if (!LoadSuccessful) { m_Impl->UnloadPE(); return false; } return LoadSuccessful; } void PE::Unload() { if (LoadSuccessful) m_Impl->UnloadPE(); } bool PE::InitProperties() { LARGE_INTEGER time; SYSTEMTIME systemTime; PH_MAPPED_IMAGE PvMappedImage = m_Impl->m_PvMappedImage; Properties = gcnew PeProperties(); Properties->Machine = PvMappedImage.NtHeaders->FileHeader.Machine; Properties->Magic = m_Impl->m_PvMappedImage.Magic; Properties->Checksum = PvMappedImage.NtHeaders->OptionalHeader.CheckSum; Properties->CorrectChecksum = (Properties->Checksum == PhCheckSumMappedImage(&PvMappedImage)); RtlSecondsSince1970ToTime(PvMappedImage.NtHeaders->FileHeader.TimeDateStamp, &time); PhLargeIntegerToLocalSystemTime(&systemTime, &time); Properties->Time = gcnew DateTime (systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds, DateTimeKind::Local); if (PvMappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { PIMAGE_OPTIONAL_HEADER32 OptionalHeader = (PIMAGE_OPTIONAL_HEADER32) &PvMappedImage.NtHeaders->OptionalHeader; Properties->ImageBase = (Int64) OptionalHeader->ImageBase; Properties->SizeOfImage = OptionalHeader->SizeOfImage; Properties->EntryPoint = (Int64) OptionalHeader->AddressOfEntryPoint; } else { PIMAGE_OPTIONAL_HEADER64 OptionalHeader = (PIMAGE_OPTIONAL_HEADER64)&PvMappedImage.NtHeaders->OptionalHeader; Properties->ImageBase = (Int64)OptionalHeader->ImageBase; Properties->SizeOfImage = OptionalHeader->SizeOfImage; Properties->EntryPoint = (Int64)OptionalHeader->AddressOfEntryPoint; } Properties->Subsystem = PvMappedImage.NtHeaders->OptionalHeader.Subsystem; Properties->SubsystemVersion = gcnew Tuple( PvMappedImage.NtHeaders->OptionalHeader.MajorSubsystemVersion, PvMappedImage.NtHeaders->OptionalHeader.MinorSubsystemVersion); Properties->Characteristics = PvMappedImage.NtHeaders->FileHeader.Characteristics; Properties->DllCharacteristics = PvMappedImage.NtHeaders->OptionalHeader.DllCharacteristics; Properties->FileSize = PvMappedImage.Size; return true; } Collections::Generic::List ^ PE::GetExports() { if (m_ExportsInit) return m_Exports; m_ExportsInit = true; m_Exports = gcnew Collections::Generic::List(); if (!LoadSuccessful) return m_Exports; if (NT_SUCCESS(PhGetMappedImageExports(&m_Impl->m_PvExports, &m_Impl->m_PvMappedImage))) { for (size_t Index = 0; Index < m_Impl->m_PvExports.NumberOfEntries; Index++) { PeExport^ exp = PeExport::FromMapimg(*m_Impl, Index); if (exp) { m_Exports->Add(exp); } } } return m_Exports; } Collections::Generic::List ^ PE::GetImports() { if (m_ImportsInit) return m_Imports; m_ImportsInit = true; m_Imports = gcnew Collections::Generic::List(); if (!LoadSuccessful) return m_Imports; // Standard Imports if (NT_SUCCESS(PhGetMappedImageImports(&m_Impl->m_PvImports, &m_Impl->m_PvMappedImage))) { for (size_t IndexDll = 0; IndexDll< m_Impl->m_PvImports.NumberOfDlls; IndexDll++) { m_Imports->Add(gcnew PeImportDll(&m_Impl->m_PvImports, IndexDll)); } } // Delayed Imports if (NT_SUCCESS(PhGetMappedImageDelayImports(&m_Impl->m_PvDelayImports, &m_Impl->m_PvMappedImage))) { for (size_t IndexDll = 0; IndexDll< m_Impl->m_PvDelayImports.NumberOfDlls; IndexDll++) { m_Imports->Add(gcnew PeImportDll(&m_Impl->m_PvDelayImports, IndexDll)); } } return m_Imports; } String^ PE::GetManifest() { if (!LoadSuccessful) return gcnew String(""); // Extract embedded manifest INT rawManifestLen; BYTE* rawManifest; if (!m_Impl->GetPeManifest(&rawManifest, &rawManifestLen)) return gcnew String(""); // Converting to wchar* and passing it to a C#-recognized String object UTF8Encoding Utf8Decoder; array ^buffer = gcnew array(rawManifestLen + 1); for (int i = 0; i < rawManifestLen; i++) { buffer[i] = rawManifest[i]; } buffer[rawManifestLen] = 0; return Utf8Decoder.GetString(buffer, 0, rawManifestLen); } bool PE::IsWow64Dll() { return ((Properties->Machine & 0xffff ) == IMAGE_FILE_MACHINE_I386); } bool PE::IsArm32Dll() { return ((Properties->Machine & 0xffff) == IMAGE_FILE_MACHINE_ARMNT); } String^ PE::GetProcessor() { if ((Properties->Machine & 0xffff) == IMAGE_FILE_MACHINE_I386) return gcnew String("x86"); if ((Properties->Machine & 0xffff) == IMAGE_FILE_MACHINE_ARMNT) return gcnew String("arm"); if ((Properties->Machine & 0xffff) == IMAGE_FILE_MACHINE_ARM64) return gcnew String("arm64"); return gcnew String("unknown"); } ================================================ FILE: ClrPhlib/src/managed/PeExport.cpp ================================================ #include #include using namespace Dependencies; using namespace ClrPh; PeExport::PeExport( ) { } PeExport^ PeExport::FromMapimg ( _In_ const UnmanagedPE &refPe, _In_ size_t Index ) { PH_MAPPED_IMAGE_EXPORT_ENTRY exportEntry; PH_MAPPED_IMAGE_EXPORT_FUNCTION exportFunction; PeExport^ exp = nullptr; if ( NT_SUCCESS(PhGetMappedImageExportEntry((PPH_MAPPED_IMAGE_EXPORTS)&refPe.m_PvExports, (ULONG) Index, &exportEntry)) && NT_SUCCESS(PhGetMappedImageExportFunction((PPH_MAPPED_IMAGE_EXPORTS)&refPe.m_PvExports, NULL, exportEntry.Ordinal, &exportFunction)) ) { exp = gcnew PeExport(); exp->Ordinal = exportEntry.Ordinal; exp->ExportByOrdinal = (exportEntry.Name == nullptr); exp->Name = gcnew String(exportEntry.Name); exp->ForwardedName = gcnew String(exportFunction.ForwardedName); if (exportEntry.Name == nullptr) exp->VirtualAddress = (Int64)exportFunction.Function; exp->VirtualAddress = (Int64) exportFunction.Function; } return exp; } PeExport::PeExport( _In_ const PeExport ^ other ) { this->Ordinal = Ordinal; this->ExportByOrdinal = ExportByOrdinal; this->Name = String::Copy(other->Name); this->ForwardedName = String::Copy(other->ForwardedName); this->VirtualAddress = other->VirtualAddress; } PeExport::~PeExport() { } ================================================ FILE: ClrPhlib/src/managed/PeImport.cpp ================================================ #include #include using namespace Dependencies; using namespace ClrPh; PeImport::PeImport( _In_ const PPH_MAPPED_IMAGE_IMPORT_DLL importDll, _In_ size_t Index ) { PH_MAPPED_IMAGE_IMPORT_ENTRY importEntry; if (NT_SUCCESS(PhGetMappedImageImportEntry((PPH_MAPPED_IMAGE_IMPORT_DLL) importDll, (ULONG)Index, &importEntry))) { this->Hint = importEntry.NameHint; this->Ordinal = importEntry.Ordinal; this->DelayImport = (importDll->Flags) & PH_MAPPED_IMAGE_DELAY_IMPORTS; this->Name = gcnew String(importEntry.Name); this->ModuleName = gcnew String(importDll->Name); this->ImportByOrdinal = (importEntry.Name == nullptr); } } PeImport::PeImport( _In_ const PeImport ^ other ) { this->Hint = other->Hint; this->Ordinal = other->Ordinal; this->DelayImport = other->DelayImport; this->Name = String::Copy(other->Name); this->ModuleName = String::Copy(other->ModuleName); this->ImportByOrdinal = other->ImportByOrdinal; } PeImport::~PeImport() { } PeImportDll::PeImportDll( _In_ const PPH_MAPPED_IMAGE_IMPORTS &PvMappedImports, _In_ size_t ImportDllIndex ) : ImportDll (new PH_MAPPED_IMAGE_IMPORT_DLL) { ImportList = gcnew Collections::Generic::List(); if (!NT_SUCCESS(PhGetMappedImageImportDll(PvMappedImports, (ULONG)ImportDllIndex, ImportDll))) { Flags = 0; Name = gcnew String("## PeImportDll error: Invalid DllName ##"); NumberOfEntries = 0; return; } Flags = ImportDll->Flags; Name = gcnew String(ImportDll->Name); NumberOfEntries = ImportDll->NumberOfEntries; for (size_t IndexImport = 0; IndexImport < (size_t) NumberOfEntries; IndexImport++) { ImportList->Add(gcnew PeImport(ImportDll, IndexImport)); } } PeImportDll::~PeImportDll() { delete ImportDll; } PeImportDll::!PeImportDll() { delete ImportDll; } PeImportDll::PeImportDll( _In_ const PeImportDll ^ other ) : ImportDll(new PH_MAPPED_IMAGE_IMPORT_DLL) { ImportList = gcnew Collections::Generic::List(); memcpy(ImportDll, other->ImportDll, sizeof(PH_MAPPED_IMAGE_IMPORT_DLL)); Flags = other->Flags; Name = String::Copy(other->Name); NumberOfEntries = other->NumberOfEntries; for (size_t IndexImport = 0; IndexImport < (size_t)NumberOfEntries; IndexImport++) { ImportList->Add(gcnew PeImport(other->ImportList[(int) IndexImport])); } } bool PeImportDll::IsDelayLoad() { return this->Flags & PH_MAPPED_IMAGE_DELAY_IMPORTS; } ================================================ FILE: ClrPhlib/src/managed/PhSymbolProvider.cpp ================================================ #include #include #include using namespace Dependencies; using namespace ClrPh; using namespace Runtime::InteropServices; PhSymbolProvider::PhSymbolProvider() :m_Impl(UnmanagedSymPrv::Create()) { } PhSymbolProvider::~PhSymbolProvider() { if (m_Impl) { delete m_Impl; } } PhSymbolProvider::!PhSymbolProvider() { if (m_Impl) { delete m_Impl; } } String^ PhSymbolProvider::UndecorateNameDemumble( _In_ String ^DecoratedName ) { return UndecorateNamePrv(DecoratedName, DemumbleDemangleName); } String^ PhSymbolProvider::UndecorateNameLLVMItanium(_In_ String ^DecoratedName) { return UndecorateNamePrv(DecoratedName, LLVMItaniumDemangleName); } String^ PhSymbolProvider::UndecorateNameLLVMMicrosoft(_In_ String ^DecoratedName) { return UndecorateNamePrv(DecoratedName, LLVMMicrosoftDemangleName); } String^ PhSymbolProvider::UndecorateNamePh(_In_ String ^DecoratedName) { return UndecorateNamePrv(DecoratedName, UndecorateSymbolDemangleName); } Tuple^ PhSymbolProvider::UndecorateName(_In_ String ^DecoratedName) { String ^ManagedUndName; wchar_t* UndecoratedName = NULL; size_t UndecoratedNameLen = 0; CLRPH_DEMANGLER Demangler = CLRPH_DEMANGLER::None; if (!m_Impl || !DecoratedName || DecoratedName->Length == 0) { return gcnew Tuple (Demangler, gcnew String("")); } wchar_t* PvDecoratedName = (wchar_t*)(Marshal::StringToHGlobalUni(DecoratedName)).ToPointer(); size_t PvDecoratedNameLen = wcslen(PvDecoratedName); if (m_Impl->DemangleName( PvDecoratedName, PvDecoratedNameLen, &UndecoratedName, &UndecoratedNameLen, &Demangler )) { ManagedUndName = gcnew String(UndecoratedName); } else { ManagedUndName = gcnew String(""); } if (UndecoratedName) { free(UndecoratedName); } if (PvDecoratedName) { Marshal::FreeHGlobal(IntPtr((void*)PvDecoratedName)); } return gcnew Tuple(Demangler, ManagedUndName); } String^ PhSymbolProvider::UndecorateNamePrv( _In_ String ^DecoratedName, _In_ DemangleNameFn Demangler ) { String ^ManagedUndName; wchar_t* UndecoratedName = NULL; size_t UndecoratedNameLen = 0; if (!m_Impl || DecoratedName->Length == 0) { return gcnew String(""); } wchar_t* PvDecoratedName = (wchar_t*)(Marshal::StringToHGlobalUni(DecoratedName)).ToPointer(); size_t PvDecoratedNameLen = wcslen(PvDecoratedName); if (Demangler( this->m_Impl, PvDecoratedName, PvDecoratedNameLen, &UndecoratedName, &UndecoratedNameLen )) { ManagedUndName = gcnew String(UndecoratedName); } else { ManagedUndName = gcnew String(""); } if (UndecoratedName) { free(UndecoratedName); } if (PvDecoratedName) { Marshal::FreeHGlobal(IntPtr((void*)PvDecoratedName)); } return ManagedUndName; } ================================================ FILE: ClrPhlib/src/managed/Phlib.cpp ================================================ #include #include #include #include #include using namespace Dependencies; using namespace ClrPh; // Private : build the known dlls list List^ BuildKnownDllList(_In_ bool Wow64Dlls); static bool bInitializedPhLib = false; bool Phlib::InitializePhLib() { if (!bInitializedPhLib) { bInitializedPhLib = NT_SUCCESS(PhInitializePhLib()); } KnownDll64List = BuildKnownDllList(false); KnownDll32List = BuildKnownDllList(true); return bInitializedPhLib; } BOOLEAN NTAPI PhEnumDirectoryObjectsCallback( _In_ PPH_STRINGREF Name, _In_ PPH_STRINGREF TypeName, _In_opt_ PVOID Context ) { static PH_STRINGREF SectionTypeName = PH_STRINGREF_INIT(L"Section"); List^ ReturnList = ((List^*) Context)[0]; if (!PhCompareStringRef(&SectionTypeName, TypeName, TRUE)) { ReturnList->Add(gcnew String(Name->Buffer)); } return TRUE; } List^ BuildKnownDllList(_In_ bool Wow64Dlls) { List^ ReturnList = gcnew List(); HANDLE KnownDllDir = INVALID_HANDLE_VALUE; OBJECT_ATTRIBUTES oa; UNICODE_STRING name; NTSTATUS status; const PWCHAR KnownDllObjectName = (Wow64Dlls) ? L"\\KnownDlls32" : L"\\KnownDlls"; name.Length = (USHORT) wcslen(KnownDllObjectName) * sizeof(wchar_t); name.MaximumLength = (USHORT) wcslen(KnownDllObjectName) * sizeof(wchar_t); name.Buffer = KnownDllObjectName; InitializeObjectAttributes( &oa, &name, 0, NULL, NULL ); status = NtOpenDirectoryObject( &KnownDllDir, DIRECTORY_QUERY, &oa ); if (!NT_SUCCESS(status)) { return ReturnList; } status = PhEnumDirectoryObjects( KnownDllDir, (PPH_ENUM_DIRECTORY_OBJECTS) PhEnumDirectoryObjectsCallback, (PVOID) &ReturnList ); if (!NT_SUCCESS(status)) { return ReturnList; } ReturnList->Sort(); return ReturnList; } List^ Phlib::GetKnownDlls(_In_ bool Wow64Dlls) { if (Wow64Dlls){ return Phlib::KnownDll32List; } return Phlib::KnownDll64List; } #ifdef __cplusplus extern "C" { #endif PAPI_SET_NAMESPACE GetApiSetNamespace() { ULONG ReturnLength; PROCESS_BASIC_INFORMATION ProcessInformation; PAPI_SET_NAMESPACE apiSetMap = NULL; // Retrieve PEB address if (!NT_SUCCESS(NtQueryInformationProcess( GetCurrentProcess(), ProcessBasicInformation, &ProcessInformation, sizeof(PROCESS_BASIC_INFORMATION), &ReturnLength ))) { return NULL; } // Parsing PEB structure and locating api set map PPEB peb = static_cast(ProcessInformation.PebBaseAddress); apiSetMap = static_cast(peb->ApiSetMap); return apiSetMap; } #ifdef __cplusplus } #endif struct ApiSetSchemaImpl { static ApiSetSchema^ ParseApiSetSchema(API_SET_NAMESPACE const * apiSetMap); private: // private implementation of ApiSet schema parsing static ApiSetSchema^ GetApiSetSchemaV2(API_SET_NAMESPACE_V2 const * map); static ApiSetSchema^ GetApiSetSchemaV4(API_SET_NAMESPACE_V4 const * map); static ApiSetSchema^ GetApiSetSchemaV6(API_SET_NAMESPACE_V6 const * map); }; private ref class EmptyApiSetSchema sealed : ApiSetSchema { public: List>^ GetAll() override { return gcnew List>(); } ApiSetTarget^ Lookup(String^) override { return nullptr; } }; private ref class V2V4ApiSetSchema sealed : ApiSetSchema { public: List>^ const All = gcnew List>(); List>^ GetAll() override { return All; } ApiSetTarget^ Lookup(String^ name) override { // TODO : check if ext- is not present on win7 and 8.1 if (!name->StartsWith("api-", System::StringComparison::CurrentCultureIgnoreCase)) return nullptr; // Force lowercase name name = name->ToLower(); // remove "api-" or "ext-" prefix name = name->Substring(4); // Note: The list is initially alphabetically sorted!!! auto min = 0; auto max = All->Count - 1; while (min <= max) { auto const cur = (min + max) / 2; auto pair = All[cur]; if (name->StartsWith(pair.Key, System::StringComparison::CurrentCultureIgnoreCase)) return pair.Value; if (String::CompareOrdinal(name, pair.Key) < 0) max = cur - 1; else min = cur + 1; } return nullptr; } }; ApiSetSchema^ ApiSetSchemaImpl::GetApiSetSchemaV2(API_SET_NAMESPACE_V2 const * const map) { auto const base = reinterpret_cast(map); auto const schema = gcnew V2V4ApiSetSchema(); for (auto it = map->Array, eit = it + map->Count; it < eit; ++it) { // Retrieve DLLs names implementing the contract auto const targets = gcnew ApiSetTarget(); auto const value_entry = reinterpret_cast(base + it->DataOffset); for (auto it2 = value_entry->Redirections, eit2 = it2 + value_entry->NumberOfRedirections; it2 < eit2; ++it2) { auto const value_buffer = reinterpret_cast(base + it2->ValueOffset); auto const value = gcnew String(value_buffer, 0, it2->ValueLength / sizeof(WCHAR)); targets->Add(value); } // Retrieve api min-win contract name auto const name_buffer = reinterpret_cast(base + it->NameOffset); auto const name = gcnew String(name_buffer, 0, it->NameLength / sizeof(WCHAR)); // force storing lowercase variant for comparison auto const lower_name = name->ToLower(); schema->All->Add(KeyValuePair(lower_name, targets)); } return schema; } ApiSetSchema^ ApiSetSchemaImpl::GetApiSetSchemaV4(API_SET_NAMESPACE_V4 const * const map) { auto const base = reinterpret_cast(map); auto const schema = gcnew V2V4ApiSetSchema(); for (auto it = map->Array, eit = it + map->Count; it < eit; ++it) { // Retrieve DLLs names implementing the contract auto const targets = gcnew ApiSetTarget(); auto const value_entry = reinterpret_cast(base + it->DataOffset); for (auto it2 = value_entry->Redirections, eit2 = it2 + value_entry->NumberOfRedirections; it2 < eit2; ++it2) { auto const value_buffer = reinterpret_cast(base + it2->ValueOffset); auto const value = gcnew String(value_buffer, 0, it2->ValueLength / sizeof(WCHAR)); targets->Add(value); } // Retrieve api min-win contract name auto const name_buffer = reinterpret_cast(base + it->NameOffset); auto const name = gcnew String(name_buffer, 0, it->NameLength / sizeof(WCHAR)); // force storing lowercase variant for comparison auto const lower_name = name->ToLower(); schema->All->Add(KeyValuePair(lower_name, targets)); } return schema; } private ref class V6ApiSetSchema sealed : ApiSetSchema { public: List>^ const All = gcnew List>(); List>^ HashedAll = gcnew List>(); List>^ GetAll() override { return All; } ApiSetTarget^ Lookup(String^ name) override { // Force lowercase name name = name->ToLower(); // Note: The list is initially alphabetically sorted!!! auto min = 0; auto max = HashedAll->Count - 1; while (min <= max) { auto const cur = (min + max) / 2; auto pair = HashedAll[cur]; if (name->StartsWith(pair.Key, System::StringComparison::CurrentCultureIgnoreCase)) return pair.Value; if (String::CompareOrdinal(name, pair.Key) < 0) max = cur - 1; else min = cur + 1; } return nullptr; } }; ApiSetSchema^ ApiSetSchemaImpl::GetApiSetSchemaV6(API_SET_NAMESPACE_V6 const * const map) { auto const base = reinterpret_cast(map); auto const schema = gcnew V6ApiSetSchema(); for (auto it = reinterpret_cast(map->EntryOffset + base), eit = it + map->Count; it < eit; ++it) { // Iterate over all the host dll for this contract auto const targets = gcnew ApiSetTarget(); for (auto it2 = static_cast<_API_SET_VALUE_ENTRY_V6*const>(reinterpret_cast(base + it->ValueOffset)), eit2 = it2 + it->ValueCount; it2 < eit2; ++it2) { // Retrieve DLLs name implementing the contract auto const value_buffer = reinterpret_cast(base + it2->ValueOffset); auto const value = gcnew String(value_buffer, 0, it2->ValueLength / sizeof(WCHAR)); targets->Add(value); } // Retrieve api min-win contract name auto const name_buffer = reinterpret_cast(base + it->NameOffset); auto const name = gcnew String(name_buffer, 0, it->NameLength / sizeof(WCHAR)); auto const hash_name = gcnew String(name_buffer, 0, it->HashedLength / sizeof(WCHAR)); // force storing lowercase variant for comparison auto const lower_name = name->ToLower(); auto const lower_hash_name = hash_name->ToLower(); schema->All->Add(KeyValuePair(lower_name, targets)); schema->HashedAll->Add(KeyValuePair(lower_hash_name, targets)); } return schema; } ApiSetSchema^ Phlib::GetApiSetSchema() { // Api set schema resolution adapted from https://github.com/zodiacon/WindowsInternals/blob/master/APISetMap/APISetMap.cpp // References : // * Windows Internals v7 // * @aionescu's slides on "Hooking Nirvana" (RECON 2015) // * Quarkslab blog posts : // https://blog.quarkslab.com/runtime-dll-name-resolution-apisetschema-part-i.html // https://blog.quarkslab.com/runtime-dll-name-resolution-apisetschema-part-ii.html return ApiSetSchemaImpl::ParseApiSetSchema(GetApiSetNamespace()); } ApiSetSchema^ PE::GetApiSetSchema() { PH_MAPPED_IMAGE mappedImage = m_Impl->m_PvMappedImage; for (auto n = 0u; n < mappedImage.NumberOfSections; ++n) { IMAGE_SECTION_HEADER const & section = mappedImage.Sections[n]; if (strncmp(".apiset", reinterpret_cast(section.Name), IMAGE_SIZEOF_SHORT_NAME) == 0) return ApiSetSchemaImpl::ParseApiSetSchema(reinterpret_cast(PTR_ADD_OFFSET(mappedImage.ViewBase, section.PointerToRawData))); } return gcnew EmptyApiSetSchema(); } ApiSetSchema^ ApiSetSchemaImpl::ParseApiSetSchema(API_SET_NAMESPACE const * const apiSetMap) { // Check the returned api namespace is correct if (!apiSetMap) return gcnew EmptyApiSetSchema(); switch (apiSetMap->Version) { case 2: // Win7 return GetApiSetSchemaV2(&apiSetMap->ApiSetNameSpaceV2); case 4: // Win8.1 return GetApiSetSchemaV4(&apiSetMap->ApiSetNameSpaceV4); case 6: // Win10 return GetApiSetSchemaV6(&apiSetMap->ApiSetNameSpaceV6); default: // unsupported return gcnew EmptyApiSetSchema(); } } ================================================ FILE: ClrPhlib/src/unmanaged/UnmanagedPE.cpp ================================================ #include #include #include using namespace System; using namespace Dependencies::ClrPh; UnmanagedPE::UnmanagedPE() :m_bImageLoaded(false) { memset(&m_PvMappedImage, 0, sizeof(PH_MAPPED_IMAGE)); } UnmanagedPE::~UnmanagedPE() { UnloadPE(); } bool UnmanagedPE::LoadPE(LPWSTR Filepath) { if (m_bImageLoaded) { PhUnloadMappedImage(&m_PvMappedImage); } memset(&m_PvMappedImage, 0, sizeof(PH_MAPPED_IMAGE)); m_bImageLoaded = NT_SUCCESS(PhLoadMappedImage( Filepath, NULL, TRUE, &m_PvMappedImage )); return m_bImageLoaded; } void UnmanagedPE::UnloadPE() { if (m_bImageLoaded) { PhUnloadMappedImage(&m_PvMappedImage); m_bImageLoaded = false; } } bool UnmanagedPE::GetPeManifest( _Out_ BYTE* *manifest, _Out_ INT *manifestLen ) { PH_MAPPED_IMAGE_RESOURCES resources; bool manifestFound = false; if (!m_bImageLoaded) return false; if (!NT_SUCCESS(PhGetMappedImageResources(&resources, &m_PvMappedImage))) return false; *manifest = NULL; *manifestLen = 0; for (ULONG i = 0; i < resources.NumberOfEntries; i++) { PH_IMAGE_RESOURCE_ENTRY entry; entry = resources.ResourceEntries[i]; if (entry.Type == (ULONG_PTR) RT_MANIFEST) { // Manifest entry is utf-8 only *manifest = (BYTE*)entry.Data; *manifestLen = entry.Size; manifestFound = true; } // stops on first manifest found if (manifestFound) break; } PhFree(resources.ResourceEntries); return manifestFound; } ================================================ FILE: ClrPhlib/src/unmanaged/UnmanagedSymPrv.cpp ================================================ #include using namespace System; using namespace Dependencies::ClrPh; #define DBGHELP_RELPATH VOID PvpGetDefaultPathForDbgHelp( _Inout_ PWSTR DefaultDbgHelpPath ) { #if _WIN64 wsprintf((LPWSTR)DefaultDbgHelpPath, L"%s%s", _wgetenv(L"ProgramFiles"), L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll"); #define DBGHELP_PATH _wgetenv(L"ProgramFiles") L"" DBGHELP_RELPATH #else if (PhIsExecutingInWow64()) { wsprintf((LPWSTR)DefaultDbgHelpPath, L"%s%s", _wgetenv(L"ProgramFiles(x86)"), L"\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll"); } else { wsprintf((LPWSTR)DefaultDbgHelpPath, L"%s%s", _wgetenv(L"ProgramFiles"), L"\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll"); } #endif // _WIN64 } /*! @brief PhLoadLibrarySafe prevents the loader from searching in an unsafe order by first requiring the loader try to load and resolve through System32. Then upping the loading flags until the library is loaded. @param[in] LibFileName - The file name of the library to load. @return HMODULE to the library on success, null on failure. */ _Ret_maybenull_ PVOID PhLoadLibrarySafe( _In_ PCWSTR LibFileName ) { PVOID baseAddress; // // Force LOAD_LIBRARY_SEARCH_SYSTEM32. If the library file name is a fully // qualified path this will succeed. // baseAddress = LoadLibraryExW(LibFileName, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); if (baseAddress) { return baseAddress; } // // Include the application directory now. // return LoadLibraryExW(LibFileName, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_APPLICATION_DIR); } VOID PvpLoadDbgHelpFromPath( _In_ PWSTR DbgHelpPath ) { HMODULE dbghelpModule; // try to load from windows kits installed on the machine dbghelpModule = LoadLibrary(DbgHelpPath); // try system32, and then current dir if (!dbghelpModule) { dbghelpModule = (HMODULE) PhLoadLibrarySafe(L"dbghelp.dll"); } // try to load symsrv.dll from the same folder as dbghelp.dll if (dbghelpModule) { PPH_STRING fullDbghelpPath; ULONG indexOfFileName; PH_STRINGREF dbghelpFolder; PPH_STRING symsrvPath; fullDbghelpPath = PhGetDllFileName(dbghelpModule, &indexOfFileName); if (fullDbghelpPath) { if (indexOfFileName != 0) { static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll"); dbghelpFolder.Buffer = fullDbghelpPath->Buffer; dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR); symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString); LoadLibrary(symsrvPath->Buffer); PhDereferenceObject(symsrvPath); } PhDereferenceObject(fullDbghelpPath); } PhSymbolProviderCompleteInitialization(dbghelpModule); } //else //{ // dbghelpModule = LoadLibrary(L"dbghelp.dll"); //} /*PhSymbolProviderCompleteInitialization(dbghelpModule);*/ } BOOLEAN PvpLoadDbgHelp( _Inout_ PPH_SYMBOL_PROVIDER *SymbolProvider ) { static UNICODE_STRING symbolPathVarName = RTL_CONSTANT_STRING(L"_NT_SYMBOL_PATH"); PPH_STRING symbolSearchPath; PPH_SYMBOL_PROVIDER symbolProvider; WCHAR buffer[MAX_PATH] = L""; UNICODE_STRING symbolPathUs; const wchar_t DefaultDbgHelpPath[MAX_PATH] = { 0 }; symbolPathUs.Buffer = buffer; symbolPathUs.Length = sizeof(buffer) - sizeof(UNICODE_NULL); symbolPathUs.MaximumLength = sizeof(buffer); if (!PhSymbolProviderInitialization()) return FALSE; PvpGetDefaultPathForDbgHelp((PWSTR)DefaultDbgHelpPath); PvpLoadDbgHelpFromPath((PWSTR)DefaultDbgHelpPath); symbolProvider = PhCreateSymbolProvider(NULL); // Load symbol path from _NT_SYMBOL_PATH if configured by the user. if (NT_SUCCESS(RtlQueryEnvironmentVariable_U(NULL, &symbolPathVarName, &symbolPathUs))) { symbolSearchPath = PhFormatString(L"SRV*%s*http://msdl.microsoft.com/download/symbols", symbolPathUs.Buffer); } else { symbolSearchPath = PhCreateString(L"SRV**http://msdl.microsoft.com/download/symbols"); } PhSetSearchPathSymbolProvider(symbolProvider, symbolSearchPath->Buffer); PhDereferenceObject(symbolSearchPath); *SymbolProvider = symbolProvider; return TRUE; } UnmanagedSymPrv* UnmanagedSymPrv::Create() { UnmanagedSymPrv *Instance = new UnmanagedSymPrv; if (!PvpLoadDbgHelp(&Instance->m_SymbolProvider)) { delete Instance; return NULL; } return Instance; } ================================================ FILE: ClrPhlib/src/unmanaged/demangle.cpp ================================================ #include #include #include #using extern "C" { char* __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status); } #define DEMANGLER_DEBUGLOG_ON (false) #define DEMANGLER_DEBUGLOG_CAT ("demangler") #define DEMANGLER_DEBUGLOG_ONE (DemanglerDebugOneArg) #define DEMANGLER_DEBUGLOG_TWO (DemanglerDebugTwoArg) void DemanglerDebugOneArg(wchar_t *Format, wchar_t *Arg0) { if (!DEMANGLER_DEBUGLOG_ON) return; do { System::Diagnostics::Debug::WriteLine( System::String::Format( gcnew System::String(Format), gcnew System::String(Arg0) ), gcnew System::String(DEMANGLER_DEBUGLOG_CAT) ); } while (false); } void DemanglerDebugTwoArg(wchar_t *Format, wchar_t *Arg0, wchar_t *Arg1) { if (!DEMANGLER_DEBUGLOG_ON) return; do { System::Diagnostics::Debug::WriteLine( System::String::Format( gcnew System::String(Format), gcnew System::String(Arg0), gcnew System::String(Arg1) ), gcnew System::String(DEMANGLER_DEBUGLOG_CAT) ); } while (false); } bool DemumbleDemangleName( _In_ UnmanagedSymPrv* obj, _In_ wchar_t* DecoratedName, _In_ size_t DecoratedNameLen, _Out_ wchar_t** UndecoratedName, _Out_ size_t* UndecoratedNameLen ) { size_t NameLen; int status; size_t MbstowcsStatus = 0; char *AsciiUndecoratedName = NULL; char *DecoratedNameAscii = (char*)malloc(DecoratedNameLen + 1); sprintf_s(DecoratedNameAscii, DecoratedNameLen + 1, "%ws", DecoratedName); if ((!UndecoratedName) || (!UndecoratedNameLen)) { return false; } *UndecoratedNameLen = 0; NameLen = DecoratedNameLen; AsciiUndecoratedName = __cxa_demangle( DecoratedNameAscii, NULL, &NameLen, &status ); if (!status) { *UndecoratedName = (wchar_t*)malloc(NameLen * sizeof(wchar_t) + sizeof(wchar_t)); mbstowcs_s( &MbstowcsStatus, *UndecoratedName, NameLen, AsciiUndecoratedName, NameLen ); *UndecoratedNameLen = NameLen * sizeof(wchar_t); } free(DecoratedNameAscii); // UNIX-style error code return status == 0; } bool LLVMItaniumDemangleName( _In_ UnmanagedSymPrv* obj, _In_ wchar_t* DecoratedName, _In_ size_t DecoratedNameLen, _Out_ wchar_t** UndecoratedName, _Out_ size_t* UndecoratedNameLen ) { size_t NameLen; int status; size_t MbstowcsStatus = 0; char *AsciiUndecoratedName = NULL; char *DecoratedNameAscii = (char*)malloc(DecoratedNameLen + 1); sprintf_s(DecoratedNameAscii, DecoratedNameLen + 1, "%ws", DecoratedName); if ((!UndecoratedName) || (!UndecoratedNameLen)) { return false; } *UndecoratedNameLen = 0; NameLen = DecoratedNameLen; AsciiUndecoratedName = llvm::itaniumDemangle( DecoratedNameAscii, nullptr, &NameLen, &status ); if (!status) { *UndecoratedName = (wchar_t*)malloc(NameLen * sizeof(wchar_t) + sizeof(wchar_t)); mbstowcs_s( &MbstowcsStatus, *UndecoratedName, NameLen, AsciiUndecoratedName, NameLen ); *UndecoratedNameLen = NameLen * sizeof(wchar_t); } free(DecoratedNameAscii); // UNIX-style error code return status == 0; } bool LLVMMicrosoftDemangleName( _In_ UnmanagedSymPrv* obj, _In_ wchar_t* DecoratedName, _In_ size_t DecoratedNameLen, _Out_ wchar_t** UndecoratedName, _Out_ size_t* UndecoratedNameLen ) { size_t NameLen; int status; size_t MbstowcsStatus = 0; char *AsciiUndecoratedName = NULL; char *DecoratedNameAscii = (char*)malloc(DecoratedNameLen + 1); sprintf_s(DecoratedNameAscii, DecoratedNameLen + 1, "%ws", DecoratedName); if ((!UndecoratedName) || (!UndecoratedNameLen)) { return false; } *UndecoratedNameLen = 0; NameLen = DecoratedNameLen; AsciiUndecoratedName = llvm::microsoftDemangle( DecoratedNameAscii, nullptr, &NameLen, &status ); if (!status) { *UndecoratedName = (wchar_t*)malloc(NameLen * sizeof(wchar_t) + sizeof(wchar_t)); mbstowcs_s( &MbstowcsStatus, *UndecoratedName, NameLen, AsciiUndecoratedName, NameLen ); *UndecoratedNameLen = NameLen * sizeof(wchar_t); } free(DecoratedNameAscii); // UNIX-style error code return status == 0; } bool UndecorateSymbolDemangleName( _In_ UnmanagedSymPrv* obj, _In_ wchar_t* DecoratedName, _In_ size_t DecoratedNameLen, _Out_ wchar_t** UndecoratedName, _Out_ size_t* UndecoratedNameLen ) { PPH_STRING PhUndecoratedName = NULL; wchar_t* Undname = NULL; if ((!UndecoratedName) || (!UndecoratedNameLen)) { return false; } PhUndecoratedName = PhUndecorateNameW( obj->m_SymbolProvider, DecoratedName ); if (!PhUndecoratedName) { return false; } if (!wcsncmp(PhUndecoratedName->Buffer, DecoratedName, PhUndecoratedName->Length)) { PhDereferenceObject(PhUndecoratedName); return false; } Undname = (wchar_t*)calloc(PhUndecoratedName->Length + sizeof(wchar_t), 1); if (!Undname) { PhDereferenceObject(PhUndecoratedName); return false; } memcpy(Undname, PhUndecoratedName->Buffer, PhUndecoratedName->Length); *UndecoratedNameLen = PhUndecoratedName->Length; *UndecoratedName = Undname; PhDereferenceObject(PhUndecoratedName); return true; } bool UnmanagedSymPrv::DemangleName( _In_ wchar_t* DecoratedName, _In_ size_t DecoratedNameLen, _Out_ wchar_t** UndecoratedName, _Out_ size_t* UndecoratedNameLen, _Out_ Dependencies::ClrPh::CLRPH_DEMANGLER *Demangler ) { // try to undecorate GCC/LLVM symbols using demumble if (DemumbleDemangleName( this, DecoratedName, DecoratedNameLen, UndecoratedName, UndecoratedNameLen )) { *Demangler = Dependencies::ClrPh::CLRPH_DEMANGLER::Demumble; DEMANGLER_DEBUGLOG_TWO(L"Demumble {0:s} -> {1:s}", DecoratedName, *UndecoratedName); return true; } // try llvm-demangler. the heuristic is copied from .\llvm-7.0.0.src\lib\DebugInfo\Symbolize\Symbolize.cpp: LLVMSymbolizer::DemangleName if (!_wcsnicmp(DecoratedName, L"_Z", 2)) { if (LLVMItaniumDemangleName( this, DecoratedName, DecoratedNameLen, UndecoratedName, UndecoratedNameLen )) { *Demangler = Dependencies::ClrPh::CLRPH_DEMANGLER::LLVMItanium; DEMANGLER_DEBUGLOG_TWO(L"LLVM Itanium {0:s} -> {1:s}", DecoratedName, *UndecoratedName); return true; } } // try to undecorate MSVC symbols using UndecorateName if (UndecorateSymbolDemangleName( this, DecoratedName, DecoratedNameLen, UndecoratedName, UndecoratedNameLen )) { *Demangler = Dependencies::ClrPh::CLRPH_DEMANGLER::Microsoft; DEMANGLER_DEBUGLOG_TWO(L"Microsoft {0:s} -> {1:s}", DecoratedName, *UndecoratedName); return true; } // use llvm::microsoftDemangle as a last chance if (LLVMMicrosoftDemangleName( this, DecoratedName, DecoratedNameLen, UndecoratedName, UndecoratedNameLen )) { *Demangler = Dependencies::ClrPh::CLRPH_DEMANGLER::LLVMMicrosoft; DEMANGLER_DEBUGLOG_TWO(L"LLVM Microsoft {0:s} -> {1:s}", DecoratedName, *UndecoratedName); return true; } // Could not demangle name *UndecoratedNameLen = 0; *UndecoratedName = NULL; *Demangler = Dependencies::ClrPh::CLRPH_DEMANGLER::None; DEMANGLER_DEBUGLOG_ONE(L"Could not demangle \"{0:s}\" properly", DecoratedName); return false; } ================================================ FILE: Dependencies/App.config ================================================ ================================================ FILE: Dependencies/Dependencies.csproj ================================================  Debug AnyCPU {5565A612-B250-4FE0-98DD-07C56916C194} Exe Dependencies Dependencies v4.6.1 512 true Dependencies.Program true $(SolutionDir)bin\$(Configuration)$(Platform) $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(Platform) DEBUG;TRACE full x86 prompt MinimumRecommendedRules.ruleset $(SolutionDir)bin\$(Configuration)$(Platform) $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(Platform) TRACE true pdbonly x86 prompt MinimumRecommendedRules.ruleset true true $(SolutionDir)bin\$(Configuration)$(Platform) $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(Platform) DEBUG;TRACE full x64 prompt MinimumRecommendedRules.ruleset $(SolutionDir)bin\$(Configuration)$(Platform) $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(Platform) TRACE true pdbonly x64 prompt MinimumRecommendedRules.ruleset true $(SolutionDir)bin\$(Configuration)$(Platform) $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(Platform) TRACE true pdbonly x86 prompt MinimumRecommendedRules.ruleset true $(SolutionDir)bin\$(Configuration)$(Platform) $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(Platform) TRACE true pdbonly x64 prompt MinimumRecommendedRules.ruleset true ..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.dll ..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.Mdb.dll ..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.Pdb.dll ..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.Rocks.dll ..\packages\NDesk.Options.0.2.1\lib\NDesk.Options.dll ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll Designer {fc5ffcaf-982f-4a95-8fa6-2a95b1f7cdc8} ClrPhlib {4a459493-14fc-4c87-9254-60e0959535da} DependenciesLib ================================================ FILE: Dependencies/Program.cs ================================================ using System; using System.Collections.Generic; using System.Xml.Linq; using System.IO; using System.Linq; using System.Diagnostics; using NDesk.Options; using Newtonsoft.Json; using Dependencies.ClrPh; using Mono.Cecil; namespace Dependencies { interface IPrettyPrintable { void PrettyPrint(); } /// /// Printable KnownDlls object /// class NtKnownDlls : IPrettyPrintable { public NtKnownDlls() { x64 = Phlib.GetKnownDlls(false); x86 = Phlib.GetKnownDlls(true); } public void PrettyPrint() { Console.WriteLine("[-] 64-bit KnownDlls : "); foreach (String KnownDll in this.x64) { string System32Folder = Environment.GetFolderPath(Environment.SpecialFolder.System); Console.WriteLine(" {0:s}\\{1:s}", System32Folder, KnownDll); } Console.WriteLine(""); Console.WriteLine("[-] 32-bit KnownDlls : "); foreach (String KnownDll in this.x86) { string SysWow64Folder = Environment.GetFolderPath(Environment.SpecialFolder.SystemX86); Console.WriteLine(" {0:s}\\{1:s}", SysWow64Folder, KnownDll); } Console.WriteLine(""); } public List x64; public List x86; } /// /// Printable ApiSet schema object /// class NtApiSet : IPrettyPrintable { public NtApiSet() { Schema = Phlib.GetApiSetSchema(); } public NtApiSet(PE ApiSetSchemaDll) { Schema = ApiSetSchemaDll.GetApiSetSchema(); } public void PrettyPrint() { Console.WriteLine("[-] Api Sets Map : "); foreach (var ApiSetEntry in this.Schema.GetAll()) { ApiSetTarget ApiSetImpl = ApiSetEntry.Value; string ApiSetName = ApiSetEntry.Key; string ApiSetImplStr = (ApiSetImpl.Count > 0) ? String.Join(",", ApiSetImpl.ToArray()) : ""; Console.WriteLine("{0:s} -> [ {1:s} ]", ApiSetName, ApiSetImplStr); } Console.WriteLine(""); } public ApiSetSchema Schema; } class PEManifest : IPrettyPrintable { public PEManifest(PE _Application) { Application = _Application; Manifest = Application.GetManifest(); XmlManifest = null; Exception = ""; if (Manifest.Length != 0) { try { // Use a memory stream to correctly handle BOM encoding for manifest resource using (var stream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(Manifest))) { XmlManifest = SxsManifest.ParseSxsManifest(stream); } } catch (System.Xml.XmlException e) { //Console.Error.WriteLine("[x] \"Malformed\" pe manifest for file {0:s} : {1:s}", Application.Filepath, PeManifest); //Console.Error.WriteLine("[x] Exception : {0:s}", e.ToString()); XmlManifest = null; Exception = e.ToString(); } } } public void PrettyPrint() { Console.WriteLine("[-] Manifest for file : {0}", Application.Filepath); if (Manifest.Length == 0) { Console.WriteLine("[x] No embedded pe manifest for file {0:s}", Application.Filepath); return; } if (Exception.Length != 0) { Console.Error.WriteLine("[x] \"Malformed\" pe manifest for file {0:s} : {1:s}", Application.Filepath, Manifest); Console.Error.WriteLine("[x] Exception : {0:s}", Exception); return; } Console.WriteLine(XmlManifest); } public string Manifest; public XDocument XmlManifest; // stays private in order not end up in the json output private PE Application; private string Exception; } class PEImports : IPrettyPrintable { public PEImports(PE _Application) { Application = _Application; Imports = Application.GetImports(); } public void PrettyPrint() { Console.WriteLine("[-] Import listing for file : {0}", Application.Filepath); foreach (PeImportDll DllImport in Imports) { Console.WriteLine("Import from module {0:s} :", DllImport.Name); foreach (PeImport Import in DllImport.ImportList) { if (Import.ImportByOrdinal) { Console.Write("\t Ordinal_{0:d} ", Import.Ordinal); } else { Console.Write("\t Function {0:s}", Import.Name); } if (Import.DelayImport) Console.WriteLine(" (Delay Import)"); else Console.WriteLine(""); } } Console.WriteLine("[-] Import listing done"); } public List Imports; private PE Application; } class PEExports : IPrettyPrintable { public PEExports(PE _Application) { Application = _Application; Exports = Application.GetExports(); } public void PrettyPrint() { Console.WriteLine("[-] Export listing for file : {0}", Application.Filepath); foreach (PeExport Export in Exports) { Console.WriteLine("Export {0:d} :", Export.Ordinal); Console.WriteLine("\t Name : {0:s}", Export.Name); Console.WriteLine("\t VA : 0x{0:X}", (int)Export.VirtualAddress); if (Export.ForwardedName.Length > 0) Console.WriteLine("\t ForwardedName : {0:s}", Export.ForwardedName); } Console.WriteLine("[-] Export listing done"); } public List Exports; private PE Application; } class SxsDependencies : IPrettyPrintable { public SxsDependencies(PE _Application) { Application = _Application; SxS = SxsManifest.GetSxsEntries(Application); } public void PrettyPrint() { Console.WriteLine("[-] sxs dependencies for executable : {0}", Application.Filepath); foreach (var entry in SxS) { 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 SxsEntries SxS; private PE Application; } // Basic custom exception used to be able to differentiate between a "native" exception // and one that has been already catched, processed and rethrown public class RethrownException : Exception { public RethrownException(Exception e) :base(e.Message, e.InnerException) { } } internal class PEModuleReferences : IPrettyPrintable { public PEModuleReferences(PE _Application) { Application = _Application; try { var PeAssembly = AssemblyDefinition.ReadAssembly(Application.Filepath); ModuleReferences = PeAssembly.Modules.SelectMany(m => m.ModuleReferences) .Where(mr => mr.Name.Length > 0); } catch (BadImageFormatException) { } } public void PrettyPrint() { Console.WriteLine("[-] Module references listing for file : {0}", Application.Filepath); foreach (ModuleReference moduleReference in ModuleReferences) { Console.WriteLine("-{0:s}", moduleReference.Name); } Console.WriteLine("[-] Import listing done"); } private PE Application; public IEnumerable ModuleReferences { get; private set; } = new List(); } internal class PEAssemblyReferences : IPrettyPrintable { public PEAssemblyReferences(PE _Application) { Application = _Application; try { var PeAssembly = AssemblyDefinition.ReadAssembly(Application.Filepath); Resolver = new DefaultAssemblyResolver(); Resolver.AddSearchDirectory(Path.GetDirectoryName(_Application.Filepath)); AssemblyReferences = PeAssembly.Modules.SelectMany(m => m.AssemblyReferences); } catch (BadImageFormatException) { } } public void PrettyPrint() { Console.WriteLine("[-] Assembly references listing for file : {0}", Application.Filepath); foreach (AssemblyNameReference assemblyReference in AssemblyReferences) { AssemblyDefinition definition; try { definition = Resolver.Resolve(assemblyReference); Console.WriteLine("-{0:s} : {1:s}", assemblyReference.Name, definition); } catch (AssemblyResolutionException) { Console.WriteLine("-{0:s}", assemblyReference.Name); } } Console.WriteLine("[-] Import listing done"); } private PE Application; private DefaultAssemblyResolver Resolver; public IEnumerable AssemblyReferences { get; private set; } = new List(); } class ImportDll { public string Name { get; private set; } public static ImportDll From(PeImportDll i) { return new ImportDll { Name = i.Name }; } public static ImportDll From(ModuleReference m) { return new ImportDll { Name = m.Name }; } } class PeDependencyItem : IPrettyPrintable { public PeDependencyItem(PeDependencies _Root, string _ModuleName, string ModuleFilepath, ModuleSearchStrategy Strategy, int Level) { Action action = () => { Root = _Root; ModuleName = _ModuleName; Imports = new List(); Filepath = ModuleFilepath; SearchStrategy = Strategy; RecursionLevel = Level; DependenciesResolved = false; FullDependencies = new List(); ResolvedImports = new List(); ModuleReferences = new List(); AssemblyReferences = new List(); }; SafeExecutor(action); } 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); } public void ResolveDependencies() { Action action = () => { if (DependenciesResolved) { return; } List NewDependencies = new List(); foreach (ImportDll DllImport in Imports.Concat(ModuleReferences)) { string ModuleFilepath = null; ModuleSearchStrategy Strategy; // Find Dll in "paths" Tuple ResolvedModule = Root.ResolveModule(DllImport.Name); Strategy = ResolvedModule.Item1; if (Strategy != ModuleSearchStrategy.NOT_FOUND) { ModuleFilepath = ResolvedModule.Item2?.Filepath; } bool IsAlreadyCached = Root.isModuleCached(DllImport.Name, ModuleFilepath); PeDependencyItem DependencyItem = Root.GetModuleItem(DllImport.Name, ModuleFilepath, Strategy, RecursionLevel + 1); // do not add twice the same imported module if (ResolvedImports.Find(ri => ri.ModuleName == DllImport.Name) == null) { ResolvedImports.Add(DependencyItem); } // Do not process twice a dependency. It will be displayed only once if (!IsAlreadyCached) { Debug.WriteLine("[{0:d}] [{1:s}] Adding dep {2:s}", RecursionLevel, ModuleName, ModuleFilepath); NewDependencies.Add(DependencyItem); } FullDependencies.Add(DependencyItem); } DependenciesResolved = true; if ((Root.MaxRecursion > 0) && ((RecursionLevel + 1) >= Root.MaxRecursion)) { return; } // Recursively resolve dependencies foreach (var Dep in NewDependencies) { Dep.LoadPe(); Dep.ResolveDependencies(); } }; SafeExecutor(action); } public bool IsNewModule() { return Root.VisitModule(this.ModuleName, this.Filepath); } public void PrettyPrint() { string Tabs = string.Concat(Enumerable.Repeat("| ", RecursionLevel)); Console.WriteLine("{0:s}├ {1:s} ({2:s}) : {3:s} ", Tabs, ModuleName, SearchStrategy.ToString(), Filepath); foreach (var Dep in ResolvedImports) { bool NeverSeenModule = Dep.IsNewModule(); Dep.RecursionLevel = RecursionLevel + 1; if (NeverSeenModule) { Dep.PrettyPrint(); } else { Dep.BasicPrettyPrint(); } } } public void BasicPrettyPrint(int? OverrideRecursionLevel = null) { int localRecursionLevel = RecursionLevel; if (OverrideRecursionLevel != null) { localRecursionLevel = (int) OverrideRecursionLevel; } string Tabs = string.Concat(Enumerable.Repeat("| ", localRecursionLevel)); Console.WriteLine("{0:s}├ {1:s} ({2:s}) : {3:s} ", Tabs, ModuleName, SearchStrategy.ToString(), Filepath); } private void SafeExecutor(Action action) { SafeExecutor(() => { action(); return 0; }); } private T SafeExecutor(Func action) { try { return action(); } catch (RethrownException rex) { Console.Error.WriteLine(" - \"{0:s}\"", Filepath); throw rex; } catch (Exception ex) { Console.Error.WriteLine("[!] Unhandled exception occured while processing \"{1:s}\"", RecursionLevel, Filepath); Console.Error.WriteLine("Stacktrace:\n{0:s}\n", ex.StackTrace); Console.Error.WriteLine("Modules backtrace:"); throw new RethrownException(ex); } finally { // } // return default(T); } // Json exportable public string ModuleName; public string Filepath; public ModuleSearchStrategy SearchStrategy; public List Dependencies { get { return IsNewModule() ? FullDependencies : new List(); } } // not Json exportable protected List FullDependencies; protected List ResolvedImports; protected List Imports; protected List AssemblyReferences; protected List ModuleReferences; protected PeDependencies Root; protected int RecursionLevel; private bool DependenciesResolved; } class ModuleCacheKey : Tuple { public ModuleCacheKey(string Name, string Filepath) : base(Name, Filepath) { } } class ModuleEntries : Dictionary, IPrettyPrintable { public void PrettyPrint() { foreach (var item in this.Values.OrderBy(module => module.SearchStrategy)) { Console.WriteLine("[{0:s}] {1:s} : {2:s} ", item.SearchStrategy.ToString(), item.ModuleName, item.Filepath); } } } class PeDependencies : IPrettyPrintable { public PeDependencies(PE Application, int recursion_depth) { string RootFilename = Path.GetFileName(Application.Filepath); RootPe = Application; SxsEntriesCache = SxsManifest.GetSxsEntries(RootPe); ModulesCache = new ModuleEntries(); MaxRecursion = recursion_depth; ModulesVisited = new Dictionary(); Root = GetModuleItem(RootFilename, Application.Filepath, ModuleSearchStrategy.ROOT, 0); Root.LoadPe(); Root.ResolveDependencies(); } public Tuple ResolveModule(string ModuleName) { return BinaryCache.ResolveModule( RootPe, ModuleName /*DllImport.Name*/ ); } public bool isModuleCached(string ModuleName, string ModuleFilepath) { // Do not process twice the same item ModuleCacheKey ModuleKey = new ModuleCacheKey(ModuleName, ModuleFilepath); return ModulesCache.ContainsKey(ModuleKey); } public PeDependencyItem GetModuleItem(string ModuleName, string ModuleFilepath, ModuleSearchStrategy SearchStrategy, int RecursionLevel) { // Do not process twice the same item ModuleCacheKey ModuleKey = new ModuleCacheKey(ModuleName, ModuleFilepath); if (!ModulesCache.ContainsKey(ModuleKey)) { ModulesCache[ModuleKey] = new PeDependencyItem(this, ModuleName, ModuleFilepath, SearchStrategy, RecursionLevel); } return ModulesCache[ModuleKey]; } public void PrettyPrint() { ModulesVisited = new Dictionary(); Root.PrettyPrint(); } public bool VisitModule(string ModuleName, string ModuleFilepath) { //ModuleCacheKey ModuleKey = new ModuleCacheKey(ModuleName, ModuleFilepath); ModuleCacheKey ModuleKey = new ModuleCacheKey("", ModuleFilepath); // do not visit recursively the same node (in order to prevent stack overflow) if (ModulesVisited.ContainsKey(ModuleKey)) { return false; } ModulesVisited[ModuleKey] = true; return true; } public ModuleEntries GetModules { get {return ModulesCache;} } public PeDependencyItem Root; public int MaxRecursion; private PE RootPe; private SxsEntries SxsEntriesCache; private ModuleEntries ModulesCache; private Dictionary ModulesVisited; } class Program { public static void PrettyPrinter(IPrettyPrintable obj) { obj.PrettyPrint(); } public static void JsonPrinter(IPrettyPrintable obj) { JsonSerializerSettings Settings = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Serialize, //PreserveReferencesHandling = PreserveReferencesHandling.Objects, }; Console.WriteLine(JsonConvert.SerializeObject(obj, Formatting.Indented, Settings)); } public static void DumpKnownDlls(Action Printer) { NtKnownDlls KnownDlls = new NtKnownDlls(); Printer(KnownDlls); } public static void DumpApiSets(Action Printer) { NtApiSet ApiSet = new NtApiSet(); Printer(ApiSet); } public static void DumpApiSets(PE Application, Action Printer, int recursion_depth = 0) { NtApiSet ApiSet = new NtApiSet(Application); Printer(ApiSet); } public static void DumpManifest(PE Application, Action Printer, int recursion_depth = 0) { PEManifest Manifest = new PEManifest(Application); Printer(Manifest); } public static void DumpSxsEntries(PE Application, Action Printer, int recursion_depth= 0) { SxsDependencies SxsDeps = new SxsDependencies(Application); Printer(SxsDeps); } public static void DumpExports(PE Pe, Action Printer, int recursion_depth = 0) { PEExports Exports = new PEExports(Pe); Printer(Exports); } public static void DumpImports(PE Pe, Action Printer, int recursion_depth = 0) { PEImports Imports = new PEImports(Pe); Printer(Imports); } public static void DumpAssemblyReferences(PE Pe, Action Printer, int recursion_depth = 0) { PEAssemblyReferences AssemblyReferences = new PEAssemblyReferences(Pe); Printer(AssemblyReferences); } public static void DumpModuleReferences(PE Pe, Action Printer, int recursion_depth = 0) { PEModuleReferences ModuleReferences = new PEModuleReferences(Pe); Printer(ModuleReferences); } public static void DumpDependencyChain(PE Pe, Action Printer, int recursion_depth = 0) { PeDependencies Deps = new PeDependencies(Pe, recursion_depth); Printer(Deps); } public static void DumpModules(PE Pe, Action Printer, int recursion_depth = 0) { if (Printer == JsonPrinter) { Console.Error.WriteLine("Json output is not currently supported when dumping the dependency chain."); return; } PeDependencies Deps = new PeDependencies(Pe, recursion_depth); Printer(Deps.GetModules); } public static void DumpUsage() { string Usage = String.Join(Environment.NewLine, "Dependencies.exe : command line tool for dumping dependencies and various utilities.", "", "Usage : Dependencies.exe [OPTIONS] ", "", "Options :", " -h -help : display this help", " -json : activate json output.", " -cache : load and use binary cache in order to prevent dll file locking.", " -depth : limit recursion depth when analysing loaded modules or dependency chain. Default value is infinite.", " -apisets : dump the system's ApiSet schema (api set dll -> host dll)", " -apisetsdll : dump the ApiSet schema from apisetschema (api set dll -> host dll)", " -knowndll : dump all the system's known dlls (x86 and x64)", " -manifest : dump embedded manifest, if it exists.", " -sxsentries : dump all of 's sxs dependencies.", " -imports : dump imports", " -exports : dump exports", " -modules : dump resolved modules", " -chain : dump whole dependency chain" ); Console.WriteLine(Usage); } static Action GetObjectPrinter(bool export_as_json) { if (export_as_json) return JsonPrinter; return PrettyPrinter; } public delegate void DumpCommand(PE Application, Action Printer, int recursion_depth=0); 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 ", v => command = DumpApiSets }, { "manifest", "show manifest information embedded in ", v => command = DumpManifest }, { "sxsentries", "dump all of 's sxs dependencies", v => command = DumpSxsEntries }, { "imports", "dump imports", v => command = DumpImports }, { "exports", "dump exports", v => command = DumpExports }, { "assemblyrefs", "dump assemblyrefs", v => command = DumpAssemblyReferences}, { "modulerefs", "dump modulerefs", v => command = DumpModuleReferences}, { "chain", "dump whole dependency chain", v => command = DumpDependencyChain }, { "modules", "dump resolved modules", v => command = DumpModules }, }; List 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 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); } } } ================================================ FILE: Dependencies/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // Les informations générales relatives à un assembly dépendent de // l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations // associées à un assembly. [assembly: AssemblyTitle("Dependencies")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Dependencies")] [assembly: AssemblyCopyright("Copyright © 2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly // aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de // COM, affectez la valeur true à l'attribut ComVisible sur ce type. [assembly: ComVisible(false)] // Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM [assembly: Guid("5565a612-b250-4fe0-98dd-07c56916c194")] // Les informations de version pour un assembly se composent des quatre valeurs suivantes : // // Version principale // Version secondaire // Numéro de build // Révision // // Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut // en utilisant '*', comme indiqué ci-dessous : // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.10.0.0")] [assembly: AssemblyFileVersion("1.10.0.0")] ================================================ FILE: Dependencies/packages.config ================================================  ================================================ FILE: Dependencies.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30114.105 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DependenciesGui", "DependenciesGui\DependenciesGui.csproj", "{9232B9B6-F2BA-44A3-B8A6-A352777F632C}" ProjectSection(ProjectDependencies) = postProject {4A459493-14FC-4C87-9254-60E0959535DA} = {4A459493-14FC-4C87-9254-60E0959535DA} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ClrPhlib", "ClrPhlib\ClrPhlib.vcxproj", "{FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}" ProjectSection(ProjectDependencies) = postProject {477D0215-F252-41A1-874B-F27E3EA1ED17} = {477D0215-F252-41A1-874B-F27E3EA1ED17} {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1} = {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1} {FC532FFF-EBB1-4601-B903-C09EFB79ECED} = {FC532FFF-EBB1-4601-B903-C09EFB79ECED} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dependencies", "Dependencies\Dependencies.csproj", "{5565A612-B250-4FE0-98DD-07C56916C194}" ProjectSection(ProjectDependencies) = postProject {4A459493-14FC-4C87-9254-60E0959535DA} = {4A459493-14FC-4C87-9254-60E0959535DA} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "third_party", "third_party", "{A2A2925A-0582-4436-9A12-8567E979A621}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phlib", "third_party\phlib\phlib.vcxproj", "{477D0215-F252-41A1-874B-F27E3EA1ED17}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dragablz.net45", "third_party\Dragablz\Dragablz\Dragablz.net45.csproj", "{7B11011C-7FD7-4AB0-A1AD-04E940B026DE}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demumble", "third_party\demumble\demumble.vcxproj", "{BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DependenciesLib", "DependenciesLib\DependenciesLib.csproj", "{4A459493-14FC-4C87-9254-60E0959535DA}" ProjectSection(ProjectDependencies) = postProject {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8} = {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "llvm-demangle", "third_party\llvm-demangle\llvm-demangle.vcxproj", "{FC532FFF-EBB1-4601-B903-C09EFB79ECED}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D142CC15-3DBD-4295-BDD9-472FE53A00A7}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "demangler-test", "test\demangler-test\demangler-test.csproj", "{24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "binarycache-test", "test\binarycache-test\binarycache-test.csproj", "{FF973409-2F2A-46F7-B01D-C6405EA40422}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|ARM = Debug|ARM Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|ARM = Release|ARM Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Debug|ARM.ActiveCfg = Debug|x86 {9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Debug|x64.ActiveCfg = Debug|x64 {9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Debug|x64.Build.0 = Debug|x64 {9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Debug|x86.ActiveCfg = Debug|x86 {9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Debug|x86.Build.0 = Debug|x86 {9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Release|Any CPU.ActiveCfg = Release|Any CPU {9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Release|ARM.ActiveCfg = Release|x86 {9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Release|x64.ActiveCfg = Release|x64 {9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Release|x64.Build.0 = Release|x64 {9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Release|x86.ActiveCfg = Release|x86 {9232B9B6-F2BA-44A3-B8A6-A352777F632C}.Release|x86.Build.0 = Release|x86 {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Debug|Any CPU.ActiveCfg = Debug|Win32 {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Debug|ARM.ActiveCfg = Debug|Win32 {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Debug|x64.ActiveCfg = Debug|x64 {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Debug|x64.Build.0 = Debug|x64 {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Debug|x86.ActiveCfg = Debug|Win32 {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Debug|x86.Build.0 = Debug|Win32 {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Release|Any CPU.ActiveCfg = Release|Win32 {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Release|ARM.ActiveCfg = Release|Win32 {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Release|x64.ActiveCfg = Release|x64 {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Release|x64.Build.0 = Release|x64 {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Release|x86.ActiveCfg = Release|Win32 {FC5FFCAF-982F-4A95-8FA6-2A95B1F7CDC8}.Release|x86.Build.0 = Release|Win32 {5565A612-B250-4FE0-98DD-07C56916C194}.Debug|Any CPU.ActiveCfg = Debug|x86 {5565A612-B250-4FE0-98DD-07C56916C194}.Debug|ARM.ActiveCfg = Debug|x86 {5565A612-B250-4FE0-98DD-07C56916C194}.Debug|x64.ActiveCfg = Debug|x64 {5565A612-B250-4FE0-98DD-07C56916C194}.Debug|x64.Build.0 = Debug|x64 {5565A612-B250-4FE0-98DD-07C56916C194}.Debug|x86.ActiveCfg = Debug|x86 {5565A612-B250-4FE0-98DD-07C56916C194}.Debug|x86.Build.0 = Debug|x86 {5565A612-B250-4FE0-98DD-07C56916C194}.Release|Any CPU.ActiveCfg = Release|x86 {5565A612-B250-4FE0-98DD-07C56916C194}.Release|ARM.ActiveCfg = Release|x86 {5565A612-B250-4FE0-98DD-07C56916C194}.Release|x64.ActiveCfg = Release|x64 {5565A612-B250-4FE0-98DD-07C56916C194}.Release|x64.Build.0 = Release|x64 {5565A612-B250-4FE0-98DD-07C56916C194}.Release|x86.ActiveCfg = Release|x86 {5565A612-B250-4FE0-98DD-07C56916C194}.Release|x86.Build.0 = Release|x86 {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|Any CPU.ActiveCfg = Debug|Win32 {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|ARM.ActiveCfg = Debug|Win32 {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x64.ActiveCfg = Debug|x64 {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x64.Build.0 = Debug|x64 {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x86.ActiveCfg = Debug|Win32 {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x86.Build.0 = Debug|Win32 {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|Any CPU.ActiveCfg = Release|Win32 {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|ARM.ActiveCfg = Release|Win32 {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.ActiveCfg = Release|x64 {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.Build.0 = Release|x64 {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x86.ActiveCfg = Release|Win32 {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x86.Build.0 = Release|Win32 {7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Debug|Any CPU.ActiveCfg = Debug|x86 {7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Debug|ARM.ActiveCfg = Debug|x86 {7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Debug|x64.ActiveCfg = Debug|x64 {7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Debug|x64.Build.0 = Debug|x64 {7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Debug|x86.ActiveCfg = Debug|x86 {7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Debug|x86.Build.0 = Debug|x86 {7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Release|Any CPU.ActiveCfg = Release|x86 {7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Release|ARM.ActiveCfg = Release|x86 {7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Release|x64.ActiveCfg = Release|x64 {7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Release|x64.Build.0 = Release|x64 {7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Release|x86.ActiveCfg = Release|x86 {7B11011C-7FD7-4AB0-A1AD-04E940B026DE}.Release|x86.Build.0 = Release|x86 {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Debug|Any CPU.ActiveCfg = Debug|Win32 {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Debug|ARM.ActiveCfg = Debug|Win32 {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Debug|x64.ActiveCfg = Debug|x64 {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Debug|x64.Build.0 = Debug|x64 {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Debug|x86.ActiveCfg = Debug|Win32 {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Debug|x86.Build.0 = Debug|Win32 {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Release|Any CPU.ActiveCfg = Release|Win32 {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Release|ARM.ActiveCfg = Release|Win32 {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Release|x64.ActiveCfg = Release|x64 {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Release|x64.Build.0 = Release|x64 {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Release|x86.ActiveCfg = Release|Win32 {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1}.Release|x86.Build.0 = Release|Win32 {4A459493-14FC-4C87-9254-60E0959535DA}.Debug|Any CPU.ActiveCfg = Debug|x86 {4A459493-14FC-4C87-9254-60E0959535DA}.Debug|ARM.ActiveCfg = Debug|x86 {4A459493-14FC-4C87-9254-60E0959535DA}.Debug|x64.ActiveCfg = Debug|x64 {4A459493-14FC-4C87-9254-60E0959535DA}.Debug|x64.Build.0 = Debug|x64 {4A459493-14FC-4C87-9254-60E0959535DA}.Debug|x86.ActiveCfg = Debug|x86 {4A459493-14FC-4C87-9254-60E0959535DA}.Debug|x86.Build.0 = Debug|x86 {4A459493-14FC-4C87-9254-60E0959535DA}.Release|Any CPU.ActiveCfg = Release|x86 {4A459493-14FC-4C87-9254-60E0959535DA}.Release|ARM.ActiveCfg = Release|x86 {4A459493-14FC-4C87-9254-60E0959535DA}.Release|x64.ActiveCfg = Release|x64 {4A459493-14FC-4C87-9254-60E0959535DA}.Release|x64.Build.0 = Release|x64 {4A459493-14FC-4C87-9254-60E0959535DA}.Release|x86.ActiveCfg = Release|x86 {4A459493-14FC-4C87-9254-60E0959535DA}.Release|x86.Build.0 = Release|x86 {FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Debug|Any CPU.ActiveCfg = Debug|Win32 {FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Debug|ARM.ActiveCfg = Debug|Win32 {FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Debug|x64.ActiveCfg = Debug|x64 {FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Debug|x64.Build.0 = Debug|x64 {FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Debug|x86.ActiveCfg = Debug|Win32 {FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Debug|x86.Build.0 = Debug|Win32 {FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Release|Any CPU.ActiveCfg = Release|Win32 {FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Release|ARM.ActiveCfg = Release|Win32 {FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Release|x64.ActiveCfg = Release|x64 {FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Release|x64.Build.0 = Release|x64 {FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Release|x86.ActiveCfg = Release|Win32 {FC532FFF-EBB1-4601-B903-C09EFB79ECED}.Release|x86.Build.0 = Release|Win32 {24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Debug|Any CPU.ActiveCfg = Debug|x86 {24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Debug|ARM.ActiveCfg = Debug|x86 {24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Debug|x64.ActiveCfg = Debug|x64 {24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Debug|x64.Build.0 = Debug|x64 {24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Debug|x86.ActiveCfg = Debug|x86 {24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Debug|x86.Build.0 = Debug|x86 {24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Release|Any CPU.ActiveCfg = Release|x86 {24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Release|ARM.ActiveCfg = Release|x86 {24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Release|x64.ActiveCfg = Release|x64 {24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Release|x64.Build.0 = Release|x64 {24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Release|x86.ActiveCfg = Release|x86 {24F9E0C0-CA6E-4565-A9E2-88602DD9F18A}.Release|x86.Build.0 = Release|x86 {FF973409-2F2A-46F7-B01D-C6405EA40422}.Debug|Any CPU.ActiveCfg = Debug|x86 {FF973409-2F2A-46F7-B01D-C6405EA40422}.Debug|ARM.ActiveCfg = Debug|x86 {FF973409-2F2A-46F7-B01D-C6405EA40422}.Debug|x64.ActiveCfg = Debug|x64 {FF973409-2F2A-46F7-B01D-C6405EA40422}.Debug|x64.Build.0 = Debug|x64 {FF973409-2F2A-46F7-B01D-C6405EA40422}.Debug|x86.ActiveCfg = Debug|x86 {FF973409-2F2A-46F7-B01D-C6405EA40422}.Debug|x86.Build.0 = Debug|x86 {FF973409-2F2A-46F7-B01D-C6405EA40422}.Release|Any CPU.ActiveCfg = Release|x86 {FF973409-2F2A-46F7-B01D-C6405EA40422}.Release|ARM.ActiveCfg = Release|x86 {FF973409-2F2A-46F7-B01D-C6405EA40422}.Release|x64.ActiveCfg = Release|x64 {FF973409-2F2A-46F7-B01D-C6405EA40422}.Release|x64.Build.0 = Release|x64 {FF973409-2F2A-46F7-B01D-C6405EA40422}.Release|x86.ActiveCfg = Release|x86 {FF973409-2F2A-46F7-B01D-C6405EA40422}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {477D0215-F252-41A1-874B-F27E3EA1ED17} = {A2A2925A-0582-4436-9A12-8567E979A621} {7B11011C-7FD7-4AB0-A1AD-04E940B026DE} = {A2A2925A-0582-4436-9A12-8567E979A621} {BE4A9759-A412-44CB-887D-FEFBEF1ABBF1} = {A2A2925A-0582-4436-9A12-8567E979A621} {FC532FFF-EBB1-4601-B903-C09EFB79ECED} = {A2A2925A-0582-4436-9A12-8567E979A621} {24F9E0C0-CA6E-4565-A9E2-88602DD9F18A} = {D142CC15-3DBD-4295-BDD9-472FE53A00A7} {FF973409-2F2A-46F7-B01D-C6405EA40422} = {D142CC15-3DBD-4295-BDD9-472FE53A00A7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {054EFA82-95F8-4719-9F9A-546E7BEC56BF} EndGlobalSection EndGlobal ================================================ FILE: DependenciesGui/About.xaml ================================================  Dependencies v : Dependency tool made by lucasg. Please go to https://github.com/lucasg/Dependencies/issues to report issues. Check for updates ================================================ FILE: DependenciesGui/About.xaml.cs ================================================ using System; using System.Diagnostics; using System.Net; using System.Reflection; using System.Threading.Tasks; using System.Windows; using System.Windows.Documents; using System.Windows.Navigation; namespace Dependencies { /// /// Logique d'interaction pour About.xaml /// public partial class About : Window { public About() { InitializeComponent(); DataContext = this; } private void Uri_RequestNavigate(object sender, RequestNavigateEventArgs e) { Process.Start(e.Uri.ToString()); } public string VersionStr { get { return Assembly.GetEntryAssembly().GetName().Version.ToString(); } } private async void Uri_CheckUpdates(object sender, RequestNavigateEventArgs e) { string version = await GetLatestVersion("https://github.com/lucasg/Dependencies/releases/latest"); UpdateCheck.Inlines.Clear(); UpdateCheck.Inlines.Add("Latest version: "); var link = new Hyperlink() { NavigateUri = new Uri(version) }; link.Inlines.Add(version); link.RequestNavigate += Uri_RequestNavigate; UpdateCheck.Inlines.Add(link); } // Based on https://stackoverflow.com/a/28424940/4928207 private async Task GetLatestVersion(string url) { try { var req = (HttpWebRequest)HttpWebRequest.Create(url); req.Method = "HEAD"; req.AllowAutoRedirect = false; using (var resp = (HttpWebResponse)await req.GetResponseAsync()) { switch (resp.StatusCode) { case HttpStatusCode.OK: return url; case HttpStatusCode.Redirect: case HttpStatusCode.MovedPermanently: case HttpStatusCode.RedirectKeepVerb: case HttpStatusCode.RedirectMethod: if (resp.Headers["Location"] == null) return url; return resp.Headers["Location"]; default: return url; } } } catch { } return url; } } } ================================================ FILE: DependenciesGui/App.config ================================================
True True True 0 peview.exe ChildOnly Courier New 2 True ================================================ FILE: DependenciesGui/App.xaml ================================================  ================================================ FILE: DependenciesGui/App.xaml.cs ================================================ using System; using System.Windows; using System.Windows.Shell; using System.ComponentModel; using System.IO; using Dependencies.ClrPh; using System.Reflection; namespace Dependencies { /// /// Application instance /// public partial class App : Application, INotifyPropertyChanged { private string statusBarMessage = ""; private MainWindow mainWindow; public string StatusBarMessage { get { return statusBarMessage; } set { if (statusBarMessage != value) { statusBarMessage = value; OnPropertyChanged("StatusBarMessage"); } } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private void App_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "StatusBarMessage") { mainWindow.AppStatusBarMessage.Content = (object)StatusBarMessage; } } 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; } 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]); } } void App_Exit(object sender, ExitEventArgs e) { Dependencies.Properties.Settings.Default.Save(); BinaryCache.Instance.Unload(); } private static void SetDropDownMenuToBeRightAligned() { var menuDropAlignmentField = typeof(SystemParameters).GetField("_menuDropAlignment", BindingFlags.NonPublic | BindingFlags.Static); Action setAlignmentValue = () => { if (SystemParameters.MenuDropAlignment && menuDropAlignmentField != null) menuDropAlignmentField.SetValue(null, false); }; setAlignmentValue(); SystemParameters.StaticPropertyChanged += (sender, e) => { setAlignmentValue(); }; } public static void AddToRecentDocuments(String Filename) { // Create custom task JumpTask item = new JumpTask(); item.Title = System.IO.Path.GetFileName(Filename); item.Description = Filename; item.ApplicationPath = System.Reflection.Assembly.GetExecutingAssembly().CodeBase; item.Arguments = Filename; item.CustomCategory = "Tasks"; // Add document to recent category JumpList RecentsDocs = JumpList.GetJumpList(Application.Current); RecentsDocs.JumpItems.Add(item); JumpList.AddToRecentCategory(item); RecentsDocs.Apply(); // Store a copy in application settings, LRU style // First check if the item is not already present in the list int index = Dependencies.Properties.Settings.Default.RecentFiles.IndexOf(Filename); if (index != -1) { Dependencies.Properties.Settings.Default.RecentFiles.RemoveAt(index); } // Second check if the list is not full if (Dependencies.Properties.Settings.Default.RecentFiles.Count == 10) { Dependencies.Properties.Settings.Default.RecentFiles.RemoveAt(9); } // Prepend the list with the new item Dependencies.Properties.Settings.Default.RecentFiles.Insert(0, Filename); } } } ================================================ FILE: DependenciesGui/CustomHeaderViewModel.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace Dependencies { public class CustomHeaderViewModel : INotifyPropertyChanged { private string _header; private bool _isSelected; public string Header { get { return _header; } set { if (value == _header) return; _header = value; OnPropertyChanged("Header"); } } public bool IsSelected { get { return _isSelected; } set { if (value.Equals(_isSelected)) return; _isSelected = value; OnPropertyChanged("IsSelected"); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } } ================================================ FILE: DependenciesGui/Dependencies.manifest ================================================ Deependencies true true ================================================ FILE: DependenciesGui/DependenciesGui.csproj ================================================  Debug AnyCPU {9232B9B6-F2BA-44A3-B8A6-A352777F632C} WinExe Dependencies DependenciesGui v4.6.1 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 true Dependencies.ico Dependencies.App true $(SolutionDir)bin\$(Configuration)$(Platform) $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(Platform) DEBUG;TRACE true full x86 prompt MinimumRecommendedRules.ruleset $(SolutionDir)bin\$(Configuration)$(Platform) $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(Platform) TRACE true pdbonly x86 prompt MinimumRecommendedRules.ruleset true $(SolutionDir)bin\$(Configuration)$(Platform) $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(Platform) DEBUG;TRACE true full x64 prompt MinimumRecommendedRules.ruleset $(SolutionDir)bin\$(Configuration)$(Platform) $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(Platform) TRACE true pdbonly x64 prompt MinimumRecommendedRules.ruleset $(SolutionDir)bin\$(Configuration)$(Platform) $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(Platform) TRACE true pdbonly x86 prompt MinimumRecommendedRules.ruleset true $(SolutionDir)bin\$(Configuration)$(Platform) $(SolutionDir)obj\$(ProjectName)\$(Configuration)$(Platform) TRACE true pdbonly x64 prompt MinimumRecommendedRules.ruleset true ..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.dll ..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.Mdb.dll ..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.Pdb.dll ..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.Rocks.dll 4.0 MSBuild:Compile Designer About.xaml DependencyCustomListView.xaml DependencyExportList.xaml DependencyImportList.xaml DependencyModuleList.xaml ModuleSearchOrder.xaml SearchFolder.xaml UserSettings.xaml Designer MSBuild:Compile MSBuild:Compile Designer Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer App.xaml Code DependencyWindow.xaml MainWindow.xaml Code Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Code True True Resources.resx True Settings.settings True ResXFileCodeGenerator Resources.Designer.cs SettingsSingleFileGenerator Settings.Designer.cs {fc5ffcaf-982f-4a95-8fa6-2a95b1f7cdc8} ClrPhlib {4a459493-14fc-4c87-9254-60e0959535da} DependenciesLib {7b11011c-7fd7-4ab0-a1ad-04e940b026de} Dragablz.net45 ================================================ FILE: DependenciesGui/DependencyCustomListView.xaml ================================================ ================================================ FILE: DependenciesGui/DependencyCustomListView.xaml.cs ================================================ using System; using System.Collections.Generic; using System.Windows.Controls; using System.Windows.Input; using System.Diagnostics; using System.Windows; namespace Dependencies { /// /// DependencyImportList Filterable ListView for displaying exports. /// @TODO(Make this a template user control in order to share it between Modeules, Imports and Exports) /// [TemplatePart(Name = PART_SearchBar, Type = typeof(FilterControl))] public partial class DependencyCustomListView : ListView { private const string PART_SearchBar = "PART_SearchBar"; public FilterControl SearchBar = null; public DependencyCustomListView() { this.KeyDown += new KeyEventHandler(OnListViewKeyDown); } public static readonly DependencyProperty SearchListFilterProperty = DependencyProperty.Register( "SearchListFilter", typeof(string), typeof(DependencyCustomListView), new PropertyMetadata(null)); public string SearchListFilter { get { return (string)GetValue(SearchListFilterProperty); } set { SetValue(SearchListFilterProperty, value); } } public static readonly DependencyProperty CopyHandlerProperty = DependencyProperty.Register( "CopyHandler", typeof(Func), typeof(DependencyCustomListView), new PropertyMetadata(null)); public Func CopyHandler { get { return (Func)GetValue(CopyHandlerProperty); } set { SetValue(CopyHandlerProperty, value); } } public override void OnApplyTemplate() { base.OnApplyTemplate(); AttachToVisualTree(); } private void AttachToVisualTree() { SearchBar = GetTemplateChild(PART_SearchBar) as FilterControl; SearchBar.TargetControl = this; } #region events handlers protected virtual void OnListViewKeyDown(object sender, System.Windows.Input.KeyEventArgs e) { System.Windows.Controls.ListView ListView = sender as System.Windows.Controls.ListView; bool CtrlKeyDown = Keyboard.IsKeyDown(System.Windows.Input.Key.LeftCtrl) || Keyboard.IsKeyDown(System.Windows.Input.Key.RightCtrl); bool ShiftKeyDown = Keyboard.IsKeyDown(System.Windows.Input.Key.LeftShift) || Keyboard.IsKeyDown(System.Windows.Input.Key.RightShift); Debug.WriteLine("[DependencyCustomListView] Key Pressed : " + e.Key + ". Ctrl Key down : " + CtrlKeyDown); if ((e.Key == System.Windows.Input.Key.C) && CtrlKeyDown && !ShiftKeyDown) { List StrToCopy = new List(); foreach (object SelectItem in ListView.SelectedItems) { StrToCopy.Add(CopyHandler(SelectItem)); } System.Windows.Clipboard.Clear(); // sometimes another process has "opened" the clipboard, so we need to wait for it try { Clipboard.SetText((string)String.Join("\n", StrToCopy), TextDataFormat.Text); return; } catch { } } else if ((e.Key == System.Windows.Input.Key.F) && CtrlKeyDown) { if (this.SearchBar != null) { this.SearchBar.Visibility = System.Windows.Visibility.Visible; this.SearchBar.Focus(); } return; } else if (e.Key == Key.Escape) { if (this.SearchBar != null) { this.SearchBar.Clear(); } } } #endregion events handlers } } ================================================ FILE: DependenciesGui/DependencyExportList.xaml ================================================  ================================================ FILE: DependenciesGui/DependencyExportList.xaml.cs ================================================ using System; using System.Linq; using System.Windows; using System.Collections.Generic; using System.Windows.Input; using Dependencies.ClrPh; namespace Dependencies { /// /// DependencyImportList Filterable ListView for displaying exports. /// public partial class DependencyExportList : DependencyCustomListView { public static readonly RoutedUICommand CopyValuesCommand = new RoutedUICommand(); public DependencyExportList() { InitializeComponent(); } public void SetExports(List Exports, PhSymbolProvider SymPrv) { this.Items.Clear(); foreach (PeExport Export in Exports) { this.Items.Add(new DisplayPeExport(Export, SymPrv)); } } private string ExportCopyHandler(object SelectedItem) { if (SelectedItem == null) { return ""; } return (SelectedItem as DisplayPeExport).ToString(); } private void ExportListCopySelectedValues(object sender, RoutedEventArgs e) { if (this.SelectedItems.Count == 0) return; List selectedExports = new List(); foreach (var import in this.SelectedItems) { selectedExports.Add((import as DisplayPeExport)); } string SelectedValues = String.Join("\n", selectedExports.Select(exp => exp.ToString())); Clipboard.Clear(); // sometimes another process has "opened" the clipboard, so we need to wait for it try { Clipboard.SetText((string)SelectedValues, TextDataFormat.Text); return; } catch { } } public void ResetAutoSortProperty() { Wpf.Util.GridViewSort.RemoveSort(this.Items, this); } } } ================================================ FILE: DependenciesGui/DependencyImportList.xaml ================================================  ================================================ FILE: DependenciesGui/DependencyImportList.xaml.cs ================================================ using System; using System.Linq; using System.Windows; using System.Collections.Generic; using System.Windows.Input; using Dependencies.ClrPh; namespace Dependencies { /// /// DependencyImportList Filterable ListView for displaying imports. /// public partial class DependencyImportList : DependencyCustomListView { public static readonly RoutedUICommand CopyValuesCommand = new RoutedUICommand(); public DependencyImportList() { InitializeComponent(); } public void SetImports(string ModuleFilepath, List Exports, List 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 SetRootImports(List 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)); } } } private string ImportCopyHandler(object SelectedItem) { if (SelectedItem == null) { return ""; } return (SelectedItem as DisplayPeImport).ToString(); } private void ImportListCopySelectedValues(object sender, RoutedEventArgs e) { if (this.SelectedItems.Count == 0) return; List selectedImports = new List(); foreach (var import in this.SelectedItems) { selectedImports.Add((import as DisplayPeImport)); } string SelectedValues = String.Join("\n", selectedImports.Select( imp => imp.ToString())); Clipboard.Clear(); // sometimes another process has "opened" the clipboard, so we need to wait for it try { Clipboard.SetText((string)SelectedValues, TextDataFormat.Text); return; } catch { } } public void ResetAutoSortProperty() { Wpf.Util.GridViewSort.RemoveSort(this.Items, this); } } } ================================================ FILE: DependenciesGui/DependencyModuleList.xaml ================================================  ================================================ FILE: DependenciesGui/DependencyModuleList.xaml.cs ================================================ using System; using System.Windows; using System.Collections.Generic; using System.Windows.Controls; using System.Windows.Input; using System.Diagnostics; using System.ComponentModel; using System.Windows.Data; namespace Dependencies { public class ModuleCacheKey { public ModuleCacheKey(string _Name, string _Filepath, ModuleFlag _Flags = ModuleFlag.NoFlag) { Name = _Name; Filepath = _Filepath; Flags = _Flags; } public ModuleCacheKey(ImportContext import) { Name = import.ModuleName; Filepath = import.PeFilePath; Flags = import.Flags; } // mandatory since ModuleCacheKey is used as a dictionnary key public override int GetHashCode() { int hashcode = Name.GetHashCode() ^ Flags.GetHashCode(); if (Filepath != null) { hashcode ^= Filepath.GetHashCode(); } return hashcode; } public string Name; public string Filepath; public ModuleFlag Flags; } public class ModulesCache : Dictionary { } /// /// DependencyImportList Filterable ListView for displaying modules. /// public partial class DependencyModuleList : DependencyCustomListView { //public ICollectionView ModulesItemsView { get; set; } public RelayCommand DoFindModuleInTreeCommand { get { return (RelayCommand) GetValue(DoFindModuleInTreeCommandProperty); } set { SetValue(DoFindModuleInTreeCommandProperty, value);} } public RelayCommand ConfigureSearchOrderCommand { get { return (RelayCommand)GetValue(ConfigureSearchOrderCommandProperty); } set { SetValue(ConfigureSearchOrderCommandProperty, value); } } // Using a DependencyProperty as the backing store for DoFindModuleInTreeCommand. This enables animation, styling, binding, etc... public static readonly DependencyProperty DoFindModuleInTreeCommandProperty = DependencyProperty.Register("DoFindModuleInTreeCommand", typeof(RelayCommand), typeof(DependencyModuleList), new UIPropertyMetadata(null)); public static readonly DependencyProperty ConfigureSearchOrderCommandProperty = DependencyProperty.Register("ConfigureSearchOrderCommand", typeof(RelayCommand), typeof(DependencyModuleList), new UIPropertyMetadata(null)); public static readonly RoutedEvent SelectedModuleChangedEvent = EventManager.RegisterRoutedEvent("SelectedModuleChanged", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(DependencyModuleList)); public DependencyModuleList() { InitializeComponent(); } public void AddModule(DisplayModuleInfo NewModule) { // TODO : Find a way to properly bind commands instead of using this hack NewModule.DoFindModuleInTreeCommand = DoFindModuleInTreeCommand; NewModule.ConfigureSearchOrderCommand = ConfigureSearchOrderCommand; this.Items.Add(NewModule); } public event RoutedEventHandler SelectedModuleChanged { add { AddHandler(SelectedModuleChangedEvent, value); } remove { RemoveHandler(SelectedModuleChangedEvent, value); } } private void OnSelectedModuleChanged(object sender, MouseButtonEventArgs e) { RaiseEvent(new RoutedEventArgs(SelectedModuleChangedEvent)); } private string ModuleCopyHandler(object SelectedItem) { if (SelectedItem == null) { return ""; } return (SelectedItem as DisplayModuleInfo).ModuleName; } } } ================================================ FILE: DependenciesGui/DependencyWindow.xaml ================================================  ================================================ FILE: DependenciesGui/DependencyWindow.xaml.cs ================================================ using System; using System.IO; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.ComponentModel; using System.Windows.Input; using System.Diagnostics; using System.Windows.Data; using Microsoft.Win32; using Mono.Cecil; using Dependencies.ClrPh; namespace Dependencies { /// /// ImportContext : Describe an import module parsed from a PE. /// Only used during the dependency tree building phase /// public struct ImportContext { // Import "identifier" public string ModuleName; // Return how the module was found (NOT_FOUND otherwise) public ModuleSearchStrategy ModuleLocation; // If found, set the filepath and parsed PE, otherwise it's null public string PeFilePath; public PE PeProperties; // Some imports are from api sets public bool IsApiSet; public string ApiSetModuleName; // module flag attributes public ModuleFlag Flags; } /// /// Dependency tree building behaviour. /// A full recursive dependency tree can be memory intensive, therefore the /// choice is left to the user to override the default behaviour. /// public class TreeBuildingBehaviour : IValueConverter { public enum DependencyTreeBehaviour { ChildOnly, RecursiveOnlyOnDirectImports, Recursive, } public static DependencyTreeBehaviour GetGlobalBehaviour() { return (DependencyTreeBehaviour) (new TreeBuildingBehaviour()).Convert( Dependencies.Properties.Settings.Default.TreeBuildBehaviour, null,// targetType null,// parameter null // System.Globalization.CultureInfo ); } #region TreeBuildingBehaviour.IValueConverter_contract public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { string StrBehaviour = (string)value; switch (StrBehaviour) { default: case "ChildOnly": return DependencyTreeBehaviour.ChildOnly; case "RecursiveOnlyOnDirectImports": return DependencyTreeBehaviour.RecursiveOnlyOnDirectImports; case "Recursive": return DependencyTreeBehaviour.Recursive; } } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { DependencyTreeBehaviour Behaviour = (DependencyTreeBehaviour) value; switch (Behaviour) { default: case DependencyTreeBehaviour.ChildOnly: return "ChildOnly"; case DependencyTreeBehaviour.RecursiveOnlyOnDirectImports: return "RecursiveOnlyOnDirectImports"; case DependencyTreeBehaviour.Recursive: return "Recursive"; } } #endregion TreeBuildingBehaviour.IValueConverter_contract } /// /// Dependency tree building behaviour. /// A full recursive dependency tree can be memory intensive, therefore the /// choice is left to the user to override the default behaviour. /// public class BinaryCacheOption : IValueConverter { [TypeConverter(typeof(EnumToStringUsingDescription))] public enum BinaryCacheOptionValue { [Description("No (faster, but locks dll until Dependencies is closed)")] No = 0, [Description("Yes (prevents file locking issues)")] Yes = 1 } public static BinaryCacheOptionValue GetGlobalBehaviour() { return (BinaryCacheOptionValue)(new BinaryCacheOption()).Convert( Dependencies.Properties.Settings.Default.BinaryCacheOptionValue, null,// targetType null,// parameter null // System.Globalization.CultureInfo ); } #region BinaryCacheOption.IValueConverter_contract public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { bool StrOption = (bool)value; switch (StrOption) { default: case true: return BinaryCacheOptionValue.Yes; case false: return BinaryCacheOptionValue.No; } } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { BinaryCacheOptionValue Behaviour = (BinaryCacheOptionValue)(int)value; switch (Behaviour) { default: case BinaryCacheOptionValue.Yes: return true; case BinaryCacheOptionValue.No: return false; } } #endregion BinaryCacheOption.IValueConverter_contract } public class EnumToStringUsingDescription : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { return (sourceType.Equals(typeof(Enum))); } public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { return (destinationType.Equals(typeof(String))); } public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) { return base.ConvertFrom(context, culture, value); } public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) { if (!destinationType.Equals(typeof(String))) { throw new ArgumentException("Can only convert to string.", "destinationType"); } if (!value.GetType().BaseType.Equals(typeof(Enum))) { throw new ArgumentException("Can only convert an instance of enum.", "value"); } string name = value.ToString(); object[] attrs = value.GetType().GetField(name).GetCustomAttributes(typeof(DescriptionAttribute), false); return (attrs.Length > 0) ? ((DescriptionAttribute)attrs[0]).Description : name; } } /// /// User context of every dependency tree node. /// public struct DependencyNodeContext { public DependencyNodeContext(DependencyNodeContext other) { ModuleInfo = other.ModuleInfo; IsDummy = other.IsDummy; } /// /// We use a WeakReference to point towars a DisplayInfoModule /// in order to reduce memory allocations. /// public WeakReference ModuleInfo; /// /// Depending on the dependency tree behaviour, we may have to /// set up "dummy" nodes in order for the parent to display the ">" button. /// Those dummy are usually destroyed when their parents is expandend and imports resolved. /// public bool IsDummy; } /// /// Deprendency Tree custom node. It's DataContext is a DependencyNodeContext struct /// public class ModuleTreeViewItem : TreeViewItem, INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public ModuleTreeViewItem() { _importsVerified = false; _Parent = null; Dependencies.Properties.Settings.Default.PropertyChanged += this.ModuleTreeViewItem_PropertyChanged; } public ModuleTreeViewItem(ModuleTreeViewItem Parent) { _importsVerified = false; _Parent = Parent; Dependencies.Properties.Settings.Default.PropertyChanged += this.ModuleTreeViewItem_PropertyChanged; } public ModuleTreeViewItem(ModuleTreeViewItem Other, ModuleTreeViewItem Parent) { _importsVerified = false; _Parent = Parent; this.DataContext = new DependencyNodeContext( (DependencyNodeContext) Other.DataContext ); Dependencies.Properties.Settings.Default.PropertyChanged += this.ModuleTreeViewItem_PropertyChanged; } #region PropertyEventHandlers public virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private void ModuleTreeViewItem_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "FullPath") { this.Header = (object)GetTreeNodeHeaderName(Dependencies.Properties.Settings.Default.FullPath); } } #endregion PropertyEventHandlers #region Getters public string GetTreeNodeHeaderName(bool FullPath) { return (((DependencyNodeContext)this.DataContext).ModuleInfo.Target as DisplayModuleInfo).ModuleName; } public string ModuleFilePath { get { return (((DependencyNodeContext)this.DataContext).ModuleInfo.Target as DisplayModuleInfo).Filepath; } } public ModuleTreeViewItem ParentModule { get { return _Parent; } } public ModuleFlag Flags { get { return ModuleInfo.Flags; } } private bool _has_error; public bool HasErrors { get { if (!_importsVerified) { _has_error = VerifyModuleImports(); _importsVerified = true; // Update tooltip only once some basic checks are done this.ToolTip = ModuleInfo.Status; } // propagate error for parent if (_has_error) { ModuleTreeViewItem ParentModule = this.ParentModule; if (ParentModule != null) { ParentModule.HasChildErrors = true; } } return _has_error; } set { if (value == _has_error) return; _has_error = value; OnPropertyChanged("HasErrors"); } } public string Tooltip { get { return ModuleInfo.Status; } } public bool HasChildErrors { get { return _has_child_errors; } set { if (value) { ModuleInfo.Flags |= ModuleFlag.ChildrenError; } else { ModuleInfo.Flags &= ~ModuleFlag.ChildrenError; } ToolTip = ModuleInfo.Status; _has_child_errors = true; OnPropertyChanged("HasChildErrors"); // propagate error for parent ModuleTreeViewItem ParentModule = this.ParentModule; if (ParentModule != null) { ParentModule.HasChildErrors = true; } } } public DisplayModuleInfo ModuleInfo { get { return (((DependencyNodeContext)this.DataContext).ModuleInfo.Target as DisplayModuleInfo); } } 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> resolvedImports = BinaryCache.LookupImports(DllImport, ModuleInfo.Filepath); if (resolvedImports.Count == 0) { return true; } foreach (var Import in resolvedImports) { if (!Import.Item2) { return true; } } } return false; } #endregion Getters #region Commands public RelayCommand OpenPeviewerCommand { get { if (_OpenPeviewerCommand == null) { _OpenPeviewerCommand = new RelayCommand((param) => this.OpenPeviewer((object)param)); } return _OpenPeviewerCommand; } } public bool OpenPeviewer(object Context) { string programPath = Dependencies.Properties.Settings.Default.PeViewerPath; Process PeviewerProcess = new Process(); if (Context == null) { return false; } if (!File.Exists(programPath)) { System.Windows.MessageBox.Show(String.Format("{0:s} file could not be found !", programPath)); return false; } string Filepath = ModuleFilePath; if (Filepath == null) { return false; } PeviewerProcess.StartInfo.FileName = String.Format("\"{0:s}\"", programPath); PeviewerProcess.StartInfo.Arguments = String.Format("\"{0:s}\"", Filepath); return PeviewerProcess.Start(); } public RelayCommand OpenNewAppCommand { get { if (_OpenNewAppCommand == null) { _OpenNewAppCommand = new RelayCommand((param) => { string Filepath = ModuleFilePath; if (Filepath == null) { return; } Process OtherDependenciesProcess = new Process(); OtherDependenciesProcess.StartInfo.FileName = System.Windows.Forms.Application.ExecutablePath; OtherDependenciesProcess.StartInfo.Arguments = String.Format("\"{0:s}\"", Filepath); OtherDependenciesProcess.Start(); }); } return _OpenNewAppCommand; } } #endregion // Commands private RelayCommand _OpenPeviewerCommand; private RelayCommand _OpenNewAppCommand; private ModuleTreeViewItem _Parent; private bool _importsVerified; private bool _has_child_errors; } /// /// Dependemcy tree analysis window for a given PE. /// public partial class DependencyWindow : TabItem { PE Pe; public string RootFolder; public string WorkingDirectory; string Filename; PhSymbolProvider SymPrv; SxsEntries SxsEntriesCache; ApiSetSchema ApiSetmapCache; ModulesCache ProcessedModulesCache; DisplayModuleInfo _SelectedModule; bool _DisplayWarning; public List CustomSearchFolders; #region PublicAPI public DependencyWindow(String Filename, List CustomSearchFolders = null) { InitializeComponent(); if (CustomSearchFolders != null) { this.CustomSearchFolders = CustomSearchFolders; } else { this.CustomSearchFolders = new List(); } this.Filename = Filename; this.WorkingDirectory = Path.GetDirectoryName(this.Filename); InitializeView(); } public void InitializeView() { if (!NativeFile.Exists(this.Filename)) { MessageBox.Show( String.Format("{0:s} is not present on the disk", this.Filename), "Invalid PE", MessageBoxButton.OK ); return; } this.Pe = (Application.Current as App).LoadBinary(this.Filename); if (this.Pe == null || !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(this.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.Items.Clear(); this.ModulesList.DoFindModuleInTreeCommand = DoFindModuleInTree; this.ModulesList.ConfigureSearchOrderCommand = ConfigureSearchOrderCommand; var RootFilename = Path.GetFileName(this.Filename); var RootModule = new DisplayModuleInfo(RootFilename, this.Pe, ModuleSearchStrategy.ROOT); this.ProcessedModulesCache.Add(new ModuleCacheKey(RootFilename, this.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.Clear(); this.DllTreeView.Items.Add(treeNode); // Recursively construct tree of dll imports ConstructDependencyTree(treeNode, this.Pe); } #endregion PublicAPI #region TreeConstruction 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 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 TriggerWarningOnAppvIsvImports(string DllImportName) { if (String.Compare(DllImportName, "AppvIsvSubsystems32.dll", StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(DllImportName, "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 } } } private void ProcessAppInitDlls(Dictionary NewTreeContexts, PE AnalyzedPe, ImportContext ImportModule) { List 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 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); } } private void ProcessClrImports(Dictionary NewTreeContexts, PE AnalyzedPe, ImportContext ImportModule) { List 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 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 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); } } } } /// /// Background processing of a single PE file. /// It can be lengthy since there are disk access (and misses). /// /// This variable is passed as reference to be updated since this function is run in a separate thread. /// Current PE file analyzed private void ProcessPe(Dictionary NewTreeContexts, PE newPe) { List PeImports = newPe.GetImports(); foreach (PeImportDll DllImport in PeImports) { // Ignore already processed imports if (NewTreeContexts.ContainsKey(DllImport.Name)) { continue; } // Find Dll in "paths" ImportContext ImportModule = ResolveImport(DllImport); // add warning for appv isv applications TriggerWarningOnAppvIsvImports(DllImport.Name); NewTreeContexts.Add(DllImport.Name, ImportModule); // AppInitDlls are triggered by user32.dll, so if the binary does not import user32.dll they are not loaded. ProcessAppInitDlls(NewTreeContexts, newPe, ImportModule); // if mscoree.dll is imported, it means the module is a C# assembly, and we can use Mono.Cecil to enumerate its references ProcessClrImports(NewTreeContexts, newPe, ImportModule); } } private class BacklogImport : Tuple { public BacklogImport(ModuleTreeViewItem Node, string Filepath) : base(Node, Filepath) { } } private void ConstructDependencyTree(ModuleTreeViewItem RootNode, string FilePath, int RecursionLevel = 0) { PE CurrentPE = (Application.Current as App).LoadBinary(FilePath); if (null == CurrentPE) { return; } ConstructDependencyTree(RootNode, CurrentPE, RecursionLevel); } private void ConstructDependencyTree(ModuleTreeViewItem RootNode, PE CurrentPE, int RecursionLevel = 0) { // "Closured" variables (it 's a scope hack really). Dictionary NewTreeContexts = new Dictionary(); BackgroundWorker bw = new BackgroundWorker(); bw.WorkerReportsProgress = true; // useless here for now bw.DoWork += (sender, e) => { ProcessPe(NewTreeContexts, CurrentPE); }; bw.RunWorkerCompleted += (sender, e) => { TreeBuildingBehaviour.DependencyTreeBehaviour SettingTreeBehaviour = Dependencies.TreeBuildingBehaviour.GetGlobalBehaviour(); List PeWithDummyEntries = new List(); List PEProcessingBacklog = new List(); // Important ! // // This handler is executed in the STA (Single Thread Application) // which is authorized to manipulate UI elements. The BackgroundWorker is not. // foreach (ImportContext NewTreeContext in NewTreeContexts.Values) { ModuleTreeViewItem childTreeNode = new ModuleTreeViewItem(RootNode); DependencyNodeContext childTreeNodeContext = new DependencyNodeContext(); childTreeNodeContext.IsDummy = false; string ModuleName = NewTreeContext.ModuleName; string ModuleFilePath = NewTreeContext.PeFilePath; ModuleCacheKey ModuleKey = new ModuleCacheKey(NewTreeContext); // Newly seen modules if (!this.ProcessedModulesCache.ContainsKey(ModuleKey)) { // Missing module "found" if ((NewTreeContext.PeFilePath == null) || !NativeFile.Exists(NewTreeContext.PeFilePath)) { if (NewTreeContext.IsApiSet) { this.ProcessedModulesCache[ModuleKey] = new ApiSetNotFoundModuleInfo(ModuleName, NewTreeContext.ApiSetModuleName); } else { this.ProcessedModulesCache[ModuleKey] = new NotFoundModuleInfo(ModuleName); } } else { if (NewTreeContext.IsApiSet) { var ApiSetContractModule = new DisplayModuleInfo(NewTreeContext.ApiSetModuleName, NewTreeContext.PeProperties, NewTreeContext.ModuleLocation, NewTreeContext.Flags); var NewModule = new ApiSetModuleInfo(NewTreeContext.ModuleName, ref ApiSetContractModule); this.ProcessedModulesCache[ModuleKey] = NewModule; if (SettingTreeBehaviour == TreeBuildingBehaviour.DependencyTreeBehaviour.Recursive) { PEProcessingBacklog.Add(new BacklogImport(childTreeNode, ApiSetContractModule.ModuleName)); } } else { var NewModule = new DisplayModuleInfo(NewTreeContext.ModuleName, NewTreeContext.PeProperties, NewTreeContext.ModuleLocation, NewTreeContext.Flags); this.ProcessedModulesCache[ModuleKey] = NewModule; switch(SettingTreeBehaviour) { case TreeBuildingBehaviour.DependencyTreeBehaviour.RecursiveOnlyOnDirectImports: if ((NewTreeContext.Flags & ModuleFlag.DelayLoad) == 0) { PEProcessingBacklog.Add(new BacklogImport(childTreeNode, NewModule.ModuleName)); } break; case TreeBuildingBehaviour.DependencyTreeBehaviour.Recursive: PEProcessingBacklog.Add(new BacklogImport(childTreeNode, NewModule.ModuleName)); break; } } } // add it to the module list this.ModulesList.AddModule(this.ProcessedModulesCache[ModuleKey]); } // Since we uniquely process PE, for thoses who have already been "seen", // we set a dummy entry in order to set the "[+]" icon next to the node. // The dll dependencies are actually resolved on user double-click action // We can't do the resolution in the same time as the tree construction since // it's asynchronous (we would have to wait for all the background to finish and // use another Async worker to resolve). if ((NewTreeContext.PeProperties != null) && (NewTreeContext.PeProperties.GetImports().Count > 0)) { ModuleTreeViewItem DummyEntry = new ModuleTreeViewItem(); DependencyNodeContext DummyContext = new DependencyNodeContext() { ModuleInfo = new WeakReference(new NotFoundModuleInfo("Dummy")), IsDummy = true }; DummyEntry.DataContext = DummyContext; DummyEntry.Header = "@Dummy : if you see this header, it's a bug."; DummyEntry.IsExpanded = false; childTreeNode.Items.Add(DummyEntry); childTreeNode.Expanded += ResolveDummyEntries; } // Add to tree view childTreeNodeContext.ModuleInfo = new WeakReference(this.ProcessedModulesCache[ModuleKey]); childTreeNode.DataContext = childTreeNodeContext; childTreeNode.Header = childTreeNode.GetTreeNodeHeaderName(Dependencies.Properties.Settings.Default.FullPath); RootNode.Items.Add(childTreeNode); } // Process next batch of dll imports only if : // 1. Recursive tree building has been activated // 2. Recursion is not hitting the max depth level bool doProcessNextLevel = (SettingTreeBehaviour != TreeBuildingBehaviour.DependencyTreeBehaviour.ChildOnly) && (RecursionLevel < Dependencies.Properties.Settings.Default.TreeDepth); if (doProcessNextLevel) { foreach (var ImportNode in PEProcessingBacklog) { ConstructDependencyTree(ImportNode.Item1, ImportNode.Item2, RecursionLevel + 1); // warning : recursive call } } }; bw.RunWorkerAsync(); } /// /// Resolve imports when the user expand the node. /// private void ResolveDummyEntries(object sender, RoutedEventArgs e) { ModuleTreeViewItem NeedDummyPeNode = e.OriginalSource as ModuleTreeViewItem; if (NeedDummyPeNode.Items.Count == 0) { return; } ModuleTreeViewItem MaybeDummyNode = (ModuleTreeViewItem) NeedDummyPeNode.Items[0]; DependencyNodeContext Context = (DependencyNodeContext)MaybeDummyNode.DataContext; //TODO: Improve resolution predicate if (!Context.IsDummy) { return; } NeedDummyPeNode.Items.Clear(); string Filepath = NeedDummyPeNode.ModuleFilePath; ConstructDependencyTree(NeedDummyPeNode, Filepath); } #endregion TreeConstruction #region Commands private void OnModuleViewSelectedItemChanged(object sender, RoutedEventArgs e) { DisplayModuleInfo SelectedModule = (sender as DependencyModuleList).SelectedItem as DisplayModuleInfo; // Selected Pe has not been found on disk if (SelectedModule == null) return; // Display module as root (since we can't know which parent it's attached to) UpdateImportExportLists(SelectedModule, null); } private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e) { if (this.DllTreeView.SelectedItem == null) { UpdateImportExportLists(null, null); return; } DependencyNodeContext childTreeContext = ((DependencyNodeContext)(this.DllTreeView.SelectedItem as ModuleTreeViewItem).DataContext); DisplayModuleInfo SelectedModule = childTreeContext.ModuleInfo.Target as DisplayModuleInfo; if (SelectedModule == null) { return; } // Selected Pe has not been found on disk : unvalidate current module SelectedModule.HasErrors = !NativeFile.Exists(SelectedModule.Filepath); if (SelectedModule.HasErrors) { // TODO : do a proper refresh instead of asking the user to do it System.Windows.MessageBox.Show(String.Format("We could not find {0:s} file on the disk anymore, please fix this problem and refresh the window via F5", SelectedModule.Filepath)); } // Root Item : no parent ModuleTreeViewItem TreeRootItem = this.DllTreeView.Items[0] as ModuleTreeViewItem; ModuleTreeViewItem SelectedItem = this.DllTreeView.SelectedItem as ModuleTreeViewItem; if (SelectedItem == TreeRootItem) { // Selected Pe has not been found on disk : unvalidate current module if (SelectedModule.HasErrors) { UpdateImportExportLists(null, null); } else { SelectedModule.HasErrors = false; UpdateImportExportLists(SelectedModule, null); } return; } // Tree Item DisplayModuleInfo parentModule = SelectedItem.ParentModule.ModuleInfo; UpdateImportExportLists(SelectedModule, parentModule); } private void UpdateImportExportLists(DisplayModuleInfo SelectedModule, DisplayModuleInfo Parent) { if (SelectedModule == null) { this.ImportList.Items.Clear(); this.ExportList.Items.Clear(); } else { if (Parent == null) // root module { this.ImportList.SetRootImports(SelectedModule.Imports, SymPrv, this); } else { // Imports from the same dll are not necessarly sequential (see: HDDGuru\RawCopy.exe) var machingImports = Parent.Imports.FindAll(imp => imp.Name == SelectedModule._Name); this.ImportList.SetImports(SelectedModule.Filepath, SelectedModule.Exports, machingImports, SymPrv, this); } this.ImportList.ResetAutoSortProperty(); this.ExportList.SetExports(SelectedModule.Exports, SymPrv); this.ExportList.ResetAutoSortProperty(); } } public PE LoadImport(string ModuleName, DisplayModuleInfo CurrentModule = null, bool DelayLoad = false) { if (CurrentModule == null) { CurrentModule = this._SelectedModule; } Tuple ResolvedModule = BinaryCache.ResolveModule( this.Pe, ModuleName, this.SxsEntriesCache, this.CustomSearchFolders, this.WorkingDirectory ); string ModuleFilepath = (ResolvedModule.Item2 != null) ? ResolvedModule.Item2.Filepath : null; // Not found module, returning PE without update module list if (ModuleFilepath == null) { return ResolvedModule.Item2; } ModuleFlag ModuleFlags = ModuleFlag.NoFlag; if (DelayLoad) ModuleFlags |= ModuleFlag.DelayLoad; if (ResolvedModule.Item1 == ModuleSearchStrategy.ApiSetSchema) ModuleFlags |= ModuleFlag.ApiSet; ModuleCacheKey ModuleKey = new ModuleCacheKey(ModuleName, ModuleFilepath, ModuleFlags); if (!this.ProcessedModulesCache.ContainsKey(ModuleKey)) { DisplayModuleInfo NewModule; // apiset resolution are a bit trickier if (ResolvedModule.Item1 == ModuleSearchStrategy.ApiSetSchema) { var ApiSetContractModule = new DisplayModuleInfo( BinaryCache.LookupApiSetLibrary(ModuleName), ResolvedModule.Item2, ResolvedModule.Item1, ModuleFlags ); NewModule = new ApiSetModuleInfo(ModuleName, ref ApiSetContractModule); } else { NewModule = new DisplayModuleInfo( ModuleName, ResolvedModule.Item2, ResolvedModule.Item1, ModuleFlags ); } this.ProcessedModulesCache[ModuleKey] = NewModule; // add it to the module list this.ModulesList.AddModule(this.ProcessedModulesCache[ModuleKey]); } return ResolvedModule.Item2; } /// /// Reentrant version of Collapse/Expand Node /// /// /// private void CollapseOrExpandAllNodes(ModuleTreeViewItem Item, bool ExpandNode) { Item.IsExpanded = ExpandNode; foreach(ModuleTreeViewItem ChildItem in Item.Items) { CollapseOrExpandAllNodes(ChildItem, ExpandNode); } } private void ExpandAllNodes_Executed(object sender, ExecutedRoutedEventArgs e) { // Expanding all nodes tends to slow down the application (massive allocations for node DataContext) // TODO : Reduce memory pressure by storing tree nodes data context in a HashSet and find an async trick // to improve the command responsiveness. System.Windows.Controls.TreeView TreeNode = sender as System.Windows.Controls.TreeView; CollapseOrExpandAllNodes((TreeNode.Items[0] as ModuleTreeViewItem), true); } private void CollapseAllNodes_Executed(object sender, ExecutedRoutedEventArgs e) { System.Windows.Controls.TreeView TreeNode = sender as System.Windows.Controls.TreeView; CollapseOrExpandAllNodes((TreeNode.Items[0] as ModuleTreeViewItem), false); } private void DoFindModuleInList_Executed(object sender, ExecutedRoutedEventArgs e) { ModuleTreeViewItem Source = e.Source as ModuleTreeViewItem; String SelectedModuleName = Source.GetTreeNodeHeaderName(Dependencies.Properties.Settings.Default.FullPath); foreach (DisplayModuleInfo item in this.ModulesList.Items) { if (item.ModuleName == SelectedModuleName) { this.ModulesList.SelectedItem = item; this.ModulesList.ScrollIntoView(item); return; } } } private void ExpandAllParentNode(ModuleTreeViewItem Item) { if (Item != null) { ExpandAllParentNode(Item.Parent as ModuleTreeViewItem); Item.IsExpanded = true; } } /// /// Reentrant version of Collapse/Expand Node /// /// /// private ModuleTreeViewItem FindModuleInTree(ModuleTreeViewItem Item, DisplayModuleInfo Module, bool Highlight=false) { if (Item.GetTreeNodeHeaderName(Dependencies.Properties.Settings.Default.FullPath) == Module.ModuleName) { if (Highlight) { ExpandAllParentNode(Item.Parent as ModuleTreeViewItem); Item.IsSelected = true; Item.BringIntoView(); Item.Focus(); } return Item; } // BFS style search -> return the first matching node with the lowest "depth" foreach (ModuleTreeViewItem ChildItem in Item.Items) { if(ChildItem.GetTreeNodeHeaderName(Dependencies.Properties.Settings.Default.FullPath) == Module.ModuleName) { if (Highlight) { ExpandAllParentNode(Item); ChildItem.IsSelected = true; ChildItem.BringIntoView(); ChildItem.Focus(); } return Item; } } foreach (ModuleTreeViewItem ChildItem in Item.Items) { ModuleTreeViewItem matchingItem = FindModuleInTree(ChildItem, Module, Highlight); // early exit as soon as we find a matching node if (matchingItem != null) return matchingItem; } return null; } public RelayCommand DoFindModuleInTree { get { return new RelayCommand((param) => { DisplayModuleInfo SelectedModule = (param as DisplayModuleInfo); ModuleTreeViewItem TreeRootItem = this.DllTreeView.Items[0] as ModuleTreeViewItem; FindModuleInTree(TreeRootItem, SelectedModule, true); }); } } public RelayCommand ConfigureSearchOrderCommand { get { return new RelayCommand((param) => { ModuleSearchOrder modalWindow = new ModuleSearchOrder(ProcessedModulesCache); modalWindow.ShowDialog(); }); } } #endregion // Commands } } ================================================ FILE: DependenciesGui/DragablzCustomHeader.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace Dependencies { public partial class DragablzCustomHeader : UserControl { public DragablzCustomHeader() { InitializeComponent(); } } } ================================================ FILE: DependenciesGui/DragablzCustomHeader.xaml ================================================  ================================================ FILE: DependenciesGui/FilterControl/FilterControl.cs ================================================ using System; using System.Windows.Controls; using System.Windows; using System.Windows.Threading; using System.Windows.Data; using System.Windows.Input; using System.Collections; using System.Reflection; using System.ComponentModel; using System.Linq; namespace Dependencies { public delegate void FilterRoutedEventHandler(object sender, FilterEventArgs e); public delegate void DirectionRoutedEventHandler(object sender, DirectionEventArgs e); public enum DirectionEnum { Default, Up, Down, Left, Right, } [TemplatePart(Name = PART_FilterBox, Type = typeof(TextBox))] [TemplatePart(Name = PART_ClearButton, Type = typeof(Button))] [TemplatePart(Name = PART_Header, Type = typeof(TextBlock))] public class FilterControl : Control { #region Declarations private const string PART_FilterBox = "PART_FilterBox"; private const string PART_ClearButton = "PART_ClearButton"; private const string PART_Header = "PART_Header"; public static readonly RoutedEvent FilterEvent; public static readonly RoutedEvent DirectionEvent; public static readonly RoutedEvent ClearFilterEvent; private Button clearButton = null; private TextBox filterBox = null; private TextBlock textBlock = null; private int tickCount; private bool byPassEvent = false; private DispatcherTimer timer; #endregion #region Constructors static FilterControl() { //This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class. //This style is defined in themes\generic.xaml DefaultStyleKeyProperty.OverrideMetadata(typeof(FilterControl), new FrameworkPropertyMetadata(typeof(FilterControl))); FilterEvent = EventManager.RegisterRoutedEvent("Filter", RoutingStrategy.Bubble, typeof(FilterRoutedEventHandler), typeof(FilterControl)); DirectionEvent = EventManager.RegisterRoutedEvent("Direction", RoutingStrategy.Bubble, typeof(DirectionRoutedEventHandler), typeof(FilterControl)); ClearFilterEvent = EventManager.RegisterRoutedEvent("ClearFilter", RoutingStrategy.Bubble, typeof(RoutedEventArgs), typeof(FilterControl)); } public FilterControl() { timer = new DispatcherTimer(DispatcherPriority.Normal); timer.Interval = new TimeSpan(0, 0, 0, 0, FilterFiringInterval); timer.Tick += new EventHandler(OnDispatcherTimerTick); Visibility = System.Windows.Visibility.Collapsed; } #endregion #region FilterText property public string FilterText { get { return (string)GetValue(FilterTextProperty); } set { SetValue(FilterTextProperty, value); } } public static readonly DependencyProperty FilterTextProperty = DependencyProperty.Register("FilterText", typeof(string), typeof(FilterControl), new PropertyMetadata(string.Empty)); #endregion #region Header property public string Header { get { return (string)GetValue(HeaderProperty); } set { SetValue(HeaderProperty, value); } } public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(string), typeof(FilterControl), new UIPropertyMetadata(string.Empty)); #endregion #region TargetControl property public ItemsControl TargetControl { get { return (ItemsControl)GetValue(TargetControlProperty); } set { SetValue(TargetControlProperty, value); } } public static readonly DependencyProperty TargetControlProperty = DependencyProperty.Register("TargetControl", typeof(ItemsControl), typeof(FilterControl), new UIPropertyMetadata(null)); #endregion #region FilterTextBindingPath property public string FilterTextBindingPath { get { return (string)GetValue(FilterTextBindingPathProperty); } set { SetValue(FilterTextBindingPathProperty, value); } } public static readonly DependencyProperty FilterTextBindingPathProperty = DependencyProperty.Register("FilterTextBindingPath", typeof(string), typeof(FilterControl), new PropertyMetadata(string.Empty)); #endregion #region FilterOnEnter property public bool FilterOnEnter { get { return (bool)GetValue(FilterOnEnterProperty); } set { SetValue(FilterOnEnterProperty, value); } } public static readonly DependencyProperty FilterOnEnterProperty = DependencyProperty.Register("FilterOnEnter", typeof(bool), typeof(FilterControl), new UIPropertyMetadata(false)); #endregion #region FilterFiringInterval property public int FilterFiringInterval { get { return (int)GetValue(FilterFiringIntervalProperty); } set { SetValue(FilterFiringIntervalProperty, value); } } public static readonly DependencyProperty FilterFiringIntervalProperty = DependencyProperty.Register("FilterFiringInterval", typeof(int), typeof(FilterControl), new UIPropertyMetadata(300, new PropertyChangedCallback(OnFilterFiringIntervalChanged))); private static void OnFilterFiringIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { FilterControl filterBox = d as FilterControl; filterBox.timer.Interval = new TimeSpan(0, 0, 0, 0, filterBox.FilterFiringInterval); } #endregion #region Filter event public event FilterRoutedEventHandler Filter { add { base.AddHandler(FilterEvent, value); } remove { base.RemoveHandler(FilterEvent, value); } } #endregion #region Direction event public event DirectionRoutedEventHandler Direction { add { base.AddHandler(DirectionEvent, value); } remove { base.RemoveHandler(DirectionEvent, value); } } #endregion #region ClearFilter event public event RoutedEventHandler ClearFilter { add { base.AddHandler(ClearFilterEvent, value); } remove { base.RemoveHandler(ClearFilterEvent, value); } } #endregion #region Overridden Functions/Methods public override void OnApplyTemplate() { base.OnApplyTemplate(); AttachToVisualTree(); } #endregion #region Private Functions/Methods private void ApplyFilterOnTarget() { if (TargetControl == null || TargetControl.Items.SourceCollection == null) return; ICollectionView collectionView = CollectionViewSource.GetDefaultView(TargetControl.Items.SourceCollection); if (collectionView == null) { throw new InvalidOperationException("The TargetConrol should use ICollectionView as ItemSource."); } if (string.IsNullOrEmpty(this.FilterTextBindingPath)) { throw new InvalidOperationException("FilterTextBindingPath is not set."); } collectionView.Filter = (m => (GetDataValue(m, this.FilterTextBindingPath).IndexOf(this.FilterText, StringComparison.InvariantCultureIgnoreCase) > -1)); } private void ClearFilterOnTarget() { if (TargetControl == null || TargetControl.Items.SourceCollection == null) return; ICollectionView collectionView = CollectionViewSource.GetDefaultView(TargetControl.Items.SourceCollection); if (collectionView == null) { throw new InvalidOperationException("The TargetControl should use ICollectionView as ItemSource."); } collectionView.Filter = null; this.Visibility = System.Windows.Visibility.Collapsed; } public void RaiseFilterEvent() { FilterEventArgs args = new FilterEventArgs(FilterEvent, this, this.FilterText); RaiseEvent(args); if (!args.IsFilterApplied) { ApplyFilterOnTarget(); } } private T GetDataValue(object data, string propertyName) { PropertyInfo[] propinfo = data.GetType().GetProperties(); PropertyDescriptorCollection descriptors = TypeDescriptor.GetProperties(data.GetType()); PropertyDescriptor descriptor = descriptors[propertyName]; if (descriptor == null) { throw new InvalidOperationException(); } T value = (T)descriptor.GetValue(data); return value; } private void AttachToVisualTree() { textBlock = GetTemplateChild(PART_Header) as TextBlock; filterBox = GetTemplateChild(PART_FilterBox) as TextBox; if (filterBox != null) { filterBox.Focus(); filterBox.LostKeyboardFocus += new System.Windows.Input.KeyboardFocusChangedEventHandler(OnLostKeyboardFocus); filterBox.GotKeyboardFocus += new System.Windows.Input.KeyboardFocusChangedEventHandler(OnGotKeyboardFocus); filterBox.TextChanged += new TextChangedEventHandler(OnFilterBoxTextChanged); } clearButton = GetTemplateChild(PART_ClearButton) as Button; if (clearButton != null) { clearButton.Click += new RoutedEventHandler(OnClearButtonClick); } this.KeyDown += new KeyEventHandler(OnControlKeyDown); this.GotKeyboardFocus += new KeyboardFocusChangedEventHandler(OnKeyboardGotFocus); } private void OnKeyboardGotFocus(object sender, KeyboardFocusChangedEventArgs e) { Keyboard.Focus(filterBox); } private void OnControlKeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Escape) /* && !string.IsNullOrEmpty(FilterText)) */ { Clear(); } else if (e.Key == Key.Enter && FilterOnEnter) { RaiseFilterEvent(); } else if (e.Key == Key.Up) { DirectionEventArgs args = new DirectionEventArgs(DirectionEvent, this, DirectionEnum.Up); RaiseEvent(args); } else if (e.Key == Key.Down) { DirectionEventArgs args = new DirectionEventArgs(DirectionEvent, this, DirectionEnum.Down); RaiseEvent(args); } else if (e.Key == Key.Right) { DirectionEventArgs args = new DirectionEventArgs(DirectionEvent, this, DirectionEnum.Right); RaiseEvent(args); } else if (e.Key == Key.Left) { DirectionEventArgs args = new DirectionEventArgs(DirectionEvent, this, DirectionEnum.Left); RaiseEvent(args); } } private void OnClearButtonClick(object sender, RoutedEventArgs e) { Clear(); } public void Clear() { byPassEvent = true; filterBox.Text = string.Empty; Keyboard.Focus(filterBox); RoutedEventArgs args = new RoutedEventArgs(ClearFilterEvent, this); RaiseEvent(args); if (!args.Handled) { ClearFilterOnTarget(); } } private void OnFilterBoxTextChanged(object sender, TextChangedEventArgs e) { if (!FilterOnEnter) { tickCount = 0; timer.Start(); } if (string.IsNullOrEmpty(filterBox.Text)) { // clearButton.Visibility = Visibility.Collapsed; if (!filterBox.IsFocused) textBlock.Visibility = Visibility.Visible; else textBlock.Visibility = Visibility.Collapsed; } else { //clearButton.Visibility = Visibility.Visible; textBlock.Visibility = Visibility.Collapsed; } } private void OnGotKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e) { textBlock.Visibility = Visibility.Collapsed; } private void OnLostKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e) { if (string.IsNullOrEmpty(filterBox.Text)) { textBlock.Visibility = Visibility.Visible; } } private void OnDispatcherTimerTick(object sender, EventArgs e) { if (tickCount == 2) { tickCount = 0; timer.Stop(); if (!byPassEvent) { RaiseFilterEvent(); } byPassEvent = false; } tickCount++; } #endregion } public class FilterEventArgs : RoutedEventArgs { public string FilterText { get; private set; } public bool IsFilterApplied { get; set; } public FilterEventArgs() : base() { FilterText = null; IsFilterApplied = false; } public FilterEventArgs(RoutedEvent routedEvent, object source) : this(routedEvent, source, string.Empty) { } public FilterEventArgs(RoutedEvent routedEvent, object source, string filterText) : base(routedEvent, source) { FilterText = filterText; } } public class DirectionEventArgs : RoutedEventArgs { public DirectionEnum Direction { get; private set; } public DirectionEventArgs() : base() { Direction = DirectionEnum.Default; } public DirectionEventArgs(RoutedEvent routedEvent, object source) : this(routedEvent, source, DirectionEnum.Default) { } public DirectionEventArgs(RoutedEvent routedEvent, object source, DirectionEnum direction) : base(routedEvent, source) { Direction = direction; } } } ================================================ FILE: DependenciesGui/FilterControl/FilterControl.generic.xaml ================================================  ================================================ FILE: DependenciesGui/GridViewSort.cs ================================================ using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Documents; namespace Wpf.Util { public class GridViewSort { #region Public attached properties public static ICommand GetCommand(DependencyObject obj) { return (ICommand)obj.GetValue(CommandProperty); } public static void SetCommand(DependencyObject obj, ICommand value) { obj.SetValue(CommandProperty, value); } // Using a DependencyProperty as the backing store for Command. This enables animation, styling, binding, etc... public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached( "Command", typeof(ICommand), typeof(GridViewSort), new UIPropertyMetadata( null, (o, e) => { ItemsControl listView = o as ItemsControl; if (listView != null) { if (!GetAutoSort(listView)) // Don't change click handler if AutoSort enabled { if (e.OldValue != null && e.NewValue == null) { listView.RemoveHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click)); } if (e.OldValue == null && e.NewValue != null) { listView.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click)); } } } } ) ); public static bool GetAutoSort(DependencyObject obj) { return (bool)obj.GetValue(AutoSortProperty); } public static void SetAutoSort(DependencyObject obj, bool value) { obj.SetValue(AutoSortProperty, value); } // Using a DependencyProperty as the backing store for AutoSort. This enables animation, styling, binding, etc... public static readonly DependencyProperty AutoSortProperty = DependencyProperty.RegisterAttached( "AutoSort", typeof(bool), typeof(GridViewSort), new UIPropertyMetadata( false, (o, e) => { ListView listView = o as ListView; if (listView != null) { if (GetCommand(listView) == null) // Don't change click handler if a command is set { bool oldValue = (bool)e.OldValue; bool newValue = (bool)e.NewValue; if (oldValue && !newValue) { listView.RemoveHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click)); } if (!oldValue && newValue) { listView.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click)); } } } } ) ); public static string GetPropertyName(DependencyObject obj) { return (string)obj.GetValue(PropertyNameProperty); } public static void SetPropertyName(DependencyObject obj, string value) { obj.SetValue(PropertyNameProperty, value); } // Using a DependencyProperty as the backing store for PropertyName. This enables animation, styling, binding, etc... public static readonly DependencyProperty PropertyNameProperty = DependencyProperty.RegisterAttached( "PropertyName", typeof(string), typeof(GridViewSort), new UIPropertyMetadata(null) ); public static bool GetShowSortGlyph(DependencyObject obj) { return (bool)obj.GetValue(ShowSortGlyphProperty); } public static void SetShowSortGlyph(DependencyObject obj, bool value) { obj.SetValue(ShowSortGlyphProperty, value); } // Using a DependencyProperty as the backing store for ShowSortGlyph. This enables animation, styling, binding, etc... public static readonly DependencyProperty ShowSortGlyphProperty = DependencyProperty.RegisterAttached("ShowSortGlyph", typeof(bool), typeof(GridViewSort), new UIPropertyMetadata(true)); public static ImageSource GetSortGlyphAscending(DependencyObject obj) { return (ImageSource)obj.GetValue(SortGlyphAscendingProperty); } public static void SetSortGlyphAscending(DependencyObject obj, ImageSource value) { obj.SetValue(SortGlyphAscendingProperty, value); } // Using a DependencyProperty as the backing store for SortGlyphAscending. This enables animation, styling, binding, etc... public static readonly DependencyProperty SortGlyphAscendingProperty = DependencyProperty.RegisterAttached("SortGlyphAscending", typeof(ImageSource), typeof(GridViewSort), new UIPropertyMetadata(null)); public static ImageSource GetSortGlyphDescending(DependencyObject obj) { return (ImageSource)obj.GetValue(SortGlyphDescendingProperty); } public static void SetSortGlyphDescending(DependencyObject obj, ImageSource value) { obj.SetValue(SortGlyphDescendingProperty, value); } // Using a DependencyProperty as the backing store for SortGlyphDescending. This enables animation, styling, binding, etc... public static readonly DependencyProperty SortGlyphDescendingProperty = DependencyProperty.RegisterAttached("SortGlyphDescending", typeof(ImageSource), typeof(GridViewSort), new UIPropertyMetadata(null)); #endregion #region Private attached properties private static GridViewColumnHeader GetSortedColumnHeader(DependencyObject obj) { return (GridViewColumnHeader)obj.GetValue(SortedColumnHeaderProperty); } private static void SetSortedColumnHeader(DependencyObject obj, GridViewColumnHeader value) { obj.SetValue(SortedColumnHeaderProperty, value); } // Using a DependencyProperty as the backing store for SortedColumn. This enables animation, styling, binding, etc... private static readonly DependencyProperty SortedColumnHeaderProperty = DependencyProperty.RegisterAttached("SortedColumnHeader", typeof(GridViewColumnHeader), typeof(GridViewSort), new UIPropertyMetadata(null)); #endregion #region Column header click event handler private static void ColumnHeader_Click(object sender, RoutedEventArgs e) { GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader; if (headerClicked != null && headerClicked.Column != null) { string propertyName = GetPropertyName(headerClicked.Column); if (!string.IsNullOrEmpty(propertyName)) { ListView listView = GetAncestor(headerClicked); if (listView != null) { ICommand command = GetCommand(listView); if (command != null) { if (command.CanExecute(propertyName)) { command.Execute(propertyName); } } else if (GetAutoSort(listView)) { ApplySort(listView.Items, propertyName, listView, headerClicked); } } } } } #endregion #region Helper methods public static T GetAncestor(DependencyObject reference) where T : DependencyObject { DependencyObject parent = VisualTreeHelper.GetParent(reference); while (!(parent is T)) { parent = VisualTreeHelper.GetParent(parent); } if (parent != null) return (T)parent; else return null; } public static void ApplySort(ICollectionView view, string propertyName, ListView listView, GridViewColumnHeader sortedColumnHeader) { ListSortDirection direction = ListSortDirection.Ascending; if (view.SortDescriptions.Count > 0) { SortDescription currentSort = view.SortDescriptions[0]; if (currentSort.PropertyName == propertyName) { if (currentSort.Direction == ListSortDirection.Ascending) direction = ListSortDirection.Descending; else direction = ListSortDirection.Ascending; } view.SortDescriptions.Clear(); GridViewColumnHeader currentSortedColumnHeader = GetSortedColumnHeader(listView); if (currentSortedColumnHeader != null) { RemoveSortGlyph(currentSortedColumnHeader); } } if (!string.IsNullOrEmpty(propertyName)) { view.SortDescriptions.Add(new SortDescription(propertyName, direction)); if (GetShowSortGlyph(listView)) AddSortGlyph( sortedColumnHeader, direction, direction == ListSortDirection.Ascending ? GetSortGlyphAscending(listView) : GetSortGlyphDescending(listView)); SetSortedColumnHeader(listView, sortedColumnHeader); } } public static void RemoveSort(ICollectionView view, ListView listView) { view.SortDescriptions.Clear(); GridViewColumnHeader currentSortedColumnHeader = GetSortedColumnHeader(listView); if (currentSortedColumnHeader != null) { RemoveSortGlyph(currentSortedColumnHeader); } } private static void AddSortGlyph(GridViewColumnHeader columnHeader, ListSortDirection direction, ImageSource sortGlyph) { AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(columnHeader); adornerLayer.Add( new SortGlyphAdorner( columnHeader, direction, sortGlyph )); } private static void RemoveSortGlyph(GridViewColumnHeader columnHeader) { AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(columnHeader); Adorner[] adorners = adornerLayer.GetAdorners(columnHeader); if (adorners != null) { foreach (Adorner adorner in adorners) { if (adorner is SortGlyphAdorner) adornerLayer.Remove(adorner); } } } #endregion #region SortGlyphAdorner nested class private class SortGlyphAdorner : Adorner { private GridViewColumnHeader _columnHeader; private ListSortDirection _direction; private ImageSource _sortGlyph; public SortGlyphAdorner(GridViewColumnHeader columnHeader, ListSortDirection direction, ImageSource sortGlyph) : base(columnHeader) { _columnHeader = columnHeader; _direction = direction; _sortGlyph = sortGlyph; } private Geometry GetDefaultGlyph() { double x1 = _columnHeader.ActualWidth - 13; double x2 = x1 + 10; double x3 = x1 + 5; double y1 = _columnHeader.ActualHeight / 2 - 3; double y2 = y1 + 5; if (_direction == ListSortDirection.Ascending) { double tmp = y1; y1 = y2; y2 = tmp; } PathSegmentCollection pathSegmentCollection = new PathSegmentCollection(); pathSegmentCollection.Add(new LineSegment(new Point(x2, y1), true)); pathSegmentCollection.Add(new LineSegment(new Point(x3, y2), true)); PathFigure pathFigure = new PathFigure( new Point(x1, y1), pathSegmentCollection, true); PathFigureCollection pathFigureCollection = new PathFigureCollection(); pathFigureCollection.Add(pathFigure); PathGeometry pathGeometry = new PathGeometry(pathFigureCollection); return pathGeometry; } protected override void OnRender(DrawingContext drawingContext) { base.OnRender(drawingContext); if (_sortGlyph != null) { double x = _columnHeader.ActualWidth - 13; double y = _columnHeader.ActualHeight / 2 - 5; Rect rect = new Rect(x, y, 10, 10); drawingContext.DrawImage(_sortGlyph, rect); } else { drawingContext.DrawGeometry(Brushes.LightGray, new Pen(Brushes.Gray, 1.0), GetDefaultGlyph()); } } } #endregion } } ================================================ FILE: DependenciesGui/Helpers/RelayCommand.cs ================================================ using System; using System.Windows.Input; using System.Diagnostics; namespace Dependencies { public class RelayCommand : ICommand { #region Fields readonly Action _execute; readonly Predicate _canExecute; #endregion // Fields #region Constructors public RelayCommand(Action execute) : this(execute, null) { } public RelayCommand(Action execute, Predicate canExecute) { if (execute == null) throw new ArgumentNullException("execute"); _execute = execute; _canExecute = canExecute; } #endregion // Constructors #region ICommand Members [DebuggerStepThrough] public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute(parameter); } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public void Execute(object parameter) { _execute(parameter); } #endregion // ICommand Members } } ================================================ FILE: DependenciesGui/Helpers/SettingBindingHandler.cs ================================================ using System.ComponentModel; using System.Collections.Generic; namespace Dependencies { public class SettingBindingHandler : INotifyPropertyChanged { public delegate string CallbackEventHandler(bool settingValue); public struct EventHandlerInfo { public string Property; public string Settings; public string MemberBindingName; public CallbackEventHandler Handler; } public event PropertyChangedEventHandler PropertyChanged; private List Handlers; public SettingBindingHandler() { Dependencies.Properties.Settings.Default.PropertyChanged += this.Handler_PropertyChanged; Handlers = new List(); } public void AddNewEventHandler(string PropertyName, string SettingsName, string MemberBindingName, CallbackEventHandler Handler) { EventHandlerInfo info = new EventHandlerInfo(); info.Property = PropertyName; info.Settings = SettingsName; info.MemberBindingName = MemberBindingName; info.Handler = Handler; Handlers.Add(info); } public virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private void Handler_PropertyChanged(object sender, PropertyChangedEventArgs e) { foreach (EventHandlerInfo Handler in Handlers.FindAll(x => x.Property == e.PropertyName)) { Handler.Handler(((bool)Dependencies.Properties.Settings.Default[Handler.Settings])); OnPropertyChanged(Handler.MemberBindingName); } } } } ================================================ FILE: DependenciesGui/MainWindow.xaml ================================================  Analyze a new binary via "File -> Open" (Ctrl+O) or simply by dragging it into the application. "Welcome to Dependencies !" ================================================ FILE: DependenciesGui/MainWindow.xaml.cs ================================================ using System; using System.IO; using System.Windows; using System.Windows.Input; using System.Windows.Forms; using System.Windows.Data; using Dragablz; using System.Windows.Shell; using System.Globalization; using System.Collections.ObjectModel; using System.ComponentModel; namespace Dependencies { /// /// We override the default Dragablz.IInterTabClient in order to change /// it's behaviour on closing all tabs. /// public class DependenciesInterTabClient : DefaultInterTabClient { /// /// When closing all tabs on a particular MainWindow instances, we want /// to know if it's okay to close the application also. the MainWindow created /// by the "App" entry point is marked as "master" and is not closed, /// whereas all the others are. /// public override TabEmptiedResponse TabEmptiedHandler(TabablzControl tabControl, Window window) { MainWindow main = window as MainWindow; if (main.IsMaster) { //main.DefaultMessage.Visibility = Visibility.Visible; return TabEmptiedResponse.DoNothing; } return TabEmptiedResponse.CloseWindowOrLayoutBranch; } } public class RecentMenuItem : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public RecentMenuItem(string _Filepath) { Filepath = _Filepath; if (Properties.Settings.Default.FullPath) HeaderTitle = Filepath; else HeaderTitle = System.IO.Path.GetFileName(Filepath); Properties.Settings.Default.PropertyChanged += this.RecentMenuItem_PropertyChanged; } private void RecentMenuItem_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "FullPath") { if (Properties.Settings.Default.FullPath) HeaderTitle = Filepath; else HeaderTitle = System.IO.Path.GetFileName(Filepath); if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("HeaderTitle")); } } } public string Filepath {get; set;} public string HeaderTitle { get; set; } } /// /// MainWindow : container for displaying one or sereral DependencyWindow tree elements. /// public partial class MainWindow : Window { public static readonly RoutedUICommand OpenAboutCommand = new RoutedUICommand(); public static readonly RoutedUICommand OpenUserSettingsCommand = new RoutedUICommand(); public static readonly RoutedUICommand OpenCustomizeSearchFolderCommand = new RoutedUICommand(); public ObservableCollection _recentsItems; private readonly IInterTabClient _interTabClient = new DependenciesInterTabClient(); private About AboutPage; private UserSettings UserSettings; private SearchFolder SearchFolder; private bool _Master; private bool _EnableSearchFolderCustomization; #region PublicAPI public MainWindow() { InitializeComponent(); _recentsItems = new ObservableCollection(); PopulateRecentFilesMenuItems(); this.AboutPage = new About(); this.UserSettings = new UserSettings(); this.SearchFolder = null; // TODO : understand how to reliably bind in xaml this.TabControl.InterTabController.InterTabClient = DoNothingInterTabClient; this.TabControl.IsEmptyChanged += MainWindow_TabControlIsEmptyHandler; this._Master = false; this.DataContext = this; } public ObservableCollection RecentsItems { get { return _recentsItems; } } /// /// Open a new depedency tree window on a given PE. /// /// File path to a PE to process. public void OpenNewDependencyWindow(String Filename) { var newDependencyWindow = new DependencyWindow(Filename); newDependencyWindow.Header = new CustomHeaderViewModel { Header = Path.GetFileNameWithoutExtension(Filename) }; this.TabControl.AddToSource(newDependencyWindow); this.TabControl.SelectedItem = newDependencyWindow; // Update recent files entries App.AddToRecentDocuments(Filename); PopulateRecentFilesMenuItems(); } /// /// We override the default Dragablz.IInterTabClient in order to change /// it's behaviour on closing all tabs. /// public IInterTabClient DoNothingInterTabClient { get { return _interTabClient; } } public bool EnableSearchFolderCustomization { // find a way to update the toggle based on the number of window opened without relying on // creating a custom IsEnabledChanged event get { return true;/*this.TabControl.SelectedItem != null;*/ } } /// /// When closing all tabs on a particular MainWindow instances, we want /// to know if it's okay to close the application also. the MainWindow created /// by the "App" entry point is marked as "master" and is not closed, /// whereas all the others are. /// public bool IsMaster { get { return _Master; } set { _Master = value; } } #endregion PublicAPI /// /// Populate "recent entries" menu items /// public void PopulateRecentFilesMenuItems() { //System.Windows.Controls.MenuItem FileMenuItem = (System.Windows.Controls.MenuItem)this.MainMenu.Items[0]; if (Properties.Settings.Default.RecentFiles.Count == 0) { return; } foreach (var RecentFilePath in Properties.Settings.Default.RecentFiles) { // Ignore empty dummy entries if (String.IsNullOrEmpty(RecentFilePath)) { continue; } AddRecentFilesMenuItem(RecentFilePath, Properties.Settings.Default.RecentFiles.IndexOf(RecentFilePath)); } } private void AddRecentFilesMenuItem(string Filepath, int index) { //System.Windows.Controls.MenuItem FileMenuItem = (System.Windows.Controls.MenuItem)this.MainMenu.Items[0]; // Create new menu item //System.Windows.Controls.MenuItem newRecentFileItem = new System.Windows.Controls.MenuItem(); //newRecentFileItem.DataContext = Filepath; //newRecentFileItem.Click += new RoutedEventHandler(RecentFileCommandBinding_Clicked); //newRecentFileItem.Style = "FullpathStyle"; //RecentsItems.Add(new RecentMenuItem { // MenuItemName = "Edit" //}); //RecentsItems.Add( // new RecentMenuItem{ // MenuItemName = "Search" // } //); RecentsItems.Add(new RecentMenuItem(Filepath)); //// check if the item already is in the list, diregarding others menu items //if (index + 5 < FileMenuItem.Items.Count) //{ // FileMenuItem.Items[3 + index] = newRecentFileItem; //} //else //{ // // Add it to the list at the top // FileMenuItem.Items.Insert(3, newRecentFileItem); //} } #region Commands private void RecentFileCommandBinding_Clicked(object sender, RoutedEventArgs e) { System.Windows.Controls.MenuItem RecentFile = sender as System.Windows.Controls.MenuItem; String RecentFilePath = (RecentFile.DataContext as RecentMenuItem).Filepath; if (RecentFilePath.Length != 0 ) { OpenNewDependencyWindow(RecentFilePath); } } private void OpenCommandBinding_Executed(object sender, RoutedEventArgs e) { OpenFileDialog InputFileNameDlg = new OpenFileDialog { Filter = "exe files (*.exe, *.dll)| *.exe;*.dll; | All files (*.*)|*.*", FilterIndex = 0, RestoreDirectory = true, }; if (InputFileNameDlg.ShowDialog() != System.Windows.Forms.DialogResult.OK) return; OpenNewDependencyWindow(InputFileNameDlg.FileName); } private void ExitCommandBinding_Executed(object sender, RoutedEventArgs e) { System.Windows.Application.Current.Shutdown(); } private void OpenAboutCommandBinding_Executed(object sender, RoutedEventArgs e) { this.AboutPage.Close(); this.AboutPage = new About(); this.AboutPage.Show(); } private void OpenUserSettingsCommandBinding_Executed(object sender, RoutedEventArgs e) { this.UserSettings.Close(); this.UserSettings = new UserSettings(); this.UserSettings.Owner = this; this.UserSettings.Show(); } private void OpenCustomizeSearchFolderCommand_Executed(object sender, RoutedEventArgs e) { DependencyWindow SelectedItem = this.TabControl.SelectedItem as DependencyWindow; if (SelectedItem == null) return; if (this.SearchFolder != null) { this.SearchFolder.Close(); } this.SearchFolder = new SearchFolder(SelectedItem); this.SearchFolder.Show(); } private void RefreshCommandBinding_Executed(object sender, RoutedEventArgs e) { DependencyWindow SelectedItem = this.TabControl.SelectedItem as DependencyWindow; if (SelectedItem == null) return; SelectedItem.InitializeView(); } #endregion Commands #region EventsHandler /// /// Application.Close event handler. Save user settings and close every child windows. /// protected override void OnClosing(System.ComponentModel.CancelEventArgs e) { this.UserSettings.Close(); this.AboutPage.Close(); if (this.SearchFolder!= null) { this.SearchFolder.Close(); } base.OnClosing(e); } /// /// file drag-and-drop event handler. /// private void MainWindow_Drop(object sender, System.Windows.DragEventArgs e) { if (e.Data.GetDataPresent(System.Windows.Forms.DataFormats.FileDrop)) { string[] files = (string[])e.Data.GetData(System.Windows.Forms.DataFormats.FileDrop); foreach (var file in files) { OpenNewDependencyWindow(file); } } } private void MainWindow_TabControlIsEmptyHandler(object sender, RoutedPropertyChangedEventArgs e) { this.DefaultMessage.Visibility = (e.NewValue) ? Visibility.Visible : Visibility.Hidden; this._RefreshItem.IsEnabled = !e.NewValue; } #endregion EventsHandler } /// /// Converter to transform a boolean into a Visibility settings. /// Why is this not part of the WPF standard lib ? Everybody ends up coding one in every project. /// public class BooleanToVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { Boolean SettingValue = (Boolean) value; if (SettingValue) return Visibility.Visible; return Visibility.Collapsed; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } } ================================================ FILE: DependenciesGui/Models/ModuleInfo.cs ================================================ using System; using System.Collections.Generic; using System.Windows.Forms; using System.Diagnostics; using System.IO; using System.ComponentModel; using Dependencies.ClrPh; [Flags] public enum PeTypes { None = 0, IMAGE_FILE_EXECUTABLE_IMAGE = 0x02, IMAGE_FILE_DLL = 0x2000, } [Flags] public enum ModuleFlag { NoFlag = 0x00, DelayLoad = 0x01, ClrReference = 0x02, ApiSet = 0x04, ApiSetExt = 0x08, NotFound = 0x10, MissingImports = 0x20, ChildrenError = 0x40, } namespace Dependencies { public struct ModuleInfo { // @TODO(Hack: refactor correctly for image generation) // public TreeViewItemContext context; public Int16 Machine; public Int16 Magic; public UInt64 ImageBase; public Int32 SizeOfImage; public UInt64 EntryPoint; public Int32 Checksum; public Boolean CorrectChecksum; public Int16 Subsystem; public Tuple SubsystemVersion; public Int16 Characteristics; public Int16 DllCharacteristics; public UInt64 Filesize; } public class ApiSetNotFoundModuleInfo : NotFoundModuleInfo { public ApiSetNotFoundModuleInfo(string ApiSetModuleName, string NotFoundHostModule) :base(ApiSetModuleName) { _HostName = NotFoundHostModule; _Flags |= ModuleFlag.ApiSet; _Flags |= ModuleFlag.NotFound; if (ApiSetModuleName.StartsWith("ext-")) { _Flags |= ModuleFlag.ApiSetExt; } } public override string ModuleName { get { return String.Format("{0:s} -> {1:s}", this._Name, _HostName); } } private string _HostName; } public class NotFoundModuleInfo : DisplayModuleInfo { public NotFoundModuleInfo(string NotFoundModuleName) : base(NotFoundModuleName) { _Flags |= ModuleFlag.NotFound; } public override string Filepath { get { return _Name; } } public override List Imports { get { return new List(); } } public override List Exports { get { return new List(); } } public override string Cpu { get { return null; } } public override string Type { get { return null; } } public override UInt64? Filesize { get { return null; } } public override UInt64? ImageBase { get { return null; } } public override int? VirtualSize { get { return null; } } public override UInt64? EntryPoint { get { return null; } } public override int? Subsystem { get { return null; } } public override string SubsystemVersion { get { return null; } } public override int? Checksum { get { return null; } } public override bool? CorrectChecksum { get { return null; } } public override ModuleSearchStrategy Location { get { return ModuleSearchStrategy.NOT_FOUND; } } } public class ApiSetModuleInfo : DisplayModuleInfo { public ApiSetModuleInfo(string ApiSetModuleName, ref DisplayModuleInfo _UnderlyingModule) : base(ApiSetModuleName) { UnderlyingModule = _UnderlyingModule; _Flags = _UnderlyingModule.Flags; _Flags |= ModuleFlag.ApiSet; if (ApiSetModuleName.StartsWith("ext-")) { _Flags |= ModuleFlag.ApiSetExt; } } public override string ModuleName { get { return String.Format("{0:s} -> {1:s}", this._Name, UnderlyingModule.ModuleName);}} public override string Filepath { get { return UnderlyingModule.Filepath; } } public override List Imports { get { return UnderlyingModule.Imports; } } public override List Exports { get { return UnderlyingModule.Exports; } } public override string Cpu { get { return UnderlyingModule.Cpu; } } public override string Type { get { return UnderlyingModule.Type; } } public override UInt64? Filesize { get { return UnderlyingModule.Filesize; } } public override UInt64? ImageBase { get { return UnderlyingModule.ImageBase; } } public override int? VirtualSize { get { return UnderlyingModule.VirtualSize; } } public override UInt64? EntryPoint { get { return UnderlyingModule.EntryPoint; } } public override int? Subsystem { get { return UnderlyingModule.Subsystem; } } public override string SubsystemVersion { get { return UnderlyingModule.SubsystemVersion; } } public override int? Checksum { get { return UnderlyingModule.Checksum; } } public override bool? CorrectChecksum { get { return UnderlyingModule.CorrectChecksum; } } public override ModuleSearchStrategy Location { get { return ModuleSearchStrategy.ApiSetSchema; } } /// /// The pointed module which actually does implement the api set contract /// TODO : there might be more than one contract modules ? /// private DisplayModuleInfo UnderlyingModule; } public class DisplayModuleInfo : SettingBindingHandler, INotifyPropertyChanged { #region Constructors public DisplayModuleInfo(string ModuleName) { _Name = ModuleName; _Filepath = null; _Flags = 0; AddNewEventHandler("FullPath", "FullPath", "ModuleName", this.GetPathDisplayName); } public DisplayModuleInfo(string ModuleName, PE Pe, ModuleSearchStrategy Location, ModuleFlag Flags = 0) { _Name = ModuleName; _Filepath = Pe.Filepath; _Flags = Flags; // Do not set this variables in order to // lessen memory allocations _Imports = null; _Exports = null; _Location = Location; _Info = new ModuleInfo() { Machine = Pe.Properties.Machine, Magic = Pe.Properties.Magic, Filesize = Pe.Properties.FileSize, ImageBase = (UInt64)Pe.Properties.ImageBase, SizeOfImage = Pe.Properties.SizeOfImage, EntryPoint = (UInt64)Pe.Properties.EntryPoint, Checksum = Pe.Properties.Checksum, CorrectChecksum = Pe.Properties.CorrectChecksum, Subsystem = Pe.Properties.Subsystem, SubsystemVersion = Pe.Properties.SubsystemVersion, Characteristics = Pe.Properties.Characteristics, DllCharacteristics = Pe.Properties.DllCharacteristics, }; AddNewEventHandler("FullPath", "FullPath", "ModuleName", this.GetPathDisplayName); } #endregion // Constructors #region PublicAPI public virtual string ModuleName { get { return GetPathDisplayName(Dependencies.Properties.Settings.Default.FullPath); } } public virtual string Filepath { get { return _Filepath; } } public virtual bool DelayLoad { get { return (_Flags & ModuleFlag.DelayLoad) != 0; } } public virtual ModuleFlag Flags { get { return _Flags; } set { _Flags = value; } } public virtual List Imports { get { if (_Imports == null) { _Imports = (System.Windows.Application.Current as App).LoadBinary(Filepath).GetImports(); } return _Imports; } } public virtual List Exports { get { if (_Exports == null) { _Exports = (System.Windows.Application.Current as App).LoadBinary(Filepath).GetExports(); } return _Exports; } } protected string GetPathDisplayName(bool FullPath) { if ((FullPath) && (_Filepath != null)) return _Filepath; return _Name; } public virtual string Cpu { get { int machine_id = _Info.Machine & 0xffff; switch (machine_id) { case 0x014c: /*IMAGE_FILE_MACHINE_I386*/ return "i386"; case 0x8664: /*IMAGE_FILE_MACHINE_AMD64*/ return "AMD64"; case 0x0200:/*IMAGE_FILE_MACHINE_IA64*/ return "IA64"; case 0x01c4:/*IMAGE_FILE_MACHINE_ARMNT*/ return "ARM Thumb-2"; case 0xAA64:/*IMAGE_FILE_MACHINE_ARM64*/ return "ARM64"; default: return "Unknown"; } } } public virtual string Type { get { List TypeList = new List(); PeTypes Type = (PeTypes)_Info.Characteristics; if ((Type & PeTypes.IMAGE_FILE_DLL) != PeTypes.None)/* IMAGE_FILE_DLL */ TypeList.Add("Dll"); if ((Type & PeTypes.IMAGE_FILE_EXECUTABLE_IMAGE) != PeTypes.None) /* IMAGE_FILE_EXECUTABLE_IMAGE */ TypeList.Add("Executable"); return String.Join("; ", TypeList.ToArray()); } } public bool HasErrors { get { return _ErrorImport; } set { _ErrorImport = value; OnPropertyChanged("HasErrors"); } } public virtual UInt64? Filesize { get { return _Info.Filesize; } } public virtual UInt64? ImageBase { get { return _Info.ImageBase; } } public virtual int? VirtualSize { get { return _Info.SizeOfImage; } } public virtual UInt64? EntryPoint { get { return _Info.EntryPoint; } } public virtual int? Subsystem { get { return _Info.Subsystem; } } public virtual string SubsystemVersion { get { return String.Format("{0:d}.{1:d}" , _Info.SubsystemVersion.Item1, _Info.SubsystemVersion.Item2); } } public virtual int? Checksum { get { return _Info.Checksum; } } public virtual bool? CorrectChecksum { get { return _Info.CorrectChecksum; } } public virtual ModuleSearchStrategy Location { get { return _Location; } } public string Status { get { if ((this.Flags & ModuleFlag.NotFound) != 0) { return String.Format("{0:s} module could not be found on disk", this.Filepath); } if ((this.Flags & ModuleFlag.MissingImports) != 0) { return String.Format("{0:s} module has missing imports", this.Filepath); } if ((this.Flags & ModuleFlag.DelayLoad) != 0) { return String.Format("{0:s} module is delay-load", this.Filepath); } if ((this.Flags & ModuleFlag.ChildrenError) != 0) { return String.Format("{0:s} module has an erroneous child module", this.Filepath); } return String.Format("{0:s} module loaded correctly", this.Filepath); ; } } #endregion PublicAPI #region Commands private RelayCommand _DoFindModuleInTreeCommand; private RelayCommand _ConfigureSearchOrderCommand; public RelayCommand DoFindModuleInTreeCommand { get { return _DoFindModuleInTreeCommand; } set { _DoFindModuleInTreeCommand = value; } } public RelayCommand ConfigureSearchOrderCommand { get { return _ConfigureSearchOrderCommand; } set { _ConfigureSearchOrderCommand = value; } } public RelayCommand OpenPeviewerCommand { get { if (_OpenPeviewerCommand == null) { _OpenPeviewerCommand = new RelayCommand((param) => this.OpenPeviewer((object)param)); } return _OpenPeviewerCommand; } } public bool OpenPeviewer(object Module) { string programPath = Dependencies.Properties.Settings.Default.PeViewerPath; Process PeviewerProcess = new Process(); if ((Module == null)) { return false; } if (!File.Exists(programPath)) { MessageBox.Show("peview.exe file could not be found !"); return false; } string Filepath = (Module as DisplayModuleInfo).GetPathDisplayName(true); if (Filepath == null) { return false; } PeviewerProcess.StartInfo.FileName = programPath; PeviewerProcess.StartInfo.Arguments = Filepath; return PeviewerProcess.Start(); } public RelayCommand OpenNewAppCommand { get { if (_OpenPeviewerCommand == null) { _OpenNewAppCommand = new RelayCommand((param) => { string Filepath = (param as DisplayModuleInfo).GetPathDisplayName(true); if (Filepath == null) { return; } Process OtherDependenciesProcess = new Process(); OtherDependenciesProcess.StartInfo.FileName = Application.ExecutablePath; OtherDependenciesProcess.StartInfo.Arguments = Filepath; OtherDependenciesProcess.Start(); }); } return _OpenNewAppCommand; } } public RelayCommand CopyValue { get { if (_CopyValue == null) { _CopyValue = new RelayCommand((param) => { if ((param == null)) { return; } Clipboard.Clear(); try { Clipboard.SetText((string)param, TextDataFormat.Text); } catch { } }); } return _CopyValue; } } #endregion // Commands /// /// Name : string to identify the module. /// This is the only "mandatory" data, the rest can be private. /// public string _Name; protected string _Filepath; protected ModuleFlag _Flags; private ModuleInfo _Info; private ModuleSearchStrategy _Location; private List _Imports; private List _Exports; private bool _ErrorImport; private RelayCommand _OpenPeviewerCommand; private RelayCommand _OpenNewAppCommand; private RelayCommand _CopyValue; } } ================================================ FILE: DependenciesGui/Models/PeExport.cs ================================================ using System; using System.Diagnostics; using System.Windows; using System.Collections.Generic; using Dependencies; using Dependencies.ClrPh; public class DisplayPeExport : SettingBindingHandler { # region Constructors public DisplayPeExport( PeExport PeExport, PhSymbolProvider SymPrv ) { PeInfo.ordinal = (ushort) PeExport.Ordinal; //PeInfo.hint = (ushort) (/*PeExport.Hint*/ PeExport.Ordinal - 1); // @TODO(add hints to exports) PeInfo.name = PeExport.Name; PeInfo.ForwardName = PeExport.ForwardedName; PeInfo.exportByOrdinal = PeExport.ExportByOrdinal; PeInfo.forwardedExport = PeExport.ForwardedName.Length > 0; PeInfo.exportAsCppName = (PeExport.Name.Length > 0 && PeExport.Name[0] == '?'); PeInfo.virtualAddress = PeExport.VirtualAddress; Tuple DemanglingInfos = SymPrv.UndecorateName(PeExport.Name); PeInfo.Demangler = Enum.GetName(typeof(CLRPH_DEMANGLER), DemanglingInfos.Item1); PeInfo.UndecoratedName = DemanglingInfos.Item2; AddNewEventHandler("Undecorate", "Undecorate", "Name", this.GetDisplayName); } #endregion Constructors #region PublicAPI public override string ToString() { List members = new List() { String.Format("{0} (0x{0:x04})", Ordinal), Hint != 0 ? String.Format("{0} (0x{0:x08})", Hint) : "N/A", Name, VirtualAddress, Demangler }; return String.Join(", ", members.ToArray()); } public string IconUri { get { if (PeInfo.forwardedExport) return "Images/export_forward.png"; if (PeInfo.exportByOrdinal) return "Images/export_ord.png"; if (PeInfo.exportAsCppName) return "Images/export_cpp.png"; return "Images/export_C.png"; } } public int Type { get { if (PeInfo.forwardedExport) return 1; if (PeInfo.exportByOrdinal) return 2; if (PeInfo.exportAsCppName) return 3; return 0; } } public ushort ? Hint { get { return null; } } public ushort Ordinal { get { return PeInfo.ordinal; } } public string Name { get { return GetDisplayName(Dependencies.Properties.Settings.Default.Undecorate); } } public string VirtualAddress { get { if (PeInfo.forwardedExport) return PeInfo.ForwardName; return String.Format("0x{0:x8}", PeInfo.virtualAddress); } } public string Demangler { get { return PeInfo.Demangler; } } protected string GetDisplayName(bool Undecorate) { if (PeInfo.exportByOrdinal) return String.Format("Ordinal_{0:d}", PeInfo.ordinal); if ((Undecorate) && (PeInfo.UndecoratedName.Length > 0)) return PeInfo.UndecoratedName; return PeInfo.name; } # endregion PublicAPI #region Commands public RelayCommand QueryExportApi { get { if (_QueryExportApi == null) { _QueryExportApi = new RelayCommand((param) => { if ((param == null)) { return; } string ExportName = (param as DisplayPeExport).Name; if (ExportName == null) { return; } Process.Start(@"https://docs.microsoft.com/search/?search=" + ExportName); }); } return _QueryExportApi; } } public RelayCommand CopyValue { get { if (_CopyValue == null) { _CopyValue = new RelayCommand((param) => { if ((param == null)) { return; } Clipboard.Clear(); try { Clipboard.SetText((string)param, TextDataFormat.Text); } catch { } }); } return _CopyValue; } } #endregion // Commands private PeExportInfo PeInfo; private RelayCommand _QueryExportApi; private RelayCommand _CopyValue; } public struct PeExportInfo { public Boolean exportByOrdinal; public Boolean exportAsCppName; public Boolean forwardedExport; public ushort ordinal; //public ushort hint; public long virtualAddress; public string name; public string ForwardName; public string UndecoratedName; public string Demangler; } ================================================ FILE: DependenciesGui/Models/PeImport.cs ================================================ using System; using System.Diagnostics; using System.Windows; using System.Collections.Generic; using Dependencies; using Dependencies.ClrPh; public class DisplayPeImport : SettingBindingHandler { #region Constructors public DisplayPeImport( PeImport PeImport, PhSymbolProvider SymPrv, string ModuleFilePath, bool ImportFound ) { Info.ordinal = PeImport.Ordinal; Info.hint = PeImport.Hint; Info.name = PeImport.Name; Info.moduleName = PeImport.ModuleName; Info.modulePath = ModuleFilePath; Info.importNotFound = !ImportFound; Tuple DemanglingInfos = SymPrv.UndecorateName(PeImport.Name); Info.Demangler = Enum.GetName(typeof(CLRPH_DEMANGLER), DemanglingInfos.Item1); Info.UndecoratedName = DemanglingInfos.Item2; if (ImportFound) { Info.delayedImport = PeImport.DelayImport; Info.importAsCppName = (PeImport.Name.Length > 0 && PeImport.Name[0] == '?'); Info.importByOrdinal = PeImport.ImportByOrdinal; } AddNewEventHandler("Undecorate", "Undecorate", "Name", this.GetDisplayName); AddNewEventHandler("FullPath", "FullPath", "ModuleName", this.GetPathDisplayName); } #endregion Constructors #region PublicAPI public override string ToString() { List members = new List() { Ordinal != null ? String.Format("{0} (0x{0:x08})", Ordinal) : "N/A", Hint != null ? String.Format("{0} (0x{0:x08})", Hint) : "N/A", Name, ModuleName, DelayImport.ToString(), Demangler }; return String.Join(", ", members.ToArray()); } public string IconUri { // @TODO(implement API lookup in order to test for API Export presence) get { string PathStrFormat = "Images/import_{0:s}_found.png"; if (Info.importNotFound) PathStrFormat = "Images/import_{0:s}_not_found.png"; if (Info.importByOrdinal) return String.Format(PathStrFormat, "ord"); if (Info.importAsCppName) return String.Format(PathStrFormat, "cpp"); return String.Format(PathStrFormat, "c"); } } public int Type { get { if (Info.importNotFound) return 1; if (Info.importByOrdinal) return 2; if (Info.importAsCppName) return 3; return 0; } } public ushort? Hint { get { if (Info.importByOrdinal) return null; return Info.hint; } } public ushort? Ordinal { get { if (Info.importByOrdinal) { return Info.ordinal; } return null; } } public string Name { get { return GetDisplayName(Dependencies.Properties.Settings.Default.Undecorate); } } public string ModuleName { get { return GetPathDisplayName(Dependencies.Properties.Settings.Default.FullPath); } } public string FilterName { get { return String.Format("{0:s}:{1:s}", this.ModuleName, this.Name); } } public Boolean DelayImport { get { return Info.delayedImport; } } public string Demangler { get { return this.Info.Demangler; } } protected string GetDisplayName(bool UndecorateName) { if (Info.importByOrdinal) return String.Format("Ordinal_{0:d}", Info.ordinal); if ((UndecorateName) && (Info.UndecoratedName.Length > 0)) return Info.UndecoratedName; return Info.name; } protected string GetPathDisplayName(bool FullPath) { if ((FullPath) && (Info.modulePath != null)) return Info.modulePath; return Info.moduleName; } #endregion PublicAPI #region Commands public RelayCommand QueryImportApi { get { if (_QueryImportApi == null) { _QueryImportApi = new RelayCommand((param) => { if ((param == null)) { return; } string ExportName = (param as DisplayPeImport).Name; if (ExportName == null) { return; } Process.Start(@"https://docs.microsoft.com/search/?search=" + ExportName); }); } return _QueryImportApi; } } public RelayCommand CopyValue { get { if (_CopyValue == null) { _CopyValue = new RelayCommand((param) => { if ((param == null)) { return; } Clipboard.Clear(); try { Clipboard.SetText((string)param, TextDataFormat.Text); } catch { } }); } return _CopyValue; } } #endregion // Commands private PeImportInfo Info; private RelayCommand _QueryImportApi; private RelayCommand _CopyValue; } public struct PeImportInfo { public ushort ordinal; public ushort hint; public string name; public string moduleName; public string modulePath; public string UndecoratedName; public string Demangler; public Boolean delayedImport; public Boolean importByOrdinal; public Boolean importAsCppName; public Boolean importNotFound; } ================================================ FILE: DependenciesGui/ModuleSearchOrder.xaml ================================================  ================================================ FILE: DependenciesGui/ModuleSearchOrder.xaml.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.ComponentModel; using System.Windows.Data; namespace Dependencies { public class ModuleSearchResult { public string ModuleFilePath { get; set; } public ModuleSearchStrategy SearchStrategy { get; set; } } /// /// Interaction logic for ModuleSearchOrder.xaml /// public partial class ModuleSearchOrder : Window { public ModuleSearchOrder(ModulesCache LoadedModules) { InitializeComponent(); List items = new List(); foreach (var LoadedModule in LoadedModules.Values) { items.Add(new ModuleSearchResult() { ModuleFilePath = LoadedModule.ModuleName, SearchStrategy = LoadedModule.Location }); } OrderedModules.ItemsSource = items; CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(OrderedModules.ItemsSource); PropertyGroupDescription groupDescription = new PropertyGroupDescription("SearchStrategy"); view.GroupDescriptions.Add(groupDescription); SortDescription sortDescription = new SortDescription("SearchStrategy", ListSortDirection.Ascending); view.SortDescriptions.Add(sortDescription); } } } ================================================ FILE: DependenciesGui/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Windows; // Les informations générales relatives à un assembly dépendent de // l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations // associées à un assembly. [assembly: AssemblyTitle("DependenciesGui")] [assembly: AssemblyDescription("Modern rewrite of the depends.exe tool.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Dependencies")] [assembly: AssemblyCopyright("Copyright © 2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly // aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de // COM, affectez la valeur true à l'attribut ComVisible sur ce type. [assembly: ComVisible(false)] //Pour commencer à générer des applications localisables, définissez //CultureUtiliséePourCoder dans votre fichier .csproj //dans . Par exemple, si vous utilisez le français //dans vos fichiers sources, définissez à fr-FR. Puis, supprimez les marques de commentaire de //l'attribut NeutralResourceLanguage ci-dessous. Mettez à jour "fr-FR" dans //la ligne ci-après pour qu'elle corresponde au paramètre UICulture du fichier projet. //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] [assembly: ThemeInfo( ResourceDictionaryLocation.None, //où se trouvent les dictionnaires de ressources spécifiques à un thème //(utilisé si une ressource est introuvable dans la page, // ou dictionnaires de ressources de l'application) ResourceDictionaryLocation.SourceAssembly //où se trouve le dictionnaire de ressources générique //(utilisé si une ressource est introuvable dans la page, // dans l'application ou dans l'un des dictionnaires de ressources spécifiques à un thème) )] // Les informations de version pour un assembly se composent des quatre valeurs suivantes : // // Version principale // Version secondaire // Numéro de build // Révision // // Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut // en utilisant '*', comme indiqué ci-dessous : // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.11.1.0")] [assembly: AssemblyFileVersion("1.11.1.0")] ================================================ FILE: DependenciesGui/Properties/Resources.Designer.cs ================================================ //------------------------------------------------------------------------------ // // Ce code a été généré par un outil. // Version du runtime :4.0.30319.42000 // // Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si // le code est régénéré. // //------------------------------------------------------------------------------ namespace Dependencies.Properties { using System; /// /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées. /// // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder // à l'aide d'un outil, tel que ResGen ou Visual Studio. // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen // avec l'option /str ou régénérez votre projet VS. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } /// /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Dependencies.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } /// /// Remplace la propriété CurrentUICulture du thread actuel pour toutes /// les recherches de ressources à l'aide de cette classe de ressource fortement typée. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } } } ================================================ FILE: DependenciesGui/Properties/Resources.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ================================================ FILE: DependenciesGui/Properties/Settings.Designer.cs ================================================ //------------------------------------------------------------------------------ // // Ce code a été généré par un outil. // Version du runtime :4.0.30319.42000 // // Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si // le code est régénéré. // //------------------------------------------------------------------------------ namespace Dependencies.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); public static Settings Default { get { return defaultInstance; } } [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("True")] public bool Undecorate { get { return ((bool)(this["Undecorate"])); } set { this["Undecorate"] = value; } } [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("True")] public bool ShowStatusBar { get { return ((bool)(this["ShowStatusBar"])); } set { this["ShowStatusBar"] = value; } } [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("True")] public bool FullPath { get { return ((bool)(this["FullPath"])); } set { this["FullPath"] = value; } } [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("0")] public byte RecentFilesIndex { get { return ((byte)(this["RecentFilesIndex"])); } set { this["RecentFilesIndex"] = value; } } [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("peview.exe")] public string PeViewerPath { get { return ((string)(this["PeViewerPath"])); } set { this["PeViewerPath"] = value; } } [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("ChildOnly")] public string TreeBuildBehaviour { get { return ((string)(this["TreeBuildBehaviour"])); } set { this["TreeBuildBehaviour"] = value; } } [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("Courier New")] public string Font { get { return ((string)(this["Font"])); } set { this["Font"] = value; } } [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute(@" ")] public global::System.Collections.Specialized.StringCollection RecentFiles { get { return ((global::System.Collections.Specialized.StringCollection)(this["RecentFiles"])); } set { this["RecentFiles"] = value; } } [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("2")] public int TreeDepth { get { return ((int)(this["TreeDepth"])); } set { this["TreeDepth"] = value; } } [global::System.Configuration.UserScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("True")] public bool BinaryCacheOptionValue { get { return ((bool)(this["BinaryCacheOptionValue"])); } set { this["BinaryCacheOptionValue"] = value; } } } } ================================================ FILE: DependenciesGui/Properties/Settings.settings ================================================  True True True 0 peview.exe ChildOnly Courier New <?xml version="1.0" encoding="utf-16"?> <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <string /> <string /> <string /> <string /> <string /> <string /> <string /> <string /> <string /> <string /> </ArrayOfString> 2 True ================================================ FILE: DependenciesGui/SearchFolder.xaml ================================================