Skip to content

Commit

Permalink
apply
Browse files Browse the repository at this point in the history
- [212](lucasg#212)
- [241](lucasg#241)
- [265](lucasg#265)
- [266](lucasg#266)
- [269](lucasg#269)
  • Loading branch information
nono303 committed Oct 9, 2024
1 parent 51268de commit 8acfe64
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 109 deletions.
3 changes: 3 additions & 0 deletions ClrPhlib/include/ClrPhlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ namespace Dependencies {

// Check if the PE is 32-bit
bool IsArm32Dll();

// Check if the PE is a dot net
bool IsClrDll();

// return the processorArchiture of PE
String^ GetProcessor();
Expand Down
10 changes: 10 additions & 0 deletions ClrPhlib/src/managed/PE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,16 @@ bool PE::IsArm32Dll()
return ((Properties->Machine & 0xffff) == IMAGE_FILE_MACHINE_ARMNT);
}

bool PE::IsClrDll()
{
PIMAGE_DATA_DIRECTORY dataDirectory;
if (NT_SUCCESS(PhGetMappedImageDataEntry( &m_Impl->m_PvMappedImage, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, &dataDirectory)))
{
return dataDirectory->VirtualAddress != 0;
}
return false;
}

String^ PE::GetProcessor()
{
if ((Properties->Machine & 0xffff) == IMAGE_FILE_MACHINE_I386)
Expand Down
30 changes: 16 additions & 14 deletions DependenciesGui/DependencyWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,7 @@ public void InitializeView()
var RootFilename = Path.GetFileName(this.Filename);
var RootModule = new DisplayModuleInfo(RootFilename, this.Pe, ModuleSearchStrategy.ROOT);
this.ProcessedModulesCache.Add(new ModuleCacheKey(RootFilename, this.Filename), RootModule);
this.ModulesList.AddModule(RootModule);

ModuleTreeViewItem treeNode = new ModuleTreeViewItem();
DependencyNodeContext childTreeInfoContext = new DependencyNodeContext()
Expand Down Expand Up @@ -765,16 +766,10 @@ private void ProcessAppInitDlls(Dictionary<string, ImportContext> NewTreeContext
}
}

private void ProcessClrImports(Dictionary<string, ImportContext> NewTreeContexts, PE AnalyzedPe, ImportContext ImportModule)
private void ProcessClrImports(Dictionary<string, ImportContext> NewTreeContexts, PE AnalyzedPe)
{
List<PeImportDll> PeImports = AnalyzedPe.GetImports();

// only mscorre triggers clr parsing
string User32Filepath = Path.Combine(FindPe.GetSystemPath(this.Pe), "mscoree.dll");
if (ImportModule.PeFilePath != User32Filepath)
{
return;
}
List<PeImportDll> PeImports = AnalyzedPe.GetImports();

var resolver = new DefaultAssemblyResolver();
resolver.AddSearchDirectory(RootFolder);
Expand Down Expand Up @@ -938,17 +933,19 @@ private void ProcessPe(Dictionary<string, ImportContext> NewTreeContexts, PE new

// 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);
// This should happen only if this is validated to be a C# assembly
if (newPe.IsClrDll())
{
// We use Mono.Cecil to enumerate its references
ProcessClrImports(NewTreeContexts, newPe);
}
}

Expand Down Expand Up @@ -980,6 +977,7 @@ private void ConstructDependencyTree(ModuleTreeViewItem RootNode, PE CurrentPE,
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true; // useless here for now

(Application.Current as App).StatusBarMessage = "Analyzing PE File " + CurrentPE.Filepath;

bw.DoWork += (sender, e) => {
Expand Down Expand Up @@ -1073,7 +1071,10 @@ private void ConstructDependencyTree(ModuleTreeViewItem RootNode, PE CurrentPE,
// 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))
// Some dot net dlls give 0 for GetImports() but they will always have imports
// that can be detected using the special CLR dll processing we do.
if ((NewTreeContext.PeProperties != null) &&
(NewTreeContext.PeProperties.GetImports().Count > 0 || NewTreeContext.PeProperties.IsClrDll()))
{
ModuleTreeViewItem DummyEntry = new ModuleTreeViewItem();
DependencyNodeContext DummyContext = new DependencyNodeContext()
Expand Down Expand Up @@ -1112,7 +1113,8 @@ private void ConstructDependencyTree(ModuleTreeViewItem RootNode, PE CurrentPE,
}
}
(Application.Current as App).StatusBarMessage = CurrentPE.Filepath + " Loaded successfully.";
};

bw.RunWorkerAsync();
Expand Down
3 changes: 2 additions & 1 deletion DependenciesGui/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@ public void PopulateRecentFilesMenuItems()
return;
}


// prevent the existing items appear multiple times
RecentsItems.Clear();
foreach (var RecentFilePath in Properties.Settings.Default.RecentFiles)
{
// Ignore empty dummy entries
Expand Down
152 changes: 63 additions & 89 deletions DependenciesLib/BinaryCache.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using Dependencies.ClrPh;
using System.ComponentModel;
using System.Linq;

namespace Dependencies
{
Expand Down Expand Up @@ -292,12 +293,7 @@ public class BinaryCacheImpl : BinaryCache
{
public BinaryCacheImpl(string ApplicationAppDataPath, int _MaxBinaryCount)
{

BinaryDatabase = new Dictionary<string, PE>();
FilepathDatabase = new Dictionary<string, PE>();
BinaryDatabaseLock = new Object();
LruCache = new List<string>();

MaxBinaryCount = _MaxBinaryCount;
string platform = (IntPtr.Size == 8) ? "x64" : "x86";

Expand All @@ -307,12 +303,6 @@ public BinaryCacheImpl(string ApplicationAppDataPath, int _MaxBinaryCount)

public override void Load()
{
// "warm up" the cache
foreach (var CachedBinary in Directory.EnumerateFiles(BinaryCacheFolderPath))
{
GetBinaryAsync(CachedBinary);
}

string System32Folder = Environment.GetFolderPath(Environment.SpecialFolder.System);
string SysWow64Folder = Environment.GetFolderPath(Environment.SpecialFolder.SystemX86);

Expand Down Expand Up @@ -340,53 +330,63 @@ public override void Load()
{
GetBinaryAsync(Path.Combine(SysWow64Folder, KnownDll));
}

}

}

public override void Unload()
{
// cut off the LRU cache
LruCache = LruCache.GetRange(0, Math.Min(LruCache.Count, MaxBinaryCount));

foreach (var CachedBinary in Directory.EnumerateFiles(BinaryCacheFolderPath))
foreach (var kv in BinaryDatabase)
{
string PeHash = GetBinaryHash(CachedBinary);
kv.Value.Unload();
}
BinaryDatabase.Clear();

if (LruCache.Find(Hash => (Hash == PeHash)) == null)
foreach (var file in new DirectoryInfo(BinaryCacheFolderPath).EnumerateFiles()
.OrderByDescending(fi => fi.LastAccessTime).Skip(MaxBinaryCount))
{
try
{
// Force map unloading before deleting file
if (BinaryDatabase.ContainsKey(PeHash))
{
BinaryDatabase[PeHash].Unload();
}
file.Delete();
}
catch (System.UnauthorizedAccessException uae)
{
// The BinaryCache is shared among serveral Dependencies.exe instance
// so only the last one alive can clear the cache.
Debug.WriteLine("[BinaryCache] Could not unload file {0:s} : {1:s} ", file.FullName, uae);
}
}
}

try
{
File.Delete(CachedBinary);
}
catch (System.UnauthorizedAccessException uae)
{
// The BinaryCache is shared among serveral Dependencies.exe instance
// so only the last one alive can clear the cache.
Debug.WriteLine("[BinaryCache] Could not unload file {0:s} : {1:s} ", CachedBinary, uae);
}
private PE LoadCachedBinary(string peHash)
{
var cachedBinaryFile = Path.Combine(BinaryCacheFolderPath, peHash);
if (!NativeFile.Exists(cachedBinaryFile))
{
return null;
}

}
PE cachedPE = new PE(cachedBinaryFile);
try
{
// update LastAccessTime to save LRU to disk
// note: Windows from Vista disable updating LastAccessTime by default,
// so we have to update it manually.
new FileInfo(cachedBinaryFile).LastAccessTime = DateTime.Now;
}
catch { }

if (!cachedPE.Load())
{
return null;
}

// flush the cache
BinaryDatabase.Clear();
FilepathDatabase.Clear();
return cachedPE;
}

public void GetBinaryAsync(string PePath, RunWorkerCompletedEventHandler Callback = null)
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (sender, e) => {
GetBinary(PePath);
};

Expand All @@ -395,7 +395,6 @@ public void GetBinaryAsync(string PePath, RunWorkerCompletedEventHandler Callbac
bw.RunWorkerCompleted += Callback;
}


bw.RunWorkerAsync();
}

Expand All @@ -409,47 +408,39 @@ public override PE GetBinary(string PePath)
return null;
}

string Fullpath = Path.GetFullPath(PePath);
if (FilepathDatabase.ContainsKey(Fullpath))
{
// TODO : update LRU cache
PE sShadowBinary = FilepathDatabase[Fullpath];
sShadowBinary.Filepath = Fullpath;
return sShadowBinary;
}

string PeHash = GetBinaryHash(PePath);
//Debug.WriteLine(String.Format("File {0:s} hash : {1:s} ", PePath, PeHash), "BinaryCache");

// A sync lock is mandatory here in order not to load twice the
// same binary from two differents workers
lock (BinaryDatabaseLock)
PE cachedPE;
lock (BinaryDatabase)
{
bool hit = BinaryDatabase.ContainsKey(PeHash);

// Cache "miss"
if (!hit)
// Memory Cache "miss"
if (!BinaryDatabase.TryGetValue(PeHash, out cachedPE))
{

string DestFilePath = Path.Combine(BinaryCacheFolderPath, PeHash);
if (!File.Exists(DestFilePath) && (DestFilePath != PePath))
cachedPE = LoadCachedBinary(PeHash);
if (cachedPE == null)
{
// Debug.WriteLine(String.Format("FileCopy from {0:s} to {1:s}", PePath, DestFilePath), "BinaryCache");
NativeFile.Copy(PePath, DestFilePath);
// Disk Cache miss
string DestFilePath = Path.Combine(BinaryCacheFolderPath, PeHash);
if (!File.Exists(DestFilePath) && (DestFilePath != PePath))
{
// Debug.WriteLine(String.Format("FileCopy from {0:s} to {1:s}", PePath, DestFilePath), "BinaryCache");
NativeFile.Copy(PePath, DestFilePath);
}
cachedPE = LoadCachedBinary(PeHash);
if (cachedPE == null)
{
BinaryDatabase.Remove(PeHash);
return null;
}
}

PE NewShadowBinary = new PE(DestFilePath);
NewShadowBinary.Load();

LruCache.Add(PeHash);
BinaryDatabase.Add(PeHash, NewShadowBinary);
FilepathDatabase.Add(Fullpath, NewShadowBinary);
BinaryDatabase.Add(PeHash, cachedPE);
}
}

// Cache "Hit"
UpdateLru(PeHash);
PE ShadowBinary = BinaryDatabase[PeHash];
PE ShadowBinary = cachedPE;
ShadowBinary.Filepath = Path.GetFullPath(PePath); // convert any paths to an absolute one.

Debug.WriteLine(String.Format("File {0:s} loaded from {1:s}", PePath, Path.Combine(BinaryCacheFolderPath, PeHash)), "BinaryCache");
Expand All @@ -461,28 +452,11 @@ protected string GetBinaryHash(string PePath)
return NativeFile.GetPartialHashFile(PePath, 1024);
}

protected void UpdateLru(string PeHash)
{
string MatchingHash = LruCache.Find(Hash => (Hash == PeHash));
if (null == MatchingHash)
return;

lock (BinaryDatabaseLock)
{
// prepend the matching item at the beginning of the list
LruCache.Remove(MatchingHash);
LruCache.Insert(0, MatchingHash);
}
}

#region Members
private List<string> LruCache;
private Dictionary<string, PE> BinaryDatabase;
private Dictionary<string, PE> FilepathDatabase;
private Object BinaryDatabaseLock;
private readonly Dictionary<string, PE> BinaryDatabase;
private int MaxBinaryCount;

private string BinaryCacheFolderPath;
private int MaxBinaryCount;

#endregion Members
}
Expand Down
25 changes: 25 additions & 0 deletions DependenciesLib/SxsManifest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,31 @@ public SxsEntry(XElement SxsAssemblyIdentity, XElement SxsFile, string Folder)
Type = "";
PublicKeyToken = "";

string loadFrom = SxsFile.Attribute("loadFrom")?.Value?.ToString();
if (!string.IsNullOrEmpty(loadFrom))
{
loadFrom = Environment.ExpandEnvironmentVariables(loadFrom);
if (!System.IO.Path.IsPathRooted(loadFrom))
{
loadFrom = System.IO.Path.Combine(Folder, loadFrom);
}

// It's only a folder
if (loadFrom.EndsWith("\\") || loadFrom.EndsWith("/"))
{
Path = System.IO.Path.Combine(loadFrom, RelPath);
}
else
{
// It's also a dll name!
Path = loadFrom;
if (!Path.ToLower().EndsWith(".dll"))
{
Path += ".DLL";
}
}
}

if (SxsAssemblyIdentity != null)
{
if (SxsAssemblyIdentity.Attribute("version") != null)
Expand Down
Loading

0 comments on commit 8acfe64

Please sign in to comment.