using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Process.NET.Extensions;
using Process.NET.Memory;
using Process.NET.Native.Types;
using Process.NET.Utilities;
namespace Process.NET.Modules
{
///
/// Class repesenting a module in the remote process.
///
public class RemoteModule : MemoryRegion, IProcessModule
{
///
/// The dictionary containing all cached functions of the remote module.
///
internal static readonly IDictionary, IProcessFunction> CachedFunctions =
new Dictionary, IProcessFunction>();
///
/// Initializes a new instance of the class.
///
///
/// The native object corresponding to this module.
public RemoteModule(IProcess processPlus, ProcessModule module) : base(processPlus, module.BaseAddress)
{
// Save the parameter
Native = module;
}
///
/// State if this is the main module of the remote process.
///
public bool IsMainModule => Process.Native.MainModule.BaseAddress == BaseAddress;
///
/// Gets if the is valid.
///
public override bool IsValid
{
get
{
return base.IsValid &&
Process.Native.Modules.Cast()
.Any(m => m.BaseAddress == BaseAddress && m.ModuleName == Name);
}
}
///
/// The name of the module.
///
public string Name => Native.ModuleName;
///
/// The native object corresponding to this module.
///
public ProcessModule Native { get; }
///
/// The full path of the module.
///
public string Path => Native.FileName;
///
/// The size of the module in the memory of the remote process.
///
public int Size => Native.ModuleMemorySize;
///
/// Gets the specified function in the remote module.
///
/// The name of the function.
/// A new instance of a class.
public IProcessFunction this[string functionName]
{
get { return FindFunction(functionName); }
set { CachedFunctions[Tuple.Create(functionName, Process.Handle)] = value; }
}
///
/// Ejects the loaded dynamic-link library (DLL) module.
///
public void Eject()
{
// Eject the module
Process.ModuleFactory.Eject(this);
// Remove the pointer
BaseAddress = IntPtr.Zero;
}
///
/// Finds the specified function in the remote module.
///
/// The name of the function (case sensitive).
/// A new instance of a class.
///
/// Interesting article on how DLL loading works: http://msdn.microsoft.com/en-us/magazine/bb985014.aspx
///
public IProcessFunction FindFunction(string functionName)
{
// Create the tuple
var tuple = Tuple.Create(functionName, Process.Handle);
// Check if the function is already cached
if (CachedFunctions.ContainsKey(tuple))
return CachedFunctions[tuple];
// If the function is not cached
// Check if the local process has this module loaded
var localModule =
System.Diagnostics.Process.GetCurrentProcess()
.Modules.Cast()
.FirstOrDefault(m => m.FileName.ToLower() == Path.ToLower());
var isManuallyLoaded = false;
try
{
// If this is not the case, load the module inside the local process
if (localModule == null)
{
isManuallyLoaded = true;
localModule = ModuleHelper.LoadLibrary(Native.FileName);
}
// Get the offset of the function
var offset = localModule.GetProcAddress(functionName).ToInt64() -
localModule.BaseAddress.ToInt64();
// Rebase the function with the remote module
var function = new RemoteFunction(Process, new IntPtr(Native.BaseAddress.ToInt64() + offset),
functionName);
// Store the function in the cache
CachedFunctions.Add(tuple, function);
// Return the function rebased with the remote module
return function;
}
finally
{
// Free the module if it was manually loaded
if (isManuallyLoaded)
localModule.FreeLibrary();
}
}
///
/// Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count.
///
/// The reference of the object.
/// The module to eject.
internal static void InternalEject(IProcess memorySharp, IProcessModule module)
{
// Call FreeLibrary remotely
memorySharp.ThreadFactory.CreateAndJoin(memorySharp["kernel32"]["FreeLibrary"].BaseAddress,
module.BaseAddress);
}
///
/// Returns a string that represents the current object.
///
public override string ToString()
{
return $"BaseAddress = 0x{BaseAddress.ToInt64():X} Name = {Name}";
}
}
}