Remote hooking generally involves first injecting a payload from the “injector” into the target process and then from this payload, installing the hooks.
EasyHook.RemoteHooking.Inject: injects the specified 32-bit/64-bit payload assembly into the process identified by the provided process Id. Parameters can be provided that are passed into the injected library.
EasyHook.RemoteHooking.CreateAndInject: creates a new process in a suspended state from the provided executable path and command line, and then injects the specified 32-bit/64-bit payload assembly as per Inject.
EasyHook.RemoteHooking.WakeUpProcess: used in conjunction with CreateAndInject from the payload/injected library to wake up the process when ready.
EasyHook.RemoteHooking.IpcConnectClient<T>: a helper method used to connect the client to the IPC channel after injection (called from within injected library running in the target process)
EasyHook.IEntryPoint: the payload assembly must include a public class that implements this interface.
Once injected the payload will use EasyHook.LocalHook to create the hooks (see Creating a local hook).
Internals of EasyHook.RemoteHooking.Inject
EasyHook.RemoteHooking.Inject serializes the configuration, including the payload assembly path and parameters
Injects the native EasyHook32/64.dll into the specified target process depending on whether it is 32-bit or 64-bit. If necessary EasyHook will automatically use the EasyHookSvc32/64.exe helper to inject from 32-bit into 64-bit and vice versa.
EasyHook.RemoteHooking.Inject will wait here until it times out or until it has been signalled that injection has completed/failed.
– now running within target process –
EasyHook32/64.dll completes “managed injection” by loading EasyLoad32/64.dll
(EasyLoad attempts to create a new AppDomain so that the injection library can be unloaded)
(EasyHook32/64.dll signals EasyHook.RemoteHooking.Inject that injection is complete)
EasyLoad loads the managed assembly EasyHook.dll into the target process and calls the EasyHook.InjectionLoader.Main method.
EasyHook.InjectionLoader deserializes the configuration, loads the payload assembly and looks for the EasyHook.IEntryPoint that matches the parameters provided to the call to EasyHook.RemoteHooking.Inject.
If found, the matching EasyHook.IEntryPoint in the payload assembly is instantiated and then finally the matching Run method is called.
Payload’s Run method installs any hooks
Finally when the Run method exits, EasyLoad will attempt to unload the AppDomain
Internals of EasyHook.RemoteHooking.CreateAndInject
Creates the target process in a suspended state using the provided executable name and command line.
Follows the same logic as EasyHook.RemoteHooking.Inject
The created process will remain in a suspended state until the payload assembly calls RemoteHooking.WakeUpProcess
Step 1: Create the injection payload: FileMonitorHook class library
Create a new C# class library project called FileMonitorHook.
Add the EasyHook NuGet package (right-click on the FileMonitorHook project, Manage NuGet Packages…), search for EasyHook and install.
ServerInterface class
Next we will add the interface class that will be used to communicate from the payload within the target process back to the FileMonitor console app we will add shortly. It is important that this class, and any objects it needs to pass back and forth descend from MarshalByRefObject.
InjectionEntryPoint class
Lastly we need to create a public class that implements EasyHook.IEntryPoint so that the EasyHook injection process can call our custom logic once the payload has been injected.
This class will include a constructor that sets up the IPC connection, and a method called Run with the same parameters as the constructor.
The constructor and Run method must include at least one parameter of type EasyHook.RemoteHooking.IContext, and then any number of additional parameters providing they are serializable.
For example, a minimal EasyHook.IEntryPoint that does nothing would need look like this:
In the above example, once the payload has been injected, the instance of MySimpleEntryPoint will be created, the Run method called, and then immediately afterwards the payload will be unloaded.
Our file monitor example is going to accomplish the following:
Constructor:
Connect to the server IPC channel for ServerInterface
Attempt to call the ServerInterface.Ping method we created earlier to confirm the channel is accessible
Run:
Install our hooks for CreateFile, ReadFile and WriteFile. Our hooks will not modify the original behaviour in any way, they will simply add a message to the queue of messages to be returned to the console app.
Enter an endless loop to communicate the results back to the console app. Important: if using a loop, be sure to add a Thread.Sleep so that you do not cause performance problems in the target application. If a loop is not used then consider using a signal event such as an EventWaitHandle to prevent the Run method exiting prematurely.
Step 2: Create the FileMonitor console app
Add a new C# console app project to the solution called FileMonitor.
Add the EasyHook NuGet package (right-click on the FileMonitor project, Manage NuGet Packages…), search for EasyHook and install.
Add a reference to FileMonitorHook that we added previously so that we can make use of the ServerInterface class we created.
Within Program.cs we will create the following two static methods:
Main: the program entry point where we will perform the injection and then wait for the user to exit; and
ProcessArgs: (to process the command line arguments).
FileMonitor console app code
Within the console app we will be doing the following:
Check command line arguments (either a process ID or path to executable - see ProcessArgs method in the source code listed below)
Create the IPC server channel using the EasyHook.RemoteHooking.IpcCreateServer<T> helper. The channel name will be generated for us for added security and we will be passing that into the target process during injection.
Determine the full path to the payload “FileMonitorHook.dll”
If a target process Id has been provided
Inject the payload into the target process, passing the IPC channel name as the one and only parameter to send through to the payload as part of the injection process.
If a target executable path has been specified
CreateAndInject the payload into the target process. Again the IPC channel name will be passed as the only parameter.