├── .editorconfig
├── .gitignore
├── GitInfo.txt
├── Icon.png
├── LICENSE.txt
├── README.md
├── msbuild.rsp
└── src
├── Bootstrap
├── AssemblyInfo.cpp
├── Bootstrap.vcxproj
├── Bootstrap.vcxproj.filters
├── Injector.cpp
├── Injector.h
├── Stdafx.cpp
├── Stdafx.h
├── makefile.def
└── packages.config
├── Directory.Build.props
├── Directory.Build.targets
├── Injector
├── App.config
├── Injector.csproj
├── Program.cs
└── msbuild.rsp
├── NuGet.Config
├── Sample
├── App.config
├── Program.cs
├── Properties
│ └── launchSettings.json
└── Sample.csproj
├── Windows.Injector.sln
├── Windows.Injector.snk
├── Xamarin.Windows.Injector.props
└── Xamarin.Windows.Injector.targets
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome:http://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Don't use tabs for indentation.
7 | [*]
8 | indent_style = space
9 | # (Please don't specify an indent_size here; that has too many unintended consequences.)
10 |
11 | # Code files
12 | [*.{cs,csx,vb,vbx}]
13 | indent_size = 4
14 |
15 | # Xml project files
16 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
17 | indent_size = 2
18 |
19 | # Xml config files
20 | [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
21 | indent_size = 2
22 |
23 | # JSON files
24 | [*.json]
25 | indent_size = 2
26 |
27 | # Dotnet code style settings:
28 | [*.{cs,vb}]
29 | # Sort using and Import directives with System.* appearing first
30 | dotnet_sort_system_directives_first = true
31 | # Avoid "this." and "Me." if not necessary
32 | dotnet_style_qualification_for_field = false:suggestion
33 | dotnet_style_qualification_for_property = false:suggestion
34 | dotnet_style_qualification_for_method = false:suggestion
35 | dotnet_style_qualification_for_event = false:suggestion
36 |
37 | # Use language keywords instead of framework type names for type references
38 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
39 | dotnet_style_predefined_type_for_member_access = true:suggestion
40 |
41 | # Suggest more modern language features when available
42 | dotnet_style_object_initializer = true:suggestion
43 | dotnet_style_collection_initializer = true:suggestion
44 | dotnet_style_coalesce_expression = true:suggestion
45 | dotnet_style_null_propagation = true:suggestion
46 | dotnet_style_explicit_tuple_names = true:suggestion
47 |
48 | # CSharp code style settings:
49 | [*.cs]
50 | # Prefer "var" everywhere
51 | csharp_style_var_for_built_in_types = true:suggestion
52 | csharp_style_var_when_type_is_apparent = true:suggestion
53 | csharp_style_var_elsewhere = true:suggestion
54 |
55 | # Prefer method-like constructs to have a block body
56 | csharp_style_expression_bodied_methods = false:none
57 | csharp_style_expression_bodied_constructors = false:none
58 | csharp_style_expression_bodied_operators = false:none
59 |
60 | # Prefer property-like constructs to have an expression-body
61 | csharp_style_expression_bodied_properties = true:none
62 | csharp_style_expression_bodied_indexers = true:none
63 | csharp_style_expression_bodied_accessors = true:none
64 |
65 | # Suggest more modern language features when available
66 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
67 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
68 | csharp_style_inlined_variable_declaration = true:suggestion
69 | csharp_style_throw_expression = true:suggestion
70 | csharp_style_conditional_delegate_call = true:suggestion
71 |
72 | # Newline settings
73 | csharp_new_line_before_open_brace = all
74 | csharp_new_line_before_else = true
75 | csharp_new_line_before_catch = true
76 | csharp_new_line_before_finally = true
77 | csharp_new_line_before_members_in_object_initializers = true
78 | csharp_new_line_before_members_in_anonymous_types = true
79 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | obj
3 | out
4 | .nuget
5 | .vs
6 | packages
7 | *.VC.db
8 | *.opendb
9 | *.user
10 | *.suo
11 | *.cache
12 |
--------------------------------------------------------------------------------
/GitInfo.txt:
--------------------------------------------------------------------------------
1 | 1.0.2-alpha
2 |
--------------------------------------------------------------------------------
/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xamarin/Windows.Injector/efcb3e098bb701456701159b4301466556806263/Icon.png
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Microsoft Public License (MS-PL)
2 | This license governs use of the accompanying software. If you use the software, you
3 | accept this license. If you do not accept the license, do not use the software.
4 |
5 | 1. Definitions
6 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
7 | same meaning here as under U.S. copyright law.
8 | A "contribution" is the original software, or any additions or changes to the software.
9 | A "contributor" is any person that distributes its contribution under this license.
10 | "Licensed patents" are a contributor's patent claims that read directly on its contribution.
11 |
12 | 2. Grant of Rights
13 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
14 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
15 |
16 | 3. Conditions and Limitations
17 | (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
18 | (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
19 | (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
20 | (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
21 | (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Windows.Injector
2 |
3 | [](https://www.nuget.org/packages/Xamarin.Windows.Injector)
4 | [](https://www.nuget.org/packages/Xamarin.Windows.Injector)
5 | [](http://build.azdo.io/11357)
6 |
7 | Allows injecting .NET code into a remote process on Windows
8 |
9 | Heavily based on [Cory Plott](http://www.cplotts.com)'s [Snoop](https://github.com/cplotts/snoopwpf).
10 |
11 | Usage:
12 |
13 | * Install:
14 |
15 | ```
16 | install-package Xamarin.Windows.Injector
17 | ```
18 |
19 | The following properties are used to determine which version (`x86` or `x64`) of the `boostrap.dll`
20 | assembly will be referenced: `PlatformTarget`, `Platform` and `RuntimeIdentifier`. If any of those
21 | specify either `x86` or `x64`, the assembly will be automatically referenced. Note that you cannot
22 | invoke the injector via its API from an `AnyCPU` library, since it has to be of a specific bitness.
23 |
24 | The targets automatically include as content both the assembly as well as a helper `Injector.exe`
25 | executable which you can use to inject into processes that have a different bitness than the calling one.
26 |
27 | * Launch:
28 |
29 | ```
30 | var targetProcess = System.Diagnostics.Process.GetProcessesByName("devenv.exe")[0];
31 |
32 | Injector.Launch(
33 | // IntPtr of the main window handle of the process to inject
34 | targetProcess.MainWindowHandle,
35 | // The full path to the .NET assembly to load in the remote process
36 | Assembly.GetExecutingAssembly().Location,
37 | // Full type name of the public static class to invoke in the remote process
38 | "MyApp.Startup",
39 | // Name of the static method in that class to invoke in the remote process
40 | "Start");
41 | ```
42 |
43 | Optionally, the injected method call can also receive parameters, in a `{method}:arg1:arg2:argN` format:
44 |
45 | ```
46 | var targetProcess = System.Diagnostics.Process.GetProcessesByName("devenv.exe")[0];
47 |
48 | Injector.Launch(
49 | // IntPtr of the main window handle of the process to inject
50 | targetProcess.MainWindowHandle,
51 | // The full path to the .NET assembly to load in the remote process
52 | Assembly.GetExecutingAssembly().Location,
53 | // Full type name of the public static class to invoke in the remote process
54 | "MyApp.Startup",
55 | // Name of the static method in that class to invoke in the remote process
56 | "Start:hello:42:true");
57 | ```
58 |
59 | See [Program.cs](src/Sample/Program.cs) for complete example.
60 |
61 | When referencing the package from an `AnyCPU` project, the `x86` and `x64` folders will be included as
62 | content and copied to the project output path. This allows you to run the relevant `Injector.exe` for
63 | that matches the target process bitness. This executable receives the same parameters as the `Launch`
64 | method shown above.
65 |
66 | > NOTE: parameter type conversion is supported and happens via the `TypeConverter` associated with the
67 | parameter type.
68 |
--------------------------------------------------------------------------------
/msbuild.rsp:
--------------------------------------------------------------------------------
1 | /v:m /bl
--------------------------------------------------------------------------------
/src/Bootstrap/AssemblyInfo.cpp:
--------------------------------------------------------------------------------
1 | // (c) Copyright Cory Plotts.
2 | // This source is subject to the Microsoft Public License (Ms-PL).
3 | // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
4 | // All other rights reserved.
5 |
6 | #include "stdafx.h"
7 |
8 | using namespace System;
9 | using namespace System::Reflection;
10 | using namespace System::Runtime::CompilerServices;
11 | using namespace System::Runtime::InteropServices;
12 | using namespace System::Security::Permissions;
13 |
14 | [assembly:AssemblyTitleAttribute("Bootstrap")];
15 | [assembly:AssemblyProductAttribute("Bootstrap")];
16 | [assembly:AssemblyCopyrightAttribute("Copyright (c) Cory Plotts")];
17 |
18 | [assembly:AssemblyVersionAttribute("1.0.0.0")];
19 | [assembly:ComVisible(false)];
20 | [assembly:CLSCompliantAttribute(true)];
21 |
--------------------------------------------------------------------------------
/src/Bootstrap/Bootstrap.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Debug
7 | Win32
8 |
9 |
10 | Debug
11 | x64
12 |
13 |
14 | Release
15 | Win32
16 |
17 |
18 | Release
19 | x64
20 |
21 |
22 |
23 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}
24 | v4.0
25 | Bootstrap
26 | x86
27 | $(Platform)
28 | tools
29 | ManagedCProj
30 | Bootstrap
31 | bootstrap
32 | $(MSBuildProjectDirectory)\..\Windows.Injector.snk
33 | $(MSBuildProjectDirectory)\bin\$(PlatformTarget)\$(Configuration)\
34 | $(MSBuildProjectDirectory)\obj\$(PlatformTarget)\$(Configuration)\
35 | v140
36 | v142
37 | 10.0
38 |
39 |
40 |
41 | DynamicLibrary
42 | Unicode
43 | true
44 | true
45 | false
46 |
47 |
48 | DynamicLibrary
49 | Unicode
50 | true
51 | true
52 | false
53 |
54 |
55 | DynamicLibrary
56 | Unicode
57 | true
58 | false
59 |
60 |
61 | DynamicLibrary
62 | Unicode
63 | true
64 | false
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | Disabled
88 | WIN32;_DEBUG;%(PreprocessorDefinitions)
89 | MultiThreadedDebugDLL
90 |
91 |
92 | Level3
93 | OldStyle
94 | Async
95 |
96 |
97 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;%(AdditionalDependencies)
98 | Debug
99 | true
100 |
101 |
102 | MachineX86
103 |
104 |
105 | true
106 | /OPT:REF
107 |
108 |
109 |
110 |
111 | Disabled
112 | WIN64;_DEBUG;%(PreprocessorDefinitions)
113 | MultiThreadedDebugDLL
114 |
115 |
116 | Level3
117 | OldStyle
118 | Async
119 |
120 |
121 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;%(AdditionalDependencies)
122 | Debug
123 | true
124 |
125 |
126 |
127 |
128 | true
129 | /OPT:REF
130 |
131 |
132 |
133 |
134 | WIN32;NDEBUG;%(PreprocessorDefinitions)
135 | MultiThreadedDLL
136 |
137 |
138 | Level3
139 | None
140 | Async
141 |
142 |
143 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;%(AdditionalDependencies)
144 | $(OutDir)$(TargetName).dll
145 | makefile.def
146 | false
147 | false
148 |
149 |
150 | MachineX86
151 |
152 |
153 | true
154 | /OPT:REF
155 |
156 |
157 |
158 |
159 | WIN64;NDEBUG;%(PreprocessorDefinitions)
160 | MultiThreadedDLL
161 |
162 |
163 | Level3
164 | None
165 | Async
166 |
167 |
168 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;%(AdditionalDependencies)
169 | $(OutDir)$(TargetName).dll
170 | makefile.def
171 | false
172 | false
173 |
174 |
175 |
176 |
177 | true
178 | /OPT:REF
179 |
180 |
181 |
182 |
183 | true
184 | true
185 |
186 |
187 | true
188 | true
189 |
190 |
191 | true
192 | true
193 |
194 |
195 |
196 |
197 |
198 |
199 | Create
200 | Create
201 | Create
202 | Create
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 | $(GetTargetPathDependsOn);Build
215 |
216 |
217 |
218 |
219 |
220 |
221 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
222 |
223 |
224 |
225 |
226 |
--------------------------------------------------------------------------------
/src/Bootstrap/Bootstrap.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 |
10 |
11 | Source Files
12 |
13 |
14 | Source Files
15 |
16 |
17 | Source Files
18 |
19 |
20 |
21 |
22 | Source Files
23 |
24 |
25 | Source Files
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/Bootstrap/Injector.cpp:
--------------------------------------------------------------------------------
1 | // (c) Copyright Cory Plotts.
2 | // This source is subject to the Microsoft Public License (Ms-PL).
3 | // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
4 | // All other rights reserved.
5 |
6 | #include "stdafx.h"
7 |
8 | #include "Injector.h"
9 | #include
10 |
11 | using namespace Bootstrap;
12 |
13 | static unsigned int WM_GOBABYGO = ::RegisterWindowMessage(L"Injector_GOBABYGO!");
14 | static HHOOK _messageHookHandle;
15 |
16 | //-----------------------------------------------------------------------------
17 | //Spying Process functions follow
18 | //-----------------------------------------------------------------------------
19 | void Injector::Launch(System::IntPtr windowHandle, System::String^ assemblyFile, System::String^ typeFullName, System::String^ methodName)
20 | {
21 | System::String^ assemblyClassAndMethod = assemblyFile + "$" + typeFullName + "$" + methodName;
22 | pin_ptr acmLocal = PtrToStringChars(assemblyClassAndMethod);
23 |
24 | HINSTANCE hinstDLL;
25 |
26 | if (::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)&MessageHookProc, &hinstDLL))
27 | {
28 | // Don't append the first call, so after each injection attempt, we get a clean log to inspect.
29 | LogMessage("GetModuleHandleEx successful", false);
30 | DWORD processID = 0;
31 | DWORD threadID = ::GetWindowThreadProcessId((HWND)windowHandle.ToPointer(), &processID);
32 |
33 | if (processID)
34 | {
35 | LogMessage("Got process id", true);
36 | HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
37 | if (hProcess)
38 | {
39 | LogMessage("Got process handle", true);
40 | int buffLen = (assemblyClassAndMethod->Length + 1) * sizeof(wchar_t);
41 | void* acmRemote = ::VirtualAllocEx(hProcess, NULL, buffLen, MEM_COMMIT, PAGE_READWRITE);
42 |
43 | if (acmRemote)
44 | {
45 | LogMessage("VirtualAllocEx successful", true);
46 | ::WriteProcessMemory(hProcess, acmRemote, acmLocal, buffLen, NULL);
47 |
48 | _messageHookHandle = ::SetWindowsHookEx(WH_CALLWNDPROC, &MessageHookProc, hinstDLL, threadID);
49 |
50 | if (_messageHookHandle)
51 | {
52 | LogMessage("SetWindowsHookEx successful", true);
53 | ::SendMessage((HWND)windowHandle.ToPointer(), WM_GOBABYGO, (WPARAM)acmRemote, 0);
54 | ::UnhookWindowsHookEx(_messageHookHandle);
55 | }
56 |
57 | ::VirtualFreeEx(hProcess, acmRemote, 0, MEM_RELEASE);
58 | }
59 |
60 | ::CloseHandle(hProcess);
61 | }
62 | }
63 | else
64 | {
65 | if (windowHandle == IntPtr::Zero)
66 | LogMessage("Invalid window handle received", true);
67 | else
68 | LogMessage("Could not get process from window handle " + windowHandle.ToString(), true);
69 | }
70 | ::FreeLibrary(hinstDLL);
71 | }
72 | }
73 |
74 | void Injector::LogMessage(String^ message, bool append)
75 | {
76 | String^ applicationDataPath = Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData);
77 | applicationDataPath += "\\Windows.Injector";
78 |
79 | if (!System::IO::Directory::Exists(applicationDataPath))
80 | {
81 | System::IO::Directory::CreateDirectory(applicationDataPath);
82 | }
83 |
84 | String ^ pathname = applicationDataPath + "\\log.txt";
85 |
86 | if (!append)
87 | {
88 | System::IO::File::Delete(pathname);
89 | }
90 |
91 | System::IO::FileInfo ^ fi = gcnew System::IO::FileInfo(pathname);
92 |
93 | System::IO::StreamWriter ^ sw = fi->AppendText();
94 | sw->WriteLine(System::DateTime::Now.ToString("yyyy/MM/dd HH:mm:ss") + " : " + message);
95 | sw->Close();
96 | }
97 |
98 | __declspec(dllexport)
99 | LRESULT __stdcall MessageHookProc(int nCode, WPARAM wparam, LPARAM lparam)
100 | {
101 | if (nCode == HC_ACTION)
102 | {
103 | CWPSTRUCT* msg = (CWPSTRUCT*)lparam;
104 | if (msg != NULL && msg->message == WM_GOBABYGO)
105 | {
106 | Injector::LogMessage("Got WM_GOBABYGO message", true);
107 |
108 | wchar_t* acmRemote = (wchar_t*)msg->wParam;
109 |
110 | String^ acmLocal = gcnew System::String(acmRemote);
111 | Injector::LogMessage(System::String::Format("acmLocal = {0}", acmLocal), true);
112 | cli::array^ acmSplit = acmLocal->Split('$');
113 | cli::array^ methodSplit = acmSplit[2]->Split(':');
114 |
115 | Injector::LogMessage(String::Format("About to load assembly {0}", acmSplit[0]), true);
116 | System::Reflection::Assembly^ assembly = System::Reflection::Assembly::LoadFrom(acmSplit[0]);
117 | if (assembly != nullptr)
118 | {
119 | Injector::LogMessage(String::Format("About to load type {0}", acmSplit[1]), true);
120 | System::Type^ type = assembly->GetType(acmSplit[1]);
121 | if (type != nullptr)
122 | {
123 | Injector::LogMessage(String::Format("Just loaded the type {0}", acmSplit[1]), true);
124 | // Injector::LogMessage(String::Format("Looking for full method and parameters {0}", acmSplit[2]), true);
125 | Injector::LogMessage(String::Format("Looking for method named {0}", methodSplit[0]), true);
126 |
127 | System::Reflection::MethodInfo^ methodInfo = type->GetMethod(
128 | methodSplit[0],
129 | System::Reflection::BindingFlags::Static | System::Reflection::BindingFlags::Public);
130 |
131 | if (methodInfo != nullptr)
132 | {
133 | if (methodSplit->Length > 1)
134 | {
135 | cli::array^ parameters = methodInfo->GetParameters();
136 | if (methodSplit->Length - 1 != parameters->Length)
137 | {
138 | Injector::LogMessage(System::String::Format("Did not receive the expected {0} parameters to invoke {1}.{2}", parameters->Length, acmSplit[1], methodSplit[0]), true);
139 | }
140 | else
141 | {
142 | Injector::LogMessage(System::String::Format("Converting {0} received method arguments", methodSplit->Length - 1), true);
143 | cli::array^ methodParams = nullptr;
144 |
145 | methodParams = gcnew cli::array(parameters->Length);
146 | for (int i = 0; i < parameters->Length; i++) {
147 | System::Type^ paramType = parameters[i]->ParameterType;
148 | System::ComponentModel::TypeConverter^ converter = System::ComponentModel::TypeDescriptor::GetConverter(paramType);
149 | // NOTE: take into account that the first part of the methodSplit is the method name.
150 | methodParams[i] = converter->ConvertFromString(methodSplit[i + 1]);
151 | }
152 |
153 | Injector::LogMessage(System::String::Format("Invoking {0}.{1}({2})",
154 | acmSplit[1],
155 | methodInfo->Name,
156 | System::String::Join(", ", methodSplit, 1, methodSplit->Length - 1)), true);
157 | methodInfo->Invoke(nullptr, methodParams);
158 | }
159 | }
160 | else
161 | {
162 | Injector::LogMessage(System::String::Format("Invoking {0}.{1}()", acmSplit[1], methodInfo->Name), true);
163 | methodInfo->Invoke(nullptr, nullptr);
164 | }
165 | }
166 | else
167 | {
168 | Injector::LogMessage(System::String::Format("Did not find method named {0} on type {1}", methodSplit[0], acmSplit[1]), true);
169 | }
170 | }
171 | }
172 | }
173 | }
174 | return CallNextHookEx(_messageHookHandle, nCode, wparam, lparam);
175 | }
176 |
--------------------------------------------------------------------------------
/src/Bootstrap/Injector.h:
--------------------------------------------------------------------------------
1 | // (c) Copyright Cory Plotts.
2 | // This source is subject to the Microsoft Public License (Ms-PL).
3 | // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
4 | // All other rights reserved.
5 |
6 | #pragma once
7 |
8 | __declspec(dllexport)
9 | LRESULT __stdcall MessageHookProc(int nCode, WPARAM wparam, LPARAM lparam);
10 |
11 | using namespace System;
12 |
13 | namespace Bootstrap
14 | {
15 | public ref class Injector : System::Object
16 | {
17 | public:
18 |
19 | static void Launch(System::IntPtr windowHandle, System::String^ assemblyFile, System::String^ typeFullName, System::String^ methodName);
20 |
21 | static void LogMessage(System::String^ message, bool append);
22 | };
23 | }
24 |
--------------------------------------------------------------------------------
/src/Bootstrap/Stdafx.cpp:
--------------------------------------------------------------------------------
1 | // (c) Copyright Cory Plotts.
2 | // This source is subject to the Microsoft Public License (Ms-PL).
3 | // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
4 | // All other rights reserved.
5 |
6 | // stdafx.cpp : source file that includes just the standard includes
7 | // SnoopSpyC.pch will be the pre-compiled header
8 | // stdafx.obj will contain the pre-compiled type information
9 |
10 | #include "stdafx.h"
11 |
--------------------------------------------------------------------------------
/src/Bootstrap/Stdafx.h:
--------------------------------------------------------------------------------
1 | // (c) Copyright Cory Plotts.
2 | // This source is subject to the Microsoft Public License (Ms-PL).
3 | // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
4 | // All other rights reserved.
5 |
6 | // stdafx.h : include file for standard system include files,
7 | // or project specific include files that are used frequently,
8 | // but are changed infrequently
9 |
10 | #pragma once
11 |
12 | #define _WIN32_WINNT _WIN32_WINNT_WINXP
13 |
14 | #include "Windows.h"
15 | #include "tchar.h"
16 |
--------------------------------------------------------------------------------
/src/Bootstrap/makefile.def:
--------------------------------------------------------------------------------
1 | LIBRARY "bootstrap.dll"
2 | EXPORTS
3 | MessageHookProc @1
4 |
--------------------------------------------------------------------------------
/src/Bootstrap/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | false
5 | false
6 | false
7 |
8 |
9 |
10 | false
11 | true
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | tools\$(PlatformTarget)\%(Filename)%(Extension)
7 |
8 |
9 |
10 |
11 |
12 | $(SYSTEM_PULLREQUEST_TARGETBRANCH)
13 | $(BUILD_SOURCEBRANCHNAME)
14 |
15 |
16 |
17 |
18 | false
19 | true
20 |
21 | -$(GitBranch)
22 |
23 |
24 |
25 |
26 |
28 |
29 |
31 |
32 |
34 |
35 |
36 |
37 | @(VersionMetadata -> '%(Identity)', '-')
38 | +$(VersionMetadataLabel)
39 | $(GitSemVerDashLabel).$(GitCommits)
40 |
41 | $(GitBaseVersionMajor).$(GitBaseVersionMinor).$(GitBaseVersionPatch)$(GitSemVerDashLabel)$(VersionMetadataPlusLabel)
42 |
43 | $(GitBaseVersionMajor).$(GitBaseVersionMinor).$(GitBaseVersionPatch)$(GitSemVerDashLabel)$(VersionMetadataPlusLabel)
44 | $(BuildVersion)
45 |
46 |
47 | $([System.IO.File]::ReadAllText('$(MSBuildThisFileDirectory)..\Readme.md'))
48 |
49 | Built from $(PackageProjectUrl)/commit/$(GitCommit)
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/src/Injector/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Injector/Injector.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 |
6 | net40;net45
7 | x86;x64
8 | Win32
9 | tools
10 | false
11 | bin\$(Platform)
12 |
13 |
14 |
15 | false
16 |
17 | Xamarin.Windows.Injector
18 | Microsoft
19 | microsoft xamarin
20 | © Microsoft Corporation. All rights reserved.
21 | Allows injecting .NET code into a remote process on Windows
22 | https://github.com/xamarin/Windows.Injector
23 | https://raw.githubusercontent.com/xamarin/Windows.Injector/master/LICENSE.txt
24 | https://raw.githubusercontent.com/xamarin/Windows.Injector/master/Icon.png
25 |
26 | out
27 | $(Out)
28 |
29 |
30 |
31 | x86
32 | x86
33 | true
34 |
35 |
36 |
37 | x64
38 | x64
39 | false
40 | x64
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | {8072b47b-5611-4bab-8ef4-cb3125d676a5}
56 | VisualStudioVersion=$(VisualStudioVersion);Configuration=$(Configuration);Platform=$(BootstrapPlatform)
57 | Bootstrap
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/src/Injector/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 |
4 | namespace Injector
5 | {
6 | ///
7 | /// Helper process to allow injection into processes that have different bitness
8 | /// into WPF app processes.
9 | ///
10 | /// VS is 32-bit, so it cannot write to the memory of a 64-bit process, and delegates
11 | /// that to this program instead.
12 | ///
13 | public class Program
14 | {
15 | static void Main(string[] args)
16 | {
17 | var handle = new IntPtr(int.Parse(args[0]));
18 | var supportDllPath = args[1].Trim('"');
19 | var className = args[2].Trim('"');
20 | var methodName = args[3].Trim('"');
21 |
22 | Bootstrap.Injector.Launch(handle, supportDllPath, className, methodName);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Injector/msbuild.rsp:
--------------------------------------------------------------------------------
1 | /v:m /bl
--------------------------------------------------------------------------------
/src/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/Sample/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Sample/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Runtime.InteropServices;
7 | using System.Threading;
8 |
9 | namespace Sample
10 | {
11 | class Program
12 | {
13 | static void Main(string[] args)
14 | {
15 | var exe = args.FirstOrDefault() ?? @"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\devenv.exe";
16 |
17 | var process = Process.Start(exe);
18 | process.WaitForInputIdle();
19 | // NOTE: it's important to wait until the window handle is actually created.
20 | // this may take a while if the startup of the target app is lenghty
21 | while (process.MainWindowHandle == IntPtr.Zero)
22 | {
23 | Thread.Sleep(200);
24 | }
25 |
26 | // Inspect %LocalAppData%\Windows.Injector\log.txt to troubleshoot
27 |
28 | // Dynamic injection based on the target process bitness
29 | // using the external helper process.
30 | NativeMethods.IsWow64Process(process.Handle, out var isWow);
31 | var platform = isWow ? "x86" : "x64";
32 |
33 | Process.Start(Path.Combine("Injector", platform, "Injector.exe"),
34 | process.MainWindowHandle + " " +
35 | Assembly.GetExecutingAssembly().Location + " " +
36 | typeof(Startup).FullName + " " +
37 | $"{nameof(Startup.Start)}:hello:42:true");
38 |
39 | // API-based injection if target process has same bitness as ours
40 | Bootstrap.Injector.Launch(
41 | process.MainWindowHandle,
42 | Assembly.GetExecutingAssembly().Location,
43 | typeof(Startup).FullName,
44 | $"{nameof(Startup.Start)}:hello:42:true");
45 |
46 | Console.ReadLine();
47 |
48 | if (!process.HasExited)
49 | process.Kill();
50 | }
51 | }
52 |
53 | public static class Startup
54 | {
55 | // NOTE: parameter type conversion from the {method}:arg1:argN format is done automatically
56 | public static void Start(string arg1, int arg2, bool debug)
57 | {
58 | if (debug)
59 | Debugger.Launch();
60 | }
61 | }
62 |
63 | internal static class NativeMethods
64 | {
65 | [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
66 | [return: MarshalAs(UnmanagedType.Bool)]
67 | internal static extern bool IsWow64Process([In] IntPtr process, [Out] out bool wow64Process);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Sample/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "Sample": {
4 | "commandName": "Project",
5 | "commandLineArgs": "\"$(VsInstallRoot)\\Common7\\IDE\\devenv.exe\""
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/src/Sample/Sample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Exe
7 | net472
8 | false
9 |
10 | ..\Injector\bin
11 |
12 | x86;x64
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/Windows.Injector.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.28824.287
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Injector", "Injector\Injector.csproj", "{87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Bootstrap", "Bootstrap\Bootstrap.vcxproj", "{8072B47B-5611-4BAB-8EF4-CB3125D676A5}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DEEC9CA4-3E15-4B82-B024-F5009DB3092D}"
11 | ProjectSection(SolutionItems) = preProject
12 | ..\.editorconfig = ..\.editorconfig
13 | ..\.gitignore = ..\.gitignore
14 | ..\build.proj = ..\build.proj
15 | Directory.Build.props = Directory.Build.props
16 | Directory.Build.targets = Directory.Build.targets
17 | ..\GitInfo.txt = ..\GitInfo.txt
18 | ..\README.md = ..\README.md
19 | EndProjectSection
20 | EndProject
21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample", "Sample\Sample.csproj", "{16A5E068-9E95-4A58-AFD2-B06550E82C3F}"
22 | EndProject
23 | Global
24 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
25 | Debug|x64 = Debug|x64
26 | Debug|x86 = Debug|x86
27 | Release|x64 = Release|x64
28 | Release|x86 = Release|x86
29 | EndGlobalSection
30 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
31 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Debug|x64.ActiveCfg = Debug|x64
32 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Debug|x64.Build.0 = Debug|x64
33 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Debug|x86.ActiveCfg = Debug|x86
34 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Debug|x86.Build.0 = Debug|x86
35 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Release|x64.ActiveCfg = Release|x64
36 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Release|x64.Build.0 = Release|x64
37 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Release|x86.ActiveCfg = Release|x86
38 | {87A8FBB3-AC9F-4765-9A0E-B098D43A2DE9}.Release|x86.Build.0 = Release|x86
39 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Debug|x64.ActiveCfg = Debug|x64
40 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Debug|x64.Build.0 = Debug|x64
41 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Debug|x86.ActiveCfg = Debug|Win32
42 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Debug|x86.Build.0 = Debug|Win32
43 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Release|x64.ActiveCfg = Release|x64
44 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Release|x64.Build.0 = Release|x64
45 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Release|x86.ActiveCfg = Release|Win32
46 | {8072B47B-5611-4BAB-8EF4-CB3125D676A5}.Release|x86.Build.0 = Release|Win32
47 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Debug|x64.ActiveCfg = Debug|x64
48 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Debug|x64.Build.0 = Debug|x64
49 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Debug|x86.ActiveCfg = Debug|x86
50 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Debug|x86.Build.0 = Debug|x86
51 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Release|x64.ActiveCfg = Release|x64
52 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Release|x64.Build.0 = Release|x64
53 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Release|x86.ActiveCfg = Release|x86
54 | {16A5E068-9E95-4A58-AFD2-B06550E82C3F}.Release|x86.Build.0 = Release|x86
55 | EndGlobalSection
56 | GlobalSection(SolutionProperties) = preSolution
57 | HideSolutionNode = FALSE
58 | EndGlobalSection
59 | GlobalSection(ExtensibilityGlobals) = postSolution
60 | SolutionGuid = {C34B95A2-3544-4308-81E7-249E03E05A01}
61 | EndGlobalSection
62 | EndGlobal
63 |
--------------------------------------------------------------------------------
/src/Windows.Injector.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xamarin/Windows.Injector/efcb3e098bb701456701159b4301466556806263/src/Windows.Injector.snk
--------------------------------------------------------------------------------
/src/Xamarin.Windows.Injector.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\tools'))
6 | true
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/Xamarin.Windows.Injector.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Injector\%(RecursiveDir)%(Filename)%(Extension)
7 | PreserveNewest
8 | true
9 |
10 |
11 |
12 |
13 | $(PlatformTarget)
14 | $(Platform)
15 | $(RuntimeIdentifier)
16 |
17 |
18 |
19 |
20 | $(WindowsInjectorToolsPath)\$(BootstrapPlatform)\bootstrap.dll
21 | Xamarin.Windows.Injector
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------