├── 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://github.com/falahati/NetworkAdapterSelector/blob/master/LICENSE)
3 | [](https://github.com/falahati/NetworkAdapterSelector/commits/master)
4 | [](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 | 
10 |
11 | ## How to get
12 | [](https://github.com/falahati/NetworkAdapterSelector/releases)
13 | [](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://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://zarinp.al/@falahati)
21 | [](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 | }
--------------------------------------------------------------------------------