├── .gitignore ├── LICENSE ├── SharpNeedle.sln ├── readme.md └── src ├── Bootstrapper ├── Bootstrapper.cpp ├── Bootstrapper.h ├── Bootstrapper.vcxproj ├── Bootstrapper.vcxproj.filters ├── dllmain.cpp ├── dllmain.h ├── stdafx.h └── targetver.h ├── ExampleProject ├── Example.cs ├── ExampleProject.csproj └── Properties │ └── AssemblyInfo.cs ├── Launcher ├── HCommonEnsureCleanup.h ├── Injection.cpp ├── Injection.h ├── Launcher.cpp ├── Launcher.vcxproj ├── Launcher.vcxproj.filters └── targetver.h └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | *.pydevproject 5 | .project 6 | .metadata 7 | bin/ 8 | tmp/ 9 | *.tmp 10 | *.bak 11 | *.swp 12 | *~.nib 13 | local.properties 14 | .classpath 15 | .settings/ 16 | .loadpath 17 | 18 | # External tool builders 19 | .externalToolBuilders/ 20 | 21 | # Locally stored "Eclipse launch configurations" 22 | *.launch 23 | 24 | # CDT-specific 25 | .cproject 26 | 27 | # PDT-specific 28 | .buildpath 29 | 30 | 31 | ################# 32 | ## Visual Studio 33 | ################# 34 | 35 | ## Ignore Visual Studio temporary files, build results, and 36 | ## files generated by popular Visual Studio add-ons. 37 | 38 | # User-specific files 39 | *.suo 40 | *.user 41 | *.sln.docstates 42 | *.opendb 43 | 44 | # Build results 45 | [Dd]ebug/ 46 | [Rr]elease/ 47 | *_i.c 48 | *_p.c 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 | *.vspscc 63 | .builds 64 | *.dotCover 65 | 66 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 67 | #packages/ 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | 76 | # Visual Studio profiler 77 | *.psess 78 | *.vsp 79 | 80 | # ReSharper is a .NET coding add-in 81 | _ReSharper* 82 | 83 | # Installshield output folder 84 | [Ee]xpress 85 | 86 | # DocProject is a documentation generator add-in 87 | DocProject/buildhelp/ 88 | DocProject/Help/*.HxT 89 | DocProject/Help/*.HxC 90 | DocProject/Help/*.hhc 91 | DocProject/Help/*.hhk 92 | DocProject/Help/*.hhp 93 | DocProject/Help/Html2 94 | DocProject/Help/html 95 | 96 | # Click-Once directory 97 | publish 98 | 99 | # Others 100 | [Bb]in 101 | [Oo]bj 102 | sql 103 | TestResults 104 | *.Cache 105 | ClientBin 106 | stylecop.* 107 | ~$* 108 | *.dbmdl 109 | Generated_Code #added for RIA/Silverlight projects 110 | 111 | # Backup & report files from converting an old project file to a newer 112 | # Visual Studio version. Backup files are not needed, because we have git ;-) 113 | _UpgradeReport_Files/ 114 | Backup*/ 115 | UpgradeLog*.XML 116 | 117 | 118 | 119 | ############ 120 | ## Windows 121 | ############ 122 | 123 | # Windows image file caches 124 | Thumbs.db 125 | 126 | # Folder config file 127 | Desktop.ini 128 | 129 | 130 | ############# 131 | ## Python 132 | ############# 133 | *.py[co] 134 | 135 | # Packages 136 | *.egg 137 | *.egg-info 138 | dist 139 | build 140 | eggs 141 | parts 142 | bin 143 | var 144 | sdist 145 | develop-eggs 146 | .installed.cfg 147 | 148 | # Installer logs 149 | pip-log.txt 150 | 151 | # Unit test / coverage reports 152 | .coverage 153 | .tox 154 | 155 | #Translations 156 | *.mo 157 | 158 | #Mr Developer 159 | .mr.developer.cfg 160 | 161 | # Mac crap 162 | .DS_Store 163 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Chad Zawistowski 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 16 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | -------------------------------------------------------------------------------- /SharpNeedle.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Launcher", "src\Launcher\Launcher.vcxproj", "{04EF8D93-523D-4270-85CB-9E341A453825}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Bootstrapper", "src\Bootstrapper\Bootstrapper.vcxproj", "{25750B19-1BF6-476E-887F-1E27464F1183}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4B4EEF8C-17C3-4085-9FEB-AC16E4EC3AB8}" 9 | ProjectSection(SolutionItems) = preProject 10 | readme.md = readme.md 11 | src\readme.md = src\readme.md 12 | EndProjectSection 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleProject", "src\ExampleProject\ExampleProject.csproj", "{D6C86D36-18D6-40F2-B2FD-DFC82F79252C}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Debug|Mixed Platforms = Debug|Mixed Platforms 20 | Debug|Win32 = Debug|Win32 21 | Release|Any CPU = Release|Any CPU 22 | Release|Mixed Platforms = Release|Mixed Platforms 23 | Release|Win32 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {04EF8D93-523D-4270-85CB-9E341A453825}.Debug|Any CPU.ActiveCfg = Debug|Win32 27 | {04EF8D93-523D-4270-85CB-9E341A453825}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 28 | {04EF8D93-523D-4270-85CB-9E341A453825}.Debug|Mixed Platforms.Build.0 = Debug|Win32 29 | {04EF8D93-523D-4270-85CB-9E341A453825}.Debug|Win32.ActiveCfg = Debug|Win32 30 | {04EF8D93-523D-4270-85CB-9E341A453825}.Debug|Win32.Build.0 = Debug|Win32 31 | {04EF8D93-523D-4270-85CB-9E341A453825}.Release|Any CPU.ActiveCfg = Release|Win32 32 | {04EF8D93-523D-4270-85CB-9E341A453825}.Release|Mixed Platforms.ActiveCfg = Release|Win32 33 | {04EF8D93-523D-4270-85CB-9E341A453825}.Release|Mixed Platforms.Build.0 = Release|Win32 34 | {04EF8D93-523D-4270-85CB-9E341A453825}.Release|Win32.ActiveCfg = Release|Win32 35 | {04EF8D93-523D-4270-85CB-9E341A453825}.Release|Win32.Build.0 = Release|Win32 36 | {25750B19-1BF6-476E-887F-1E27464F1183}.Debug|Any CPU.ActiveCfg = Debug|Win32 37 | {25750B19-1BF6-476E-887F-1E27464F1183}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 38 | {25750B19-1BF6-476E-887F-1E27464F1183}.Debug|Mixed Platforms.Build.0 = Debug|Win32 39 | {25750B19-1BF6-476E-887F-1E27464F1183}.Debug|Win32.ActiveCfg = Debug|Win32 40 | {25750B19-1BF6-476E-887F-1E27464F1183}.Debug|Win32.Build.0 = Debug|Win32 41 | {25750B19-1BF6-476E-887F-1E27464F1183}.Release|Any CPU.ActiveCfg = Release|Win32 42 | {25750B19-1BF6-476E-887F-1E27464F1183}.Release|Mixed Platforms.ActiveCfg = Release|Win32 43 | {25750B19-1BF6-476E-887F-1E27464F1183}.Release|Mixed Platforms.Build.0 = Release|Win32 44 | {25750B19-1BF6-476E-887F-1E27464F1183}.Release|Win32.ActiveCfg = Release|Win32 45 | {25750B19-1BF6-476E-887F-1E27464F1183}.Release|Win32.Build.0 = Release|Win32 46 | {D6C86D36-18D6-40F2-B2FD-DFC82F79252C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {D6C86D36-18D6-40F2-B2FD-DFC82F79252C}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {D6C86D36-18D6-40F2-B2FD-DFC82F79252C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 49 | {D6C86D36-18D6-40F2-B2FD-DFC82F79252C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 50 | {D6C86D36-18D6-40F2-B2FD-DFC82F79252C}.Debug|Win32.ActiveCfg = Debug|Any CPU 51 | {D6C86D36-18D6-40F2-B2FD-DFC82F79252C}.Release|Any CPU.ActiveCfg = Release|Any CPU 52 | {D6C86D36-18D6-40F2-B2FD-DFC82F79252C}.Release|Any CPU.Build.0 = Release|Any CPU 53 | {D6C86D36-18D6-40F2-B2FD-DFC82F79252C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 54 | {D6C86D36-18D6-40F2-B2FD-DFC82F79252C}.Release|Mixed Platforms.Build.0 = Release|Any CPU 55 | {D6C86D36-18D6-40F2-B2FD-DFC82F79252C}.Release|Win32.ActiveCfg = Release|Any CPU 56 | EndGlobalSection 57 | GlobalSection(SolutionProperties) = preSolution 58 | HideSolutionNode = FALSE 59 | EndGlobalSection 60 | EndGlobal 61 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # SharpNeedle 2 | 3 | A project for properly injecting C# dlls into other processes. 4 | 5 | Note: SharpNeedle currently only supports 32-bit processes. You are welcome to create a pull request which adds 64-bit support. 6 | 7 | ## Rationale 8 | 9 | While merely loading your custom dll injected into a target process' memory 10 | space is fun, that is only half of the story. Most dll injection tutorials will 11 | describe in detail the first half, but then leave you to run your code from 12 | within DllMain, a dangerous and limited proposition. For more information about 13 | why you should avoid doing anything interesting in your DllMain, read 14 | [this thread](http://blogs.msdn.com/b/oldnewthing/archive/2004/01/27/63401.aspx) 15 | by Raymond Chen. 16 | 17 | This project aims to change that dearth of good dll-injection info, providing an 18 | open-source way of not only injecting a dll, but also walking the export address 19 | table and calling a method on your dll. 20 | 21 | This project is specifically geared towards injecting managed code into another 22 | process. We will first inject the "Bootstrapper" module, then tell it to load 23 | the CLR and start our example managed project. 24 | 25 | ## Usage 26 | 27 | Developed in Visual Studio Community 2015 on Windows 10. 28 | 29 | In src\Launcher\Launcher.cpp, specify the process name to inject into. 30 | In src\ExampleProject\Example.cs, customize EntryPoint() to do as you like. 31 | Ensure the process you are injecting into is running. 32 | Compile and run with appropriate permission levels. I use an unelevated Visual Studio, then run output from an Administrator command prompt. 33 | 34 | ## Developers 35 | 36 | The most interesting file is src\Launcher\Injection.cpp, which deals with walking DLL export tables and creating remote threads. 37 | 38 | 39 | ## License 40 | 41 | The entirety of my work on this project is released under the 2-clause BSD license. 42 | 43 | 'src\Launcher\HCommonEnsureCleanup.h' was provided courtesy of [GameDeception.net](http://www.gamedeception.net/forums/184-Windows-Internals) and its license is unclear. 44 | -------------------------------------------------------------------------------- /src/Bootstrapper/Bootstrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #pragma comment(lib, "mscoree.lib") 4 | 5 | #include "Bootstrapper.h" 6 | 7 | DllExport void LoadManagedProject(const wchar_t * managedDllLocation) 8 | { 9 | HRESULT hr; 10 | 11 | // Secure a handle to the CLR v4.0 12 | ICLRRuntimeHost* pClr = StartCLR(L"v4.0.30319"); 13 | if (pClr != NULL) 14 | { 15 | DWORD result; 16 | hr = pClr->ExecuteInDefaultAppDomain( 17 | managedDllLocation, 18 | L"ExampleProject.Example", 19 | L"EntryPoint", 20 | L"Argument", 21 | &result); 22 | } 23 | } 24 | 25 | ICLRRuntimeHost* StartCLR(LPCWSTR dotNetVersion) 26 | { 27 | HRESULT hr; 28 | 29 | ICLRMetaHost* pClrMetaHost = NULL; 30 | ICLRRuntimeInfo* pClrRuntimeInfo = NULL; 31 | ICLRRuntimeHost* pClrRuntimeHost = NULL; 32 | 33 | // Get the CLRMetaHost that tells us about .NET on this machine 34 | hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pClrMetaHost); 35 | if (hr == S_OK) 36 | { 37 | // Get the runtime information for the particular version of .NET 38 | hr = pClrMetaHost->GetRuntime(dotNetVersion, IID_PPV_ARGS(&pClrRuntimeInfo)); 39 | if (hr == S_OK) 40 | { 41 | // Check if the specified runtime can be loaded into the process. This 42 | // method will take into account other runtimes that may already be 43 | // loaded into the process and set pbLoadable to TRUE if this runtime can 44 | // be loaded in an in-process side-by-side fashion. 45 | BOOL fLoadable; 46 | hr = pClrRuntimeInfo->IsLoadable(&fLoadable); 47 | if ((hr == S_OK) && fLoadable) 48 | { 49 | // Load the CLR into the current process and return a runtime interface 50 | // pointer. 51 | hr = pClrRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, 52 | IID_PPV_ARGS(&pClrRuntimeHost)); 53 | if (hr == S_OK) 54 | { 55 | // Start it. This is okay to call even if the CLR is already running 56 | pClrRuntimeHost->Start(); 57 | return pClrRuntimeHost; 58 | } 59 | } 60 | } 61 | } 62 | 63 | // Cleanup if failed 64 | if (pClrRuntimeHost) 65 | { 66 | pClrRuntimeHost->Release(); 67 | pClrRuntimeHost = NULL; 68 | } 69 | if (pClrRuntimeInfo) 70 | { 71 | pClrRuntimeInfo->Release(); 72 | pClrRuntimeInfo = NULL; 73 | } 74 | if (pClrMetaHost) 75 | { 76 | pClrMetaHost->Release(); 77 | pClrMetaHost = NULL; 78 | } 79 | 80 | return NULL; 81 | } 82 | -------------------------------------------------------------------------------- /src/Bootstrapper/Bootstrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.h" 3 | #include 4 | #pragma comment(lib, "mscoree.lib") 5 | 6 | // For exporting functions without name-mangling 7 | #define DllExport extern "C" __declspec( dllexport ) 8 | 9 | // Our sole export for the time being 10 | DllExport void LoadManagedProject(const wchar_t * managedDllLocation); 11 | 12 | // Not exporting, so go ahead and name-mangle 13 | ICLRRuntimeHost* StartCLR(LPCWSTR dotNetVersion); 14 | -------------------------------------------------------------------------------- /src/Bootstrapper/Bootstrapper.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {25750B19-1BF6-476E-887F-1E27464F1183} 15 | Win32Proj 16 | Venom 17 | 18 | 19 | 20 | DynamicLibrary 21 | true 22 | v140 23 | Unicode 24 | 25 | 26 | DynamicLibrary 27 | false 28 | v140 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | $(SolutionDir)bin\$(Configuration)\ 45 | 46 | 47 | false 48 | true 49 | 50 | 51 | 52 | Use 53 | Level3 54 | Disabled 55 | WIN32;_DEBUG;_WINDOWS;_USRDLL;VENOM_EXPORTS;%(PreprocessorDefinitions) 56 | true 57 | 58 | 59 | Windows 60 | true 61 | 62 | 63 | 64 | 65 | Level3 66 | NotUsing 67 | MaxSpeed 68 | true 69 | true 70 | WIN32;NDEBUG;_WINDOWS;_USRDLL;VENOM_EXPORTS;%(PreprocessorDefinitions) 71 | true 72 | true 73 | 74 | 75 | Windows 76 | true 77 | true 78 | true 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | Create 90 | 91 | 92 | false 93 | 94 | 95 | false 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /src/Bootstrapper/Bootstrapper.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 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/Bootstrapper/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | 4 | #include "dllmain.h" 5 | 6 | BOOL APIENTRY DllMain( HMODULE hModule, 7 | DWORD ul_reason_for_call, 8 | LPVOID lpReserved 9 | ) 10 | { 11 | switch (ul_reason_for_call) 12 | { 13 | case DLL_PROCESS_ATTACH: 14 | //DisplayPid(); 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | 21 | return TRUE; 22 | } 23 | 24 | void DisplayPid() 25 | { 26 | DWORD pid = GetCurrentProcessId(); 27 | wchar_t buf[64]; 28 | wsprintf(buf, L"Hey, it worked! Pid is %d", pid); 29 | 30 | MessageBox(NULL, buf, L"Injected MessageBox", NULL); 31 | } 32 | -------------------------------------------------------------------------------- /src/Bootstrapper/dllmain.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stdafx.h" 4 | #include 5 | 6 | /** 7 | * Displays the pid of the current process. 8 | * Mainly included for debugging purposes. 9 | */ 10 | void DisplayPid(); 11 | 12 | /** 13 | * Dll entry point. 14 | */ 15 | BOOL APIENTRY DllMain( HMODULE hModule, 16 | DWORD ul_reason_for_call, 17 | LPVOID lpReserved 18 | ); 19 | -------------------------------------------------------------------------------- /src/Bootstrapper/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "targetver.h" 4 | 5 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 6 | #include 7 | 8 | #include "Bootstrapper.h" 9 | -------------------------------------------------------------------------------- /src/Bootstrapper/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /src/ExampleProject/Example.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Windows.Forms; 7 | 8 | namespace ExampleProject 9 | { 10 | public class Example 11 | { 12 | public static int EntryPoint(string pwzArgument) 13 | { 14 | string processName = Process.GetCurrentProcess().ProcessName; 15 | MessageBox.Show("The current process is " + processName); 16 | return 0; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/ExampleProject/ExampleProject.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {D6C86D36-18D6-40F2-B2FD-DFC82F79252C} 8 | Library 9 | Properties 10 | ExampleProject 11 | ExampleProject 12 | v4.0 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | $(SolutionDir)bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | $(SolutionDir)bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 54 | -------------------------------------------------------------------------------- /src/ExampleProject/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using System.Security; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("ExampleProject")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("ExampleProject")] 14 | [assembly: AssemblyCopyright("Copyright © 2013")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // Setting ComVisible to false makes the types in this assembly not visible 19 | // to COM components. If you need to access a type in this assembly from 20 | // COM, set the ComVisible attribute to true on that type. 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | [assembly: Guid("56f092c5-a229-44ee-8862-f8d33761ffcb")] 25 | 26 | // Version information for an assembly consists of the following four values: 27 | // 28 | // Major Version 29 | // Minor Version 30 | // Build Number 31 | // Revision 32 | // 33 | // You can specify all the values or you can default the Build and Revision Numbers 34 | // by using the '*' as shown below: 35 | // [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyVersion("1.0.0.0")] 37 | [assembly: AssemblyFileVersion("1.0.0.0")] 38 | [assembly: AllowPartiallyTrustedCallers] 39 | -------------------------------------------------------------------------------- /src/Launcher/HCommonEnsureCleanup.h: -------------------------------------------------------------------------------- 1 | // Source code courtesy of http://www.gamedeception.net/forums/184-Windows-Internals 2 | 3 | #pragma once 4 | #ifndef HCOMMON__ENSURECLEANUP_H 5 | #define HCOMMON__ENSURECLEANUP_H 6 | 7 | // Windows API 8 | #include 9 | 10 | // Hades namespace 11 | namespace Hades 12 | { 13 | // Data type representing the address of the object's cleanup function. 14 | // I used UINT_PTR so that this class works properly in 64-bit Windows. 15 | typedef VOID (WINAPI* PFNENSURECLEANUP)(UINT_PTR); 16 | 17 | // Each template instantiation requires a data type, address of cleanup 18 | // function, and a value that indicates an invalid value. 19 | template 20 | class EnsureCleanup 21 | { 22 | public: 23 | // Default constructor assumes an invalid value (nothing to cleanup) 24 | EnsureCleanup() 25 | { m_t = tInvalid; } 26 | 27 | // This constructor sets the value to the specified value 28 | EnsureCleanup(TYPE t) : m_t((UINT_PTR) t) 29 | { } 30 | 31 | // The destructor performs the cleanup. 32 | ~EnsureCleanup() 33 | { Cleanup(); } 34 | 35 | // Helper methods to tell if the value represents a valid object or not.. 36 | BOOL IsValid() const 37 | { return(m_t != tInvalid); } 38 | BOOL IsInvalid() const 39 | { return(!IsValid()); } 40 | 41 | // Re-assigning the object forces the current object to be cleaned-up. 42 | TYPE operator= (TYPE t) 43 | { 44 | Cleanup(); 45 | m_t = (UINT_PTR) t; 46 | return(*this); 47 | } 48 | 49 | // Returns the value (supports both 32-bit and 64-bit Windows). 50 | operator TYPE() const 51 | { return (TYPE) m_t; } 52 | 53 | // Cleanup the object if the value represents a valid object 54 | void Cleanup() 55 | { 56 | if (IsValid()) 57 | { 58 | // In 64-bit Windows, all parameters are 64-bits, 59 | // so no casting is required 60 | pfn(m_t); // Close the object. 61 | m_t = tInvalid; // We no longer represent a valid object. 62 | } 63 | } 64 | 65 | private: 66 | UINT_PTR m_t; // The member representing the object 67 | }; 68 | 69 | // Macros to make it easier to declare instances of the template 70 | // class for specific data types. 71 | 72 | #define MakeCleanupClass(className, tData, pfnCleanup) \ 73 | typedef EnsureCleanup className 74 | 75 | #define MakeCleanupClassX(className, tData, pfnCleanup, tInvalid) \ 76 | typedef EnsureCleanup className 78 | 79 | // Instances of the template C++ class for common data types. 80 | MakeCleanupClass(EnsureCloseHandle, HANDLE, CloseHandle); 81 | MakeCleanupClass(EnsureLocalFree, HLOCAL, LocalFree); 82 | MakeCleanupClass(EnsureGlobalFree, HGLOBAL, GlobalFree); 83 | MakeCleanupClass(EnsureGlobalUnlock, LPVOID, GlobalUnlock); 84 | MakeCleanupClass(EnsureRegCloseKey, HKEY, RegCloseKey); 85 | MakeCleanupClass(EnsureCloseServiceHandle, SC_HANDLE, CloseServiceHandle); 86 | MakeCleanupClass(EnsureCloseWindowStation, HWINSTA, CloseWindowStation); 87 | MakeCleanupClass(EnsureCloseDesktop, HDESK, CloseDesktop); 88 | MakeCleanupClass(EnsureUnmapViewOfFile, PVOID, UnmapViewOfFile); 89 | MakeCleanupClass(EnsureFreeLibrary, HMODULE, FreeLibrary); 90 | MakeCleanupClass(EnsureRemoveVEH, PVOID, RemoveVectoredExceptionHandler); 91 | MakeCleanupClassX(EnsureCloseFile, HANDLE, CloseHandle, INVALID_HANDLE_VALUE); 92 | 93 | // Special class for releasing a reserved region. 94 | // Special class is required because VirtualFree requires 3 parameters 95 | class EnsureReleaseRegion 96 | { 97 | public: 98 | EnsureReleaseRegion(PVOID pv = NULL) : m_pv(pv) 99 | { } 100 | 101 | ~EnsureReleaseRegion() 102 | { Cleanup(); } 103 | 104 | PVOID operator= (PVOID pv) 105 | { 106 | Cleanup(); 107 | m_pv = pv; 108 | return(m_pv); 109 | } 110 | 111 | operator PVOID() const 112 | { return(m_pv); } 113 | 114 | void Cleanup() 115 | { 116 | if (m_pv != NULL) 117 | { 118 | VirtualFree(m_pv, 0, MEM_RELEASE); 119 | m_pv = NULL; 120 | } 121 | } 122 | 123 | private: 124 | PVOID m_pv; 125 | }; 126 | 127 | // Special class for freeing a block from a heap 128 | // Special class is required because HeapFree requires 3 parameters 129 | class EnsureHeapFree 130 | { 131 | public: 132 | EnsureHeapFree(PVOID pv = NULL, HANDLE hHeap = GetProcessHeap()) 133 | : m_pv(pv), m_hHeap(hHeap) 134 | { } 135 | ~EnsureHeapFree() 136 | { Cleanup(); } 137 | 138 | PVOID operator= (PVOID pv) 139 | { 140 | Cleanup(); 141 | m_pv = pv; 142 | return(m_pv); 143 | } 144 | 145 | operator PVOID() const 146 | { return(m_pv); } 147 | 148 | void Cleanup() 149 | { 150 | if (m_pv != NULL) 151 | { 152 | HeapFree(m_hHeap, 0, m_pv); 153 | m_pv = NULL; 154 | } 155 | } 156 | 157 | private: 158 | HANDLE m_hHeap; 159 | PVOID m_pv; 160 | }; 161 | 162 | // Special class for releasing a remote reserved region. 163 | // Special class is required because VirtualFreeEx requires 4 parameters 164 | class EnsureReleaseRegionEx 165 | { 166 | public: 167 | EnsureReleaseRegionEx(PVOID pv = NULL, HANDLE proc = NULL) : m_pv(pv), 168 | m_proc(proc) 169 | { } 170 | ~EnsureReleaseRegionEx() 171 | { Cleanup(); } 172 | 173 | PVOID operator= (PVOID pv) 174 | { 175 | Cleanup(); 176 | m_pv = pv; 177 | return(m_pv); 178 | } 179 | 180 | operator PVOID() const 181 | { return(m_pv); } 182 | 183 | void Cleanup() 184 | { 185 | if (m_pv != NULL && m_proc != NULL) 186 | { 187 | VirtualFreeEx(m_proc, m_pv, 0, MEM_RELEASE); 188 | m_pv = NULL; 189 | } 190 | } 191 | 192 | private: 193 | PVOID m_pv; 194 | HANDLE m_proc; 195 | }; 196 | 197 | // Special class for closing the clipboard. 198 | // Special class is required because no params are required. 199 | class EnsureCloseClipboard 200 | { 201 | public: 202 | EnsureCloseClipboard(BOOL Success) : m_Success(Success) 203 | { } 204 | ~EnsureCloseClipboard() 205 | { Cleanup(); } 206 | 207 | BOOL operator= (BOOL Success) 208 | { 209 | Cleanup(); 210 | m_Success = Success; 211 | return(m_Success); 212 | } 213 | 214 | operator BOOL() const 215 | { return(m_Success); } 216 | 217 | void Cleanup() 218 | { 219 | if (m_Success) 220 | { 221 | CloseClipboard(); 222 | m_Success = FALSE; 223 | } 224 | } 225 | 226 | private: 227 | BOOL m_Success; 228 | }; 229 | } 230 | 231 | #endif // HCOMMON__ENSURECLEANUP_H 232 | -------------------------------------------------------------------------------- /src/Launcher/Injection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Injection.h" 8 | #include "HCommonEnsureCleanup.h" 9 | 10 | DWORD GetProcessIdByName(const char * name) 11 | { 12 | using namespace Hades; 13 | 14 | PROCESSENTRY32 entry; 15 | entry.dwSize = sizeof(PROCESSENTRY32); 16 | char buf[MAX_PATH]={0}; 17 | size_t charsConverted=0; 18 | 19 | EnsureCloseHandle snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); 20 | 21 | if(Process32First(snapshot, &entry) == TRUE) 22 | { 23 | while(Process32Next(snapshot, &entry) == TRUE) 24 | { 25 | wcstombs_s(&charsConverted, buf, entry.szExeFile, MAX_PATH); 26 | if(_stricmp(buf, name) == 0) 27 | { 28 | return entry.th32ProcessID; 29 | } 30 | } 31 | } 32 | return NULL; 33 | } 34 | 35 | BOOL InjectAndRunThenUnload(DWORD ProcessId, const char * DllName, const std::string& ExportName, const wchar_t * ExportArgument) 36 | { 37 | using namespace Hades; 38 | using namespace std; 39 | 40 | // This doesn't need to be freed 41 | HMODULE hKernel32 = GetModuleHandle(L"kernel32.dll"); 42 | 43 | if(!ProcessId) 44 | { 45 | cout << "Specified Process not found" << endl; 46 | return false; 47 | } 48 | 49 | EnsureCloseHandle Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId); 50 | 51 | if(!Proc) 52 | { 53 | cout << "Process found, but OpenProcess() failed: " << GetLastError() << endl; 54 | return false; 55 | } 56 | 57 | // LoadLibraryA needs a string as its argument, but it needs to be in 58 | // the remote Process' memory space. 59 | size_t StrLength = strlen(DllName); 60 | LPVOID RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, StrLength, 61 | MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); 62 | WriteProcessMemory(Proc, RemoteString, DllName, StrLength, NULL); 63 | 64 | // Start a remote thread on the targeted Process, using LoadLibraryA 65 | // as our entry point to load a custom dll. (The A is for Ansi) 66 | EnsureCloseHandle LoadThread = CreateRemoteThread(Proc, NULL, NULL, 67 | (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryA"), 68 | RemoteString, NULL, NULL); 69 | WaitForSingleObject(LoadThread, INFINITE); 70 | 71 | // Get the handle of the now loaded module 72 | DWORD hLibModule; 73 | GetExitCodeThread(LoadThread, &hLibModule); 74 | 75 | // Clean up the remote string 76 | VirtualFreeEx(Proc, RemoteString, 0, MEM_RELEASE); 77 | 78 | // Call the function we wanted in the first place 79 | CallExport(ProcessId, DllName, ExportName, ExportArgument); 80 | 81 | // Unload the dll, so we can run again if we choose 82 | EnsureCloseHandle FreeThread = CreateRemoteThread(Proc, NULL, NULL, 83 | (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "FreeLibrary"), 84 | (LPVOID)hLibModule, NULL, NULL); 85 | WaitForSingleObject(FreeThread, INFINITE); 86 | 87 | return true; 88 | } 89 | 90 | DWORD CallExport(DWORD ProcId, const std::string& ModuleName, const std::string& ExportName, const wchar_t * ExportArgument) 91 | { 92 | using namespace Hades; 93 | using namespace std; 94 | 95 | // Grab a new Snapshot of the process 96 | EnsureCloseHandle Snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcId)); 97 | if (Snapshot == INVALID_HANDLE_VALUE) 98 | { 99 | cout << "CallExport: Could not get module Snapshot for remote process." << endl; 100 | return NULL; 101 | } 102 | 103 | // Get the ModuleEntry structure of the desired library 104 | MODULEENTRY32W ModEntry = { sizeof(ModEntry) }; 105 | bool Found = false; 106 | BOOL bMoreMods = Module32FirstW(Snapshot, &ModEntry); 107 | for (; bMoreMods; bMoreMods = Module32NextW(Snapshot, &ModEntry)) 108 | { 109 | wstring ExePath(ModEntry.szExePath); 110 | wstring ModuleTmp(ModuleName.begin(), ModuleName.end()); 111 | // For debug 112 | wcout << ExePath << endl; 113 | Found = (ExePath == ModuleTmp); 114 | if (Found) 115 | break; 116 | } 117 | if (!Found) 118 | { 119 | cout << "CallExport: Could not find module in remote process." << endl; 120 | return NULL; 121 | } 122 | 123 | // Get module base address 124 | PBYTE ModuleBase = ModEntry.modBaseAddr; 125 | 126 | // Get a handle for the target process 127 | EnsureCloseHandle TargetProcess(OpenProcess( 128 | PROCESS_QUERY_INFORMATION | 129 | PROCESS_CREATE_THREAD | 130 | PROCESS_VM_OPERATION | 131 | PROCESS_VM_READ, 132 | FALSE, ProcId)); 133 | if (!TargetProcess) 134 | { 135 | cout << "CallExport: Could not get handle to process." << endl; 136 | return NULL; 137 | } 138 | 139 | // Load module as data so we can read the export address table (EAT) locally. 140 | EnsureFreeLibrary MyModule(LoadLibraryExA(ModuleName.c_str(), NULL, 141 | DONT_RESOLVE_DLL_REFERENCES)); 142 | 143 | // Get module pointer 144 | PVOID Module = static_cast(MyModule); 145 | 146 | // Get pointer to DOS header 147 | PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast( 148 | static_cast(Module)); 149 | if (!pDosHeader || pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) 150 | { 151 | cout << "CallExport: DOS PE header is invalid." << endl; 152 | return NULL; 153 | } 154 | 155 | // Get pointer to NT header 156 | PIMAGE_NT_HEADERS pNtHeader = reinterpret_cast( 157 | reinterpret_cast(Module) + pDosHeader->e_lfanew); 158 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) 159 | { 160 | cout << "CallExport: NT PE header is invalid." << endl; 161 | return NULL; 162 | } 163 | 164 | // Get pointer to image export directory 165 | PVOID pExportDirTemp = reinterpret_cast(Module) + 166 | pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]. 167 | VirtualAddress; 168 | PIMAGE_EXPORT_DIRECTORY pExportDir = 169 | reinterpret_cast(pExportDirTemp); 170 | 171 | // Symbol names could be missing entirely 172 | if (pExportDir->AddressOfNames == NULL) 173 | { 174 | cout << "CallExport: Symbol names missing entirely." << endl; 175 | return NULL; 176 | } 177 | 178 | // Get pointer to export names table, ordinal table, and address table 179 | PDWORD pNamesRvas = reinterpret_cast( 180 | reinterpret_cast(Module) + pExportDir->AddressOfNames); 181 | PWORD pNameOrdinals = reinterpret_cast( 182 | reinterpret_cast(Module) + pExportDir->AddressOfNameOrdinals); 183 | PDWORD pFunctionAddresses = reinterpret_cast( 184 | reinterpret_cast(Module) + pExportDir->AddressOfFunctions); 185 | 186 | // Variable to hold the export address 187 | FARPROC pExportAddr = 0; 188 | 189 | // Walk the array of this module's function names 190 | for (DWORD n = 0; n < pExportDir->NumberOfNames; n++) 191 | { 192 | // Get the function name 193 | PSTR CurrentName = reinterpret_cast( 194 | reinterpret_cast(Module) + pNamesRvas[n]); 195 | 196 | // If not the specified function, try the next one 197 | if (ExportName != CurrentName) continue; 198 | 199 | // We found the specified function 200 | // Get this function's Ordinal value 201 | WORD Ordinal = pNameOrdinals[n]; 202 | 203 | // Get the address of this function's address 204 | pExportAddr = reinterpret_cast(reinterpret_cast(Module) 205 | + pFunctionAddresses[Ordinal]); 206 | 207 | // We got the func. Break out. 208 | break; 209 | } 210 | 211 | // Nothing found, throw exception 212 | if (!pExportAddr) 213 | { 214 | cout << "CallExport: Could not find " << ExportName << "." << endl; 215 | return NULL; 216 | } 217 | 218 | // Convert local address to remote address 219 | PTHREAD_START_ROUTINE pfnThreadRtn = 220 | reinterpret_cast((reinterpret_cast( 221 | pExportAddr) - reinterpret_cast(Module)) + 222 | reinterpret_cast(ModuleBase)); 223 | 224 | // Open the process so we can create the remote string 225 | EnsureCloseHandle Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcId); 226 | 227 | // Copy the string argument over to the remote process 228 | size_t StrNumBytes = wcslen(ExportArgument) * sizeof(wchar_t); 229 | LPVOID RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, StrNumBytes, 230 | MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); 231 | WriteProcessMemory(Proc, RemoteString, ExportArgument, StrNumBytes, NULL); 232 | 233 | // Create a remote thread that calls the desired export 234 | EnsureCloseHandle Thread = CreateRemoteThread(TargetProcess, NULL, NULL, 235 | (LPTHREAD_START_ROUTINE)pfnThreadRtn, RemoteString, NULL, NULL); 236 | if (!Thread) 237 | { 238 | cout << "CallExport: Could not create thread in remote process." << endl; 239 | return NULL; 240 | } 241 | 242 | // Wait for the remote thread to terminate 243 | WaitForSingleObject(Thread, INFINITE); 244 | 245 | // Get thread exit code 246 | DWORD ExitCode = 0; 247 | if (!GetExitCodeThread(Thread, &ExitCode)) 248 | { 249 | cout << "CallExport: Could not get thread exit code." << endl; 250 | return NULL; 251 | } 252 | 253 | // Return thread exit code 254 | return ExitCode; 255 | } 256 | -------------------------------------------------------------------------------- /src/Launcher/Injection.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* Given a cstring, returns the pid of a running executable, or NULL if the 7 | * executable was not found. In the case of multiple executables, returns 8 | * the first one found. 9 | */ 10 | DWORD GetProcessIdByName(const char * name); 11 | 12 | /* Injects the specified dll into a running process, calls a specific 13 | * method on that dll, then unloads the dll. 14 | */ 15 | BOOL InjectAndRunThenUnload(DWORD processId, const char * dllName, const std::string& ExportName, const wchar_t * ExportArgument); 16 | 17 | /* Given a pid, a dll name, and a method name, walks the export address 18 | * table then calls the named method. 19 | */ 20 | DWORD CallExport(DWORD ProcId, const std::string& ModuleName, const std::string& ExportName, const wchar_t * ExportArgument); 21 | -------------------------------------------------------------------------------- /src/Launcher/Launcher.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Injection.h" 8 | 9 | using namespace std; 10 | 11 | /* There are two defined entry points here, one for a Windows 12 | * application, and another for a console application. 13 | * 14 | * To switch between the two versions, we need to change our 15 | * subsystem dependency and then rebuild. The compiler will 16 | * automatically choose the appropriate entry point. 17 | * 18 | * To enable Windows (hidden) mode, go to project properties, find the 19 | * 'linker' section and change the SubSystem option to Windows. 20 | * 21 | * To enable console (debugging) mode, go to project properties, find 22 | * the 'linker' section and change the SubSystem option to Console. 23 | */ 24 | 25 | /* Since there are two entry points for this program, we really 26 | * ought to get to a common point as soon as possible. This is that 27 | * common point. 28 | */ 29 | void true_main() { 30 | // Bootstrapper 31 | char DllName[MAX_PATH]; 32 | GetCurrentDirectoryA(MAX_PATH, DllName); 33 | strcat_s(DllName, "\\Bootstrapper.dll"); 34 | 35 | // ExampleProject 36 | wchar_t DllNameW[MAX_PATH]; 37 | GetCurrentDirectory(MAX_PATH, DllNameW); 38 | wcscat_s(DllNameW, L"\\ExampleProject.dll"); 39 | 40 | DWORD Pid = GetProcessIdByName("GoldWave.exe"); 41 | InjectAndRunThenUnload(Pid, DllName, "LoadManagedProject", DllNameW); 42 | } 43 | 44 | /* By starting as a Windows application but not displaying any 45 | * windows, we can become effectively invisible. 46 | */ 47 | int __stdcall WinMain (HINSTANCE hInstance, 48 | HINSTANCE hPrevInstance, 49 | LPSTR lpCmdLine, 50 | int cmdShow) 51 | { 52 | true_main(); 53 | return 0; 54 | } 55 | 56 | /* In any case, it's useful to have a console window visible 57 | * for debugging purposes. Use cout to your heart's content! 58 | */ 59 | int main() 60 | { 61 | true_main(); 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /src/Launcher/Launcher.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {04EF8D93-523D-4270-85CB-9E341A453825} 15 | Win32Proj 16 | HaxPlusPlus 17 | 18 | 19 | 20 | Application 21 | true 22 | v140 23 | Unicode 24 | 25 | 26 | Application 27 | false 28 | v140 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | $(SolutionDir)bin\$(Configuration)\ 45 | true 46 | 47 | 48 | false 49 | 50 | 51 | 52 | NotUsing 53 | Level3 54 | Disabled 55 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 56 | true 57 | true 58 | 59 | 60 | Console 61 | true 62 | 63 | 64 | 65 | 66 | Level3 67 | NotUsing 68 | MaxSpeed 69 | true 70 | true 71 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 72 | true 73 | 74 | 75 | Windows 76 | true 77 | true 78 | true 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/Launcher/Launcher.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 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/Launcher/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /src/readme.md: -------------------------------------------------------------------------------- 1 | # Project Structure 2 | 3 | ### Launcher.exe (native) 4 | 5 | This injects Bootstrapper.dll into the specified process, then invokes one if its functions. 6 | 7 | ### Bootstrapper.dll (native) 8 | 9 | This is the first dll to be injected. When invoked, this attaches to the CLR (v4.0), loads 10 | ExampleProject.dll using it, and lastly invokes the main method of ExampleProject. 11 | 12 | ### ExampleProject.dll (managed) 13 | 14 | This is the managed project, which is injected second. You must preserve the signature of the 15 | entry method, but this project can otherwise modified to do whatever you wish. Since it is in 16 | the target process' memory space, pointers can be used to access the target's data structures. 17 | (Either via P/Invoke or unsafe code blocks.) 18 | --------------------------------------------------------------------------------