├── .gitignore ├── Coverage.7z ├── LICENSE ├── README.md ├── Source ├── Icon.png ├── Reloaded.Injector.Shared │ ├── Reloaded.Injector.Shared.csproj │ └── TwoNumbers.cs ├── Reloaded.Injector.Tests.Dll32 │ ├── Calculator.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── Reloaded.Injector.Tests.Dll32.csproj ├── Reloaded.Injector.Tests.Dll64 │ ├── Calculator.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── Reloaded.Injector.Tests.Dll64.csproj ├── Reloaded.Injector.Tests.X64 │ ├── HelloWorld.cs │ ├── HelloWorld32.exe │ ├── HelloWorld64.exe │ ├── HelloWorldFixture.cs │ ├── Reloaded.Injector.Tests.X64.csproj │ └── xunit.runner.json ├── Reloaded.Injector.Tests.X86 │ ├── HelloWorld.cs │ ├── HelloWorld32.exe │ ├── HelloWorldFixture.cs │ ├── Reloaded.Injector.Tests.X86.csproj │ └── xunit.runner.json ├── Reloaded.Injector.sln └── Reloaded.Injector │ ├── Exceptions │ ├── DllInjectorException.cs │ └── ShellCodeGeneratorException.cs │ ├── Injector.cs │ ├── Interop │ ├── ModuleCollector.cs │ └── Structures │ │ └── Module.cs │ ├── Kernel32 │ └── Kernel32.cs │ ├── Reloaded.Injector.csproj │ ├── Safety.cs │ └── Shellcode.cs └── codecov.yml /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | Coverage.xml 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | *.sap 88 | 89 | # TFS 2012 Local Workspace 90 | $tf/ 91 | 92 | # Guidance Automation Toolkit 93 | *.gpState 94 | 95 | # ReSharper is a .NET coding add-in 96 | _ReSharper*/ 97 | *.[Rr]e[Ss]harper 98 | *.DotSettings.user 99 | 100 | # JustCode is a .NET coding add-in 101 | .JustCode 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | _NCrunch_* 111 | .*crunch*.local.xml 112 | nCrunchTemp_* 113 | 114 | # MightyMoose 115 | *.mm.* 116 | AutoTest.Net/ 117 | 118 | # Web workbench (sass) 119 | .sass-cache/ 120 | 121 | # Installshield output folder 122 | [Ee]xpress/ 123 | 124 | # DocProject is a documentation generator add-in 125 | DocProject/buildhelp/ 126 | DocProject/Help/*.HxT 127 | DocProject/Help/*.HxC 128 | DocProject/Help/*.hhc 129 | DocProject/Help/*.hhk 130 | DocProject/Help/*.hhp 131 | DocProject/Help/Html2 132 | DocProject/Help/html 133 | 134 | # Click-Once directory 135 | publish/ 136 | 137 | # Publish Web Output 138 | *.[Pp]ublish.xml 139 | *.azurePubxml 140 | # TODO: Comment the next line if you want to checkin your web deploy settings 141 | # but database connection strings (with potential passwords) will be unencrypted 142 | *.pubxml 143 | *.publishproj 144 | 145 | # NuGet Packages 146 | *.nupkg 147 | # The packages folder can be ignored because of Package Restore 148 | **/packages/* 149 | # except build/, which is used as an MSBuild target. 150 | !**/packages/build/ 151 | # Uncomment if necessary however generally it will be regenerated when needed 152 | #!**/packages/repositories.config 153 | 154 | # Windows Azure Build Output 155 | csx/ 156 | *.build.csdef 157 | 158 | # Windows Store app package directory 159 | AppPackages/ 160 | 161 | # Visual Studio cache files 162 | # files ending in .cache can be ignored 163 | *.[Cc]ache 164 | # but keep track of directories ending in .cache 165 | !*.[Cc]ache/ 166 | 167 | # Others 168 | ClientBin/ 169 | [Ss]tyle[Cc]op.* 170 | ~$* 171 | *~ 172 | *.dbmdl 173 | *.dbproj.schemaview 174 | *.pfx 175 | *.publishsettings 176 | node_modules/ 177 | orleans.codegen.cs 178 | 179 | # RIA/Silverlight projects 180 | Generated_Code/ 181 | 182 | # Backup & report files from converting an old project file 183 | # to a newer Visual Studio version. Backup files are not needed, 184 | # because we have git ;-) 185 | _UpgradeReport_Files/ 186 | Backup*/ 187 | UpgradeLog*.XML 188 | UpgradeLog*.htm 189 | 190 | # SQL Server files 191 | *.mdf 192 | *.ldf 193 | 194 | # Business Intelligence projects 195 | *.rdl.data 196 | *.bim.layout 197 | *.bim_*.settings 198 | 199 | # Microsoft Fakes 200 | FakesAssemblies/ 201 | 202 | # Node.js Tools for Visual Studio 203 | .ntvs_analysis.dat 204 | 205 | # Visual Studio 6 build log 206 | *.plg 207 | 208 | # Visual Studio 6 workspace options file 209 | *.opt 210 | 211 | # Visual Studio LightSwitch build output 212 | **/*.HTMLClient/GeneratedArtifacts 213 | **/*.DesktopClient/GeneratedArtifacts 214 | **/*.DesktopClient/ModelManifest.xml 215 | **/*.Server/GeneratedArtifacts 216 | **/*.Server/ModelManifest.xml 217 | _Pvt_Extensions 218 | -------------------------------------------------------------------------------- /Coverage.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reloaded-Project/Reloaded.Injector/ffc33e18bc4024e009bbd6b637dff31c042b7dd4/Coverage.7z -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |  2 | 3 |
4 |

Project Reloaded: Injector

5 | 6 |

7 | Crossing the WoW boundaries 8 |

