forked from DaxxTrias/Process.NET
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRemoteModule.cs
More file actions
171 lines (151 loc) · 6.41 KB
/
RemoteModule.cs
File metadata and controls
171 lines (151 loc) · 6.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ProcessNET.Extensions;
using ProcessNET.Memory;
using ProcessNET.Native.Types;
using ProcessNET.Utilities;
namespace ProcessNET.Modules
{
/// <summary>
/// Class repesenting a module in the remote process.
/// </summary>
public class RemoteModule : MemoryRegion, IProcessModule
{
/// <summary>
/// The dictionary containing all cached functions of the remote module.
/// </summary>
internal static readonly IDictionary<Tuple<string, SafeMemoryHandle>, IProcessFunction> CachedFunctions =
new Dictionary<Tuple<string, SafeMemoryHandle>, IProcessFunction>();
/// <summary>
/// Initializes a new instance of the <see cref="RemoteModule" /> class.
/// </summary>
/// <param name="processPlus"></param>
/// <param name="module">The native <see cref="ProcessModule" /> object corresponding to this module.</param>
public RemoteModule(IProcess processPlus, ProcessModule module) : base(processPlus, module.BaseAddress)
{
// Save the parameter
Native = module;
}
/// <summary>
/// State if this is the main module of the remote process.
/// </summary>
public bool IsMainModule => Process.Native.MainModule.BaseAddress == BaseAddress;
/// <summary>
/// Gets if the <see cref="RemoteModule" /> is valid.
/// </summary>
public override bool IsValid
{
get
{
return base.IsValid &&
Process.Native.Modules.Cast<ProcessModule>()
.Any(m => m.BaseAddress == BaseAddress && m.ModuleName == Name);
}
}
/// <summary>
/// The name of the module.
/// </summary>
public string Name => Native.ModuleName;
/// <summary>
/// The native <see cref="ProcessModule" /> object corresponding to this module.
/// </summary>
public ProcessModule Native { get; }
/// <summary>
/// The full path of the module.
/// </summary>
public string Path => Native.FileName;
/// <summary>
/// The size of the module in the memory of the remote process.
/// </summary>
public int Size => Native.ModuleMemorySize;
/// <summary>
/// Gets the specified function in the remote module.
/// </summary>
/// <param name="functionName">The name of the function.</param>
/// <returns>A new instance of a <see cref="RemoteFunction" /> class.</returns>
public IProcessFunction this[string functionName]
{
get { return FindFunction(functionName); }
set { CachedFunctions[Tuple.Create(functionName, Process.Handle)] = value; }
}
/// <summary>
/// Ejects the loaded dynamic-link library (DLL) module.
/// </summary>
public void Eject()
{
// Eject the module
Process.ModuleFactory.Eject(this);
// Remove the pointer
BaseAddress = IntPtr.Zero;
}
/// <summary>
/// Finds the specified function in the remote module.
/// </summary>
/// <param name="functionName">The name of the function (case sensitive).</param>
/// <returns>A new instance of a <see cref="RemoteFunction" /> class.</returns>
/// <remarks>
/// Interesting article on how DLL loading works: http://msdn.microsoft.com/en-us/magazine/bb985014.aspx
/// </remarks>
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<ProcessModule>()
.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
//TODO: This is not x86 safe, but that probably doesnt matter anymore?
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();
}
}
/// <summary>
/// Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count.
/// </summary>
/// <param name="memorySharp">The reference of the <see cref="MemorySharp" /> object.</param>
/// <param name="module">The module to eject.</param>
internal static void InternalEject(IProcess memorySharp, IProcessModule module)
{
// Call FreeLibrary remotely
memorySharp.ThreadFactory.CreateAndJoin(memorySharp["kernel32"]["FreeLibrary"].BaseAddress,
module.BaseAddress);
}
/// <summary>
/// Returns a string that represents the current object.
/// </summary>
public override string ToString()
{
return $"BaseAddress = 0x{BaseAddress.ToInt64():X} Name = {Name}";
}
}
}