├── screenshot.jpg ├── NetworkAdapterSelector.Hook ├── Icon.ico ├── NetworkAdapterSelector.Hook.snk ├── Unmanaged │ ├── Interfaces │ │ ├── IAddressIn.cs │ │ └── ISocketAddress.cs │ ├── Structures │ │ ├── ProcessInformation.cs │ │ ├── SocketAddressBase.cs │ │ ├── AddressIn6.cs │ │ ├── AddressIn.cs │ │ ├── SocketAddressIn.cs │ │ └── SocketAddressIn6.cs │ ├── NativeLibrary.cs │ ├── NativeWindow.cs │ ├── NativeProcess.cs │ └── NativeSocket.cs ├── Properties │ └── launchSettings.json ├── WindowTitle.cs ├── Delegates.cs ├── NetworkAdapterSelector.Hook.csproj ├── app.manifest ├── CommandLineOptions.cs ├── Program.cs └── Guest.cs ├── NetworkAdapterSelector.ShellExtension ├── Resources │ └── x16.png ├── NetworkAdapterSelector.ShellExtension.snk ├── Properties │ ├── launchSettings.json │ ├── Resources.Designer.cs │ └── Resources.resx ├── NetworkAdapterSelector.ShellExtension.csproj └── DynamicMenuExtension.cs ├── NetworkAdapterSelector.TestApp ├── Properties │ └── launchSettings.json ├── Program.cs ├── NetworkAdapterSelector.TestApp.csproj ├── Form1.cs └── Form1.Designer.cs ├── NetworkAdapterSelector.sln.DotSettings ├── NetworkAdapterSelector.sln ├── .gitignore ├── README.md └── LICENSE /screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/falahati/NetworkAdapterSelector/HEAD/screenshot.jpg -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/falahati/NetworkAdapterSelector/HEAD/NetworkAdapterSelector.Hook/Icon.ico -------------------------------------------------------------------------------- /NetworkAdapterSelector.ShellExtension/Resources/x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/falahati/NetworkAdapterSelector/HEAD/NetworkAdapterSelector.ShellExtension/Resources/x16.png -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/NetworkAdapterSelector.Hook.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/falahati/NetworkAdapterSelector/HEAD/NetworkAdapterSelector.Hook/NetworkAdapterSelector.Hook.snk -------------------------------------------------------------------------------- /NetworkAdapterSelector.TestApp/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "NetworkAdapterSelector.TestApp": { 4 | "commandName": "Project" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.ShellExtension/NetworkAdapterSelector.ShellExtension.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/falahati/NetworkAdapterSelector/HEAD/NetworkAdapterSelector.ShellExtension/NetworkAdapterSelector.ShellExtension.snk -------------------------------------------------------------------------------- /NetworkAdapterSelector.ShellExtension/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "NetworkAdapterSelector.ShellExtension": { 4 | "commandName": "Executable", 5 | "executablePath": "%windir%\\explorer.exe" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Unmanaged/Interfaces/IAddressIn.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace NetworkAdapterSelector.Hook.UnManaged.Interfaces 4 | { 5 | internal interface IAddressIn 6 | { 7 | IPAddress IPAddress { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Unmanaged/Interfaces/ISocketAddress.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Sockets; 2 | 3 | namespace NetworkAdapterSelector.Hook.UnManaged.Interfaces 4 | { 5 | internal interface ISocketAddress 6 | { 7 | IAddressIn Address { get; } 8 | AddressFamily AddressFamily { get; set; } 9 | int Port { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Unmanaged/Structures/ProcessInformation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace NetworkAdapterSelector.Hook.UnManaged.Structures 5 | { 6 | [StructLayout(LayoutKind.Sequential)] 7 | internal struct ProcessInformation 8 | { 9 | public IntPtr ProcessHandle; 10 | public IntPtr ThreadHandle; 11 | public int ProcessId; 12 | public int ThreadId; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Unmanaged/Structures/SocketAddressBase.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Sockets; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace NetworkAdapterSelector.Hook.UnManaged.Structures 5 | { 6 | [StructLayout(LayoutKind.Explicit, Size = 16)] 7 | internal struct SocketAddressBase 8 | { 9 | [FieldOffset(0)] private ushort family; 10 | 11 | public AddressFamily Family 12 | { 13 | get => (AddressFamily) family; 14 | 15 | set => family = (ushort) value; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Unmanaged/NativeLibrary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace NetworkAdapterSelector.Hook.UnManaged 5 | { 6 | internal static class NativeLibrary 7 | { 8 | [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] 9 | public static extern IntPtr LoadLibrary(string fileName); 10 | 11 | [DllImport("kernel32", SetLastError = true)] 12 | [return: MarshalAs(UnmanagedType.Bool)] 13 | public static extern bool FreeLibrary(IntPtr handle); 14 | } 15 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.sln.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | FQDN 3 | IP 4 | WSA -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Unmanaged/Structures/AddressIn6.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Runtime.InteropServices; 3 | using NetworkAdapterSelector.Hook.UnManaged.Interfaces; 4 | 5 | namespace NetworkAdapterSelector.Hook.UnManaged.Structures 6 | { 7 | [StructLayout(LayoutKind.Explicit, Size = 16)] 8 | internal struct AddressIn6 : IAddressIn 9 | { 10 | [FieldOffset(0)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 11 | private byte[] Bytes; 12 | 13 | public IPAddress IPAddress 14 | { 15 | get => new IPAddress(Bytes); 16 | set => Bytes = value.GetAddressBytes(); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Unmanaged/Structures/AddressIn.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Runtime.InteropServices; 4 | using NetworkAdapterSelector.Hook.UnManaged.Interfaces; 5 | 6 | namespace NetworkAdapterSelector.Hook.UnManaged.Structures 7 | { 8 | [StructLayout(LayoutKind.Explicit, Size = 4)] 9 | internal struct AddressIn : IAddressIn 10 | { 11 | [FieldOffset(0)] private uint Value; 12 | 13 | /// 14 | public IPAddress IPAddress 15 | { 16 | get => new IPAddress(Value); 17 | set => Value = BitConverter.ToUInt32(value.GetAddressBytes(), 0); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Chrome": { 4 | "commandName": "Project", 5 | "commandLineArgs": "-d -n \"{39F954B1-F286-4156-8AF0-88FD057B3B91}\" -e \"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe\" -c \"--profile-directory=Profile --enable-logging --v=1\" -t 0" 6 | }, 7 | "NetworkAdapterSelector.TestApp": { 8 | "commandName": "Project", 9 | "commandLineArgs": "-d -n \"{39F954B1-F286-4156-8AF0-88FD057B3B91}\" -e \"NetworkAdapterSelector.TestApp.exe\" -t 0" 10 | }, 11 | "Firefox": { 12 | "commandName": "Project", 13 | "commandLineArgs": "-d -n \"{39F954B1-F286-4156-8AF0-88FD057B3B91}\" -e \"C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe\" -t 0" 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Unmanaged/NativeWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Text; 4 | 5 | namespace NetworkAdapterSelector.Hook.UnManaged 6 | { 7 | internal static class NativeWindow 8 | { 9 | [DllImport("user32", SetLastError = true, CharSet = CharSet.Auto)] 10 | public static extern int GetWindowText(IntPtr windowHandle, StringBuilder text, int length); 11 | 12 | [DllImport("user32", SetLastError = true)] 13 | public static extern int GetWindowTextLength(IntPtr windowHandle); 14 | 15 | [DllImport("user32", SetLastError = true)] 16 | [return: MarshalAs(UnmanagedType.Bool)] 17 | public static extern bool IsWindow(IntPtr windowHandle); 18 | 19 | [DllImport("user32", SetLastError = true, CharSet = CharSet.Auto)] 20 | public static extern bool SetWindowText(IntPtr windowHandle, string text); 21 | } 22 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.TestApp/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Windows.Forms; 6 | 7 | namespace NetworkAdapterSelector.TestApp 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | #if (DEBUG) 20 | if (Debugger.IsAttached) 21 | { 22 | Process.Start("NetworkAdapterSelector.Hook.exe", 23 | "-d -n \"{39F954B1-F286-4156-8AF0-88FD057B3B91}\" -a " + Process.GetCurrentProcess().Id); 24 | } 25 | #endif 26 | Application.Run(new Form1()); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /NetworkAdapterSelector.TestApp/NetworkAdapterSelector.TestApp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | net462 6 | 1.0.0.0 7 | Soroush Falahati (falahati.net) 8 | 9 | Soroush Falahati 10 | Copyright © Soroush Falahati 2018 11 | AnyCPU 12 | Network Adapter Selector 13 | true 14 | true 15 | AnyCPU 16 | Network Adapter Selector TestApp 17 | NetworkAdapterSelector.TestApp.Program 18 | 19 | 20 | 21 | ..\Debug 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Unmanaged/Structures/SocketAddressIn.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Sockets; 2 | using System.Runtime.InteropServices; 3 | using NetworkAdapterSelector.Hook.UnManaged.Interfaces; 4 | 5 | namespace NetworkAdapterSelector.Hook.UnManaged.Structures 6 | { 7 | [StructLayout(LayoutKind.Explicit, Size = 16)] 8 | internal struct SocketAddressIn : ISocketAddress 9 | { 10 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] [FieldOffset(8)] 11 | private readonly byte[] Padding; 12 | 13 | [FieldOffset(4)] private AddressIn address; 14 | 15 | [FieldOffset(0)] private ushort family; 16 | 17 | [FieldOffset(2)] private short port; 18 | 19 | /// 20 | public int Port 21 | { 22 | get => System.Net.IPAddress.NetworkToHostOrder(port); 23 | set => port = System.Net.IPAddress.HostToNetworkOrder((short) value); 24 | } 25 | 26 | /// 27 | public IAddressIn Address 28 | { 29 | get => address; 30 | set => address = (AddressIn) value; 31 | } 32 | 33 | /// 34 | public AddressFamily AddressFamily 35 | { 36 | get => (AddressFamily) family; 37 | 38 | set => family = (ushort) value; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Unmanaged/NativeProcess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using NetworkAdapterSelector.Hook.UnManaged.Structures; 4 | 5 | namespace NetworkAdapterSelector.Hook.UnManaged 6 | { 7 | internal static class NativeProcess 8 | { 9 | [DllImport("kernel32", SetLastError = true)] 10 | // ReSharper disable once TooManyArguments 11 | public static extern bool CreateProcessW( 12 | IntPtr applicationName, 13 | IntPtr commandLine, 14 | IntPtr processAttributes, 15 | IntPtr threadAttributes, 16 | bool inheritHandles, 17 | uint creationFlags, 18 | IntPtr environment, 19 | IntPtr currentDirectory, 20 | IntPtr startupInfo, 21 | out ProcessInformation processInformation); 22 | 23 | [DllImport("kernel32", SetLastError = true)] 24 | // ReSharper disable once TooManyArguments 25 | public static extern bool CreateProcessA( 26 | IntPtr applicationName, 27 | IntPtr commandLine, 28 | IntPtr processAttributes, 29 | IntPtr threadAttributes, 30 | bool inheritHandles, 31 | uint creationFlags, 32 | IntPtr environment, 33 | IntPtr currentDirectory, 34 | IntPtr startupInfo, 35 | out ProcessInformation processInformation); 36 | } 37 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Unmanaged/Structures/SocketAddressIn6.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Net.Sockets; 3 | using System.Runtime.InteropServices; 4 | using NetworkAdapterSelector.Hook.UnManaged.Interfaces; 5 | 6 | namespace NetworkAdapterSelector.Hook.UnManaged.Structures 7 | { 8 | [StructLayout(LayoutKind.Explicit, Size = 28)] 9 | internal struct SocketAddressIn6 : ISocketAddress 10 | { 11 | [FieldOffset(8)] private AddressIn6 address; 12 | 13 | [FieldOffset(0)] private ushort family; 14 | 15 | [FieldOffset(2)] private short port; 16 | 17 | [FieldOffset(4)] private uint flowInfo; 18 | 19 | [FieldOffset(24)] private uint scopeId; 20 | 21 | /// 22 | public int Port 23 | { 24 | get => IPAddress.NetworkToHostOrder(port); 25 | set => port = IPAddress.HostToNetworkOrder((short) value); 26 | } 27 | 28 | public uint FlowInfo 29 | { 30 | get => flowInfo; 31 | set => flowInfo = value; 32 | } 33 | 34 | public uint ScopeId 35 | { 36 | get => scopeId; 37 | set => scopeId = value; 38 | } 39 | 40 | /// 41 | public AddressFamily AddressFamily 42 | { 43 | get => (AddressFamily) family; 44 | 45 | set => family = (ushort) value; 46 | } 47 | 48 | /// 49 | public IAddressIn Address 50 | { 51 | get => address; 52 | set => address = (AddressIn6) value; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.ShellExtension/NetworkAdapterSelector.ShellExtension.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net462 6 | Soroush Falahati (falahati.net) 7 | A simple solution that lets the user to force bind a program to a specific network adapter 8 | Soroush Falahati 9 | Copyright Soroush Falahati 2018 10 | AnyCPU 11 | Network Adapter Selector 12 | AnyCPU 13 | Network Adapter Selector's Shel Extension 14 | true 15 | NetworkAdapterSelector.ShellExtension.snk 16 | 1.2.0.0 17 | 18 | 19 | false 20 | 21 | 22 | ..\Debug 23 | DEBUG;TRACE 24 | 25 | 26 | ..\Release 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/WindowTitle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using NetworkAdapterSelector.Hook.UnManaged; 4 | 5 | namespace NetworkAdapterSelector.Hook 6 | { 7 | internal static class WindowTitle 8 | { 9 | public const string Separator = " <---> "; 10 | 11 | public static string AppendWindowTitle(string title, string text) 12 | { 13 | if (title.Contains(Separator)) 14 | { 15 | title = title.Substring(0, title.IndexOf(Separator, StringComparison.CurrentCulture)); 16 | } 17 | 18 | return string.IsNullOrEmpty(text) || string.IsNullOrEmpty(title) 19 | ? title 20 | : title + Separator + text; 21 | } 22 | 23 | public static bool AppendWindowTitle(IntPtr windowHandler, string text) 24 | { 25 | var title = GetWindowTitle(windowHandler); 26 | 27 | return !string.IsNullOrEmpty(text) && 28 | !string.IsNullOrEmpty(title) && 29 | NativeWindow.SetWindowText(windowHandler, AppendWindowTitle(title, text)); 30 | } 31 | 32 | public static bool CleanWindowsTitle(IntPtr windowHandler) 33 | { 34 | var title = GetWindowTitle(windowHandler); 35 | 36 | return !string.IsNullOrEmpty(title) && NativeWindow.SetWindowText(windowHandler, title); 37 | } 38 | 39 | public static string GetWindowTitle(IntPtr windowHandler) 40 | { 41 | if (windowHandler != IntPtr.Zero && NativeWindow.IsWindow(windowHandler)) 42 | { 43 | var length = NativeWindow.GetWindowTextLength(windowHandler); 44 | var sb = new StringBuilder(length + 1); 45 | NativeWindow.GetWindowText(windowHandler, sb, sb.Capacity); 46 | var title = sb.ToString(); 47 | 48 | if (title.Contains(Separator)) 49 | { 50 | title = title.Substring(0, title.IndexOf(Separator, StringComparison.CurrentCulture)); 51 | } 52 | 53 | return title; 54 | } 55 | 56 | return null; 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Delegates.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Sockets; 3 | using System.Runtime.InteropServices; 4 | using NetworkAdapterSelector.Hook.UnManaged.Structures; 5 | 6 | namespace NetworkAdapterSelector.Hook 7 | { 8 | internal static class Delegates 9 | { 10 | [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)] 11 | public delegate SocketError BindDelegate(IntPtr socket, IntPtr address, int addressSize); 12 | 13 | [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)] 14 | public delegate SocketError ConnectDelegate(IntPtr socket, IntPtr address, int addressSize); 15 | 16 | [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)] 17 | public delegate bool CreateProcessDelegate( 18 | IntPtr applicationName, 19 | IntPtr commandLine, 20 | IntPtr processAttributes, 21 | IntPtr threadAttributes, 22 | bool inheritHandles, 23 | uint creationFlags, 24 | IntPtr environment, 25 | IntPtr currentDirectory, 26 | IntPtr startupInfo, 27 | out ProcessInformation processInformation); 28 | 29 | [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)] 30 | public delegate bool SetWindowTextDelegate(IntPtr windowHandle, IntPtr textPointer); 31 | 32 | [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)] 33 | public delegate SocketError CloseDelegate(IntPtr socket); 34 | 35 | [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)] 36 | public delegate IntPtr OpenDelegate(AddressFamily addressFamily, SocketType type, ProtocolType protocol); 37 | 38 | [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)] 39 | public delegate IntPtr WSAOpenDelegate( 40 | AddressFamily addressFamily, 41 | SocketType type, 42 | ProtocolType protocol, 43 | IntPtr protocolInfo, 44 | int groupId, 45 | short flags); 46 | 47 | [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)] 48 | public delegate SocketError WSAConnectDelegate( 49 | IntPtr socket, IntPtr address, int addressSize, IntPtr inBuffer, IntPtr outBuffer, IntPtr sQos, 50 | IntPtr gQos); 51 | } 52 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/NetworkAdapterSelector.Hook.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net472 6 | Soroush Falahati (falahati.net) 7 | A simple solution that lets the user to force bind a program to a specific network adapter 8 | Soroush Falahati 9 | Copyright Soroush Falahati 2018 10 | AnyCPU 11 | Network Adapter Selector 12 | AnyCPU 13 | Network Adapter Selector 14 | false 15 | true 16 | NetworkAdapterSelector.Hook.snk 17 | app.manifest 18 | Icon.ico 19 | 1.2.0.0 20 | 1.2.0.0 21 | 22 | 23 | ..\Debug 24 | DEBUG;TRACE 25 | 26 | 27 | ..\Release 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | PreserveNewest 36 | 37 | 38 | PreserveNewest 39 | 40 | 41 | PreserveNewest 42 | 43 | 44 | PreserveNewest 45 | 46 | 47 | PreserveNewest 48 | 49 | 50 | PreserveNewest 51 | 52 | 53 | -------------------------------------------------------------------------------- /NetworkAdapterSelector.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2003 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkAdapterSelector.Hook", "NetworkAdapterSelector.Hook\NetworkAdapterSelector.Hook.csproj", "{DA87AB72-4183-4D28-ABD9-97B898AF780A}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {8C8BFF1F-D54F-474B-8652-17A44046998A} = {8C8BFF1F-D54F-474B-8652-17A44046998A} 9 | EndProjectSection 10 | EndProject 11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkAdapterSelector.ShellExtension", "NetworkAdapterSelector.ShellExtension\NetworkAdapterSelector.ShellExtension.csproj", "{FBC0EA17-BB03-426B-864B-A0289CB00609}" 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkAdapterSelector.TestApp", "NetworkAdapterSelector.TestApp\NetworkAdapterSelector.TestApp.csproj", "{8C8BFF1F-D54F-474B-8652-17A44046998A}" 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {DA87AB72-4183-4D28-ABD9-97B898AF780A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {DA87AB72-4183-4D28-ABD9-97B898AF780A}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {DA87AB72-4183-4D28-ABD9-97B898AF780A}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {DA87AB72-4183-4D28-ABD9-97B898AF780A}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {FBC0EA17-BB03-426B-864B-A0289CB00609}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {FBC0EA17-BB03-426B-864B-A0289CB00609}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {FBC0EA17-BB03-426B-864B-A0289CB00609}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {FBC0EA17-BB03-426B-864B-A0289CB00609}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {8C8BFF1F-D54F-474B-8652-17A44046998A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {8C8BFF1F-D54F-474B-8652-17A44046998A}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {8C8BFF1F-D54F-474B-8652-17A44046998A}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {8C8BFF1F-D54F-474B-8652-17A44046998A}.Release|Any CPU.Build.0 = Release|Any CPU 33 | EndGlobalSection 34 | GlobalSection(SolutionProperties) = preSolution 35 | HideSolutionNode = FALSE 36 | EndGlobalSection 37 | GlobalSection(ExtensibilityGlobals) = postSolution 38 | SolutionGuid = {86EAD9D9-67C9-492C-A4F8-F89C19B39CBD} 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /NetworkAdapterSelector.TestApp/Form1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Net; 5 | using System.Net.Sockets; 6 | using System.Threading; 7 | using System.Windows.Forms; 8 | 9 | namespace NetworkAdapterSelector.TestApp 10 | { 11 | public partial class Form1 : Form 12 | { 13 | private int _i = 1; 14 | private Socket _socket; 15 | 16 | public Form1() 17 | { 18 | InitializeComponent(); 19 | } 20 | 21 | private void button1_Click(object sender, EventArgs e) 22 | { 23 | _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 24 | _socket.Connect("google.com", 80); 25 | MessageBox.Show("Connected"); 26 | } 27 | 28 | private void button2_Click(object sender, EventArgs e) 29 | { 30 | _socket.Shutdown(SocketShutdown.Both); 31 | _socket.Disconnect(false); 32 | MessageBox.Show("Disconnected"); 33 | } 34 | 35 | private void button3_Click(object sender, EventArgs e) 36 | { 37 | var client = new WebClient {Proxy = null}; 38 | var str = client.DownloadString("https://api.myip.com"); 39 | client.Dispose(); 40 | MessageBox.Show($"Downloaded: {str}"); 41 | } 42 | 43 | private void button4_Click(object sender, EventArgs e) 44 | { 45 | var client = new WebClient(); 46 | var str = client.DownloadString("https://api.myip.com"); 47 | client.Dispose(); 48 | MessageBox.Show($"Downloaded: {str}"); 49 | } 50 | 51 | private void button5_Click(object sender, EventArgs e) 52 | { 53 | Text = (_i++).ToString(); 54 | } 55 | 56 | private void button6_Click(object sender, EventArgs e) 57 | { 58 | new Thread(() => 59 | { 60 | try 61 | { 62 | Thread.Sleep(500); 63 | var client = new WebClient {Proxy = null}; 64 | var str = client.DownloadString("https://api.myip.com"); 65 | client.Dispose(); 66 | MessageBox.Show($"Downloaded: {str}"); 67 | } 68 | catch (Exception ex) 69 | { 70 | MessageBox.Show(ex.ToString()); 71 | } 72 | }).Start(); 73 | } 74 | 75 | private void button7_Click(object sender, EventArgs e) 76 | { 77 | Process.Start(Process.GetCurrentProcess().MainModule.FileName, ""); 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Unmanaged/NativeSocket.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Sockets; 3 | using System.Runtime.InteropServices; 4 | using NetworkAdapterSelector.Hook.UnManaged.Structures; 5 | 6 | namespace NetworkAdapterSelector.Hook.UnManaged 7 | { 8 | internal static class NativeSocket 9 | { 10 | [DllImport("ws2_32", SetLastError = true, EntryPoint = "bind")] 11 | public static extern SocketError Bind(IntPtr socket, ref SocketAddressIn address, int addressSize); 12 | 13 | [DllImport("ws2_32", SetLastError = true, EntryPoint = "bind")] 14 | public static extern SocketError Bind(IntPtr socket, IntPtr address, int addressSize); 15 | 16 | [DllImport("ws2_32", SetLastError = true, EntryPoint = "bind")] 17 | public static extern SocketError Bind(IntPtr socket, ref SocketAddressIn6 address, int addressSize); 18 | 19 | [DllImport("ws2_32", SetLastError = true, EntryPoint = "closesocket")] 20 | public static extern SocketError CloseSocket(IntPtr socket); 21 | 22 | [DllImport("ws2_32", SetLastError = true, EntryPoint = "connect")] 23 | public static extern SocketError Connect(IntPtr socket, IntPtr address, int addressSize); 24 | 25 | [DllImport("ws2_32", SetLastError = true, EntryPoint = "socket")] 26 | public static extern IntPtr OpenSocket(AddressFamily addressFamily, SocketType type, ProtocolType protocol); 27 | 28 | [DllImport("ws2_32", SetLastError = true, EntryPoint = "WSAConnect")] 29 | // ReSharper disable once TooManyArguments 30 | public static extern SocketError WSAConnect( 31 | IntPtr socket, 32 | IntPtr address, 33 | int addressSize, 34 | IntPtr inBuffer, 35 | IntPtr outBuffer, 36 | IntPtr sQos, 37 | IntPtr gQos 38 | ); 39 | 40 | [DllImport("ws2_32", SetLastError = false, EntryPoint = "WSAGetLastError")] 41 | public static extern SocketError WSAGetLastError(); 42 | 43 | [DllImport("ws2_32", SetLastError = false, EntryPoint = "WSASetLastError")] 44 | public static extern void WSASetLastError(SocketError error); 45 | 46 | [DllImport("ws2_32", SetLastError = true, EntryPoint = "WSASocketA")] 47 | // ReSharper disable once TooManyArguments 48 | public static extern IntPtr WSAOpenSocketA( 49 | AddressFamily addressFamily, 50 | SocketType type, 51 | ProtocolType protocol, 52 | IntPtr protocolInfo, 53 | int groupId, 54 | short flags 55 | ); 56 | 57 | [DllImport("ws2_32", SetLastError = true, EntryPoint = "WSASocketW")] 58 | // ReSharper disable once TooManyArguments 59 | public static extern IntPtr WSAOpenSocketW( 60 | AddressFamily addressFamily, 61 | SocketType type, 62 | ProtocolType protocol, 63 | IntPtr protocolInfo, 64 | int groupId, 65 | short flags 66 | ); 67 | } 68 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 52 | 59 | 60 | 61 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/CommandLineOptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using CommandLine; 4 | 5 | namespace NetworkAdapterSelector.Hook 6 | { 7 | internal class CommandLineOptions 8 | { 9 | private static CommandLineOptions _defaultObject; 10 | 11 | [Option( 12 | 'c', 13 | "args", 14 | Required = false, 15 | HelpText = "Arguments to be send to the executable while starting." 16 | )] 17 | public string Arguments { get; set; } 18 | 19 | [Option( 20 | 'a', 21 | "attach", 22 | Required = false, 23 | HelpText = "PID of the process to attach." 24 | )] 25 | public int Attach { get; set; } 26 | 27 | [Option( 28 | 'd', 29 | "debug", 30 | Required = false, 31 | HelpText = 32 | "Debug mode creates a log file in temp directory logging all the activities of the injected code." 33 | )] 34 | public bool Debug { get; set; } 35 | 36 | public static CommandLineOptions Default 37 | { 38 | get 39 | { 40 | if (_defaultObject == null) 41 | { 42 | var args = Environment.GetCommandLineArgs().Skip(1).ToArray(); 43 | 44 | for (var i = 0; i < args.Length; i++) 45 | { 46 | if ((args[i].ToLower().Trim() == "-c" || args[i].ToLower().Trim() == "--args") && 47 | i < args.Length - 1) 48 | { 49 | args[i + 1] = '"' + args[i + 1] + '"'; 50 | } 51 | } 52 | 53 | Parser.Default.ParseArguments(args) 54 | .WithParsed(options => 55 | { 56 | _defaultObject = options; 57 | }).WithNotParsed(errors => 58 | { 59 | Environment.Exit(1); 60 | }); 61 | } 62 | 63 | return _defaultObject; 64 | } 65 | } 66 | 67 | [Option( 68 | 't', 69 | "delay", 70 | Required = false, 71 | HelpText = "Delay in milliseconds before trying to inject the code.", 72 | Default = 0 73 | )] 74 | public int Delay { get; set; } 75 | 76 | [Option( 77 | 'e', 78 | "execute", 79 | Required = false, 80 | HelpText = "Address of the executable find to start." 81 | )] 82 | public string Execute { get; set; } 83 | 84 | [Option( 85 | 'w', 86 | "title", 87 | Required = false, 88 | Default = true, 89 | HelpText = 90 | "Should the title of the process main's window be updated to contain the binded adapter information" 91 | )] 92 | 93 | public bool ChangeWindowTitle { get; set; } = true; 94 | 95 | [Option( 96 | 'n', 97 | "network", 98 | Required = true, 99 | HelpText = "Identification string of the network adapter to bind." 100 | )] 101 | public string NetworkId { get; set; } 102 | } 103 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.ShellExtension/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace NetworkAdapterSelector.ShellExtension.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NetworkAdapterSelector.ShellExtension.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to Network Adapter Selector. 65 | /// 66 | internal static string DynamicMenuExtension_BindTo_Network_Adapter_Selector { 67 | get { 68 | return ResourceManager.GetString("DynamicMenuExtension_BindTo_Network_Adapter_Selector", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to Bind to.... 74 | /// 75 | internal static string DynamicMenuExtension_CreateMenu_Bind_to { 76 | get { 77 | return ResourceManager.GetString("DynamicMenuExtension_CreateMenu_Bind_to", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to [RunAs] {0}. 83 | /// 84 | internal static string DynamicMenuExtension_CreateMenu_Run_as { 85 | get { 86 | return ResourceManager.GetString("DynamicMenuExtension_CreateMenu_Run_as", resourceCulture); 87 | } 88 | } 89 | 90 | /// 91 | /// Looks up a localized resource of type System.Drawing.Bitmap. 92 | /// 93 | internal static System.Drawing.Bitmap x16 { 94 | get { 95 | object obj = ResourceManager.GetObject("x16", resourceCulture); 96 | return ((System.Drawing.Bitmap)(obj)); 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | 24 | # Visual Studio 2015 cache/options directory 25 | .vs/ 26 | # Uncomment if you have tasks that create the project's static files in wwwroot 27 | #wwwroot/ 28 | 29 | # MSTest test Results 30 | [Tt]est[Rr]esult*/ 31 | [Bb]uild[Ll]og.* 32 | 33 | # NUNIT 34 | *.VisualState.xml 35 | TestResult.xml 36 | 37 | # Build Results of an ATL Project 38 | [Dd]ebugPS/ 39 | [Rr]eleasePS/ 40 | dlldata.c 41 | 42 | # DNX 43 | project.lock.json 44 | artifacts/ 45 | 46 | *_i.c 47 | *_p.c 48 | *_i.h 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.tmp_proj 63 | *.log 64 | *.vspscc 65 | *.vssscc 66 | .builds 67 | *.pidb 68 | *.svclog 69 | *.scc 70 | 71 | # Chutzpah Test files 72 | _Chutzpah* 73 | 74 | # Visual C++ cache files 75 | ipch/ 76 | *.aps 77 | *.ncb 78 | *.opendb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | *.sap 88 | 89 | # TFS 2012 Local Workspace 90 | $tf/ 91 | 92 | # Guidance Automation Toolkit 93 | *.gpState 94 | 95 | # ReSharper is a .NET coding add-in 96 | _ReSharper*/ 97 | *.[Rr]e[Ss]harper 98 | *.DotSettings.user 99 | 100 | # JustCode is a .NET coding add-in 101 | .JustCode 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | _NCrunch_* 111 | .*crunch*.local.xml 112 | nCrunchTemp_* 113 | 114 | # MightyMoose 115 | *.mm.* 116 | AutoTest.Net/ 117 | 118 | # Web workbench (sass) 119 | .sass-cache/ 120 | 121 | # Installshield output folder 122 | [Ee]xpress/ 123 | 124 | # DocProject is a documentation generator add-in 125 | DocProject/buildhelp/ 126 | DocProject/Help/*.HxT 127 | DocProject/Help/*.HxC 128 | DocProject/Help/*.hhc 129 | DocProject/Help/*.hhk 130 | DocProject/Help/*.hhp 131 | DocProject/Help/Html2 132 | DocProject/Help/html 133 | 134 | # Click-Once directory 135 | publish/ 136 | 137 | # Publish Web Output 138 | *.[Pp]ublish.xml 139 | *.azurePubxml 140 | # TODO: Comment the next line if you want to checkin your web deploy settings 141 | # but database connection strings (with potential passwords) will be unencrypted 142 | *.pubxml 143 | *.publishproj 144 | 145 | # NuGet Packages 146 | *.nupkg 147 | # The packages folder can be ignored because of Package Restore 148 | **/packages/* 149 | # except build/, which is used as an MSBuild target. 150 | !**/packages/build/ 151 | # Uncomment if necessary however generally it will be regenerated when needed 152 | #!**/packages/repositories.config 153 | # NuGet v3's project.json files produces more ignoreable files 154 | *.nuget.props 155 | *.nuget.targets 156 | 157 | # Microsoft Azure Build Output 158 | csx/ 159 | *.build.csdef 160 | 161 | # Microsoft Azure Emulator 162 | ecf/ 163 | rcf/ 164 | 165 | # Microsoft Azure ApplicationInsights config file 166 | ApplicationInsights.config 167 | 168 | # Windows Store app package directory 169 | AppPackages/ 170 | BundleArtifacts/ 171 | 172 | # Visual Studio cache files 173 | # files ending in .cache can be ignored 174 | *.[Cc]ache 175 | # but keep track of directories ending in .cache 176 | !*.[Cc]ache/ 177 | 178 | # Others 179 | ClientBin/ 180 | ~$* 181 | *~ 182 | *.dbmdl 183 | *.dbproj.schemaview 184 | *.pfx 185 | *.publishsettings 186 | node_modules/ 187 | orleans.codegen.cs 188 | 189 | # RIA/Silverlight projects 190 | Generated_Code/ 191 | 192 | # Backup & report files from converting an old project file 193 | # to a newer Visual Studio version. Backup files are not needed, 194 | # because we have git ;-) 195 | _UpgradeReport_Files/ 196 | Backup*/ 197 | UpgradeLog*.XML 198 | UpgradeLog*.htm 199 | 200 | # SQL Server files 201 | *.mdf 202 | *.ldf 203 | 204 | # Business Intelligence projects 205 | *.rdl.data 206 | *.bim.layout 207 | *.bim_*.settings 208 | 209 | # Microsoft Fakes 210 | FakesAssemblies/ 211 | 212 | # GhostDoc plugin setting file 213 | *.GhostDoc.xml 214 | 215 | # Node.js Tools for Visual Studio 216 | .ntvs_analysis.dat 217 | 218 | # Visual Studio 6 build log 219 | *.plg 220 | 221 | # Visual Studio 6 workspace options file 222 | *.opt 223 | 224 | # Visual Studio LightSwitch build output 225 | **/*.HTMLClient/GeneratedArtifacts 226 | **/*.DesktopClient/GeneratedArtifacts 227 | **/*.DesktopClient/ModelManifest.xml 228 | **/*.Server/GeneratedArtifacts 229 | **/*.Server/ModelManifest.xml 230 | _Pvt_Extensions 231 | 232 | # Paket dependency manager 233 | .paket/paket.exe 234 | 235 | # FAKE - F# Make 236 | .fake/ 237 | /NetworkAdapterSelector.Setup/NetworkAdapterSelector.Setup Data/* 238 | /NetworkAdapterSelector.Setup/NetworkAdapterSelector.Setup/* 239 | /NetworkAdapterSelector.Hook/*.exe 240 | /NetworkAdapterSelector.Hook/*.dll 241 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Network Adapter Selector 2 | [![](https://img.shields.io/github/license/falahati/NetworkAdapterSelector.svg?style=flat-square)](https://github.com/falahati/NetworkAdapterSelector/blob/master/LICENSE) 3 | [![](https://img.shields.io/github/commit-activity/y/falahati/NetworkAdapterSelector.svg?style=flat-square)](https://github.com/falahati/NetworkAdapterSelector/commits/master) 4 | [![](https://img.shields.io/github/issues/falahati/NetworkAdapterSelector.svg?style=flat-square)](https://github.com/falahati/NetworkAdapterSelector/issues) 5 | 6 | **THERE IS A PROBLEM WITH UNINSTALLER NOT WORKING, PLEASE DONT DOWNLOAD THIS TOOL IF YOU ARE NOT READY TO INSTALL THIRD PARTY APPLICATION TO REMOVE IT LATER** 7 | 8 | A solution containing an Injector to hook WinSock methods and bind the new connections to the specific network adapter along with a Shell Extension to simplifies the process of injecting the code into other programs. 9 | ![Screenshot](/screenshot.jpg?raw=true "Screenshot") 10 | 11 | ## How to get 12 | [![](https://img.shields.io/github/downloads/falahati/NetworkAdapterSelector/total.svg?style=flat-square)](https://github.com/falahati/NetworkAdapterSelector/releases) 13 | [![](https://img.shields.io/github/tag-date/falahati/NetworkAdapterSelector.svg?label=version&style=flat-square)](https://github.com/falahati/NetworkAdapterSelector/releases) 14 | 15 | Download the latest version of the program from the [releases](https://github.com/falahati/NetworkAdapterSelector/releases/latest) page. 16 | 17 | ## Help me fund my own Death Star 18 | 19 | [![](https://img.shields.io/badge/crypto-CoinPayments-8a00a3.svg?style=flat-square)](https://www.coinpayments.net/index.php?cmd=_donate&reset=1&merchant=820707aded07845511b841f9c4c335cd&item_name=Donate¤cy=USD&amountf=20.00000000&allow_amount=1&want_shipping=0&allow_extra=1) 20 | [![](https://img.shields.io/badge/shetab-ZarinPal-8a00a3.svg?style=flat-square)](https://zarinp.al/@falahati) 21 | [![](https://img.shields.io/badge/usd-Paypal-8a00a3.svg?style=flat-square)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=ramin.graphix@gmail.com&lc=US&item_name=Donate&no_note=0&cn=&curency_code=USD&bn=PP-DonationsBF:btn_donateCC_LG.gif:NonHosted) 22 | 23 | **--OR--** 24 | 25 | You can always donate your time by contributing to the project or by introducing it to others. 26 | 27 | ## Command line parameters 28 | If you are not interested in using the provided shell extension, you can always use the following command line parameters directly to manipulate running applications or start a new process. 29 | 30 | - `-d` `--debug`: Debug mode creates a log file in temp directory logging all activities of the injected code. [true, false] 31 | - `-n` `--network`: Identification string of the network adapter to bind. 32 | - `-a` `--attach`: Process identification number of the process to attach. **OR** 33 | - `-e` `--execute`: Address of the executable file to start. 34 | - `-c` `--args`: Arguments to be sent to the executable file. 35 | - `-t` `--delay`: Delay in milliseconds before trying to inject the code. 36 | 37 | #### Network Identification String 38 | Network identification string is the network GUID in `{00000000-0000-0000-0000-000000000000}` format, all uppercase. To get those you can run the following commands in the CMD to start the "Wired AutoConfig" and "WLAN AutoConfig" services and list network adapters: 39 | ```Shell 40 | net start "Wired AutoConfig" 41 | net start "WLAN AutoConfig" 42 | netsh lan show interfaces 43 | netsh wlan show interfaces 44 | ``` 45 | 46 | Or use the following code in a PowerShell window that uses .Net libraries to produce a similar result: 47 | ```Shell 48 | [System.Net.NetworkInformation.NetworkInterface]::GetAllNetworkInterfaces() 49 | ``` 50 | 51 | Also, you can use the registry and read them from the following path directly: 52 | ``` 53 | HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\NetworkCards 54 | ``` 55 | 56 | #### Examples 57 | Attaching to an already running process: (PID `1234`) 58 | ```Shell 59 | NetworkAdapterSelector.Hook.exe --network "{ABCDEFGH-0000-0000-0000-000000000000}" --attach 1234 60 | ``` 61 | 62 | Starting a new instance of `notepad.exe` and attaching to it after one second: 63 | ```Shell 64 | NetworkAdapterSelector.Hook.exe --network "{ABCDEFGH-0000-0000-0000-000000000000}" --execute "C:\Windows\System32\notepad.exe" --delay 1000 65 | ``` 66 | 67 | ## Technology 68 | Both parts of the solution are in pure C# using EasyHook library and SharpShell framework. It was a little experiment to see how stable is EasyHook and how SharpShell can perform in terms of performance. 69 | 70 | ## License 71 | Copyright (C) 2017-2020 Soroush Falahati 72 | 73 | This program is free software; you can redistribute it and/or modify 74 | it under the terms of the GNU General Public License as published by 75 | the Free Software Foundation; either version 2 of the License, or 76 | (at your option) any later version. 77 | 78 | This program is distributed in the hope that it will be useful, 79 | but WITHOUT ANY WARRANTY; without even the implied warranty of 80 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 81 | GNU General Public License for more details. 82 | 83 | You should have received a copy of the GNU General Public License along 84 | with this program; if not, write to the Free Software Foundation, Inc., 85 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 86 | -------------------------------------------------------------------------------- /NetworkAdapterSelector.ShellExtension/DynamicMenuExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Net.NetworkInformation; 7 | using System.Runtime.InteropServices; 8 | using System.Windows.Forms; 9 | using Microsoft.Win32; 10 | using NetworkAdapterSelector.ShellExtension.Properties; 11 | using SharpShell.Attributes; 12 | using SharpShell.SharpContextMenu; 13 | 14 | namespace NetworkAdapterSelector.ShellExtension 15 | { 16 | [ComVisible(true)] 17 | [COMServerAssociation(AssociationType.ClassOfExtension, @".exe")] 18 | internal class DynamicMenuExtension : SharpContextMenu 19 | { 20 | protected override bool CanShowMenu() 21 | { 22 | // Only show the menu when application is installed, there is just one executable 23 | // file selected and some network interface to select from 24 | return SelectedItemPaths.Count() == 1 && 25 | Path.GetExtension(SelectedItemPaths.First())?.ToLower() == ".exe" && 26 | !string.IsNullOrWhiteSpace(GetNetworkAdapterSelectorAddress()) && 27 | NetworkInterface.GetAllNetworkInterfaces() 28 | .Any(networkInterface => 29 | networkInterface.SupportsMulticast && 30 | networkInterface.OperationalStatus == OperationalStatus.Up); 31 | } 32 | 33 | // ReSharper disable once TooManyDeclarations 34 | protected override ContextMenuStrip CreateMenu() 35 | { 36 | var explorerMenu = new ContextMenuStrip(); 37 | var extensionMenu = new ToolStripMenuItem(Resources.DynamicMenuExtension_CreateMenu_Bind_to, Resources.x16); 38 | var i = 0; 39 | 40 | // Going through all network interfaces and add them to the list 41 | foreach (var networkInterface in 42 | NetworkInterface.GetAllNetworkInterfaces() 43 | .Where(networkInterface => 44 | networkInterface.SupportsMulticast && 45 | networkInterface.OperationalStatus == OperationalStatus.Up) 46 | ) 47 | { 48 | // Copying the network id to a variable 49 | var networkId = networkInterface.Id; 50 | 51 | // Add normal execution item 52 | extensionMenu.DropDownItems.Insert(i, 53 | new ToolStripMenuItem( 54 | networkInterface.Name, 55 | null, 56 | (sender, args) => BindTo(networkId, false) 57 | ) 58 | ); 59 | 60 | // Add separator, only once 61 | if (i == 0) 62 | { 63 | extensionMenu.DropDownItems.Add(new ToolStripSeparator()); 64 | } 65 | 66 | i++; 67 | 68 | // Add run as administrator execution item 69 | extensionMenu.DropDownItems.Add( 70 | new ToolStripMenuItem( 71 | string.Format(Resources.DynamicMenuExtension_CreateMenu_Run_as, networkInterface.Name), 72 | null, 73 | (sender, args) => BindTo(networkId, true) 74 | ) 75 | ); 76 | } 77 | 78 | explorerMenu.Items.Add(extensionMenu); 79 | 80 | return explorerMenu; 81 | } 82 | 83 | // ReSharper disable once FlagArgument 84 | private void BindTo(string networkInterfaceId, bool asAdmin) 85 | { 86 | try 87 | { 88 | var executableAddress = GetNetworkAdapterSelectorAddress(); 89 | 90 | if (string.IsNullOrWhiteSpace(executableAddress)) 91 | { 92 | return; 93 | } 94 | 95 | var arguments = $"-n \"{networkInterfaceId}\" -e \"{SelectedItemPaths.First()}\""; 96 | 97 | #if DEBUG 98 | arguments += " -d"; 99 | #endif 100 | 101 | // Executing the "NetworkAdapterSelector.Hook" and passing the address of executable file. 102 | var processInfo = new ProcessStartInfo(executableAddress, arguments) 103 | { 104 | WindowStyle = ProcessWindowStyle.Hidden, 105 | CreateNoWindow = true, 106 | UseShellExecute = true 107 | }; 108 | 109 | #if DEBUG 110 | processInfo.WindowStyle = ProcessWindowStyle.Normal; 111 | processInfo.CreateNoWindow = false; 112 | #endif 113 | 114 | if (asAdmin) 115 | { 116 | // Forcing administrator privileges 117 | processInfo.Verb = @"runas"; 118 | } 119 | 120 | Process.Start(processInfo); 121 | } 122 | catch (Exception e) 123 | { 124 | // Check if operation canceled by user 125 | if ((e as Win32Exception)?.NativeErrorCode == 1223) 126 | { 127 | return; 128 | } 129 | 130 | // Otherwise, show an error message to the user 131 | MessageBox.Show( 132 | e.ToString(), 133 | Resources.DynamicMenuExtension_BindTo_Network_Adapter_Selector, 134 | MessageBoxButtons.OK, 135 | MessageBoxIcon.Error 136 | ); 137 | } 138 | } 139 | 140 | private string GetNetworkAdapterSelectorAddress() 141 | { 142 | try 143 | { 144 | // Trying to get the address of the "NetworkAdapterSelector.Hook" project. If installed. 145 | using (var key = Registry.LocalMachine.OpenSubKey( 146 | @"SOFTWARE\Network Adapter Selector", 147 | false 148 | ) 149 | ) 150 | { 151 | var executableAddress = key?.GetValue("ExecutableAddress", null) as string; 152 | 153 | if (!string.IsNullOrWhiteSpace(executableAddress) && 154 | File.Exists(executableAddress)) 155 | { 156 | return executableAddress; 157 | } 158 | } 159 | } 160 | catch 161 | { 162 | // ignored 163 | } 164 | 165 | return null; 166 | } 167 | } 168 | } -------------------------------------------------------------------------------- /NetworkAdapterSelector.TestApp/Form1.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace NetworkAdapterSelector.TestApp 2 | { 3 | partial class Form1 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.button1 = new System.Windows.Forms.Button(); 32 | this.button2 = new System.Windows.Forms.Button(); 33 | this.button3 = new System.Windows.Forms.Button(); 34 | this.button4 = new System.Windows.Forms.Button(); 35 | this.button5 = new System.Windows.Forms.Button(); 36 | this.button6 = new System.Windows.Forms.Button(); 37 | this.button7 = new System.Windows.Forms.Button(); 38 | this.SuspendLayout(); 39 | // 40 | // button1 41 | // 42 | this.button1.Anchor = System.Windows.Forms.AnchorStyles.None; 43 | this.button1.Location = new System.Drawing.Point(30, 25); 44 | this.button1.Name = "button1"; 45 | this.button1.Size = new System.Drawing.Size(96, 23); 46 | this.button1.TabIndex = 0; 47 | this.button1.Text = "Connect"; 48 | this.button1.UseVisualStyleBackColor = true; 49 | this.button1.Click += new System.EventHandler(this.button1_Click); 50 | // 51 | // button2 52 | // 53 | this.button2.Anchor = System.Windows.Forms.AnchorStyles.None; 54 | this.button2.Location = new System.Drawing.Point(30, 54); 55 | this.button2.Name = "button2"; 56 | this.button2.Size = new System.Drawing.Size(96, 23); 57 | this.button2.TabIndex = 1; 58 | this.button2.Text = "Disconnect"; 59 | this.button2.UseVisualStyleBackColor = true; 60 | this.button2.Click += new System.EventHandler(this.button2_Click); 61 | // 62 | // button3 63 | // 64 | this.button3.Anchor = System.Windows.Forms.AnchorStyles.None; 65 | this.button3.Location = new System.Drawing.Point(132, 25); 66 | this.button3.Name = "button3"; 67 | this.button3.Size = new System.Drawing.Size(128, 23); 68 | this.button3.TabIndex = 2; 69 | this.button3.Text = "Download W/O Proxy"; 70 | this.button3.UseVisualStyleBackColor = true; 71 | this.button3.Click += new System.EventHandler(this.button3_Click); 72 | // 73 | // button4 74 | // 75 | this.button4.Anchor = System.Windows.Forms.AnchorStyles.None; 76 | this.button4.Location = new System.Drawing.Point(132, 54); 77 | this.button4.Name = "button4"; 78 | this.button4.Size = new System.Drawing.Size(128, 23); 79 | this.button4.TabIndex = 3; 80 | this.button4.Text = "Download with Proxy"; 81 | this.button4.UseVisualStyleBackColor = true; 82 | this.button4.Click += new System.EventHandler(this.button4_Click); 83 | // 84 | // button5 85 | // 86 | this.button5.Anchor = System.Windows.Forms.AnchorStyles.None; 87 | this.button5.Location = new System.Drawing.Point(266, 25); 88 | this.button5.Name = "button5"; 89 | this.button5.Size = new System.Drawing.Size(96, 23); 90 | this.button5.TabIndex = 4; 91 | this.button5.Text = " Window Text"; 92 | this.button5.UseVisualStyleBackColor = true; 93 | this.button5.Click += new System.EventHandler(this.button5_Click); 94 | // 95 | // button6 96 | // 97 | this.button6.Anchor = System.Windows.Forms.AnchorStyles.None; 98 | this.button6.Location = new System.Drawing.Point(132, 83); 99 | this.button6.Name = "button6"; 100 | this.button6.Size = new System.Drawing.Size(128, 23); 101 | this.button6.TabIndex = 5; 102 | this.button6.Text = "Download Async"; 103 | this.button6.UseVisualStyleBackColor = true; 104 | this.button6.Click += new System.EventHandler(this.button6_Click); 105 | // 106 | // button7 107 | // 108 | this.button7.Anchor = System.Windows.Forms.AnchorStyles.None; 109 | this.button7.Location = new System.Drawing.Point(266, 54); 110 | this.button7.Name = "button7"; 111 | this.button7.Size = new System.Drawing.Size(96, 23); 112 | this.button7.TabIndex = 6; 113 | this.button7.Text = "Create Child Process"; 114 | this.button7.UseVisualStyleBackColor = true; 115 | this.button7.Click += new System.EventHandler(this.button7_Click); 116 | // 117 | // Form1 118 | // 119 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 120 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 121 | this.ClientSize = new System.Drawing.Size(390, 127); 122 | this.Controls.Add(this.button7); 123 | this.Controls.Add(this.button6); 124 | this.Controls.Add(this.button5); 125 | this.Controls.Add(this.button4); 126 | this.Controls.Add(this.button3); 127 | this.Controls.Add(this.button2); 128 | this.Controls.Add(this.button1); 129 | this.Name = "Form1"; 130 | this.Text = "WinSocket Test"; 131 | this.ResumeLayout(false); 132 | 133 | } 134 | 135 | #endregion 136 | 137 | private System.Windows.Forms.Button button1; 138 | private System.Windows.Forms.Button button2; 139 | private System.Windows.Forms.Button button3; 140 | private System.Windows.Forms.Button button4; 141 | private System.Windows.Forms.Button button5; 142 | private System.Windows.Forms.Button button6; 143 | private System.Windows.Forms.Button button7; 144 | } 145 | } 146 | 147 | -------------------------------------------------------------------------------- /NetworkAdapterSelector.ShellExtension/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 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 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\x16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | 125 | Network Adapter Selector 126 | 127 | 128 | Bind to... 129 | 130 | 131 | [RunAs] {0} 132 | 133 | -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Net.NetworkInformation; 6 | using System.Reflection; 7 | using System.Threading; 8 | using EasyHook; 9 | using ThreadState = System.Diagnostics.ThreadState; 10 | 11 | namespace NetworkAdapterSelector.Hook 12 | { 13 | internal class Program 14 | { 15 | private static void CreateAndInjectProcess(string networkId, string filePath, string arguments) 16 | { 17 | var injectorAddress = Assembly.GetExecutingAssembly().Location; 18 | var tries = 0; 19 | var processId = 0; 20 | 21 | while (true) 22 | { 23 | try 24 | { 25 | Console.WriteLine("Trying to create the process as suspended."); 26 | RemoteHooking.CreateAndInject( 27 | filePath, 28 | arguments, 29 | 0, 30 | injectorAddress, 31 | injectorAddress, 32 | out processId, 33 | networkId, 34 | injectorAddress, 35 | CommandLineOptions.Default.Delay, 36 | CommandLineOptions.Default.ChangeWindowTitle, 37 | CommandLineOptions.Default.Debug); 38 | 39 | var process = Process.GetProcessById(processId); 40 | 41 | Thread.Sleep(2000); 42 | 43 | if (process.HasExited) 44 | { 45 | return; 46 | } 47 | 48 | if (IsProcessStuckByInjection(process)) 49 | { 50 | Console.WriteLine("Process stuck in suspended state."); 51 | 52 | // Create and Inject failed 53 | if (!process.HasExited) 54 | { 55 | Console.WriteLine("Killing process ..."); 56 | process.Kill(); 57 | process.WaitForExit(3000); 58 | } 59 | 60 | throw new AccessViolationException("Failed to start the application."); 61 | } 62 | 63 | return; 64 | } 65 | catch 66 | { 67 | if (tries < 3 && processId == 0) 68 | { 69 | tries++; 70 | Thread.Sleep(1000); 71 | } 72 | else 73 | { 74 | throw; 75 | } 76 | } 77 | } 78 | } 79 | 80 | 81 | // ReSharper disable once TooManyDeclarations 82 | private static bool IsProcessStuckByInjection(Process process) 83 | { 84 | var allThreads = process.Threads.Cast().ToArray(); 85 | 86 | var suspendedThreads = allThreads 87 | .Where(thread => 88 | thread.ThreadState == ThreadState.Wait && 89 | thread.WaitReason == ThreadWaitReason.Suspended 90 | ) 91 | .ToArray(); 92 | 93 | var lpcStuckThreads = allThreads 94 | .Where(thread => 95 | thread.ThreadState == ThreadState.Wait && 96 | thread.WaitReason != ThreadWaitReason.Suspended 97 | ) 98 | .ToArray(); 99 | 100 | var activeThreads = allThreads 101 | .Where(thread => 102 | thread.ThreadState != ThreadState.Wait 103 | ) 104 | .ToArray(); 105 | 106 | return activeThreads.Length == 0 && 107 | allThreads.Length - 1 >= suspendedThreads.Length && 108 | (lpcStuckThreads.Length == 0 || 109 | lpcStuckThreads.Length == 1 && 110 | lpcStuckThreads.FirstOrDefault()?.Id == allThreads.FirstOrDefault()?.Id); 111 | } 112 | 113 | private static void InjectProcess(string networkId, int processId) 114 | { 115 | var injectorAddress = Assembly.GetExecutingAssembly().Location; 116 | var tries = 0; 117 | 118 | while (true) 119 | { 120 | try 121 | { 122 | Console.WriteLine("Trying to inject process #{0}.", processId); 123 | RemoteHooking.Inject( 124 | processId, 125 | injectorAddress, 126 | injectorAddress, 127 | networkId, 128 | injectorAddress, 129 | CommandLineOptions.Default.Delay, 130 | CommandLineOptions.Default.ChangeWindowTitle, 131 | CommandLineOptions.Default.Debug 132 | ); 133 | 134 | return; 135 | } 136 | catch 137 | { 138 | if (tries < 3) 139 | { 140 | tries++; 141 | Thread.Sleep(1000); 142 | } 143 | else 144 | { 145 | throw; 146 | } 147 | } 148 | } 149 | } 150 | 151 | private static void Main() 152 | { 153 | try 154 | { 155 | // Check for network id validity 156 | var networkId = CommandLineOptions.Default.NetworkId.Trim().ToLower(); 157 | 158 | if (!NetworkInterface.GetAllNetworkInterfaces() 159 | .Any( 160 | @interface => 161 | @interface.Id.Equals(networkId, StringComparison.CurrentCultureIgnoreCase) && 162 | @interface.SupportsMulticast && 163 | @interface.OperationalStatus == OperationalStatus.Up)) 164 | { 165 | throw new ArgumentException( 166 | "Selected network id is invalid or the selected interface is not functional."); 167 | } 168 | 169 | // Inject or create and inject to the program 170 | var processId = CommandLineOptions.Default.Attach; 171 | 172 | if (processId <= 0 && string.IsNullOrWhiteSpace(CommandLineOptions.Default.Execute)) 173 | { 174 | throw new InvalidOperationException("Nothing to do."); 175 | } 176 | 177 | if (!string.IsNullOrWhiteSpace(CommandLineOptions.Default.Execute)) 178 | { 179 | if (!File.Exists(CommandLineOptions.Default.Execute)) 180 | { 181 | throw new FileNotFoundException("File not found."); 182 | } 183 | 184 | Console.WriteLine("Creating process ..."); 185 | 186 | if (CommandLineOptions.Default.Delay <= 0) 187 | { 188 | try 189 | { 190 | CreateAndInjectProcess( 191 | networkId, 192 | CommandLineOptions.Default.Execute, 193 | CommandLineOptions.Default.Arguments?.Trim('"') ?? "" 194 | ); 195 | 196 | Console.WriteLine("SUCCESS"); 197 | Environment.Exit(0); 198 | } 199 | catch (Exception e) 200 | { 201 | Console.WriteLine(e); 202 | Console.WriteLine("Failed to start process. Fallback to delayed injection."); 203 | } 204 | } 205 | 206 | // Delayed attach 207 | processId = Process.Start( 208 | CommandLineOptions.Default.Execute, 209 | CommandLineOptions.Default.Arguments?.Trim('"') ?? "" 210 | )?.Id ?? 0; 211 | } 212 | 213 | if (processId <= 0 || Process.GetProcesses().All(p => p.Id != processId)) 214 | { 215 | throw new ArgumentException("Invalid process id provided or failed to start the process."); 216 | } 217 | 218 | Thread.Sleep(Math.Max(CommandLineOptions.Default.Delay, 1000)); 219 | 220 | InjectProcess(networkId, processId); 221 | 222 | Console.WriteLine("SUCCESS"); 223 | Environment.Exit(0); 224 | } 225 | catch (Exception e) 226 | { 227 | Console.WriteLine(e); 228 | 229 | Console.WriteLine("FATAL"); 230 | Environment.Exit(1); 231 | } 232 | } 233 | } 234 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /NetworkAdapterSelector.Hook/Guest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Net.NetworkInformation; 8 | using System.Net.Sockets; 9 | using System.Runtime.InteropServices; 10 | using System.Threading; 11 | using EasyHook; 12 | using NetworkAdapterSelector.Hook.UnManaged; 13 | using NetworkAdapterSelector.Hook.UnManaged.Interfaces; 14 | using NetworkAdapterSelector.Hook.UnManaged.Structures; 15 | 16 | namespace NetworkAdapterSelector.Hook 17 | { 18 | /// 19 | /// 20 | /// A class containing the code to be injected into the application 21 | /// 22 | // ReSharper disable once ClassTooBig 23 | public sealed class Guest : IEntryPoint 24 | { 25 | // ReSharper disable once UnusedParameter.Local 26 | /// 27 | /// Initializing the Guest class 28 | /// 29 | /// Should contain information about the environment 30 | /// identification of the desired network adapter 31 | /// Address of the injection assembly to be used for child processes 32 | /// Number of milliseconds after child process creation to try to inject the code 33 | /// 34 | /// A boolean value indicating if the title of the main windows of the process should be 35 | /// modified 36 | /// 37 | /// Indicates if injected code should create a log file and print activity information 38 | // ReSharper disable once TooManyDependencies 39 | public Guest( 40 | RemoteHooking.IContext inContext, 41 | string adapterId, 42 | string injectionGuessAddress, 43 | int injectionDelay, 44 | bool changeWindowTitle, 45 | bool isInDebug) 46 | { 47 | DebugMessage( 48 | nameof(Guest), 49 | null, 50 | "Initializing ..." 51 | ); 52 | ChangeWindowTitle = changeWindowTitle; 53 | InjectionGuessAddress = injectionGuessAddress; 54 | InjectionDelay = injectionDelay; 55 | AdapterId = adapterId; 56 | 57 | if (isInDebug) 58 | { 59 | try 60 | { 61 | var process = Process.GetCurrentProcess(); 62 | LogPath = Path.Combine(Path.GetTempPath(), 63 | "NetworkAdapterSelector-" + process.ProcessName + "[" + process.Id + "].log"); 64 | } 65 | catch 66 | { 67 | // ignored 68 | } 69 | } 70 | } 71 | 72 | private IntPtr ActiveWindow { get; set; } = IntPtr.Zero; 73 | private string AdapterId { get; } 74 | public bool ChangeWindowTitle { get; } 75 | private List Hooks { get; } = new List(); 76 | private int InjectionDelay { get; } 77 | private string InjectionGuessAddress { get; } 78 | private string LogPath { get; } 79 | public Dictionary SocketLookupTable { get; } = new Dictionary(); 80 | 81 | /// 82 | /// Starts the hooking process 83 | /// 84 | /// Should contain information about the environment 85 | /// identification of the desired network adapter 86 | /// Address of the injection assembly to be used for child processes 87 | /// Number of milliseconds after child process creation to try to inject the code 88 | /// Indicates if injected code should create a log file and print activity information 89 | // ReSharper disable once TooManyArguments 90 | // ReSharper disable once MethodTooLong 91 | // ReSharper disable once MethodNameNotMeaningful 92 | public void Run( 93 | RemoteHooking.IContext inContext, 94 | string injectionAddress, 95 | string adapterId, 96 | int injectionDelay, 97 | bool isDebug) 98 | { 99 | DebugMessage( 100 | nameof(Run), 101 | null, 102 | "Starting ..." 103 | ); 104 | 105 | LoadLibrary(@"ws2_32.dll", () => 106 | { 107 | AddHook(@"ws2_32.dll", @"socket", new Delegates.OpenDelegate(OnOpenSocket)); 108 | AddHook(@"ws2_32.dll", @"WSASocketA", 109 | new Delegates.WSAOpenDelegate((family, type, protocol, info, groupId, flags) => 110 | OnWSAOpenSocket(family, type, protocol, info, groupId, flags, false) 111 | ) 112 | ); 113 | AddHook(@"ws2_32.dll", @"WSASocketW", 114 | new Delegates.WSAOpenDelegate((family, type, protocol, info, groupId, flags) => 115 | OnWSAOpenSocket(family, type, protocol, info, groupId, flags, true) 116 | ) 117 | ); 118 | AddHook(@"ws2_32.dll", @"connect", new Delegates.ConnectDelegate(OnConnect)); 119 | AddHook(@"ws2_32.dll", @"WSAConnect", new Delegates.WSAConnectDelegate(OnWSAConnect)); 120 | AddHook(@"ws2_32.dll", @"bind", new Delegates.BindDelegate(OnBind)); 121 | // ReSharper disable once StringLiteralTypo 122 | AddHook(@"ws2_32.dll", @"closesocket", new Delegates.CloseDelegate(OnCloseSocket)); 123 | }); 124 | 125 | AddHook(@"kernel32.dll", @"CreateProcessA", 126 | new Delegates.CreateProcessDelegate( 127 | ( 128 | IntPtr applicationName, 129 | IntPtr commandLine, 130 | IntPtr processAttributes, 131 | IntPtr threadAttributes, 132 | bool inheritHandles, 133 | uint creationFlags, 134 | IntPtr environment, 135 | IntPtr currentDirectory, 136 | IntPtr startupInfo, 137 | out ProcessInformation processInformation 138 | ) => OnCreateProcess( 139 | applicationName, 140 | commandLine, 141 | processAttributes, 142 | threadAttributes, 143 | inheritHandles, 144 | creationFlags, 145 | environment, 146 | currentDirectory, 147 | startupInfo, 148 | out processInformation, 149 | false 150 | ) 151 | ) 152 | ); 153 | 154 | AddHook(@"kernel32.dll", @"CreateProcessW", 155 | new Delegates.CreateProcessDelegate( 156 | ( 157 | IntPtr applicationName, 158 | IntPtr commandLine, 159 | IntPtr processAttributes, 160 | IntPtr threadAttributes, 161 | bool inheritHandles, 162 | uint creationFlags, 163 | IntPtr environment, 164 | IntPtr currentDirectory, 165 | IntPtr startupInfo, 166 | out ProcessInformation processInformation 167 | ) => OnCreateProcess( 168 | applicationName, 169 | commandLine, 170 | processAttributes, 171 | threadAttributes, 172 | inheritHandles, 173 | creationFlags, 174 | environment, 175 | currentDirectory, 176 | startupInfo, 177 | out processInformation, 178 | true 179 | ) 180 | ) 181 | ); 182 | 183 | if (ChangeWindowTitle) 184 | { 185 | // Ansi version of the SetWindowText method 186 | AddHook(@"user32.dll", @"SetWindowTextA", 187 | new Delegates.SetWindowTextDelegate( 188 | (handle, text) => OnSetWindowText(handle, text, false) 189 | ) 190 | ); 191 | 192 | // Unicode (Wide) version of the SetWindowText method 193 | AddHook(@"user32.dll", @"SetWindowTextW", 194 | new Delegates.SetWindowTextDelegate( 195 | (handle, text) => OnSetWindowText(handle, text, true) 196 | ) 197 | ); 198 | } 199 | 200 | // Return if we failed to hook any method 201 | lock (Hooks) 202 | { 203 | if (!Hooks.Any()) 204 | { 205 | DebugMessage( 206 | nameof(Run), 207 | null, 208 | "FATAL: Failed to hook any function." 209 | ); 210 | 211 | return; 212 | } 213 | } 214 | 215 | // In case we started the application using CreateAndInject method 216 | RemoteHooking.WakeUpProcess(); 217 | 218 | if (ChangeWindowTitle) 219 | { 220 | // Going into a loop to update the application's main window's title bar 221 | WindowTitleCheckLoop(); 222 | } 223 | } 224 | 225 | private void AddHook(string libName, string entryPoint, Delegate newProcedure) 226 | { 227 | try 228 | { 229 | var localHook = LocalHook.Create(LocalHook.GetProcAddress(libName, entryPoint), newProcedure, null); 230 | 231 | // Exclude current thread (EasyHook) 232 | localHook.ThreadACL.SetExclusiveACL(new[] {0}); 233 | 234 | lock (Hooks) 235 | { 236 | Hooks.Add(localHook); 237 | } 238 | 239 | DebugMessage( 240 | nameof(AddHook), 241 | null, 242 | "`{0}` @ `{1}` hooked successfully.", 243 | entryPoint, 244 | libName 245 | ); 246 | } 247 | catch (Exception e) 248 | { 249 | DebugMessage(nameof(AddHook), null, e.ToString()); 250 | DebugMessage( 251 | nameof(AddHook), 252 | null, 253 | "Failed to hook `{0}` @ `{1}`.", 254 | entryPoint, 255 | libName 256 | ); 257 | } 258 | } 259 | 260 | private SocketError BindSocketByAddress(IntPtr socket, ISocketAddress socketAddress) 261 | { 262 | if (IsSpecialAddress(socket, socketAddress)) 263 | { 264 | return SocketError.Success; 265 | } 266 | 267 | if (IsSocketMarkedAsBinded(socket)) 268 | { 269 | DebugMessage( 270 | nameof(BindSocketByAddress), 271 | socket, 272 | "Binding to interface skipped as the socket should be already binded." 273 | ); 274 | 275 | return SocketError.Success; 276 | } 277 | 278 | var networkInterface = GetNetworkInterface(); 279 | var interfaceAddress = GetInterfaceAddress(networkInterface, socketAddress.AddressFamily, false); 280 | 281 | if (networkInterface == null || interfaceAddress == null) 282 | { 283 | DebugMessage( 284 | nameof(BindSocketByAddress), 285 | socket, 286 | "Binding for the `{0}:{1}` rejected due to lack of a valid interface address.", 287 | socketAddress.Address?.IPAddress, 288 | socketAddress.Port 289 | ); 290 | 291 | return SocketError.SocketError; 292 | } 293 | 294 | if (interfaceAddress.AddressFamily == AddressFamily.InterNetwork) 295 | { 296 | var bindIn = new SocketAddressIn 297 | { 298 | Address = new AddressIn {IPAddress = interfaceAddress}, 299 | AddressFamily = interfaceAddress.AddressFamily, 300 | Port = 0 // Assign a random port 301 | }; 302 | 303 | DebugMessage( 304 | nameof(BindSocketByAddress), 305 | socket, 306 | "Binding to `{0}:{1}` ...", 307 | bindIn.Address?.IPAddress, 308 | bindIn.Port 309 | ); 310 | 311 | MarkSocketAsBinded(socket); 312 | 313 | return NativeSocket.Bind(socket, ref bindIn, Marshal.SizeOf(bindIn)); 314 | } 315 | 316 | if (interfaceAddress.AddressFamily == AddressFamily.InterNetworkV6) 317 | { 318 | var scopeId = (uint?) networkInterface.GetIPProperties()?.GetIPv6Properties()?.Index ?? 0; 319 | var flowInfo = (socketAddress as SocketAddressIn6?)?.FlowInfo ?? 0; 320 | 321 | var bindIn6 = new SocketAddressIn6 322 | { 323 | Address = new AddressIn6 {IPAddress = interfaceAddress}, 324 | AddressFamily = interfaceAddress.AddressFamily, 325 | Port = 0, // Assign a random port 326 | ScopeId = scopeId, 327 | FlowInfo = flowInfo 328 | }; 329 | 330 | DebugMessage( 331 | nameof(BindSocketByAddress), 332 | socket, 333 | "Binding to `{0}:{1}` ...", 334 | bindIn6.Address?.IPAddress, 335 | bindIn6.Port 336 | ); 337 | 338 | MarkSocketAsBinded(socket); 339 | 340 | return NativeSocket.Bind(socket, ref bindIn6, Marshal.SizeOf(bindIn6)); 341 | } 342 | 343 | DebugMessage( 344 | nameof(BindSocketByAddress), 345 | socket, 346 | "Binding to interface skipped due an unsupported interface address family of `{0}`.", 347 | interfaceAddress.AddressFamily 348 | ); 349 | 350 | return SocketError.Success; 351 | } 352 | 353 | // ReSharper disable once TooManyArguments 354 | private void DebugMessage(string scope, IntPtr? socket, string message, params object[] args) 355 | { 356 | var lastError = NativeSocket.WSAGetLastError(); 357 | 358 | try 359 | { 360 | var space = Math.Max(20 - scope.Length, 0); 361 | 362 | message = string.Format( 363 | "{0:s} - #{4:D8} [`{1}`] {2}{3}", 364 | DateTime.UtcNow, 365 | scope, 366 | new string(' ', space), 367 | args?.Length > 0 ? string.Format(message, args) : message, 368 | socket?.ToInt64() ?? 0 369 | ); 370 | 371 | #if DEBUG 372 | try 373 | { 374 | Debug.WriteLine(message); 375 | Console.WriteLine(message); 376 | } 377 | catch 378 | { 379 | // ignored 380 | } 381 | #endif 382 | 383 | try 384 | { 385 | if (string.IsNullOrWhiteSpace(LogPath)) 386 | { 387 | return; 388 | } 389 | 390 | File.AppendAllText(LogPath, message + Environment.NewLine); 391 | } 392 | catch 393 | { 394 | // ignored 395 | } 396 | } 397 | catch 398 | { 399 | // ignored 400 | } 401 | 402 | NativeSocket.WSASetLastError(lastError); 403 | } 404 | 405 | private string GenerateCaptionText() 406 | { 407 | var networkInterface = GetNetworkInterface(); 408 | var interfaceAddress = GetInterfaceAddress(networkInterface, AddressFamily.InterNetwork, true); 409 | 410 | if (networkInterface == null || interfaceAddress == null) 411 | { 412 | return null; 413 | } 414 | 415 | return "[" + networkInterface.Name + " - " + interfaceAddress + "]"; 416 | } 417 | 418 | // ReSharper disable once FlagArgument 419 | private IPAddress GetInterfaceAddress( 420 | NetworkInterface @interface, 421 | AddressFamily? preferredFamily, 422 | bool fallback) 423 | { 424 | var result = preferredFamily == null 425 | ? null 426 | : @interface 427 | ?.GetIPProperties() 428 | ?.UnicastAddresses 429 | ?.FirstOrDefault(information => information.Address.AddressFamily == preferredFamily.Value) 430 | ?.Address; 431 | 432 | if (result == null && fallback) 433 | { 434 | return @interface 435 | ?.GetIPProperties() 436 | ?.UnicastAddresses 437 | ?.FirstOrDefault(information => 438 | information.Address.AddressFamily == AddressFamily.InterNetwork || 439 | information.Address.AddressFamily == AddressFamily.InterNetworkV6) 440 | ?.Address; 441 | } 442 | 443 | return result; 444 | } 445 | 446 | private NetworkInterface GetNetworkInterface() 447 | { 448 | return NetworkInterface.GetAllNetworkInterfaces() 449 | .FirstOrDefault( 450 | @interface => 451 | @interface.Id.Equals(AdapterId, StringComparison.CurrentCultureIgnoreCase) && 452 | @interface.OperationalStatus == OperationalStatus.Up && 453 | @interface.SupportsMulticast); 454 | } 455 | 456 | private ISocketAddress GetSocketAddress(IntPtr socketAddressPointer) 457 | { 458 | if (socketAddressPointer == IntPtr.Zero) 459 | { 460 | return null; 461 | } 462 | 463 | try 464 | { 465 | var socketAddress = 466 | (SocketAddressBase) Marshal.PtrToStructure(socketAddressPointer, typeof(SocketAddressBase)); 467 | 468 | Type type; 469 | 470 | switch (socketAddress.Family) 471 | { 472 | case AddressFamily.InterNetwork: 473 | { 474 | type = typeof(SocketAddressIn); 475 | 476 | break; 477 | } 478 | case AddressFamily.InterNetworkV6: 479 | { 480 | type = typeof(SocketAddressIn6); 481 | 482 | break; 483 | } 484 | default: 485 | 486 | return null; 487 | } 488 | 489 | return (ISocketAddress) Marshal.PtrToStructure(socketAddressPointer, type); 490 | } 491 | catch 492 | { 493 | return null; 494 | } 495 | } 496 | 497 | private bool IsInternalAddress(IntPtr socket, ISocketAddress socketAddress) 498 | { 499 | switch (socketAddress?.AddressFamily) 500 | { 501 | case AddressFamily.InterNetwork: 502 | 503 | if (socketAddress.Address?.IPAddress?.Equals(IPAddress.Any) == true) 504 | { 505 | DebugMessage( 506 | nameof(IsInternalAddress), 507 | socket, 508 | "Binding to interface skipped due to the nature of passed IP Address. [0.0.0.0]" 509 | ); 510 | 511 | { 512 | return true; 513 | } 514 | } 515 | 516 | if (IsIpInRange(socketAddress.Address?.IPAddress, IPAddress.Parse("127.0.0.0"), 517 | IPAddress.Parse("127.255.255.255"))) 518 | { 519 | DebugMessage( 520 | nameof(IsInternalAddress), 521 | socket, 522 | "Binding to interface skipped due to the nature of passed IP Address. [Loop Back]" 523 | ); 524 | 525 | { 526 | return true; 527 | } 528 | } 529 | 530 | break; 531 | case AddressFamily.InterNetworkV6: 532 | 533 | if (socketAddress.Address?.IPAddress?.Equals(IPAddress.IPv6Any) == true) 534 | { 535 | DebugMessage( 536 | nameof(IsInternalAddress), 537 | socket, 538 | "Binding to interface skipped due to the nature of passed IP Address. [0000:]" 539 | ); 540 | 541 | { 542 | return true; 543 | } 544 | } 545 | 546 | if (socketAddress.Address?.IPAddress?.Equals(IPAddress.IPv6Loopback) == true) 547 | { 548 | DebugMessage( 549 | nameof(IsInternalAddress), 550 | socket, 551 | "Binding to interface skipped due to the nature of passed IP Address. [Loop Back]" 552 | ); 553 | 554 | { 555 | return true; 556 | } 557 | } 558 | 559 | break; 560 | } 561 | 562 | return false; 563 | } 564 | 565 | private bool IsIpInRange(IPAddress address, IPAddress lowerRange, IPAddress upperRange) 566 | { 567 | if (address == null) 568 | { 569 | return false; 570 | } 571 | 572 | var lowerBytes = lowerRange.GetAddressBytes(); 573 | var upperBytes = upperRange.GetAddressBytes(); 574 | var addressBytes = address.GetAddressBytes(); 575 | var lowerBoundary = true; 576 | var upperBoundary = true; 577 | 578 | for (var i = 0; 579 | i < lowerBytes.Length && 580 | (lowerBoundary || upperBoundary); 581 | i++) 582 | { 583 | if (lowerBoundary && addressBytes[i] < lowerBytes[i] || 584 | upperBoundary && addressBytes[i] > upperBytes[i]) 585 | { 586 | return false; 587 | } 588 | 589 | lowerBoundary &= addressBytes[i] == lowerBytes[i]; 590 | upperBoundary &= addressBytes[i] == upperBytes[i]; 591 | } 592 | 593 | return true; 594 | } 595 | 596 | private bool IsSocketMarkedAsBinded(IntPtr socket) 597 | { 598 | lock (SocketLookupTable) 599 | { 600 | if (SocketLookupTable.ContainsKey(socket)) 601 | { 602 | return SocketLookupTable[socket]; 603 | } 604 | } 605 | 606 | return false; 607 | } 608 | 609 | private bool IsSpecialAddress(IntPtr socket, ISocketAddress socketAddress) 610 | { 611 | if (IsInternalAddress(socket, socketAddress)) 612 | { 613 | return true; 614 | } 615 | 616 | switch (socketAddress?.AddressFamily) 617 | { 618 | case AddressFamily.InterNetwork: 619 | 620 | if (IsIpInRange(socketAddress.Address?.IPAddress, IPAddress.Parse("10.0.0.0"), 621 | IPAddress.Parse("10.255.255.255"))) 622 | { 623 | DebugMessage( 624 | nameof(IsSpecialAddress), 625 | socket, 626 | "Binding to interface skipped due to the nature of passed IP Address. [Private Range]" 627 | ); 628 | 629 | { 630 | return true; 631 | } 632 | } 633 | 634 | if (IsIpInRange(socketAddress.Address?.IPAddress, IPAddress.Parse("172.16.0.0"), 635 | IPAddress.Parse("172.31.255.255"))) 636 | { 637 | DebugMessage( 638 | nameof(IsSpecialAddress), 639 | socket, 640 | "Binding to interface skipped due to the nature of passed IP Address. [Private Range]" 641 | ); 642 | 643 | { 644 | return true; 645 | } 646 | } 647 | 648 | if (IsIpInRange(socketAddress.Address?.IPAddress, IPAddress.Parse("192.168.0.0"), 649 | IPAddress.Parse("192.168.255.255"))) 650 | { 651 | DebugMessage( 652 | nameof(IsSpecialAddress), 653 | socket, 654 | "Binding to interface skipped due to the nature of passed IP Address. [Private Range]" 655 | ); 656 | 657 | { 658 | return true; 659 | } 660 | } 661 | 662 | if (IsIpInRange(socketAddress.Address?.IPAddress, IPAddress.Parse("169.254.1.0"), 663 | IPAddress.Parse("169.254.254.255"))) 664 | { 665 | DebugMessage( 666 | nameof(IsSpecialAddress), 667 | socket, 668 | "Binding to interface skipped due to the nature of passed IP Address. [Link Local Network]" 669 | ); 670 | 671 | { 672 | return true; 673 | } 674 | } 675 | 676 | if (IsIpInRange(socketAddress.Address?.IPAddress, IPAddress.Parse("224.0.0.0"), 677 | IPAddress.Parse("239.255.255.255"))) 678 | { 679 | DebugMessage( 680 | nameof(IsSpecialAddress), 681 | socket, 682 | "Binding to interface skipped due to the nature of passed IP Address. [MultiCast Address]" 683 | ); 684 | 685 | { 686 | return true; 687 | } 688 | } 689 | 690 | break; 691 | case AddressFamily.InterNetworkV6: 692 | 693 | if (IsIpInRange(socketAddress.Address?.IPAddress, 694 | IPAddress.Parse("fc00:0000:0000:0000:0000:0000:0000:0000"), 695 | IPAddress.Parse("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))) 696 | { 697 | DebugMessage( 698 | nameof(IsSpecialAddress), 699 | socket, 700 | "Binding to interface skipped due to the nature of passed IP Address. [fc00:]" 701 | ); 702 | 703 | { 704 | return true; 705 | } 706 | } 707 | 708 | break; 709 | default: 710 | DebugMessage( 711 | nameof(IsSpecialAddress), 712 | socket, 713 | "Binding to interface skipped due an unsupported address family of `{0}`.", 714 | socketAddress?.AddressFamily 715 | ); 716 | 717 | { 718 | return true; 719 | } 720 | } 721 | 722 | return false; 723 | } 724 | 725 | private void LoadLibrary(string libraryName, Action code) 726 | { 727 | // Forcing the hook by pre-loading the desired library 728 | var library = NativeLibrary.LoadLibrary(libraryName); 729 | code(); 730 | 731 | // Unload the library only if we were the one loading it for the first time 732 | if (!library.Equals(IntPtr.Zero)) 733 | { 734 | NativeLibrary.FreeLibrary(library); 735 | DebugMessage( 736 | nameof(LoadLibrary), 737 | null, 738 | "Library `{1}` loaded and unloaded to override hooked function addresses.", 739 | libraryName 740 | ); 741 | } 742 | } 743 | 744 | private void MarkSocketAsBinded(IntPtr socket) 745 | { 746 | lock (SocketLookupTable) 747 | { 748 | if (!SocketLookupTable.ContainsKey(socket)) 749 | { 750 | SocketLookupTable.Add(socket, true); 751 | } 752 | else 753 | { 754 | SocketLookupTable[socket] = true; 755 | } 756 | } 757 | } 758 | 759 | private SocketError OnBind(IntPtr socket, IntPtr address, int addressSize) 760 | { 761 | var socketAddress = GetSocketAddress(address); 762 | 763 | DebugMessage( 764 | nameof(OnBind), 765 | socket, 766 | "Binding to `{0}:{1}` ...", 767 | socketAddress?.Address?.IPAddress, 768 | socketAddress?.Port 769 | ); 770 | 771 | SocketError bindResult; 772 | 773 | if (IsInternalAddress(socket, socketAddress)) 774 | { 775 | bindResult = NativeSocket.Bind(socket, address, addressSize); 776 | } 777 | else 778 | { 779 | var networkInterface = GetNetworkInterface(); 780 | var interfaceAddress = GetInterfaceAddress(networkInterface, socketAddress?.AddressFamily, true); 781 | 782 | if (socketAddress?.Address == null || networkInterface == null || interfaceAddress == null) 783 | { 784 | DebugMessage( 785 | nameof(OnBind), 786 | socket, 787 | "Binding to `{0}:{1}` rejected due to lack of a valid interface address.", 788 | socketAddress?.Address?.IPAddress, 789 | socketAddress?.Port 790 | ); 791 | 792 | return SocketError.SocketError; 793 | } 794 | 795 | 796 | if (interfaceAddress.AddressFamily == AddressFamily.InterNetwork && 797 | !interfaceAddress.Equals(socketAddress.Address.IPAddress)) 798 | { 799 | var bindIn = new SocketAddressIn 800 | { 801 | Address = new AddressIn {IPAddress = interfaceAddress}, 802 | AddressFamily = interfaceAddress.AddressFamily, 803 | Port = socketAddress.Port 804 | }; 805 | 806 | DebugMessage( 807 | nameof(OnBind), 808 | socket, 809 | "Binding to `{0}:{1}` replaced by a binding request to `{2}:{3}`.", 810 | socketAddress.Address.IPAddress, 811 | socketAddress.Port, 812 | bindIn.Address.IPAddress, 813 | bindIn.Port 814 | ); 815 | 816 | MarkSocketAsBinded(socket); 817 | 818 | socketAddress = bindIn; 819 | 820 | bindResult = NativeSocket.Bind(socket, ref bindIn, Marshal.SizeOf(bindIn)); 821 | } 822 | else if (interfaceAddress.AddressFamily == AddressFamily.InterNetworkV6 && 823 | !interfaceAddress.Equals(socketAddress.Address.IPAddress)) 824 | { 825 | var scopeId = (uint?) networkInterface.GetIPProperties()?.GetIPv6Properties()?.Index ?? 0; 826 | var flowInfo = (socketAddress as SocketAddressIn6?)?.FlowInfo ?? 0; 827 | 828 | var bindIn6 = new SocketAddressIn6 829 | { 830 | Address = new AddressIn6 {IPAddress = interfaceAddress}, 831 | AddressFamily = interfaceAddress.AddressFamily, 832 | Port = socketAddress.Port, // Assign a random port 833 | ScopeId = scopeId, 834 | FlowInfo = flowInfo 835 | }; 836 | 837 | DebugMessage( 838 | nameof(OnBind), 839 | socket, 840 | "Binding to `{0}:{1}` replaced by a binding request to `{2}:{3}`.", 841 | socketAddress.Address.IPAddress, 842 | socketAddress.Port, 843 | bindIn6.Address.IPAddress, 844 | bindIn6.Port 845 | ); 846 | 847 | MarkSocketAsBinded(socket); 848 | 849 | socketAddress = bindIn6; 850 | 851 | bindResult = NativeSocket.Bind(socket, ref bindIn6, Marshal.SizeOf(bindIn6)); 852 | } 853 | else 854 | { 855 | bindResult = NativeSocket.Bind(socket, address, addressSize); 856 | } 857 | } 858 | 859 | DebugMessage( 860 | nameof(OnBind), 861 | socket, 862 | "Binding to `{0}:{1}` resulted in a `{2}` response. [WSALastError = `{3}`]", 863 | socketAddress?.Address?.IPAddress, 864 | socketAddress?.Port, 865 | bindResult, 866 | NativeSocket.WSAGetLastError() 867 | ); 868 | 869 | return bindResult; 870 | } 871 | 872 | private SocketError OnCloseSocket(IntPtr socket) 873 | { 874 | var result = NativeSocket.CloseSocket(socket); 875 | 876 | if (socket != IntPtr.Zero && (result == SocketError.Success || result == SocketError.WouldBlock)) 877 | { 878 | lock (SocketLookupTable) 879 | { 880 | if (SocketLookupTable.ContainsKey(socket)) 881 | { 882 | DebugMessage( 883 | nameof(OnCloseSocket), 884 | socket, 885 | "Socket destroyed." 886 | ); 887 | SocketLookupTable.Remove(socket); 888 | } 889 | } 890 | } 891 | 892 | return result; 893 | } 894 | 895 | private SocketError OnConnect(IntPtr socket, IntPtr address, int addressSize) 896 | { 897 | var socketAddress = GetSocketAddress(address); 898 | 899 | DebugMessage( 900 | nameof(OnConnect), 901 | socket, 902 | "Connecting to `{0}:{1}` ...", 903 | socketAddress?.Address?.IPAddress, 904 | socketAddress?.Port 905 | ); 906 | 907 | var bindResult = BindSocketByAddress(socket, socketAddress); 908 | 909 | DebugMessage( 910 | nameof(OnConnect), 911 | socket, 912 | "Binding `{0}:{1}` to interface resulted in a `{2}` response. [WSALastError = `{3}`]", 913 | socketAddress?.Address?.IPAddress, 914 | socketAddress?.Port, 915 | bindResult, 916 | NativeSocket.WSAGetLastError() 917 | ); 918 | 919 | if (bindResult != SocketError.Success) 920 | { 921 | if (bindResult != SocketError.SocketError) 922 | { 923 | DebugMessage( 924 | nameof(OnConnect), 925 | socket, 926 | NativeSocket.WSAGetLastError().ToString() 927 | ); 928 | } 929 | 930 | DebugMessage( 931 | nameof(OnConnect), 932 | socket, 933 | "Connecting to `{0}:{1}` rejected.", 934 | socketAddress?.Address?.IPAddress, 935 | socketAddress?.Port 936 | ); 937 | 938 | return SocketError.SocketError; 939 | } 940 | 941 | var returnValue = NativeSocket.Connect(socket, address, addressSize); 942 | 943 | DebugMessage( 944 | nameof(OnConnect), 945 | socket, 946 | "Connecting to `{0}:{1}` resulted in a `{2}` response. [WSALastError = `{3}`]", 947 | socketAddress?.Address?.IPAddress, 948 | socketAddress?.Port, 949 | returnValue, 950 | NativeSocket.WSAGetLastError() 951 | ); 952 | 953 | //if (returnValue == SocketError.SocketError && Socket.WSAGetLastError() == SocketError.Success) 954 | //{ 955 | // returnValue = SocketError.Success; 956 | //} 957 | 958 | return returnValue; 959 | } 960 | 961 | // ReSharper disable once TooManyArguments 962 | private bool OnCreateProcess( 963 | IntPtr applicationName, 964 | IntPtr commandLine, 965 | IntPtr processAttributes, 966 | IntPtr threadAttributes, 967 | bool inheritHandles, 968 | uint creationFlags, 969 | IntPtr environment, 970 | IntPtr currentDirectory, 971 | IntPtr startupInfo, 972 | out ProcessInformation processInformation, 973 | bool isUnicode) 974 | { 975 | var resultValue = isUnicode 976 | ? NativeProcess.CreateProcessW( 977 | applicationName, 978 | commandLine, 979 | processAttributes, 980 | threadAttributes, 981 | inheritHandles, 982 | creationFlags, 983 | environment, 984 | currentDirectory, 985 | startupInfo, 986 | out processInformation 987 | ) 988 | : NativeProcess.CreateProcessA( 989 | applicationName, 990 | commandLine, 991 | processAttributes, 992 | threadAttributes, 993 | inheritHandles, 994 | creationFlags, 995 | environment, 996 | currentDirectory, 997 | startupInfo, 998 | out processInformation 999 | ); 1000 | 1001 | if (!resultValue) 1002 | { 1003 | return false; 1004 | } 1005 | 1006 | if (processInformation.ProcessId <= 0) 1007 | { 1008 | return true; 1009 | } 1010 | 1011 | var processId = processInformation.ProcessId; 1012 | 1013 | DebugMessage(nameof(OnCreateProcess), 1014 | null, 1015 | "A new process with identification number of #{0} is created.", 1016 | processId 1017 | ); 1018 | 1019 | new Thread(() => 1020 | { 1021 | Thread.Sleep(InjectionDelay); 1022 | var tries = 1; 1023 | 1024 | while (true) 1025 | { 1026 | try 1027 | { 1028 | RemoteHooking.Inject( 1029 | processId, 1030 | InjectionGuessAddress, 1031 | InjectionGuessAddress, 1032 | AdapterId, 1033 | InjectionGuessAddress, 1034 | InjectionDelay, 1035 | !string.IsNullOrWhiteSpace(LogPath) 1036 | ); 1037 | 1038 | DebugMessage( 1039 | nameof(OnCreateProcess), 1040 | null, 1041 | "Process #{0} injected with the guest code.", 1042 | processId 1043 | ); 1044 | 1045 | return; 1046 | } 1047 | catch 1048 | { 1049 | if (tries < 3) 1050 | { 1051 | tries++; 1052 | 1053 | Thread.Sleep(1000); 1054 | 1055 | continue; 1056 | } 1057 | 1058 | DebugMessage( 1059 | nameof(OnCreateProcess), 1060 | null, 1061 | "Failed to inject the guest code to process #{0}.", 1062 | processId 1063 | ); 1064 | 1065 | return; 1066 | } 1067 | } 1068 | }).Start(); 1069 | 1070 | return true; 1071 | } 1072 | 1073 | private IntPtr OnOpenSocket(AddressFamily addressFamily, SocketType type, ProtocolType protocol) 1074 | { 1075 | var socket = NativeSocket.OpenSocket(addressFamily, type, protocol); 1076 | 1077 | if (socket != IntPtr.Zero) 1078 | { 1079 | lock (SocketLookupTable) 1080 | { 1081 | if (!SocketLookupTable.ContainsKey(socket)) 1082 | { 1083 | DebugMessage( 1084 | nameof(OnOpenSocket), 1085 | socket, 1086 | "New socket created." 1087 | ); 1088 | SocketLookupTable.Add(socket, false); 1089 | } 1090 | } 1091 | } 1092 | 1093 | return socket; 1094 | } 1095 | 1096 | private bool OnSetWindowText(IntPtr windowHandle, IntPtr text, bool unicode) 1097 | { 1098 | var title = unicode ? Marshal.PtrToStringUni(text) : Marshal.PtrToStringAnsi(text); 1099 | 1100 | if (!ChangeWindowTitle) 1101 | { 1102 | return NativeWindow.SetWindowText(windowHandle, title); 1103 | } 1104 | 1105 | if (!string.IsNullOrEmpty(title) && windowHandle.Equals(ActiveWindow)) 1106 | { 1107 | DebugMessage( 1108 | nameof(OnSetWindowText), 1109 | null, 1110 | "Window #{0} title changing to `{1}`.", 1111 | windowHandle, 1112 | title 1113 | ); 1114 | title = WindowTitle.AppendWindowTitle(title, GenerateCaptionText()); 1115 | } 1116 | 1117 | return NativeWindow.SetWindowText(windowHandle, title); 1118 | } 1119 | 1120 | 1121 | // ReSharper disable once TooManyArguments 1122 | private SocketError OnWSAConnect( 1123 | IntPtr socket, 1124 | IntPtr address, 1125 | int addressSize, 1126 | IntPtr inBuffer, 1127 | IntPtr outBuffer, 1128 | IntPtr sQos, 1129 | IntPtr gQos) 1130 | { 1131 | var socketAddress = GetSocketAddress(address); 1132 | 1133 | DebugMessage( 1134 | nameof(OnWSAConnect), 1135 | socket, 1136 | "Connecting to `{0}:{1}` ...", 1137 | socketAddress?.Address?.IPAddress, 1138 | socketAddress?.Port 1139 | ); 1140 | 1141 | var bindResult = BindSocketByAddress(socket, socketAddress); 1142 | 1143 | DebugMessage( 1144 | nameof(OnWSAConnect), 1145 | socket, 1146 | "Binding `{0}:{1}` to interface resulted in a `{2}` response. [WSALastError = `{3}`]", 1147 | socketAddress?.Address?.IPAddress, 1148 | socketAddress?.Port, 1149 | bindResult, 1150 | NativeSocket.WSAGetLastError() 1151 | ); 1152 | 1153 | if (bindResult != SocketError.Success) 1154 | { 1155 | if (bindResult != SocketError.SocketError) 1156 | { 1157 | DebugMessage( 1158 | nameof(OnWSAConnect), 1159 | socket, 1160 | NativeSocket.WSAGetLastError().ToString() 1161 | ); 1162 | } 1163 | 1164 | DebugMessage( 1165 | nameof(OnWSAConnect), 1166 | socket, 1167 | "Connecting to `{0}:{1}` rejected.", 1168 | socketAddress?.Address?.IPAddress, 1169 | socketAddress?.Port 1170 | ); 1171 | 1172 | return SocketError.SocketError; 1173 | } 1174 | 1175 | var returnValue = NativeSocket.WSAConnect(socket, address, addressSize, inBuffer, outBuffer, sQos, gQos); 1176 | 1177 | DebugMessage( 1178 | nameof(OnWSAConnect), 1179 | socket, 1180 | "Connecting to `{0}:{1}` resulted in a `{2}` response. [WSALastError = `{3}`]", 1181 | socketAddress?.Address?.IPAddress, 1182 | socketAddress?.Port, 1183 | returnValue, 1184 | NativeSocket.WSAGetLastError() 1185 | ); 1186 | 1187 | //if (returnValue == SocketError.SocketError && Socket.WSAGetLastError() == SocketError.Success) 1188 | //{ 1189 | // returnValue = SocketError.Success; 1190 | //} 1191 | 1192 | return returnValue; 1193 | } 1194 | 1195 | // ReSharper disable once TooManyArguments 1196 | private IntPtr OnWSAOpenSocket( 1197 | AddressFamily addressFamily, 1198 | SocketType type, 1199 | ProtocolType protocol, 1200 | IntPtr protocolInfo, 1201 | int groupId, 1202 | short flags, 1203 | bool isUnicode) 1204 | { 1205 | var socket = isUnicode 1206 | ? NativeSocket.WSAOpenSocketW(addressFamily, type, protocol, protocolInfo, groupId, flags) 1207 | : NativeSocket.WSAOpenSocketA(addressFamily, type, protocol, protocolInfo, groupId, flags); 1208 | 1209 | if (socket != IntPtr.Zero) 1210 | { 1211 | lock (SocketLookupTable) 1212 | { 1213 | if (!SocketLookupTable.ContainsKey(socket)) 1214 | { 1215 | DebugMessage( 1216 | nameof(OnWSAOpenSocket), 1217 | socket, 1218 | "New socket created." 1219 | ); 1220 | SocketLookupTable.Add(socket, false); 1221 | } 1222 | } 1223 | } 1224 | 1225 | return socket; 1226 | } 1227 | 1228 | private void WindowTitleCheckLoop() 1229 | { 1230 | while (true) 1231 | { 1232 | try 1233 | { 1234 | // Get the host process 1235 | var currentProcess = Process.GetCurrentProcess(); 1236 | 1237 | // We do care only about the main window 1238 | var mainWindowHandler = currentProcess.MainWindowHandle; 1239 | 1240 | if (mainWindowHandler != IntPtr.Zero && 1241 | !string.IsNullOrEmpty(currentProcess.MainWindowTitle)) 1242 | { 1243 | if (ActiveWindow != mainWindowHandler) 1244 | { 1245 | if (ActiveWindow != IntPtr.Zero) 1246 | { 1247 | DebugMessage( 1248 | nameof(WindowTitleCheckLoop), 1249 | null, 1250 | "Main window changed from #{0} to #{1}. Cleaning old window's title bar.", 1251 | ActiveWindow, 1252 | mainWindowHandler 1253 | ); 1254 | 1255 | // In case main window changed, we need to clean the older one 1256 | try 1257 | { 1258 | WindowTitle.CleanWindowsTitle(ActiveWindow); 1259 | } 1260 | catch 1261 | { 1262 | // ignored 1263 | } 1264 | } 1265 | 1266 | ActiveWindow = mainWindowHandler; 1267 | } 1268 | 1269 | // Making sure that our special text is in the title bar 1270 | WindowTitle.AppendWindowTitle(ActiveWindow, GenerateCaptionText()); 1271 | } 1272 | 1273 | Thread.Sleep(300); 1274 | } 1275 | catch (Exception e) 1276 | { 1277 | // Ignoring the InvalidOperationException as it happens a lot when program don't have 1278 | // a valid window 1279 | if (!(e is InvalidOperationException)) 1280 | { 1281 | DebugMessage( 1282 | nameof(WindowTitleCheckLoop), 1283 | null, 1284 | e.ToString() 1285 | ); 1286 | } 1287 | 1288 | Thread.Sleep(1000); 1289 | } 1290 | } 1291 | 1292 | // ReSharper disable once FunctionNeverReturns 1293 | } 1294 | 1295 | /// 1296 | /// Removes all active hooks 1297 | /// 1298 | ~Guest() 1299 | { 1300 | try 1301 | { 1302 | lock (Hooks) 1303 | { 1304 | foreach (var localHook in Hooks) 1305 | { 1306 | try 1307 | { 1308 | localHook.Dispose(); 1309 | } 1310 | catch 1311 | { 1312 | // ignored 1313 | } 1314 | } 1315 | 1316 | Hooks.Clear(); 1317 | } 1318 | } 1319 | catch 1320 | { 1321 | // ignored 1322 | } 1323 | } 1324 | } 1325 | } --------------------------------------------------------------------------------