9 | 10 | 11 | Coverage 12 | 13 | 14 | 15 | NuGet 16 | 17 | 18 | 19 | Build Status 20 | 21 |
22 | 23 | # Introduction 24 | Reloaded.Injector is a DLL Injector, what is there more to say? 25 | 26 | Well, there are many kinds of DLL Injectors and libraries out there in the wild, so I guess the question is rather *why did I write another one and use something already out there*? 27 | 28 | ![XKCD: Standards](https://imgs.xkcd.com/comics/standards.png) 29 | 30 | 31 | Well, there indeed are many DLL injectors, but for C# one unfortunately did not exist that had the particular feature set I needed: Inject DLLs into *both x86 and x64 targets* from the same program. 32 | 33 | That's the reason this project exists. 34 | 35 | ## Notable Features 36 | - Find & Call exported methods in injected/loaded remote DLLs. 37 | - Execute LoadLibraryW, GetProcAddress in remote processes. 38 | - Does not load DLLs into current process. Safe for DLLs with code in DllMain. 39 | - Does not waste/leave memory in remote process after injection. 40 | - Uses circular buffer for parameter passing. No slow heap allocations in remote process for calling functions. 41 | - **All of this is also supported for x86 processes from x64 processes.**. 42 | 43 | ## Getting Started 44 | 45 | To get started, install the package from NuGet and simply create a new instance of the `Injector` class from the `Reloaded.Injector` namespace: 46 | 47 | ```csharp 48 | injector = new Injector(process); 49 | ``` 50 | You're done; that's all you need to do. 51 | 52 | PS. When you're done, be a good person and dispose your waste 😉. 53 | 54 | ```csharp 55 | injector.Dispose(); 56 | ``` 57 | 58 | ## Contributions 59 | As with the standard for all of the `Reloaded-Project`, repositories; contributions are very welcome and encouraged. 60 | 61 | Feel free to implement new features, make bug fixes or suggestions so long as they are accompanied by an issue with a clear description of the pull request 😉. 62 | 63 | -------------------------------------------------------------------------------- /Source/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reloaded-Project/Reloaded.Injector/ffc33e18bc4024e009bbd6b637dff31c042b7dd4/Source/Icon.png -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Shared/Reloaded.Injector.Shared.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Shared/TwoNumbers.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | namespace Reloaded.Injector.Shared 4 | { 5 | [ExcludeFromCodeCoverage] 6 | public struct TwoNumbers 7 | { 8 | public int A { get; private set; } 9 | public int B { get; private set; } 10 | 11 | public TwoNumbers(int a, int b) : this() 12 | { 13 | A = a; 14 | B = b; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.Dll32/Calculator.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using NXPorts.Attributes; 3 | using Reloaded.Injector.Shared; 4 | 5 | namespace Reloaded.Injector.Tests.Dll32 6 | { 7 | [ExcludeFromCodeCoverage] 8 | public unsafe class Calculator 9 | { 10 | [Export] 11 | public static int Add(TwoNumbers* twoNumbers) 12 | { 13 | return twoNumbers->A + twoNumbers->B; 14 | } 15 | 16 | [Export] 17 | public static int Subtract(TwoNumbers* twoNumbers) 18 | { 19 | return twoNumbers->A - twoNumbers->B; 20 | } 21 | 22 | [Export] 23 | public static int Multiply(TwoNumbers* twoNumbers) 24 | { 25 | return twoNumbers->A * twoNumbers->B; 26 | } 27 | 28 | [Export] 29 | public static int Divide(TwoNumbers* twoNumbers) 30 | { 31 | return twoNumbers->A / twoNumbers->B; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.Dll32/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // Setting ComVisible to false makes the types in this assembly not visible 5 | // to COM components. If you need to access a type in this assembly from 6 | // COM, set the ComVisible attribute to true on that type. 7 | [assembly: ComVisible(false)] 8 | 9 | // The following GUID is for the ID of the typelib if this project is exposed to COM 10 | [assembly: Guid("e128f48a-6a39-4699-89d4-39a97974f533")] 11 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.Dll32/Reloaded.Injector.Tests.Dll32.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {E128F48A-6A39-4699-89D4-39A97974F533} 4 | net472 5 | Reloaded.Injector.Tests.Dll32 6 | Reloaded.Injector.Tests.Dll32 7 | Copyright © 2019 8 | true 9 | x86 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.Dll64/Calculator.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using NXPorts.Attributes; 3 | using Reloaded.Injector.Shared; 4 | 5 | namespace Reloaded.Injector.Tests.Dll64 6 | { 7 | [ExcludeFromCodeCoverage] 8 | public unsafe class Calculator 9 | { 10 | [Export] 11 | public static int Add(TwoNumbers* twoNumbers) 12 | { 13 | return twoNumbers->A + twoNumbers->B; 14 | } 15 | 16 | [Export] 17 | public static int Subtract(TwoNumbers* twoNumbers) 18 | { 19 | return twoNumbers->A - twoNumbers->B; 20 | } 21 | 22 | [Export] 23 | public static int Multiply(TwoNumbers* twoNumbers) 24 | { 25 | return twoNumbers->A * twoNumbers->B; 26 | } 27 | 28 | [Export] 29 | public static int Divide(TwoNumbers* twoNumbers) 30 | { 31 | return twoNumbers->A / twoNumbers->B; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.Dll64/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // Setting ComVisible to false makes the types in this assembly not visible 5 | // to COM components. If you need to access a type in this assembly from 6 | // COM, set the ComVisible attribute to true on that type. 7 | [assembly: ComVisible(false)] 8 | 9 | // The following GUID is for the ID of the typelib if this project is exposed to COM 10 | [assembly: Guid("a24706e2-eb50-4716-b036-c747462c4e93")] 11 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.Dll64/Reloaded.Injector.Tests.Dll64.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {A24706E2-EB50-4716-B036-C747462C4E93} 4 | net472 5 | Reloaded.Injector.Tests.Dll64 6 | Reloaded.Injector.Tests.Dll64 7 | Copyright © 2019 8 | true 9 | x64 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.X64/HelloWorld.cs: -------------------------------------------------------------------------------- 1 | using Reloaded.Injector.Shared; 2 | using Xunit; 3 | 4 | namespace Reloaded.Injector.Tests.X64 5 | { 6 | public class HelloWorld : IClassFixture 7 | { 8 | private const string InjectModule64 = "Reloaded.Injector.Tests.Dll64.dll"; 9 | private const string InjectModule32 = "Reloaded.Injector.Tests.Dll32.dll"; 10 | private const string CalculatorAdd = "Add"; 11 | private const string CalculatorSubtract = "Subtract"; 12 | private const string CalculatorMultiply = "Multiply"; 13 | private const string CalculatorDivide = "Divide"; 14 | 15 | /* For testing on low end hardware. Reduce this value for faster tests. */ 16 | private const int XLoops = 15; 17 | private const int YLoops = 15; 18 | 19 | private HelloWorldFixture _helloWorldFixture; 20 | 21 | public HelloWorld(HelloWorldFixture helloWorldFixture) 22 | { 23 | _helloWorldFixture = helloWorldFixture; 24 | } 25 | 26 | /* Shellcode Test */ 27 | 28 | [Fact] 29 | public void GetFunctionAddress64() 30 | { 31 | var addAddress = _helloWorldFixture.Injector64.GetFunctionAddress(InjectModule64, CalculatorAdd); 32 | var subAddress = _helloWorldFixture.Injector64.GetFunctionAddress(InjectModule64, CalculatorSubtract); 33 | var mulAddress = _helloWorldFixture.Injector64.GetFunctionAddress(InjectModule64, CalculatorMultiply); 34 | var divAddress = _helloWorldFixture.Injector64.GetFunctionAddress(InjectModule64, CalculatorDivide); 35 | 36 | Assert.NotEqual(0, addAddress); 37 | Assert.NotEqual(0, subAddress); 38 | Assert.NotEqual(0, mulAddress); 39 | Assert.NotEqual(0, divAddress); 40 | } 41 | 42 | [Fact] 43 | public void GetFunctionAddress32() 44 | { 45 | var addAddress = _helloWorldFixture.Injector32.GetFunctionAddress(InjectModule32, CalculatorAdd); 46 | var subAddress = _helloWorldFixture.Injector32.GetFunctionAddress(InjectModule32, CalculatorSubtract); 47 | var mulAddress = _helloWorldFixture.Injector32.GetFunctionAddress(InjectModule32, CalculatorMultiply); 48 | var divAddress = _helloWorldFixture.Injector32.GetFunctionAddress(InjectModule32, CalculatorDivide); 49 | 50 | Assert.NotEqual(0, addAddress); 51 | Assert.NotEqual(0, subAddress); 52 | Assert.NotEqual(0, mulAddress); 53 | Assert.NotEqual(0, divAddress); 54 | } 55 | 56 | /* Calculator Test */ 57 | 58 | [Fact] 59 | public void Add64() 60 | { 61 | for (int x = 0; x < XLoops; x++) 62 | { 63 | for (int y = YLoops; y > 0; y--) 64 | { 65 | int expected = x + y; 66 | int result = _helloWorldFixture.Injector64.CallFunction(InjectModule64, CalculatorAdd, new TwoNumbers(x, y)); 67 | 68 | Assert.Equal(expected, result); 69 | } 70 | } 71 | } 72 | 73 | [Fact] 74 | public void Add32() 75 | { 76 | for (int x = 0; x < XLoops; x++) 77 | { 78 | for (int y = YLoops; y > 0; y--) 79 | { 80 | int expected = x + y; 81 | int result = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorAdd, new TwoNumbers(x, y)); 82 | 83 | Assert.Equal(expected, result); 84 | } 85 | } 86 | } 87 | 88 | [Fact] 89 | public void Subtract64() 90 | { 91 | for (int x = 0; x < XLoops; x++) 92 | { 93 | for (int y = YLoops; y > 0; y--) 94 | { 95 | int expected = x - y; 96 | int result = _helloWorldFixture.Injector64.CallFunction(InjectModule64, CalculatorSubtract, new TwoNumbers(x, y)); 97 | 98 | Assert.Equal(expected, result); 99 | } 100 | } 101 | } 102 | 103 | [Fact] 104 | public void Subtract32() 105 | { 106 | for (int x = 0; x < XLoops; x++) 107 | { 108 | for (int y = YLoops; y > 0; y--) 109 | { 110 | int expected = x - y; 111 | int result = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorSubtract, new TwoNumbers(x, y)); 112 | 113 | Assert.Equal(expected, result); 114 | } 115 | } 116 | } 117 | 118 | [Fact] 119 | public void Multiply64() 120 | { 121 | for (int x = 0; x < XLoops; x++) 122 | { 123 | for (int y = YLoops; y > 0; y--) 124 | { 125 | int expected = x * y; 126 | int result = _helloWorldFixture.Injector64.CallFunction(InjectModule64, CalculatorMultiply, new TwoNumbers(x, y)); 127 | 128 | Assert.Equal(expected, result); 129 | } 130 | } 131 | } 132 | 133 | [Fact] 134 | public void Multiply32() 135 | { 136 | for (int x = 0; x < XLoops; x++) 137 | { 138 | for (int y = YLoops; y > 0; y--) 139 | { 140 | int expected = x * y; 141 | int result = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorMultiply, new TwoNumbers(x, y)); 142 | 143 | Assert.Equal(expected, result); 144 | } 145 | } 146 | } 147 | 148 | [Fact] 149 | public void Divide64() 150 | { 151 | for (int x = 0; x < XLoops; x++) 152 | { 153 | for (int y = YLoops; y > 0; y--) 154 | { 155 | int expected = x / y; 156 | int result = _helloWorldFixture.Injector64.CallFunction(InjectModule64, CalculatorDivide, new TwoNumbers(x, y)); 157 | 158 | Assert.Equal(expected, result); 159 | } 160 | } 161 | } 162 | 163 | [Fact] 164 | public void Divide32() 165 | { 166 | for (int x = 0; x < XLoops; x++) 167 | { 168 | for (int y = YLoops; y > 0; y--) 169 | { 170 | int expected = x / y; 171 | int result = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorDivide, new TwoNumbers(x, y)); 172 | 173 | Assert.Equal(expected, result); 174 | } 175 | } 176 | } 177 | 178 | [Fact] 179 | public void All64() 180 | { 181 | for (int x = 0; x < XLoops; x++) 182 | { 183 | for (int y = YLoops; y > 0; y--) 184 | { 185 | int addExpected = x + y; 186 | int subExpected = x - y; 187 | int mulExpected = x * y; 188 | int divExpected = x / y; 189 | 190 | int addResult = _helloWorldFixture.Injector64.CallFunction(InjectModule64, CalculatorAdd, new TwoNumbers(x, y)); 191 | int subResult = _helloWorldFixture.Injector64.CallFunction(InjectModule64, CalculatorSubtract, new TwoNumbers(x, y)); 192 | int mulResult = _helloWorldFixture.Injector64.CallFunction(InjectModule64, CalculatorMultiply, new TwoNumbers(x, y)); 193 | int divResult = _helloWorldFixture.Injector64.CallFunction(InjectModule64, CalculatorDivide, new TwoNumbers(x, y)); 194 | 195 | Assert.Equal(addExpected, addResult); 196 | Assert.Equal(subExpected, subResult); 197 | Assert.Equal(mulExpected, mulResult); 198 | Assert.Equal(divExpected, divResult); 199 | } 200 | } 201 | } 202 | 203 | 204 | [Fact] 205 | public void All32() 206 | { 207 | for (int x = 0; x < XLoops; x++) 208 | { 209 | for (int y = YLoops; y > 0; y--) 210 | { 211 | int addExpected = x + y; 212 | int subExpected = x - y; 213 | int mulExpected = x * y; 214 | int divExpected = x / y; 215 | 216 | int addResult = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorAdd, new TwoNumbers(x, y)); 217 | int subResult = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorSubtract, new TwoNumbers(x, y)); 218 | int mulResult = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorMultiply, new TwoNumbers(x, y)); 219 | int divResult = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorDivide, new TwoNumbers(x, y)); 220 | 221 | Assert.Equal(addExpected, addResult); 222 | Assert.Equal(subExpected, subResult); 223 | Assert.Equal(mulExpected, mulResult); 224 | Assert.Equal(divExpected, divResult); 225 | } 226 | } 227 | } 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.X64/HelloWorld32.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reloaded-Project/Reloaded.Injector/ffc33e18bc4024e009bbd6b637dff31c042b7dd4/Source/Reloaded.Injector.Tests.X64/HelloWorld32.exe -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.X64/HelloWorld64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reloaded-Project/Reloaded.Injector/ffc33e18bc4024e009bbd6b637dff31c042b7dd4/Source/Reloaded.Injector.Tests.X64/HelloWorld64.exe -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.X64/HelloWorldFixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace Reloaded.Injector.Tests.X64 5 | { 6 | public class HelloWorldFixture : IDisposable 7 | { 8 | private const string InjectModule32 = "Reloaded.Injector.Tests.Dll32.dll"; 9 | private const string InjectModule64 = "Reloaded.Injector.Tests.Dll64.dll"; 10 | 11 | public Process Target32 { get; set; } 12 | public Process Target64 { get; set; } 13 | 14 | public Injector Injector32 { get; set; } 15 | public Injector Injector64 { get; set; } 16 | 17 | public HelloWorldFixture() 18 | { 19 | Target32 = Process.Start("HelloWorld32"); 20 | Target64 = Process.Start("HelloWorld64"); 21 | 22 | Injector32 = new Injector(Target32); 23 | Injector32.Inject(InjectModule32); 24 | 25 | Injector64 = new Injector(Target64); 26 | Injector64.Inject(InjectModule64); 27 | } 28 | 29 | public void Dispose() 30 | { 31 | // Order is important here. 32 | // If eject crashes the process, exception here throws and tests fail. 33 | Injector32.Eject(InjectModule32); 34 | Injector64.Eject(InjectModule64); 35 | 36 | Target32?.Kill(); 37 | Target32?.Dispose(); 38 | 39 | Target64?.Kill(); 40 | Target64?.Dispose(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.X64/Reloaded.Injector.Tests.X64.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NET472 5 | 6 | false 7 | 8 | AnyCPU;x64 9 | 10 | 11 | 12 | full 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Always 35 | 36 | 37 | Always 38 | 39 | 40 | PreserveNewest 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.X64/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "parallelizeAssembly": false, 3 | "parallelizeTestCollections": false 4 | } -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.X86/HelloWorld.cs: -------------------------------------------------------------------------------- 1 | using Reloaded.Injector.Shared; 2 | using Xunit; 3 | 4 | namespace Reloaded.Injector.Tests.X86 5 | { 6 | public class HelloWorld : IClassFixture 7 | { 8 | private const string InjectModule32 = "Reloaded.Injector.Tests.Dll32.dll"; 9 | private const string CalculatorAdd = "Add"; 10 | private const string CalculatorSubtract = "Subtract"; 11 | private const string CalculatorMultiply = "Multiply"; 12 | private const string CalculatorDivide = "Divide"; 13 | 14 | /* For testing on low end hardware. Reduce this value for faster tests. */ 15 | private const int XLoops = 15; 16 | private const int YLoops = 15; 17 | 18 | private HelloWorldFixture _helloWorldFixture; 19 | 20 | public HelloWorld(HelloWorldFixture helloWorldFixture) 21 | { 22 | _helloWorldFixture = helloWorldFixture; 23 | } 24 | 25 | /* Shellcode Test */ 26 | 27 | [Fact] 28 | public void GetFunctionAddress32() 29 | { 30 | var addAddress = _helloWorldFixture.Injector32.GetFunctionAddress(InjectModule32, CalculatorAdd); 31 | var subAddress = _helloWorldFixture.Injector32.GetFunctionAddress(InjectModule32, CalculatorSubtract); 32 | var mulAddress = _helloWorldFixture.Injector32.GetFunctionAddress(InjectModule32, CalculatorMultiply); 33 | var divAddress = _helloWorldFixture.Injector32.GetFunctionAddress(InjectModule32, CalculatorDivide); 34 | 35 | Assert.NotEqual(0, addAddress); 36 | Assert.NotEqual(0, subAddress); 37 | Assert.NotEqual(0, mulAddress); 38 | Assert.NotEqual(0, divAddress); 39 | } 40 | 41 | /* Calculator Test */ 42 | 43 | [Fact] 44 | public void Add32() 45 | { 46 | Injector injector = new Injector(_helloWorldFixture.Target32); 47 | try { injector.Inject(InjectModule32); } catch { } // May already be injected. 48 | 49 | for (int x = 0; x < XLoops; x++) 50 | { 51 | for (int y = YLoops; y > 0; y--) 52 | { 53 | int expected = x + y; 54 | int result = injector.CallFunction(InjectModule32, CalculatorAdd, new TwoNumbers(x, y)); 55 | 56 | Assert.Equal(expected, result); 57 | } 58 | } 59 | 60 | injector.Eject(InjectModule32); 61 | } 62 | 63 | [Fact] 64 | public void Subtract32() 65 | { 66 | for (int x = 0; x < XLoops; x++) 67 | { 68 | for (int y = YLoops; y > 0; y--) 69 | { 70 | int expected = x - y; 71 | int result = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorSubtract, new TwoNumbers(x, y)); 72 | 73 | Assert.Equal(expected, result); 74 | } 75 | } 76 | } 77 | 78 | [Fact] 79 | public void Multiply32() 80 | { 81 | for (int x = 0; x < XLoops; x++) 82 | { 83 | for (int y = YLoops; y > 0; y--) 84 | { 85 | int expected = x * y; 86 | int result = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorMultiply, new TwoNumbers(x, y)); 87 | 88 | Assert.Equal(expected, result); 89 | } 90 | } 91 | } 92 | 93 | [Fact] 94 | public void Divide32() 95 | { 96 | for (int x = 0; x < XLoops; x++) 97 | { 98 | for (int y = YLoops; y > 0; y--) 99 | { 100 | int expected = x / y; 101 | int result = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorDivide, new TwoNumbers(x, y)); 102 | 103 | Assert.Equal(expected, result); 104 | } 105 | } 106 | } 107 | 108 | [Fact] 109 | public void All32() 110 | { 111 | for (int x = 0; x < XLoops; x++) 112 | { 113 | for (int y = YLoops; y > 0; y--) 114 | { 115 | int addExpected = x + y; 116 | int subExpected = x - y; 117 | int mulExpected = x * y; 118 | int divExpected = x / y; 119 | 120 | int addResult = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorAdd, new TwoNumbers(x, y)); 121 | int subResult = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorSubtract, new TwoNumbers(x, y)); 122 | int mulResult = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorMultiply, new TwoNumbers(x, y)); 123 | int divResult = _helloWorldFixture.Injector32.CallFunction(InjectModule32, CalculatorDivide, new TwoNumbers(x, y)); 124 | 125 | Assert.Equal(addExpected, addResult); 126 | Assert.Equal(subExpected, subResult); 127 | Assert.Equal(mulExpected, mulResult); 128 | Assert.Equal(divExpected, divResult); 129 | } 130 | } 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.X86/HelloWorld32.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reloaded-Project/Reloaded.Injector/ffc33e18bc4024e009bbd6b637dff31c042b7dd4/Source/Reloaded.Injector.Tests.X86/HelloWorld32.exe -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.X86/HelloWorldFixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace Reloaded.Injector.Tests.X86 5 | { 6 | public class HelloWorldFixture : IDisposable 7 | { 8 | private const string InjectModule32 = "Reloaded.Injector.Tests.Dll32.dll"; 9 | 10 | public Process Target32 { get; set; } 11 | public Injector Injector32 { get; set; } 12 | 13 | public HelloWorldFixture() 14 | { 15 | Target32 = Process.Start("HelloWorld32"); 16 | Injector32 = new Injector(Target32); 17 | Injector32.Inject(InjectModule32); 18 | } 19 | 20 | public void Dispose() 21 | { 22 | // Order is important here. 23 | // If eject crashes the process, exception here throws and tests fail. 24 | Injector32.Eject(InjectModule32); 25 | 26 | Target32?.Kill(); 27 | Target32?.Dispose(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.X86/Reloaded.Injector.Tests.X86.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NET472 5 | 6 | false 7 | 8 | AnyCPU;x86 9 | 10 | 11 | 12 | full 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | Always 31 | 32 | 33 | PreserveNewest 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector.Tests.X86/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "parallelizeAssembly": false, 3 | "parallelizeTestCollections": false 4 | } -------------------------------------------------------------------------------- /Source/Reloaded.Injector.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29613.14 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reloaded.Injector", "Reloaded.Injector\Reloaded.Injector.csproj", "{9560FF17-DB47-488A-AAC1-98A247D13AEE}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reloaded.Injector.Tests.X86", "Reloaded.Injector.Tests.X86\Reloaded.Injector.Tests.X86.csproj", "{5BE91758-E6B1-4584-B6A1-14A5D6452461}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reloaded.Injector.Tests.X64", "Reloaded.Injector.Tests.X64\Reloaded.Injector.Tests.X64.csproj", "{EA753687-A4BB-47B9-9512-D1207654B07E}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reloaded.Injector.Tests.Dll32", "Reloaded.Injector.Tests.Dll32\Reloaded.Injector.Tests.Dll32.csproj", "{E128F48A-6A39-4699-89D4-39A97974F533}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reloaded.Injector.Tests.Dll64", "Reloaded.Injector.Tests.Dll64\Reloaded.Injector.Tests.Dll64.csproj", "{A24706E2-EB50-4716-B036-C747462C4E93}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reloaded.Injector.Shared", "Reloaded.Injector.Shared\Reloaded.Injector.Shared.csproj", "{73BE9C7A-F7E8-4CD3-A48C-6CBB541DAED6}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {9560FF17-DB47-488A-AAC1-98A247D13AEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {9560FF17-DB47-488A-AAC1-98A247D13AEE}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {9560FF17-DB47-488A-AAC1-98A247D13AEE}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {9560FF17-DB47-488A-AAC1-98A247D13AEE}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {5BE91758-E6B1-4584-B6A1-14A5D6452461}.Debug|Any CPU.ActiveCfg = Debug|x86 29 | {5BE91758-E6B1-4584-B6A1-14A5D6452461}.Debug|Any CPU.Build.0 = Debug|x86 30 | {5BE91758-E6B1-4584-B6A1-14A5D6452461}.Release|Any CPU.ActiveCfg = Release|x86 31 | {5BE91758-E6B1-4584-B6A1-14A5D6452461}.Release|Any CPU.Build.0 = Release|x86 32 | {EA753687-A4BB-47B9-9512-D1207654B07E}.Debug|Any CPU.ActiveCfg = Debug|x64 33 | {EA753687-A4BB-47B9-9512-D1207654B07E}.Debug|Any CPU.Build.0 = Debug|x64 34 | {EA753687-A4BB-47B9-9512-D1207654B07E}.Release|Any CPU.ActiveCfg = Release|x64 35 | {EA753687-A4BB-47B9-9512-D1207654B07E}.Release|Any CPU.Build.0 = Release|x64 36 | {E128F48A-6A39-4699-89D4-39A97974F533}.Debug|Any CPU.ActiveCfg = Debug|x86 37 | {E128F48A-6A39-4699-89D4-39A97974F533}.Debug|Any CPU.Build.0 = Debug|x86 38 | {E128F48A-6A39-4699-89D4-39A97974F533}.Release|Any CPU.ActiveCfg = Release|x86 39 | {A24706E2-EB50-4716-B036-C747462C4E93}.Debug|Any CPU.ActiveCfg = Debug|x64 40 | {A24706E2-EB50-4716-B036-C747462C4E93}.Debug|Any CPU.Build.0 = Debug|x64 41 | {A24706E2-EB50-4716-B036-C747462C4E93}.Release|Any CPU.ActiveCfg = Release|x64 42 | {73BE9C7A-F7E8-4CD3-A48C-6CBB541DAED6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {73BE9C7A-F7E8-4CD3-A48C-6CBB541DAED6}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {73BE9C7A-F7E8-4CD3-A48C-6CBB541DAED6}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {73BE9C7A-F7E8-4CD3-A48C-6CBB541DAED6}.Release|Any CPU.Build.0 = Release|Any CPU 46 | EndGlobalSection 47 | GlobalSection(SolutionProperties) = preSolution 48 | HideSolutionNode = FALSE 49 | EndGlobalSection 50 | GlobalSection(ExtensibilityGlobals) = postSolution 51 | SolutionGuid = {380684B3-1FA9-49A4-A91F-A720DEEDCB28} 52 | EndGlobalSection 53 | EndGlobal 54 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector/Exceptions/DllInjectorException.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 2 | 3 | using System; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.Runtime.Serialization; 6 | 7 | namespace Reloaded.Injector.Exceptions 8 | { 9 | [ExcludeFromCodeCoverage] 10 | public class DllInjectorException : Exception 11 | { 12 | /* For any other exceptions. */ 13 | public DllInjectorException() { } 14 | public DllInjectorException(string message) : base(message) { } 15 | public DllInjectorException(string message, Exception innerException) : base(message, innerException) { } 16 | protected DllInjectorException(SerializationInfo info, StreamingContext context) : base(info, context) { } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector/Exceptions/ShellCodeGeneratorException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Runtime.Serialization; 4 | 5 | namespace Reloaded.Injector.Exceptions 6 | { 7 | [ExcludeFromCodeCoverage] 8 | class ShellCodeGeneratorException : Exception 9 | { 10 | public ShellCodeGeneratorException() { } 11 | public ShellCodeGeneratorException(string message) : base(message) { } 12 | public ShellCodeGeneratorException(string message, Exception innerException) : base(message, innerException) { } 13 | protected ShellCodeGeneratorException(SerializationInfo info, StreamingContext context) : base(info, context) { } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector/Injector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using Reloaded.Injector.Exceptions; 5 | using Reloaded.Injector.Interop; 6 | using Reloaded.Memory.Sources; 7 | using Reloaded.Memory.Utilities; 8 | using static Reloaded.Injector.Kernel32.Kernel32; 9 | 10 | namespace Reloaded.Injector 11 | { 12 | /// 13 | /// Provides a means by which a target DLLs may be injected into an individual process. 14 | /// If the target process is running the administrator, the injector should also be 15 | /// ran as administrator. 16 | /// 17 | public class Injector : IDisposable 18 | { 19 | /// 20 | /// True when the target process to inject is no longer running, else false. 21 | /// 22 | public bool HasExited => _process.HasExited; 23 | 24 | /// 25 | /// Provides access to the raw GetProcAddress and LoadLibrary calls. 26 | /// 27 | public Shellcode ShellCode { get; private set; } /* Call GetProcAddress and LoadLibraryW in remote process. */ 28 | 29 | private CircularBuffer _circularBuffer; /* Used for calling foreign functions. */ 30 | private Process _process; /* Process to DLL Inject into. */ 31 | 32 | /// 33 | /// Initializes the DLL Injector. 34 | /// 35 | /// The process to inject DLLs into. 36 | public Injector(Process process) 37 | { 38 | // Initiate target process. 39 | _process = process; 40 | _circularBuffer = new CircularBuffer(4096, new ExternalMemory(process)); 41 | ShellCode = new Shellcode(process); 42 | } 43 | 44 | ~Injector() 45 | { 46 | Dispose(); 47 | } 48 | 49 | /// 50 | public void Dispose() 51 | { 52 | _circularBuffer?.Dispose(); 53 | ShellCode?.Dispose(); 54 | GC.SuppressFinalize(this); 55 | } 56 | 57 | /// 58 | /// Injects a DLL into the target process. 59 | /// 60 | /// The absolute path to your DLL to be injected. 61 | /// This function executes LoadLibraryW inside the remote process. 62 | /// The target process is not running. 63 | /// The address/handle of the loaded in library inside the target process. Zero if the operation failed. 64 | public long Inject(string modulePath) 65 | { 66 | // Error checking. 67 | AssertProcessNotRunning(); 68 | 69 | var moduleHandle = IsAbsolutePath(modulePath) ? GetModuleHandleFromPath(modulePath) : GetModuleHandleFromName(modulePath); 70 | if (moduleHandle != IntPtr.Zero) 71 | return (long)moduleHandle; 72 | 73 | long address = ShellCode.LoadLibraryW(modulePath); 74 | 75 | return address; 76 | } 77 | 78 | /// 79 | /// Retrieves the address of a function in a module loaded inside the target process. 80 | /// 81 | /// The name or full path of the module. 82 | /// The function of that module to be executed. 83 | /// This function remotely executes GetProcAddress inside the given process. 84 | /// The DLL is not loaded in the target process. 85 | public long GetFunctionAddress(string module, string functionToExecute) 86 | { 87 | var moduleHandle = IsAbsolutePath(module) ? GetModuleHandleFromPath(module) : GetModuleHandleFromName(module); 88 | if (moduleHandle == IntPtr.Zero) 89 | throw new DllInjectorException("Module not found in target process."); 90 | 91 | return ShellCode.GetProcAddress((long)moduleHandle, functionToExecute); 92 | } 93 | 94 | /// 95 | /// Calls a function in a remote process using CreateRemoteThread. 96 | /// 97 | /// A structure type to pass as a parameter to the target function. 98 | /// The name or full path of the module to execute a function. 99 | /// The function of that module to be executed. 100 | /// 101 | /// A parameter to pass onto the function. It is written into memory and a pointer to it 102 | /// is passed to the target function. 103 | /// 104 | /// 105 | /// Set to true to enable marshalling of the parameter being passed into the receiving application. 106 | /// 107 | /// 108 | /// Passing of only 1 parameter is supported. If you want to pass multiple parameters, pass a struct 109 | /// This function passes a pointer to your parameter to the target function. 110 | /// A parameter must be passed and the target method must expect it. This is a limitation of CreateRemoteThread. 111 | /// 112 | /// A 32bit truncated exit code/return value. CreateRemoteThread does not support 64bit returns. 113 | public int CallFunction(string module, string functionToExecute, TStruct parameter = default, bool marshalParameter = false) 114 | { 115 | var parameterPtr = _circularBuffer.Add(ref parameter, marshalParameter); 116 | return CallFunction(module, functionToExecute, (long)parameterPtr); 117 | } 118 | 119 | /// 120 | /// Calls a function in a remote process using CreateRemoteThread. 121 | /// 122 | /// The name or full path of the module to execute a function. 123 | /// The function of that module to be executed. 124 | /// Raw value/pointer to parameter to pass to the target function. 125 | /// A 32bit truncated exit code/return value. CreateRemoteThread does not support 64bit returns. 126 | public int CallFunction(string module, string functionToExecute, long parameterPtr) 127 | { 128 | long methodAddress = GetFunctionAddress(module, functionToExecute); 129 | return CallRemoteFunction(_process.Handle, (IntPtr)methodAddress, (IntPtr) parameterPtr); 130 | } 131 | 132 | /// 133 | /// Unloads a library with a specified path from the target process. 134 | /// 135 | /// False if the operation failed, else true. 136 | public bool Eject(string module) 137 | { 138 | // Get handle of module. 139 | var moduleHandle = IsAbsolutePath(module) ? GetModuleHandleFromPath(module) : GetModuleHandleFromName(module); 140 | if (moduleHandle == IntPtr.Zero) 141 | return false; 142 | 143 | long methodAddress = ShellCode.GetProcAddress(ShellCode.Kernel32Handle, "FreeLibrary"); 144 | 145 | int result = CallRemoteFunction(_process.Handle, (IntPtr)methodAddress, moduleHandle); 146 | return Convert.ToBoolean(result); 147 | } 148 | 149 | /// 150 | /// Retrieves the handle (memory address) of where the module with a specified file path is loaded in the target process. 151 | /// 152 | /// The absolute path of the module (including extension). 153 | /// 0 if the operation fails, else an address. 154 | public IntPtr GetModuleHandleFromPath(string modulePath) 155 | { 156 | string fullPath = Path.GetFullPath(modulePath); 157 | foreach (var module in Safety.TryGetModules(_process)) 158 | { 159 | if (Path.GetFullPath(module.ModulePath) == fullPath) 160 | return module.BaseAddress; 161 | } 162 | 163 | return IntPtr.Zero; 164 | } 165 | 166 | /// 167 | /// Retrieves the handle (memory address) of where the module with a specified name is loaded in the target process. 168 | /// 169 | /// The name of the module (including extension). 170 | /// 0 if the operation fails, else an address. 171 | public IntPtr GetModuleHandleFromName(string moduleName) 172 | { 173 | foreach (var module in Safety.TryGetModules(_process)) 174 | { 175 | if (Path.GetFileName(module.ModulePath) == moduleName) 176 | return module.BaseAddress; 177 | } 178 | 179 | return IntPtr.Zero; 180 | } 181 | 182 | /* Core Functionality */ 183 | 184 | private int CallRemoteFunction(IntPtr processHandle, IntPtr methodAddress, IntPtr parameterAddress) 185 | { 186 | // Create and initialize a thread at our address and parameter address. 187 | IntPtr hThread = CreateRemoteThread(processHandle, IntPtr.Zero, UIntPtr.Zero, methodAddress, parameterAddress, 0, out uint threadId); 188 | 189 | WaitForSingleObject(hThread, uint.MaxValue); 190 | GetExitCodeThread(hThread, out uint exitCode); 191 | 192 | return (int)exitCode; 193 | } 194 | 195 | /* Utilities */ 196 | 197 | private bool IsAbsolutePath(string path) 198 | { 199 | return Path.IsPathRooted(path); 200 | } 201 | 202 | private void AssertProcessNotRunning() 203 | { 204 | if (HasExited) 205 | throw new DllInjectorException("The target process to inject to has exited, it is no longer running."); 206 | } 207 | 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector/Interop/ModuleCollector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | using Reloaded.Injector.Exceptions; 7 | using Reloaded.Injector.Interop.Structures; 8 | 9 | namespace Reloaded.Injector.Interop 10 | { 11 | internal static unsafe class ModuleCollector 12 | { 13 | private static StringBuilder _modulePathBuilder = new StringBuilder(32767); 14 | 15 | /// Bytes to fill module list returned 0. The process is probably not yet initialized. 16 | public static List CollectModules(Process process) 17 | { 18 | List collectedModules = new List(); 19 | IntPtr[] modulePointers = new IntPtr[0]; 20 | int numberOfModules; 21 | int bytesNeeded; 22 | 23 | // Determine number of modules. 24 | if (!EnumProcessModulesEx(process.Handle, modulePointers, 0, out bytesNeeded, (uint)ModuleFilter.ListModulesAll)) 25 | return collectedModules; 26 | 27 | if (bytesNeeded == 0) 28 | throw new DllInjectorException("Bytes needed to dump module list returned 0. This means that either the process probably not yet fully initialized."); 29 | 30 | numberOfModules = bytesNeeded / IntPtr.Size; 31 | modulePointers = new IntPtr[numberOfModules]; 32 | 33 | // Collect modules from the process 34 | if (EnumProcessModulesEx(process.Handle, modulePointers, bytesNeeded, out bytesNeeded, (uint)ModuleFilter.ListModulesAll)) 35 | { 36 | for (int x = 0; x < numberOfModules; x++) 37 | { 38 | ModuleInformation moduleInformation = new ModuleInformation(); 39 | 40 | GetModuleFileNameEx(process.Handle, modulePointers[x], _modulePathBuilder, (uint)(_modulePathBuilder.Capacity)); 41 | GetModuleInformation(process.Handle, modulePointers[x], out moduleInformation, (uint)sizeof(ModuleInformation)); 42 | 43 | // Convert to a normalized module and add it to our list 44 | string modulePath = _modulePathBuilder.ToString(); 45 | Module module = new Module(modulePath, moduleInformation.lpBaseOfDll, moduleInformation.SizeOfImage, moduleInformation.EntryPoint); 46 | collectedModules.Add(module); 47 | } 48 | } 49 | 50 | return collectedModules; 51 | } 52 | 53 | [StructLayout(LayoutKind.Sequential)] 54 | public struct ModuleInformation 55 | { 56 | public IntPtr lpBaseOfDll; 57 | public uint SizeOfImage; 58 | public IntPtr EntryPoint; 59 | } 60 | 61 | internal enum ModuleFilter 62 | { 63 | ListModulesDefault = 0x0, 64 | ListModules32Bit = 0x01, 65 | ListModules64Bit = 0x02, 66 | ListModulesAll = 0x03, 67 | } 68 | 69 | [DllImport("psapi.dll")] 70 | private static extern bool EnumProcessModulesEx(IntPtr hProcess, IntPtr[] lphModule, int cb, out int lpcbNeeded, uint dwFilterFlag); 71 | 72 | [DllImport("psapi.dll")] 73 | private static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, uint nSize); 74 | 75 | [DllImport("psapi.dll", SetLastError = true)] 76 | private static extern bool GetModuleInformation(IntPtr hProcess, IntPtr hModule, out ModuleInformation lpmodinfo, uint cb); 77 | } 78 | } 79 | 80 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector/Interop/Structures/Module.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Reloaded.Injector.Interop.Structures 5 | { 6 | public class Module 7 | { 8 | public string ModulePath { get; set; } 9 | public IntPtr BaseAddress { get; set; } 10 | public IntPtr EntryPoint { get; set; } 11 | public uint Size { get; set; } 12 | 13 | public Module(string modulePath, IntPtr baseAddress, uint size, IntPtr entryPoint) 14 | { 15 | this.ModulePath = modulePath; 16 | this.BaseAddress = baseAddress; 17 | this.Size = size; 18 | this.EntryPoint = entryPoint; 19 | } 20 | 21 | public override string ToString() => Path.GetFileName(ModulePath); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector/Kernel32/Kernel32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Text; 4 | 5 | namespace Reloaded.Injector.Kernel32 6 | { 7 | internal static class Kernel32 8 | { 9 | [DllImport("kernel32.dll", SetLastError = true)] 10 | public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, UIntPtr dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, CREATE_THREAD_FLAGS dwCreationFlags, out uint lpThreadId); 11 | 12 | [DllImport("kernel32.dll", SetLastError = true)] 13 | public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); 14 | 15 | [DllImport("kernel32.dll", SetLastError = true)] 16 | [return: MarshalAs(UnmanagedType.Bool)] 17 | public static extern bool GetExitCodeThread(IntPtr hThread, out uint lpExitCode); 18 | 19 | [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 20 | public static extern uint GetSystemWow64Directory(StringBuilder lpBuffer, uint uSize); 21 | 22 | [Flags] 23 | public enum CREATE_THREAD_FLAGS 24 | { 25 | RUN_IMMEDIATELY = 0, 26 | CREATE_SUSPENDED = 4, 27 | STACK_SIZE_PARAM_IS_A_RESERVATION = 65536 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector/Reloaded.Injector.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0; NET472 5 | Sewer56 6 | 7 | Reloaded 8 | Advanced DLL Injector capable of injecting x86 DLLs to x86 process from x64 processes. 9 | true 10 | 11 | https://github.com/Reloaded-Project/Reloaded.Injector 12 | 13 | https://github.com/Reloaded-Project/Reloaded.Injector 14 | git 15 | true 16 | 1.2.5 17 | LGPLV3 18 | LICENSE 19 | Icon.png 20 | true 21 | 22 | 23 | 24 | 25 | True 26 | 27 | 28 | 29 | True 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | All 38 | None 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector/Safety.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using Reloaded.Injector.Interop; 5 | using Reloaded.Injector.Interop.Structures; 6 | 7 | namespace Reloaded.Injector 8 | { 9 | public static class Safety 10 | { 11 | /// 12 | /// Waits for the modules to initialize in a target process. 13 | /// See remarks of EnumProcessModulesEx for details. 14 | /// 15 | public static List TryGetModules(Process targetProcess, int timeout = 1000) 16 | { 17 | List modules = new List(); 18 | Stopwatch watch = new Stopwatch(); 19 | watch.Start(); 20 | 21 | while (watch.ElapsedMilliseconds < timeout) 22 | { 23 | try 24 | { 25 | modules = ModuleCollector.CollectModules(targetProcess); 26 | break; 27 | } 28 | catch { /* ignored */ } 29 | } 30 | 31 | if (modules.Count == 0) 32 | throw new Exception($"Failed to find information on any of the modules inside the process " + 33 | $"using EnumProcessModulesEx within the { timeout } millisecond timeout. " + 34 | "The process has likely not yet initialized."); 35 | 36 | return modules; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Source/Reloaded.Injector/Shellcode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | using PeNet; 7 | using Reloaded.Injector.Exceptions; 8 | using Reloaded.Injector.Interop; 9 | using Reloaded.Injector.Interop.Structures; 10 | using Reloaded.Memory.Buffers; 11 | using Reloaded.Memory.Sources; 12 | using Reloaded.Memory.Utilities; 13 | using static Reloaded.Injector.Kernel32.Kernel32; 14 | 15 | namespace Reloaded.Injector 16 | { 17 | /// 18 | /// Builds the shellcode inside a target process which can be used to 19 | /// call LoadLibrary and GetProcAddress inside a remote process. 20 | /// 21 | public class Shellcode : IDisposable 22 | { 23 | /* Setup/Build Shellcode */ 24 | public long Kernel32Handle { get; } /* Address of Kernel32 in remote process. */ 25 | public long LoadLibraryAddress { get; private set; } /* Address of LoadLibrary function. */ 26 | public long GetProcAddressAddress { get; private set; } /* Address of GetProcAddress function. */ 27 | 28 | private uint _loadLibraryWOffset; /* Address of LoadLibraryW in remote process. */ 29 | private uint _getProcAddressOffset; /* Address of GetProcAddress in remote process. */ 30 | private MachineType _machineType; /* Is remote process 64 or 32bit? */ 31 | 32 | /* Temp Helpers */ 33 | private Assembler.Assembler _assembler; /* Provides JIT Assembly of x86/x64 mnemonics. */ 34 | private PrivateMemoryBuffer _privateBuffer; /* Provides us with somewhere to write our shellcode. */ 35 | 36 | /* Perm Helpers */ 37 | private ExternalMemory _memory; /* Provides access to other process' memory. */ 38 | private CircularBuffer _circularBuffer;/* For passing in our parameters to shellcode. */ 39 | private Process _targetProcess; /* The process we will be calling functions in. */ 40 | 41 | /* Final products. */ /* stdcall for x86, Microsoft for x64 */ 42 | private long _loadLibraryWShellPtr; /* Pointer to shellcode to execute LoadLibraryW. */ 43 | private long _getProcAddressShellPtr; /* Pointer to shellcode to execute GetProcAddress. */ 44 | 45 | private long _loadLibraryWReturnValuePtr; /* Address of LoadLibraryW's return value. */ 46 | private long _getProcAddressReturnValuePtr; /* Address of GetProcAddress' return value. */ 47 | 48 | /// 49 | /// Builds the shellcode necessary to successfully call LoadLibraryW and GetProcAddress 50 | /// inside the address space of another executable. 51 | /// 52 | /// Process inside which to execute. 53 | public Shellcode(Process targetProcess) 54 | { 55 | _privateBuffer = new MemoryBufferHelper(targetProcess).CreatePrivateMemoryBuffer(4096); 56 | _assembler = new Assembler.Assembler(); 57 | _memory = new ExternalMemory(targetProcess); 58 | _circularBuffer = new CircularBuffer(4096, _memory); 59 | _targetProcess = targetProcess; 60 | 61 | // Get arch of target process. 62 | PeFile targetPeFile = new PeFile(targetProcess.Modules[0].FileName); 63 | _machineType = (MachineType) targetPeFile.ImageNtHeaders.FileHeader.Machine; 64 | 65 | // Get Kernel32 load address in target. 66 | Module kernel32Module = GetKernel32InRemoteProcess(targetProcess); 67 | Kernel32Handle = (long) kernel32Module.BaseAddress; 68 | 69 | // We need to change the module path if 32bit process; because the given path is not true, 70 | // it is being actively redirected by Windows on Windows 64 (WoW64) 71 | if (_machineType == MachineType.I386 && Environment.Is64BitOperatingSystem) 72 | { 73 | StringBuilder builder = new StringBuilder(256); 74 | GetSystemWow64Directory(builder, (uint)builder.Capacity); 75 | kernel32Module.ModulePath = builder.ToString() + "\\" + Path.GetFileName(kernel32Module.ModulePath); 76 | } 77 | 78 | // Parse Kernel32 loaded by target and get address of LoadLibrary & GetProcAddress. 79 | PeFile kernel32PeFile = new PeFile(kernel32Module.ModulePath); 80 | var exportedFunctions = kernel32PeFile.ExportedFunctions; 81 | 82 | _loadLibraryWOffset = GetExportedFunctionOffset(exportedFunctions, "LoadLibraryW"); 83 | _getProcAddressOffset = GetExportedFunctionOffset(exportedFunctions, "GetProcAddress"); 84 | 85 | if (_loadLibraryWOffset == 0 || _getProcAddressOffset == 0) 86 | throw new ShellCodeGeneratorException("Failed to find GetProcAddress or LoadLibraryW methods in target process' Kernel32."); 87 | 88 | if (_machineType == MachineType.AMD64) 89 | { 90 | BuildLoadLibraryW64(); 91 | BuildGetProcAddress64(); 92 | } 93 | else 94 | { 95 | BuildLoadLibraryW86(); 96 | BuildGetProcAddress86(); 97 | } 98 | 99 | _assembler.Dispose(); 100 | _assembler = null; 101 | } 102 | 103 | ~Shellcode() 104 | { 105 | Dispose(); 106 | } 107 | 108 | /// 109 | public void Dispose() 110 | { 111 | _assembler?.Dispose(); 112 | _privateBuffer?.Dispose(); 113 | _circularBuffer?.Dispose(); 114 | GC.SuppressFinalize(this); 115 | } 116 | 117 | /* Call Shellcode */ 118 | 119 | public long GetProcAddress(long hModule, string functionName) 120 | { 121 | var getProcAddressParams = new GetProcAddressParams(hModule, WriteNullTerminatedASCIIString(functionName)); 122 | long lpParameter = (long)_circularBuffer.Add(ref getProcAddressParams); 123 | IntPtr threadHandle = CreateRemoteThread(_targetProcess.Handle, IntPtr.Zero, UIntPtr.Zero, (IntPtr)_getProcAddressShellPtr, (IntPtr)lpParameter, CREATE_THREAD_FLAGS.RUN_IMMEDIATELY, out uint threadId); 124 | 125 | WaitForSingleObject(threadHandle, uint.MaxValue); 126 | 127 | _memory.Read((UIntPtr)_getProcAddressReturnValuePtr, out long value); 128 | return value; 129 | } 130 | 131 | public long LoadLibraryW(string modulePath) 132 | { 133 | long lpParameter = WriteNullTerminatedUnicodeString(modulePath); 134 | IntPtr threadHandle = CreateRemoteThread(_targetProcess.Handle, IntPtr.Zero, UIntPtr.Zero, (IntPtr)_loadLibraryWShellPtr, (IntPtr)lpParameter, CREATE_THREAD_FLAGS.RUN_IMMEDIATELY, out uint threadId); 135 | 136 | WaitForSingleObject(threadHandle, uint.MaxValue); 137 | 138 | _memory.Read((UIntPtr)_loadLibraryWReturnValuePtr, out long value); 139 | return value; 140 | } 141 | 142 | /* Build Shellcode */ 143 | 144 | private void BuildGetProcAddress86() 145 | { 146 | // GetProcAddress(long hModule, char* lpProcName) 147 | // lpParameter: Address of first struct member. 148 | // Using stdcall calling convention. 149 | long getProcAddressAddress = Kernel32Handle + _getProcAddressOffset; 150 | GetProcAddressAddress = getProcAddressAddress; 151 | var getProcAddressPtr = _privateBuffer.Add(ref getProcAddressAddress); 152 | 153 | long dummy = 0; 154 | _getProcAddressReturnValuePtr = (long)_privateBuffer.Add(ref dummy); 155 | 156 | string[] getProcAddress = 157 | { 158 | $"use32", 159 | "mov eax, dword [esp + 4]", // CreateRemoteThread lpParameter 160 | "push dword [eax + 8]", // lpProcName 161 | "push dword [eax + 0]", // hModule 162 | $"call dword [dword {getProcAddressPtr}]", 163 | $"mov dword [dword 0x{_getProcAddressReturnValuePtr.ToString("X")}], eax", 164 | "ret 4" // Restore stack ptr. (Callee cleanup) 165 | }; 166 | 167 | 168 | byte[] bytes = _assembler.Assemble(getProcAddress); 169 | _getProcAddressShellPtr = (long)_privateBuffer.Add(bytes); 170 | } 171 | 172 | private void BuildGetProcAddress64() 173 | { 174 | // GetProcAddress(long hModule, char* lpProcName) 175 | // lpParameter: Address of first struct member. 176 | // Using Microsoft X64 calling convention. 177 | long getProcAddressAddress = Kernel32Handle + _getProcAddressOffset; 178 | GetProcAddressAddress = getProcAddressAddress; 179 | var getProcAddressPtr = _privateBuffer.Add(ref getProcAddressAddress); 180 | 181 | long dummy = 0; 182 | _getProcAddressReturnValuePtr = (long)_privateBuffer.Add(ref dummy); 183 | 184 | string[] getProcAddress = 185 | { 186 | $"use64", 187 | // CreateRemoteThread lpParameter @ ECX 188 | "sub rsp, 40", // Re-align stack to 16 byte boundary +32 shadow space 189 | "mov rdx, qword [qword rcx + 8]", // lpProcName 190 | "mov rcx, qword [qword rcx + 0]", // hModule 191 | $"call qword [qword {getProcAddressPtr}]", 192 | $"mov qword [qword 0x{_getProcAddressReturnValuePtr.ToString("X")}], rax", 193 | "add rsp, 40", // Re-align stack to 16 byte boundary + shadow space. 194 | "ret" // Restore stack ptr. (Callee cleanup) 195 | }; 196 | 197 | 198 | byte[] bytes = _assembler.Assemble(getProcAddress); 199 | _getProcAddressShellPtr = (long)_privateBuffer.Add(bytes); 200 | } 201 | 202 | private void BuildLoadLibraryW86() 203 | { 204 | // Using stdcall calling convention. 205 | long loadLibraryAddress = Kernel32Handle + _loadLibraryWOffset; 206 | LoadLibraryAddress = loadLibraryAddress; 207 | var loadLibraryPtr = _privateBuffer.Add(ref loadLibraryAddress); 208 | 209 | long dummy = 0; 210 | _loadLibraryWReturnValuePtr = (long)_privateBuffer.Add(ref dummy); 211 | 212 | string[] loadLibraryW = 213 | { 214 | $"use32", 215 | "push dword [ESP + 4]", // CreateRemoteThread lpParameter 216 | $"call dword [dword {loadLibraryPtr}]", 217 | $"mov dword [dword 0x{_loadLibraryWReturnValuePtr.ToString("X")}], eax", 218 | "ret 4" // Restore stack ptr. (Callee cleanup) 219 | }; 220 | 221 | 222 | byte[] bytes = _assembler.Assemble(loadLibraryW); 223 | _loadLibraryWShellPtr = (long)_privateBuffer.Add(bytes); 224 | } 225 | 226 | 227 | private void BuildLoadLibraryW64() 228 | { 229 | // Using Microsoft X64 calling convention. 230 | long loadLibraryAddress = Kernel32Handle + _loadLibraryWOffset; 231 | LoadLibraryAddress = loadLibraryAddress; 232 | var loadLibraryPtr = _privateBuffer.Add(ref loadLibraryAddress); 233 | 234 | long dummy = 0; 235 | _loadLibraryWReturnValuePtr = (long)_privateBuffer.Add(ref dummy); 236 | 237 | string[] loadLibraryW = 238 | { 239 | $"use64", 240 | "sub rsp, 40", // Re-align stack to 16 byte boundary + shadow space. 241 | $"call qword [qword {loadLibraryPtr}]", // CreateRemoteThread lpParameter with string already in ECX. 242 | $"mov qword [qword 0x{_loadLibraryWReturnValuePtr.ToString("X")}], rax", 243 | "add rsp, 40", // Re-align stack to 16 byte boundary + shadow space. 244 | "ret" // Restore stack ptr. (Callee cleanup) 245 | }; 246 | 247 | byte[] bytes = _assembler.Assemble(loadLibraryW); 248 | _loadLibraryWShellPtr = (long)_privateBuffer.Add(bytes); 249 | } 250 | 251 | /* Utility functions. */ 252 | 253 | private uint GetExportedFunctionOffset(ExportFunction[] exportFunctions, string functionName) // Case sensitive. 254 | { 255 | foreach (var function in exportFunctions) 256 | if (function.Name == functionName) 257 | return function.Address; 258 | 259 | return 0; 260 | } 261 | 262 | private long WriteNullTerminatedASCIIString(string libraryPath) 263 | { 264 | byte[] libraryNameBytes = Encoding.ASCII.GetBytes(libraryPath + '\0'); 265 | return (long)_circularBuffer.Add(libraryNameBytes); 266 | } 267 | 268 | private long WriteNullTerminatedUnicodeString(string libraryPath) 269 | { 270 | byte[] libraryNameBytes = Encoding.Unicode.GetBytes(libraryPath + '\0'); 271 | return (long)_circularBuffer.Add(libraryNameBytes); 272 | } 273 | 274 | /* One off construction functions. */ 275 | 276 | private Module GetKernel32InRemoteProcess(Process process) 277 | { 278 | foreach (Module module in Safety.TryGetModules(process)) 279 | if (Path.GetFileName(module.ModulePath).Equals("KERNEL32.DLL", StringComparison.InvariantCultureIgnoreCase)) 280 | return module; 281 | 282 | throw new ShellCodeGeneratorException("Failed to find Kernel32 in target process' modules."); 283 | } 284 | 285 | /* Other types. */ 286 | 287 | [StructLayout(LayoutKind.Sequential)] 288 | private struct GetProcAddressParams 289 | { 290 | public long HModule { get; set; } 291 | public long LPProcName { get; set; } 292 | 293 | public GetProcAddressParams(long hModule, long lPProcName) : this() 294 | { 295 | HModule = hModule; 296 | LPProcName = lPProcName; 297 | } 298 | } 299 | 300 | private enum MachineType 301 | { 302 | AMD64 = 34404, 303 | I386 = 332, 304 | IA64 = 512 305 | } 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | range: 50..100 3 | round: up 4 | precision: 2 5 | --------------------------------------------------------------------------------