├── .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 | [![Version](https://img.shields.io/nuget/vpre/Xamarin.Windows.Injector.svg)](https://www.nuget.org/packages/Xamarin.Windows.Injector) 4 | [![Downloads](https://img.shields.io/nuget/dt/Xamarin.Windows.Injector.svg)](https://www.nuget.org/packages/Xamarin.Windows.Injector) 5 | [![Build Status](https://dev.azure.com/devdiv/DevDiv/_apis/build/status/Xamarin/VisualStudio/Windows.Injector?branchName=master)](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 | --------------------------------------------------------------------------------