-
Notifications
You must be signed in to change notification settings - Fork 3
Interaction With Remote Objects
RemoteNET's goal is to allow the developer of the manipulating app to
access remote objects as if they were local objects.
This includes reading fields & properties, setting properties, invoking functions and subscribing to/usubscribing from events.
To allow a smooth coding expereince, RemoteNET is utilizing a special dynamic object which any RemoteObject
can turn into.
This object can be used to access field/properties just if they were field/properties of a local object:
// Reading the 'Capacity' property of a newly created StringBuilder
RemoteObject remoteStringBuilder = remoteApp.Activator.CreateInstance(typeof(StringBuilder));
dynamic dynamicStringBuilder = remoteStringBuilder.Dynamify();
Console.WriteLine("Remote StringBuilder's Capacity: " + dynamicStringBuilder.Capacity);
A more interesting example would be retrieving the ConnectionString
s of every SqlConnection
instance:
var sqlConCandidates = remoteApp.QueryInstances(typeof(SqlConnection));
foreach (CandidateObject candidate in sqlConCandidates)
{
RemoteObject remoteSqlConnection = remoteApp.GetRemoteObject(candidate);
dynamic dynamicSqlConnection = remoteSqlConnection.Dynamify();
Console.WriteLine("ConnectionString: " + dynamicSqlConnection.ConnectionString);
}
Setting fields/properties are done just as you'd expect:
Console.WriteLine("Remote StringBuilder's Old Capacity: " + dynamicStringBuilder.Capacity)
dynamicStringBuilder.Capacity = 1337;
Console.WriteLine("Remote StringBuilder's New Capacity: " + dynamicStringBuilder.Capacity)
Just like accessing fields & properties, invoking methods can be done on the dynamic objects directly.
This fun example dumps all private RSA keys (which are stored in RSACryptoServiceProvider
s) found in the target's memory:
(Note the invocation of RSACryptoServiceProvider.ExportParameters()
)
Func<byte[], string> ToHex = ba => BitConverter.ToString(ba).Replace("-", "");
// Finding every RSACryptoServiceProvider instance
var rsaProviderCandidates = remoteApp.QueryInstances(typeof(RSACryptoServiceProvider));
foreach (CandidateObject candidateRsa in rsaProviderCandidates)
{
RemoteObject rsaProv = remoteApp.GetRemoteObject(candidateRsa);
dynamic dynamicRsaProv = rsaProv.Dynamify();
// Calling remote `ExportParameters`.
// First parameter (true) indicates we want the private key.
Console.WriteLine(" * Key found:");
dynamic parameters = dynamicRsaProv.ExportParameters(true);
Console.WriteLine("Modulus: " + ToHex(parameters.Modulus));
Console.WriteLine("Exponent: " + ToHex(parameters.Exponent));
Console.WriteLine("D: " + ToHex(parameters.D));
Console.WriteLine("P: " + ToHex(parameters.P));
Console.WriteLine("Q: " + ToHex(parameters.Q));
Console.WriteLine("DP: " + ToHex(parameters.DP));
Console.WriteLine("DQ: " + ToHex(parameters.DQ));
Console.WriteLine("InverseQ: " + ToHex(parameters.InverseQ));
}
You can also subscribe to/unsubscribe from remote events.
Note that the syntax is similar to "normal" C# events altough not exact:
CandidateObject cand = remoteApp.QueryInstances("System.IO.FileSystemWatcher").Single();
RemoteObject remoteFileSysWatcher = remoteApp.GetRemoteObject(cand);
dynamic dynFileSysWatcher = remoteFileSysWatcher.Dynamify();
Action<dynamic, dynamic> callback = (dynamic o, dynamic e) => Console.WriteLine("Event Invoked!");
dynFileSysWatcher.Changed += callback;
/* ... Somewhere further ... */
dynFileSysWatcher.Changed -= callback;
The limitations:
- The parameters for the callback must be
dynamic
s - The callback must define the exact number of parameters for that event
- Lambda expression are not allowed. The callback must be casted to an
Action<...>
.