Skip to content

Commit

Permalink
Created wpf sample and extensions library
Browse files Browse the repository at this point in the history
  • Loading branch information
thenameless314159 committed Feb 26, 2020
1 parent aacbd21 commit 88c8d7b
Show file tree
Hide file tree
Showing 35 changed files with 1,885 additions and 3 deletions.
44 changes: 41 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# <img src="https://cdn3.iconfinder.com/data/icons/medicon/512/syringe_injection_drug_steroid-512.png" width="32" height="32"> SocketHook
# <img src="https://cdn3.iconfinder.com/data/icons/medicon/512/syringe_injection_drug_steroid-512.png" width="32" height="32"> SocketHook [![NuGet Badge](https://buildstats.info/nuget/SocketHook.Extensions)](https://www.nuget.org/packages/SocketHook.Extensions/1.0.0)

This application allow the user to redirect any call to the windows API [*connect*](https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect) of any process in order to redirect its connection to the configured local port.

![](https://i.ibb.co/dbpVg64/AJSr7-LQg-U0.png)

## Get started

Thanks to the recent update, you can either start the application with regular **CLI args** or with a **json configuration file** on the working directory of the application (or with both). Here are two examples of json config files :
The hook was meant to be **controlled by a REST API**, thanks to this, any kind of application can "*plug*" to it and send inject directives. A **WPF application using .NET Core 3.1** and the *generic hosting APIs* was made to show the potential of this architecture, you can see the code [on this repository ](https://github.com/thenameless314159/SocketHook/tree/master/samples/SocketHook.HostedWpfSample) or [**download the release directly**](https://github.com/thenameless314159/SocketHook/releases).

The API can either be started using regular **CLI args** or with a **json configuration file** on the working directory of the application (or with both). Here are two examples of json config files :

```json
{
Expand Down Expand Up @@ -36,7 +40,41 @@ Also, if no *InjectTo* args are being provided, the application will bind a **RE
- also with [*this json model*](https://github.com/thenameless314159/SocketHook/tree/master/src/SocketHook.API/Models/InjectionSettings.cs) in the request body.
- DELETE `http://127.0.0.1:80/api/killall` for the **killAll** directive

## Go further

The WPF application takes advantage of the new .NET Core *generic hosting APIs*, therefore [a library](https://github.com/thenameless314159/SocketHook/tree/master/src/SocketHook.Extensions) that provides interaction with the hook REST API and extensions methods to register thoses services into the commonly used **`IServiceCollection`**. This library is also available [*on nuget at this address*](https://www.nuget.org/packages/SocketHook.Extensions/1.0.0).

The registration logic looks like this :

```csharp
services.AddSocketHook(opt =>
{
opt.AddConfiguration(ctx.Configuration);
opt.Configure(x =>
{
x.UseHookServiceFactory = true;
x.OpenHookOnStartup = true;
x.KillAllOnExit = true;
});
});
```

And this will registers at least an **`ISocketHookServiceFactory`** which will be responsible of creating **`ISocketHookService`** instances with their relative [**`InjectOptions`**](https://github.com/thenameless314159/SocketHook/tree/master/src/SocketHook.Extensions/Options/InjectOptions.cs).

The **`ISocketHookService`** provides 3 methods to interact with the hook API :

```csharp
public interface ISocketHookService
{
ValueTask<bool> TryCreateAndInject(string exePath, CancellationToken token = default);
ValueTask<bool> TryInject(int pId, CancellationToken token = default);

/// <exception cref="HttpRequestException" />
ValueTask KillAllInjectedProcesses(CancellationToken token = default);
}
```

## Important

If you are experiencing any issue binding the HTTP server to your specified port please check this article from Microsoft :
https://docs.microsoft.com/fr-fr/dotnet/framework/wcf/feature-details/configuring-http-and-https?redirectedfrom=MSDN
[https://docs.microsoft.com/fr-fr/dotnet/framework/wcf/feature-details/configuring-http-and-https?redirectedfrom=MSDN](https://docs.microsoft.com/fr-fr/dotnet/framework/wcf/feature-details/configuring-http-and-https?redirectedfrom=MSDN)
16 changes: 16 additions & 0 deletions SocketHook.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketHook", "src\SocketHoo
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketHook.API", "src\SocketHook.API\SocketHook.API.csproj", "{049BADE4-9257-48FA-9D82-16452B89CDA6}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{B1B68385-416A-47C1-A443-51FEB7AB6DDA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketHook.Extensions", "src\SocketHook.Extensions\SocketHook.Extensions.csproj", "{9D5FB345-75B2-453B-8DB9-F7301973380B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SocketHook.HostedWpfSample", "samples\SocketHook.HostedWpfSample\SocketHook.HostedWpfSample.csproj", "{03C42374-08EC-4CAA-8088-9A8B012C1BAC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -23,13 +29,23 @@ Global
{049BADE4-9257-48FA-9D82-16452B89CDA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{049BADE4-9257-48FA-9D82-16452B89CDA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{049BADE4-9257-48FA-9D82-16452B89CDA6}.Release|Any CPU.Build.0 = Release|Any CPU
{9D5FB345-75B2-453B-8DB9-F7301973380B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9D5FB345-75B2-453B-8DB9-F7301973380B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D5FB345-75B2-453B-8DB9-F7301973380B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D5FB345-75B2-453B-8DB9-F7301973380B}.Release|Any CPU.Build.0 = Release|Any CPU
{03C42374-08EC-4CAA-8088-9A8B012C1BAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{03C42374-08EC-4CAA-8088-9A8B012C1BAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{03C42374-08EC-4CAA-8088-9A8B012C1BAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{03C42374-08EC-4CAA-8088-9A8B012C1BAC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{847BFE7D-83B6-478B-81E4-A57B5EDA6C27} = {2F405002-93D6-4837-96D1-E2CC2F9D4438}
{049BADE4-9257-48FA-9D82-16452B89CDA6} = {2F405002-93D6-4837-96D1-E2CC2F9D4438}
{9D5FB345-75B2-453B-8DB9-F7301973380B} = {2F405002-93D6-4837-96D1-E2CC2F9D4438}
{03C42374-08EC-4CAA-8088-9A8B012C1BAC} = {B1B68385-416A-47C1-A443-51FEB7AB6DDA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {41D08C75-E025-4873-962A-E906D8C5B8FC}
Expand Down
43 changes: 43 additions & 0 deletions samples/SocketHook.HostedWpfSample/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<Application x:Class="SocketHook.HostedWpfSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:SocketHook.HostedWpfSample.Converters"
ShutdownMode="OnMainWindowClose">

<Application.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<converters:BitmapToSource x:Key="BitmapToSourceConverter"/>
<Style TargetType="ScrollBar">
<Setter Property="Background" Value="#3f3f46" />
<Setter Property="BorderBrush" Value="#3f3f46" />
<Setter Property="Foreground" Value="#686868" />
</Style>

<Style TargetType="Grid">
<Setter Property="Background" Value="#252526" />
</Style>

<Style TargetType="Label">
<Setter Property="Foreground" Value="#f1f1f1" />
</Style>

<Style TargetType="TextBox">
<Setter Property="BorderBrush" Value="#3f3f46" />
<Setter Property="Background" Value="#333337" />
<Setter Property="Foreground" Value="#f1f1f1" />
</Style>

<Style TargetType="{x:Type Button}">
<Setter Property="BorderBrush" Value="#3f3f46" />
<Setter Property="Background" Value="#2d2d30" />
<Setter Property="Foreground" Value="#f1f1f1" />

<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#3e3e40"/>
<Setter Property="BorderBrush" Value="#3399ff"/>
</Trigger>
</Style.Triggers>
</Style>
</Application.Resources>
</Application>
86 changes: 86 additions & 0 deletions samples/SocketHook.HostedWpfSample/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.IO;
using System.Windows;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using SocketHook.Extensions;
using SocketHook.HostedWpfSample.Services;
using SocketHook.HostedWpfSample.ViewModels;
using SocketHook.HostedWpfSample.Views;

namespace SocketHook.HostedWpfSample
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
public static IHost RunningHost { get; private set; } // keeps a lifetime instance

private static IHost CreateHost(string[] args) =>
Host.CreateDefaultBuilder(args)
//.ConfigureHostConfiguration(config => config.AddCommandLine(args))
.ConfigureAppConfiguration(config =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddJsonFile("appsettings.json", optional: true);
config.AddCommandLine(args);
})
.ConfigureServices((ctx, services) =>
{
if(ctx.HostingEnvironment.IsDevelopment())
services.AddLogging(logger =>
{
logger.SetMinimumLevel(LogLevel.Trace);
logger.AddFile($"app{DateTime.Now:yyyy-dd-M--HH-mm-ss}.log");
});
services.AddSocketHook(opt =>
{
opt.AddConfiguration(ctx.Configuration);
opt.Configure(x =>
{
x.UseHookServiceFactory = true;
x.OpenHookOnStartup = true;
x.KillAllOnExit = true;
});
});
services.AddSingleton<IProcessObserverService, ProcessObserverService>();
services.AddSingleton<IInjectOptionsService, InjectOptionsService>();
services.AddTransient<InjectOptionsViewModel>();
services.AddTransient<MainWindowViewModel>();
services.AddTransient<InjectOptionsView>();
services.AddTransient<MainWindow>();
}).Build();

protected override void OnStartup(StartupEventArgs e)
{
DispatcherUnhandledException += (o, s) =>
{
if (s.Handled) return;
MessageBox.Show($"An unhandled exception was propagated to the UI thread :\n{s.Exception}", "Fatal error",
MessageBoxButton.OK, MessageBoxImage.Error);
RunningHost?.StopAsync()?.GetAwaiter().GetResult();
RunningHost?.Dispose();
};

RunningHost = CreateHost(e.Args);
RunningHost.Start();

var mainWindow = RunningHost.Services.GetRequiredService<MainWindow>();
MainWindow = mainWindow;
mainWindow.Show();
base.OnStartup(e);
}

protected override void OnExit(ExitEventArgs e)
{
try { RunningHost.Dispose(); } catch { /* discarded */ }
base.OnExit(e);
}
}
}
10 changes: 10 additions & 0 deletions samples/SocketHook.HostedWpfSample/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Windows;

[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
57 changes: 57 additions & 0 deletions samples/SocketHook.HostedWpfSample/Commands/ActionCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System;
using System.Windows.Input;

namespace SocketHook.HostedWpfSample.Commands
{
public class ActionCommand : ICommand
{
private readonly Action _execute;
private Func<bool> _predicate;

public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}

private ActionCommand(Action execute, Func<bool> predicate = default)
{
_execute = execute;
_predicate = predicate;
}

public static ICommand Create(Action execute, Func<bool> predicate = default) =>
new ActionCommand(execute, predicate);

public static ICommand Create<T>(Action<T> execute, Predicate<T> predicate = default) =>
new ActionCommand<T>(execute, predicate);

public bool CanExecute(object parameter) => (_predicate ??= () => true)();
public void Execute(object parameter) => _execute();
}

public class ActionCommand<T> : ICommand
{
private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;

public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}

public ActionCommand(Action<T> execute)
: this(execute, null) => _execute = execute;

public ActionCommand(Action<T> execute, Predicate<T> canExecute)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}

public bool CanExecute(object parameter) => _canExecute == null || _canExecute((T)parameter);

public void Execute(object parameter) => _execute((T)parameter);
}
}
Loading

0 comments on commit 88c8d7b

Please sign in to comment.