using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Process.NET.Memory;
namespace Process.NET.Modules
{
///
/// Class providing tools for manipulating modules and libraries.
///
public class ModuleFactory : IModuleFactory
{
///
/// The list containing all injected modules (writable).
///
protected readonly List InternalInjectedModules;
protected readonly IProcess ProcessPlus;
///
/// Initializes a new instance of the class.
///
/// The reference of the object.
public ModuleFactory(IProcess processPlus)
{
// Save the parameter
ProcessPlus = processPlus;
// Create a list containing all injected modules
InternalInjectedModules = new List();
}
///
/// Gets a pointer from the remote process.
///
/// The address of the pointer.
/// A new instance of a class.
public IPointer this[IntPtr address] => new MemoryPointer(ProcessPlus, address);
///
/// Gets the main module for the remote process.
///
public IProcessModule MainModule => FetchModule(ProcessPlus.Native.MainModule);
///
/// Gets the modules that have been loaded in the remote process.
///
public IEnumerable RemoteModules => NativeModules.Select(FetchModule);
///
/// Gets the native modules that have been loaded in the remote process.
///
public IEnumerable NativeModules => ProcessPlus.Native.Modules.Cast();
///
/// Gets the specified module in the remote process.
///
/// The name of module (not case sensitive).
/// A new instance of a class.
public IProcessModule this[string moduleName] => FetchModule(moduleName);
///
/// Releases all resources used by the object.
///
public virtual void Dispose()
{
// Release all injected modules which must be disposed
foreach (var injectedModule in InternalInjectedModules.Where(m => m.MustBeDisposed))
injectedModule.Dispose();
// Clean the cached functions related to this process
foreach (
var cachedFunction in
RemoteModule.CachedFunctions.ToArray()
.Where(cachedFunction => cachedFunction.Key.Item2 == ProcessPlus.Handle))
RemoteModule.CachedFunctions.Remove(cachedFunction);
// Avoid the finalizer
GC.SuppressFinalize(this);
}
///
/// A collection containing all injected modules.
///
public IEnumerable InjectedModules => InternalInjectedModules.AsReadOnly();
///
/// Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count.
///
/// The name of module to eject.
public void Eject(string moduleName)
{
// Fint the module to eject
var module = RemoteModules.FirstOrDefault(m => m.Name == moduleName);
// Eject the module is it's valid
if (module != null)
RemoteModule.InternalEject(ProcessPlus, module);
}
///
/// Injects the specified module into the address space of the remote process.
///
///
/// The path of the module. This can be either a library module (a .dll file) or an executable module
/// (an .exe file).
///
/// The module will be ejected when the finalizer collects the object.
/// A new instance of the class.
public InjectedModule Inject(string path, bool mustBeDisposed = true)
{
// Injects the module
var module = InjectedModule.InternalInject(ProcessPlus, path);
// Add the module in the list
InternalInjectedModules.Add(module);
// Return the module
return module;
}
///
/// Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count.
///
/// The module to eject.
public void Eject(IProcessModule module)
{
// If the module is valid
if (!module.IsValid) return;
// Find if the module is an injected one
var injected = InternalInjectedModules.FirstOrDefault(m => m.Equals(module));
if (injected != null)
InternalInjectedModules.Remove(injected);
// Eject the module
RemoteModule.InternalEject(ProcessPlus, module);
}
///
/// Frees resources and perform other cleanup operations before it is reclaimed by garbage collection.
///
~ModuleFactory()
{
Dispose();
}
///
/// Fetches a module from the remote process.
///
///
/// A module name (not case sensitive). If the file name extension is omitted, the default library
/// extension .dll is appended.
///
/// A new instance of a class.
public IProcessModule FetchModule(string moduleName)
{
// Convert module name with lower chars
moduleName = moduleName.ToLower();
// Check if the module name has an extension
if (!Path.HasExtension(moduleName))
moduleName += ".dll";
// Fetch and return the module
return new RemoteModule(ProcessPlus, NativeModules.First(m => m.ModuleName.ToLower() == moduleName));
}
///
/// Fetches a module from the remote process.
///
/// A module in the remote process.
/// A new instance of a class.
public IProcessModule FetchModule(ProcessModule module)
{
return FetchModule(module.ModuleName);
}
}
}