Skip to content

Interaction With Remote Objects

Shai S edited this page Aug 25, 2023 · 2 revisions

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.

✳️ Reading Remote Fields/Properties

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 ConnectionStrings 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)

✳️ Invoking Remote Methods

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 RSACryptoServiceProviders) 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));
}

✳️ Remote Events

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:

  1. The parameters for the callback must be dynamics
  2. The callback must define the exact number of parameters for that event
  3. Lambda expression are not allowed. The callback must be casted to an Action<...>.
Clone this wiki locally