├── .gitattributes ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md └── loader ├── CRC32.cpp ├── CRC32.hpp ├── CrashRpt.h ├── CurlWrapper.cpp ├── CurlWrapper.hpp ├── Detection.hpp ├── Includes.hpp ├── Iset.hpp ├── StreamRcver.cpp ├── StreamRcver.hpp ├── Tools.cpp ├── Tools.hpp ├── WinStruct.hpp ├── lazy_importer.hpp ├── loader.sln ├── loader.vcxproj ├── loader.vcxproj.filters ├── main.cpp └── utils.hpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.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/main/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 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 298 | *.vbp 299 | 300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 301 | *.dsw 302 | *.dsp 303 | 304 | # Visual Studio 6 technical files 305 | *.ncb 306 | *.aps 307 | 308 | # Visual Studio LightSwitch build output 309 | **/*.HTMLClient/GeneratedArtifacts 310 | **/*.DesktopClient/GeneratedArtifacts 311 | **/*.DesktopClient/ModelManifest.xml 312 | **/*.Server/GeneratedArtifacts 313 | **/*.Server/ModelManifest.xml 314 | _Pvt_Extensions 315 | 316 | # Paket dependency manager 317 | .paket/paket.exe 318 | paket-files/ 319 | 320 | # FAKE - F# Make 321 | .fake/ 322 | 323 | # CodeRush personal settings 324 | .cr/personal 325 | 326 | # Python Tools for Visual Studio (PTVS) 327 | __pycache__/ 328 | *.pyc 329 | 330 | # Cake - Uncomment if you are using it 331 | # tools/** 332 | # !tools/packages.config 333 | 334 | # Tabs Studio 335 | *.tss 336 | 337 | # Telerik's JustMock configuration file 338 | *.jmconfig 339 | 340 | # BizTalk build output 341 | *.btp.cs 342 | *.btm.cs 343 | *.odx.cs 344 | *.xsd.cs 345 | 346 | # OpenCover UI analysis results 347 | OpenCover/ 348 | 349 | # Azure Stream Analytics local run output 350 | ASALocalRun/ 351 | 352 | # MSBuild Binary and Structured Log 353 | *.binlog 354 | 355 | # NVidia Nsight GPU debugger configuration file 356 | *.nvuser 357 | 358 | # MFractors (Xamarin productivity tool) working folder 359 | .mfractor/ 360 | 361 | # Local History for Visual Studio 362 | .localhistory/ 363 | 364 | # Visual Studio History (VSHistory) files 365 | .vshistory/ 366 | 367 | # BeatPulse healthcheck temp database 368 | healthchecksdb 369 | 370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 371 | MigrationBackup/ 372 | 373 | # Ionide (cross platform F# VS Code tools) working folder 374 | .ionide/ 375 | 376 | # Fody - auto-generated XML schema 377 | FodyWeavers.xsd 378 | 379 | # VS Code files for those working on multiple tools 380 | .vscode/* 381 | !.vscode/settings.json 382 | !.vscode/tasks.json 383 | !.vscode/launch.json 384 | !.vscode/extensions.json 385 | *.code-workspace 386 | 387 | # Local History for Visual Studio Code 388 | .history/ 389 | 390 | # Windows Installer files from build outputs 391 | *.cab 392 | *.msi 393 | *.msix 394 | *.msm 395 | *.msp 396 | 397 | # JetBrains Rider 398 | *.sln.iml 399 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "blackbone"] 2 | path = blackbone 3 | url = https://github.com/DarthTon/Blackbone.git 4 | [submodule "imgui"] 5 | path = imgui 6 | url = https://github.com/ocornut/imgui.git 7 | [submodule "dxsdk"] 8 | path = dxsdk 9 | url = https://github.com/MarilynDafa/Microsoft-DirectX-SDK-June-2010-.git 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Ricardo Carvalho 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cheat Loader Project 2 | 3 | That's an old project of mine that i've used in the past, it was not a "paid" product but free one simply to stream free cheats from a website/host. 4 | 5 | It's using Blackbone as injection library for manual mapping and syscalls calling. 6 | 7 | ImGUI for GUI. 8 | RapidJSON for Json parsing. 9 | CURL for HTTP POST/GET. 10 | CryptoPP for cryptographic functions such as AES encrypt/decryption. 11 | 12 | There's no web files on this project, mainly because i lost them but should be straighfoward to implement them yourselfs. 13 | 14 | The project will not compile as is right now, some .lib's like Blackbone should be linked and etc.. 15 | 16 | There's very simple anti-debug measures, with a web report sample aswell. 17 | 18 | The idea of this project is not to be used as is right now but serve as an example. 19 | -------------------------------------------------------------------------------- /loader/CRC32.cpp: -------------------------------------------------------------------------------- 1 | #include "Includes.hpp" 2 | 3 | CheckSum crc32; 4 | 5 | void CheckSum::Initialize( void ) 6 | { 7 | memset( &this->ulTable, 0, sizeof( this->ulTable ) ); 8 | 9 | for( int iCodes = 0; iCodes <= 0xFF; iCodes++ ) 10 | { 11 | this->ulTable[ iCodes ] = this->Reflect( iCodes, 8 ) << 24; 12 | 13 | for( int iPos = 0; iPos < 8; iPos++ ) 14 | { 15 | this->ulTable[ iCodes ] = ( this->ulTable[ iCodes ] << 1 ) ^ 16 | ( this->ulTable[ iCodes ] & ( 1 << 31 ) ? CRC32_POLYNOMIAL : 0 ); 17 | } 18 | this->ulTable[ iCodes ] = this->Reflect( this->ulTable[ iCodes ], 32 ); 19 | } 20 | } 21 | 22 | unsigned long CheckSum::Reflect( unsigned long ulReflect, char cChar ) 23 | { 24 | unsigned long ulValue = 0; 25 | for( int iPos = 1; iPos < ( cChar + 1 ); iPos++ ) 26 | { 27 | if( ulReflect & 1 ) ulValue |= 1 << ( cChar - iPos ); 28 | ulReflect >>= 1; 29 | } 30 | return ulValue; 31 | } 32 | 33 | unsigned long CheckSum::FileCRC( const char* sFileName ) 34 | { 35 | unsigned long ulCRC = 0xffffffff; 36 | unsigned char sBuf[ CRC32BUFSZ ]; 37 | 38 | size_t iBytesRead = 0; 39 | 40 | FILE* f = nullptr; 41 | fopen_s( &f, sFileName, "rb" ); 42 | 43 | if( !f ) 44 | { 45 | return 0xffffffff; 46 | } 47 | do 48 | { 49 | iBytesRead = fread( sBuf, sizeof( char ), sizeof sBuf, f ); 50 | this->PartialCRC( &ulCRC, sBuf, iBytesRead ); 51 | } while( iBytesRead == CRC32BUFSZ ); 52 | 53 | fclose( f ); 54 | return( ulCRC ^ 0xffffffff ); 55 | } 56 | 57 | unsigned long CheckSum::FullCRC( unsigned char* sData, size_t ulLength ) 58 | { 59 | unsigned long ulCRC = 0xffffffff; 60 | this->PartialCRC( &ulCRC, sData, ulLength ); 61 | return ulCRC ^ 0xffffffff; 62 | } 63 | 64 | void CheckSum::PartialCRC( unsigned long* ulInCRC, unsigned char* sData, size_t ulLength ) 65 | { 66 | while( ulLength-- ) 67 | { 68 | *ulInCRC = ( *ulInCRC >> 8 ) ^ this->ulTable[ ( *ulInCRC & 0xFF ) ^ *sData++ ]; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /loader/CRC32.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef CHECKSUM_H 4 | #define CHECKSUM_H 5 | 6 | #define CRC32_POLYNOMIAL 0x04c11db7 7 | #define CRC32BUFSZ 1024 8 | 9 | class CheckSum 10 | { 11 | 12 | public: 13 | 14 | void Initialize(void); 15 | unsigned long FileCRC(const char *sFileName); 16 | unsigned long FullCRC(unsigned char *sData, size_t ulLength); 17 | void PartialCRC(unsigned long *ulInCRC, unsigned char *sData, size_t ulLength); 18 | 19 | private: 20 | 21 | unsigned long Reflect(unsigned long ulReflect, char cChar); 22 | unsigned long ulTable[256]; 23 | }; 24 | 25 | extern CheckSum crc32; 26 | 27 | #endif -------------------------------------------------------------------------------- /loader/CrashRpt.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, Idol Software, Inc. 2 | // All rights reserved. 3 | // 4 | // This file is part of Doctor Dump SDK. 5 | // 6 | // Redistribution and use in source and binary forms without modification, are permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer 11 | // in the documentation and/or other materials provided with the distribution. 12 | // 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 14 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 15 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 16 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 17 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 18 | // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19 | // 20 | // Project web site https://drdump.com 21 | 22 | #ifndef __CRASH_RPT_H__ 23 | #define __CRASH_RPT_H__ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | /** @file */ 31 | 32 | #if !(defined CRASHRPT_ENABLE_RELEASE_ASSERTS) 33 | //! To redefine C \b assert macro behavior define macro \b CRASHRPT_ENABLE_RELEASE_ASSERTS as \b 1 and include CrashRpt.h 34 | //! in each translation unit as soon as possible (precompiled header is the best place for that). 35 | //! \code 36 | //! #define CRASHRPT_ENABLE_RELEASE_ASSERTS 1 37 | //! #include 38 | //! \endcode 39 | //! When \b _DEBUG define is not defined (it is Release configuration) \b assert macro evaluates an expression and, when the result is false, 40 | //! sends report and continues execution. 41 | //! When \b _DEBUG define is defined (it is Debug configuration) \b assert macro works as standard assert macro from assert.h header. 42 | //! \note All assert calls before CrashRpt.h inclusion would work as standard asserts. 43 | //! \sa crash_rpt::CrashRpt::ExceptionAssertionViolated crash_rpt::CrashRpt::SkipDoctorDump_SendAssertionViolated 44 | # define CRASHRPT_ENABLE_RELEASE_ASSERTS 1 45 | # undef CRASHRPT_ENABLE_RELEASE_ASSERTS // this is to make doxygen document CRASHRPT_ENABLE_RELEASE_ASSERTS macro 46 | #elif CRASHRPT_ENABLE_RELEASE_ASSERTS == 1 47 | # include 48 | # ifndef _DEBUG 49 | # undef assert 50 | # define assert(expr) ((void) (!(expr) && (crash_rpt::SkipDoctorDump_ReportAssertionViolation<__COUNTER__>(__FUNCTION__ ": "#expr " is false" ), true))) 51 | # endif // !_DEBUG 52 | #endif // CRASHRPT_ENABLE_RELEASE_ASSERTS 53 | 54 | //! This is namespace crash_rpt 55 | namespace crash_rpt { 56 | 57 | namespace { 58 | 59 | // This template should be in anonymous namespace since __COUNTER__ is unique only for a single translation unit (as anonymous namespace items) 60 | template 61 | __forceinline static void SkipDoctorDump_ReportAssertionViolation(LPCSTR dumpGroup) 62 | { 63 | static LONG volatile isAlreadyReported = FALSE; 64 | if (TRUE == InterlockedCompareExchange(&isAlreadyReported, TRUE, FALSE)) 65 | return; 66 | ::RaiseException(CrashRpt::ExceptionAssertionViolated, 0, 1, reinterpret_cast(&dumpGroup)); 67 | } 68 | 69 | } // namespace { 70 | 71 | //! Information about exception being processed. 72 | struct ExceptionInfo 73 | { 74 | DWORD ExceptionInfoSize; //!< Size of this structure. Should be set to sizeof(ExceptionInfo). 75 | BOOL FromSendReport; //!< Indicates is exception processed using CrashRpt::SendReport() call. 76 | PEXCEPTION_POINTERS ExceptionPointers; //!< Exception pointers. ExceptionPointers->ExceptionRecord->ExceptionCode contains SEH code or ExceptionAssertionViolated or other Exception* constants for C/C++ special handlers. 77 | DWORD ThreadId; //!< Thread identifier of the crashed thread. 78 | }; 79 | 80 | //! Stages when crash processing callback called. 81 | enum CrashProcessingCallbackStage 82 | { 83 | BeforeSendReport, //!< Callback is called before report send. 84 | AfterSendReport //!< Callback is called after the report has been sent. 85 | }; 86 | 87 | //! Result code for crash processing callback. 88 | enum CrashProcessingCallbackResult 89 | { 90 | DoDefaultActions, //!< Default result. Crash handler continues its default processing. 91 | SkipSendReportReturnDefaultResult, //!< Crash handler doesn't send the report and returns its default result. 92 | ContinueExecution, //!< Explicitly force crash handler to return EXCEPTION_CONTINUE_EXECUTION. 93 | ContinueSearch, //!< Explicitly force crash handler to return EXCEPTION_CONTINUE_SEARCH. 94 | ExecuteHandler //!< Explicitly force crash handler to return EXCEPTION_EXECUTE_HANDLER. 95 | }; 96 | 97 | //! Client crash callback function prototype. 98 | typedef CrashProcessingCallbackResult (CALLBACK *PFNCRASHPROCESSINGCALLBACK)( 99 | CrashProcessingCallbackStage stage, //!< Current crash processing stage. 100 | ExceptionInfo* exceptionInfo, //!< Information about exception being processed. 101 | LPVOID userData //!< Pointer to user-defined data. 102 | ); 103 | 104 | 105 | //! Optional custom data collection after the crash in context of sendrpt.exe process. 106 | namespace custom_data_collection { 107 | 108 | //! Result of custom data collection. 109 | enum Result 110 | { 111 | ShowUploadConfirmDialog, //!< Proceed to upload confirm dialog stage. 112 | DoUpload, //!< Skip upload confirm dialog and proceed to upload stage. 113 | CancelUpload, //!< Cancel upload. 114 | }; 115 | 116 | //! Information about the exception. 117 | struct ExceptionInfo 118 | { 119 | DWORD ExceptionInfoSize; //!< Size of this structure. Should be set to sizeof(ExceptionInfo). 120 | LPBYTE UserData; //!< Pointer to user-defined data buffer. 121 | DWORD UserDataSize; //!< Size of userData buffer. 122 | HANDLE Process; //!< Handle to the crashed process. 123 | DWORD ProcessId; //!< Process ID of the crashed process. 124 | LPVOID ExceptInfo; //!< Pointer to \b MINIDUMP_EXCEPTION_INFORMATION structure. 125 | BOOL WasAssert; //!< Is it assert? (see \ref crash_rpt::CrashRpt::SkipDoctorDump_SendAssertionViolated). 126 | LPCSTR DumpGroup; //!< Used-defined dump group (see \ref crash_rpt::CrashRpt::SkipDoctorDump_SendAssertionViolated). 127 | int DumpID; //!< Dump ID of this crash in DrDump service. 128 | int DumpGroupID; //!< DumpGroup ID of this crash in DrDump service. 129 | int ProblemID; //!< Problem ID of this crash in DrDump service. 130 | }; 131 | 132 | //! This interface used to add custom data to crash report. 133 | struct IDataBag 134 | { 135 | //! You may add any file to crash report. This file will be read when crash appears and will be sent within the report. 136 | //! Multiple files may be added. Filename of the file in the report may be changed to any name. 137 | //! \return If the function succeeds, the return value is \b true. 138 | virtual bool AddFileToReport( 139 | LPCWSTR path, //!< [in] Path to the file, that will be added to the report. 140 | LPCWSTR reportFileName /* = NULL */ //!< [in] Filename that will be used in report for this file. If parameter is \b NULL, original name from path will be used. 141 | ) = 0; 142 | 143 | //! Remove from report the file that was registered earlier to be sent within report. 144 | //! \return If the function succeeds, the return value is \b true. 145 | virtual bool RemoveFileFromReport( 146 | LPCWSTR path //!< [in] Path to the file, that will be removed from the report. 147 | ) = 0; 148 | 149 | //! You may add any key/value pair to crash report. 150 | //! \return If the function succeeds, the return value is \b true. 151 | virtual bool AddUserInfoToReport( 152 | LPCWSTR key, //!< [in] key string that will be added to the report. 153 | LPCWSTR value //!< [in] value for the key. 154 | ) = 0; 155 | 156 | //! You may remove any key that was added previously to crash report by \ref crash_rpt::CrashRpt::AddUserInfoToReport. 157 | //! \return If the function succeeds, the return value is \b true. 158 | virtual bool RemoveUserInfoFromReport( 159 | LPCWSTR key //!< [in] key string that will be removed from the report. 160 | ) = 0; 161 | }; 162 | 163 | //! Client crash callback function prototype. 164 | typedef Result (CALLBACK *PFNCUSTOMDATACOLLECTIONCALLBACK)( 165 | const ExceptionInfo& exceptionInfo, //!< Information about exception being processed. 166 | IDataBag* dataBag //!< Interface for adding custom data to crash report. 167 | ); 168 | 169 | //! Contains data for optional custom data collection after the crash in context of sendrpt.exe process. 170 | struct Settings 171 | { 172 | DWORD SettingsSize; //!< Size of this structure. Should be set to sizeof(crash_rpt::custom_data_collection::Settings). 173 | LPCWSTR CollectionLibraryPath; //!< Path to dll where collection function exported from. 174 | LPCSTR CollectionFunctionName; //!< Name of collection function exported from \ref CollectionLibraryPath. It should have \ref crash_rpt::custom_data_collection::PFNCUSTOMDATACOLLECTIONCALLBACK prototype. 175 | LPBYTE UserData; //!< Pointer to user-defined data buffer. 176 | DWORD UserDataSize; //!< Size of \ref UserData buffer. 177 | }; 178 | 179 | } // namespace custom_data_collection 180 | 181 | //! This is namespace crash_rpt::crt_error_handlers 182 | namespace crt_error_handlers { 183 | 184 | typedef void(__cdecl *_crt_signal_t)(int); 185 | typedef _crt_signal_t(__cdecl *pfn_signal)(int sig, _crt_signal_t func); 186 | typedef void(__cdecl* terminate_function)(); 187 | typedef terminate_function(__cdecl *pfn_set_terminate)(terminate_function); 188 | typedef void(__cdecl* _invalid_parameter_handler)(wchar_t const*, wchar_t const*, wchar_t const*, unsigned int, uintptr_t); 189 | typedef _invalid_parameter_handler(__cdecl *pfn_set_invalid_parameter_handler)(_invalid_parameter_handler); 190 | typedef void(__cdecl* _purecall_handler)(void); 191 | typedef _purecall_handler(__cdecl *pfn_set_purecall_handler)(_purecall_handler); 192 | 193 | //! Setters for CRT error handlers. 194 | struct Settings 195 | { 196 | DWORD SettingsSize; //!< Size of this structure. Should be set to sizeof(crash_rpt::crt_error_handlers::Settings). 197 | pfn_signal Signal; //!< Address of signal function. 198 | pfn_set_terminate SetTerminate; //!< Address of set_terminate function. 199 | pfn_set_invalid_parameter_handler SetInvalidParameterHandler; //!< Address of _set_invalid_parameter_handler function. 200 | pfn_set_purecall_handler SetPureCallHandler; //!< Address of _set_purecall_handler function. 201 | }; 202 | 203 | } // namespace crt_error_handlers 204 | 205 | //! Contains data that identifies your application. 206 | struct ApplicationInfo 207 | { 208 | DWORD ApplicationInfoSize; //!< Size of this structure. Should be set to sizeof(ApplicationInfo). 209 | LPCSTR ApplicationGUID; //!< GUID assigned to this application in form 00000000-0000-0000-0000-000000000000. 210 | LPCSTR Prefix; //!< Prefix that will be used with the dump name: YourPrefix_v1.v2.v3.v4_YYYYMMDD_HHMMSS.mini.dmp. 211 | LPCWSTR AppName; //!< Application name that will be shown in message box. 212 | LPCWSTR Company; //!< Company name that will be shown in message box. 213 | USHORT V[4]; //!< Version of this application. 214 | USHORT Hotfix; //!< Version of hotfix for this application (reserved for future use, should be 0). 215 | LPCWSTR PrivacyPolicyUrl; //!< URL to privacy policy. If NULL default privacy policy is used. 216 | }; 217 | 218 | //! \brief Contains crash handling behavior customization parameters. 219 | //! 220 | //! Default values for all parameters are 0/FALSE. 221 | struct HandlerSettings 222 | { 223 | DWORD HandlerSettingsSize; //!< Size of this structure. Should be set to sizeof(HandlerSettings). 224 | BOOL LeaveDumpFilesInTempFolder; //!< To leave error reports in temp folder you should set this member to TRUE. Your support or test lab teams can use that reports later. 225 | BOOL OpenProblemInBrowser; //!< To open Web-page belonging to the uploaded report after it was uploaded set this member to TRUE. It is useful for test lab to track the bug or write some comments. 226 | BOOL UseWER; //!< To continue use Microsoft Windows Error Reporting (WER) set this member to TRUE. In that case after Doctor Dump send report dialog Microsoft send report dialog also will be shown. This can be necessary in case of Windows Logo program. 227 | DWORD SubmitterID; //!< Doctor Dump user ID. Uploaded report will be marked as uploaded by this user. This is useful for Doctor Dump and bug tracking system integration. Set to \b 0 if user using this application is anonymous. 228 | BOOL SendAdditionalDataWithoutApproval; //!< To automatically accepted the question "Do you want to send more information about the problem?" set this member to TRUE . 229 | BOOL OverrideDefaultFullDumpType;//!< To override default type of data gathered by the library set this member to TRUE and set required type of data in \a FullDumpType. 230 | DWORD FullDumpType; //!< The type of information to be generated when full dump is requested by Doctor Dump. This parameter can be one or more of the values from the MINIDUMP_TYPE enumeration. 231 | LPCWSTR LangFilePath; //!< To customize localization set this member to the path to the language file (including file name). 232 | LPCWSTR SendRptPath; //!< Set this member to NULL to use default behavior when SendRpt is named sendrpt.exe and exist in same folder with crashrpt.dll. Set to filename if sendrpt.exe has another name but it is in same folder as crashrpt.dll. Set to full path in other cases. 233 | LPCWSTR DbgHelpPath; //!< Set this member to NULL to use default behavior when DbgHelp is named dbghelp.dll and exist in same folder with crashrpt.dll. Set to filename if dbghelp.dll has another name but it is in same folder as crashrpt.dll. Set to full path in other cases. 234 | //!< \note You should use dbghelp.dll that distributed with crashrpt.dll and not the %SystemRoot%\\System32\\dbghelp.dll, because only that dll supports all required functionality. See DbgHelp Versions for more information. 235 | PFNCRASHPROCESSINGCALLBACK CrashProcessingCallback; //!< Callback function that will be called when crash reporting occurs. Set to NULL if no special processing needed. 236 | LPVOID CrashProcessingCallbackUserData; //!< User defined parameter for CrashProcessingCallback. Optional. 237 | custom_data_collection::Settings* CustomDataCollectionSettings; 238 | //!< Contains data for optional custom data collection after the crash in context of sendrpt.exe process. 239 | crt_error_handlers::Settings* CrtErrorHandlersSettings; 240 | //!< Contains setters for CRT error handlers. Set to NULL to use default handlers. 241 | }; 242 | 243 | //! \brief To enable crash processing you should create an instance of this class. 244 | //! 245 | //! It should be created as global static object and correctly initialized. 246 | //! Also you may instantiate it in your main() or WinMain() function as soon as possible. 247 | class CrashRpt 248 | { 249 | public: 250 | //! \example Sample.cpp 251 | //! This is an example of how to use the CrashRpt class. 252 | 253 | //! CrashRpt constructor. Loads crashrpt.dll and initializes crash handling. 254 | //! \note The crashrpt.dll is allowed to be missing. In that case there will be no crash handling. 255 | CrashRpt( 256 | LPCSTR applicationGUID, //!< [in] GUID assigned to this application. 257 | LPCWSTR appName, //!< [in] Application name that will be shown in message box. 258 | LPCWSTR company //!< [in] Company name that will be shown in message box. 259 | ) throw() 260 | { 261 | if (!LoadDll()) 262 | return; 263 | 264 | InitCrashRpt(applicationGUID, NULL, appName, company, TRUE); 265 | } 266 | 267 | //! CrashRpt constructor. Loads crashrpt.dll and initializes crash handling. 268 | //! \note The crashrpt.dll is allowed to be missing. In that case there will be no crash handling. 269 | CrashRpt( 270 | LPCSTR applicationGUID, //!< [in] GUID assigned to this application. 271 | LPCSTR prefix, //!< [in] Prefix that will be used with the dump name: YourPrefix_v1.v2.v3.v4_YYYYMMDD_HHMMSS.mini.dmp. 272 | LPCWSTR appName, //!< [in] Application name that will be shown in message box. 273 | LPCWSTR company, //!< [in] Company name that will be shown in message box. 274 | BOOL ownProcess = TRUE //!< [in] If you own the process your code running in set this option to \b TRUE. If don't (for example you write 275 | //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly 276 | //!< catch exceptions. See \ref SendReport for more information. 277 | ) throw() 278 | { 279 | if (!LoadDll()) 280 | return; 281 | 282 | InitCrashRpt(applicationGUID, prefix, appName, company, ownProcess); 283 | } 284 | 285 | //! CrashRpt constructor. Loads crashrpt.dll and initializes crash handling. 286 | //! \note The crashrpt.dll is allowed to be missing. In that case there will be no crash handling. 287 | CrashRpt( 288 | LPCWSTR crashrptPath, //!< [in] Path to crashrpt.dll file. File may be renamed. 289 | LPCSTR applicationGUID, //!< [in] GUID assigned to this application. 290 | LPCSTR prefix, //!< [in] Prefix that will be used with the dump name: YourPrefix_v1.v2.v3.v4_YYYYMMDD_HHMMSS.mini.dmp. 291 | LPCWSTR appName, //!< [in] Application name that will be shown in message box. 292 | LPCWSTR company, //!< [in] Company name that will be shown in message box. 293 | BOOL ownProcess = TRUE //!< [in] If you own the process your code running in set this option to \b TRUE. If don't (for example you write 294 | //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly 295 | //!< catch exceptions. See \ref SendReport for more information. 296 | ) throw() 297 | { 298 | if (!LoadDll(crashrptPath)) 299 | return; 300 | 301 | InitCrashRpt(applicationGUID, prefix, appName, company, ownProcess); 302 | } 303 | 304 | //! CrashRpt constructor. Loads crashrpt.dll and initializes crash handling. 305 | //! \note The crashrpt.dll is allowed to be missing. In that case there will be no crash handling. 306 | CrashRpt( 307 | ApplicationInfo* applicationInfo, //!< [in] Pointer to the ApplicationInfo structure that identifies your application. 308 | HandlerSettings* handlerSettings, //!< [in] Pointer to the HandlerSettings structure that customizes crash handling behavior. This parameter can be \b NULL. 309 | BOOL ownProcess = TRUE //!< [in] If you own the process your code running in set this option to \b TRUE. If don't (for example you write 310 | //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly 311 | //!< catch exceptions. See \ref SendReport for more information. 312 | ) throw() 313 | { 314 | if (!LoadDll()) 315 | return; 316 | 317 | InitCrashRpt(applicationInfo, handlerSettings, ownProcess); 318 | } 319 | 320 | //! CrashRpt constructor. Loads crashrpt.dll and initializes crash handling. 321 | //! \note The crashrpt.dll is allowed to be missing. In that case there will be no crash handling. 322 | CrashRpt( 323 | LPCWSTR crashrptPath, //!< [in] Path to crashrpt.dll file. File may be renamed. 324 | ApplicationInfo* applicationInfo, //!< [in] Pointer to the ApplicationInfo structure that identifies your application. 325 | HandlerSettings* handlerSettings, //!< [in] Pointer to the HandlerSettings structure that customizes crash handling behavior. This parameter can be \b NULL. 326 | BOOL ownProcess = TRUE //!< [in] If you own the process your code running in set this option to \b TRUE. If don't (for example you write 327 | //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly 328 | //!< catch exceptions. See \ref SendReport for more information. 329 | ) throw() 330 | { 331 | if (!LoadDll(crashrptPath)) 332 | return; 333 | 334 | InitCrashRpt(applicationInfo, handlerSettings, ownProcess); 335 | } 336 | 337 | 338 | //! CrashRpt constructor. Loads crashrpt.dll. You should call \ref InitCrashRpt to turn on crash handling. 339 | //! \note The crashrpt.dll is allowed to be missing. In that case there will be no crash handling. 340 | CrashRpt( 341 | LPCWSTR crashrptPath = NULL //!< [in] Path to crashrpt.dll file. File may be renamed. 342 | ) throw() 343 | { 344 | LoadDll(crashrptPath); 345 | } 346 | 347 | //! CrashRpt destructor. 348 | //! \note It doesn't unload crashrpt.dll and doesn't disable crash handling since crash may appear on very late phase of application exit. 349 | //! For example destructor of some static variable that is called after return from main() may crash. 350 | ~CrashRpt() 351 | { 352 | if (!m_IsReadyToExit) 353 | return; 354 | 355 | // If crash has happen not in main thread we should wait here until report will be sent 356 | // or else program will be terminated after return from main() and report sending will be halted. 357 | while (!m_IsReadyToExit()) 358 | ::Sleep(100); 359 | 360 | #if _WIN32_WINNT >= 0x0501 /*_WIN32_WINNT_WINXP*/ 361 | if (m_bSkipAssertsAdded) 362 | RemoveVectoredExceptionHandler(SkipAsserts); 363 | #endif 364 | } 365 | 366 | //! Checks that crash handling was enabled. 367 | //! \return Return \b true if crash handling was enabled. 368 | bool IsCrashHandlingEnabled() const 369 | { 370 | return m_bWorking; 371 | } 372 | 373 | //! Initializes crash handler. 374 | //! \note You may call this function multiple times if some data has changed. 375 | //! \return Return \b true if crash handling was enabled. 376 | bool InitCrashRpt( 377 | ApplicationInfo* applicationInfo, //!< [in] Pointer to the ApplicationInfo structure that identifies your application. 378 | HandlerSettings* handlerSettings, //!< [in] Pointer to the HandlerSettings structure that customizes crash handling behavior. This parameter can be \b NULL. 379 | BOOL ownProcess = TRUE //!< [in] If you own the process your code running in set this option to \b TRUE. If don't (for example you write 380 | //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly 381 | //!< catch exceptions. See \ref SendReport for more information. 382 | ) throw() 383 | { 384 | if (!m_InitCrashRpt) 385 | return false; 386 | 387 | crt_error_handlers::Settings crtErrorHandlersSettings; 388 | memset(&crtErrorHandlersSettings, 0, sizeof(crtErrorHandlersSettings)); 389 | crtErrorHandlersSettings.SettingsSize = sizeof(crtErrorHandlersSettings); 390 | crtErrorHandlersSettings.Signal = signal; 391 | crtErrorHandlersSettings.SetTerminate = set_terminate; 392 | #if defined(_MSC_VER) 393 | crtErrorHandlersSettings.SetInvalidParameterHandler = _set_invalid_parameter_handler; 394 | crtErrorHandlersSettings.SetPureCallHandler = _set_purecall_handler; 395 | #endif 396 | 397 | HandlerSettings defHandlerSettings; 398 | memset(&defHandlerSettings, 0, sizeof(defHandlerSettings)); 399 | defHandlerSettings.HandlerSettingsSize = sizeof(defHandlerSettings); 400 | defHandlerSettings.OpenProblemInBrowser = TRUE; 401 | defHandlerSettings.CrtErrorHandlersSettings = &crtErrorHandlersSettings; 402 | 403 | if (handlerSettings == NULL) 404 | { 405 | handlerSettings = &defHandlerSettings; 406 | } 407 | else if (handlerSettings->CrtErrorHandlersSettings == NULL) 408 | { 409 | handlerSettings->CrtErrorHandlersSettings = &crtErrorHandlersSettings; 410 | } 411 | 412 | m_bWorking = m_InitCrashRpt(applicationInfo, handlerSettings, ownProcess) != FALSE; 413 | 414 | return m_bWorking; 415 | } 416 | 417 | //! Initializes crash handler. 418 | //! \note You may call this function multiple times if some data has changed. 419 | //! \return Return \b true if crash handling was enabled. 420 | bool InitCrashRpt( 421 | LPCSTR applicationGUID, //!< [in] GUID assigned to this application. 422 | LPCSTR prefix, //!< [in] Prefix that will be used with the dump name: YourPrefix_v1.v2.v3.v4_YYYYMMDD_HHMMSS.mini.dmp. 423 | LPCWSTR appName, //!< [in] Application name that will be shown in message box. 424 | LPCWSTR company, //!< [in] Company name that will be shown in message box. 425 | BOOL ownProcess = TRUE //!< [in] If you own the process your code running in set this option to \b TRUE. If don't (for example you write 426 | //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly 427 | //!< catch exceptions. See \ref SendReport for more information. 428 | ) throw() 429 | { 430 | if (!m_GetVersionFromApp) 431 | return false; 432 | 433 | ApplicationInfo appInfo; 434 | memset(&appInfo, 0, sizeof(appInfo)); 435 | appInfo.ApplicationInfoSize = sizeof(appInfo); 436 | appInfo.ApplicationGUID = applicationGUID; 437 | appInfo.Prefix = prefix; 438 | appInfo.AppName = appName; 439 | appInfo.Company = company; 440 | if (!m_GetVersionFromApp(&appInfo)) 441 | appInfo.V[0] = 1; 442 | 443 | return InitCrashRpt(&appInfo, NULL, ownProcess); 444 | } 445 | 446 | //! You may set custom information for your possible report. 447 | //! This text will be available on Doctor Dump dumps page. 448 | //! The text should not contain private information. 449 | //! \warning This function is experimental and may not be available and may not be support by Doctor Dump in the future. 450 | //! \return If the function succeeds, the return value is \b true. 451 | bool SetCustomInfo( 452 | LPCWSTR text //!< [in] custom info for the report. The text will be cut to 100 characters. 453 | ) 454 | { 455 | if (!m_SetCustomInfo) 456 | return false; 457 | m_SetCustomInfo(text); 458 | return true; 459 | } 460 | 461 | //! You may add any key/value pair to crash report. 462 | //! \return If the function succeeds, the return value is \b true. 463 | //! \note This function is thread safe. 464 | bool AddUserInfoToReport( 465 | LPCWSTR key, //!< [in] key string that will be added to the report. 466 | LPCWSTR value //!< [in] value for the key. 467 | ) throw() 468 | { 469 | if (!m_AddUserInfoToReport) 470 | return false; 471 | m_AddUserInfoToReport(key, value); 472 | return true; 473 | } 474 | 475 | //! You may remove any key that was added previously to crash report by \a AddUserInfoToReport. 476 | //! \return If the function succeeds, the return value is \b true. 477 | //! \note This function is thread safe. 478 | bool RemoveUserInfoFromReport( 479 | LPCWSTR key //!< [in] key string that will be removed from the report. 480 | ) 481 | { 482 | if (!m_RemoveUserInfoFromReport) 483 | return false; 484 | m_RemoveUserInfoFromReport(key); 485 | return true; 486 | } 487 | 488 | //! You may add any file to crash report. This file will be read when crash appears and will be sent within the report. 489 | //! Multiple files may be added. Filename of the file in the report may be changed to any name. 490 | //! \return If the function succeeds, the return value is \b true. 491 | //! \note The file should be accessible with \b GENERIC_READ access and \b FILE_SHARE_READ share mode. 492 | //! If your program uses this file with another access options (for example this is log file and it is open for writing) 493 | //! you should release the file in \ref crash_rpt::HandlerSettings::CrashProcessingCallback on #BeforeSendReport stage. 494 | //! \note This function is thread safe. 495 | bool AddFileToReport( 496 | LPCWSTR path, //!< [in] Path to the file, that will be added to the report. 497 | LPCWSTR reportFileName /* = NULL */ //!< [in] Filename that will be used in report for this file. If parameter is \b NULL, original name from path will be used. 498 | ) throw() 499 | { 500 | if (!m_AddFileToReport) 501 | return false; 502 | m_AddFileToReport(path, reportFileName); 503 | return true; 504 | } 505 | 506 | //! Remove from report the file that was registered earlier to be sent within report. 507 | //! \return If the function succeeds, the return value is \b true. 508 | //! \note This function is thread safe. 509 | bool RemoveFileFromReport( 510 | LPCWSTR path //!< [in] Path to the file, that will be removed from the report. 511 | ) throw() 512 | { 513 | if (!m_RemoveFileFromReport) 514 | return false; 515 | m_RemoveFileFromReport(path); 516 | return true; 517 | } 518 | 519 | //! Fills version field (V) of ApplicationInfo with product version 520 | //! found in the executable file of the current process. 521 | //! \return If the function succeeds, the return value is \b true. 522 | bool GetVersionFromApp( 523 | ApplicationInfo* appInfo //!< [out] Pointer to ApplicationInfo structure. Its version field (V) will be set to product version. 524 | ) throw() 525 | { 526 | if (!m_GetVersionFromApp) 527 | return false; 528 | return m_GetVersionFromApp(appInfo) != FALSE; 529 | } 530 | 531 | //! Fill version field (V) of ApplicationInfo with product version found in the file specified. 532 | //! \return If the function succeeds, the return value is \b true. 533 | bool GetVersionFromFile( 534 | LPCWSTR path, //!< [in] Path to the file product version will be extracted from. 535 | ApplicationInfo* appInfo //!< [out] Pointer to ApplicationInfo structure. Its version field (V) will be set to product version. 536 | ) throw() 537 | { 538 | if (!m_GetVersionFromFile) 539 | return false; 540 | return m_GetVersionFromFile(path, appInfo) != FALSE; 541 | } 542 | 543 | //! If you do not own the process your code running in (for example you write a plugin to some 544 | //! external application) you need to properly initialize CrashRpt using \b ownProcess option. 545 | //! Also you need to explicitly catch all exceptions in all entry points to your code and in all 546 | //! threads you create. To do so use this construction: 547 | //! \code 548 | //! bool SomeEntryPoint(PARAM p) 549 | //! { 550 | //! __try 551 | //! { 552 | //! return YouCode(p); 553 | //! } 554 | //! __except (CrashRpt::SendReport(GetExceptionInformation())) 555 | //! { 556 | //! ::ExitProcess(0); // It is better to stop the process here or else corrupted data may incomprehensibly crash it later. 557 | //! return false; 558 | //! } 559 | //! } 560 | //! \endcode 561 | LONG SendReport( 562 | EXCEPTION_POINTERS* exceptionPointers //!< [in] Pointer to EXCEPTION_POINTERS structure. You should get it using GetExceptionInformation() 563 | //!< function inside __except keyword. 564 | ) 565 | { 566 | if (!m_SendReport) 567 | { 568 | // There is no crash handler but asserts should not crash application anyway, so let's continue 569 | if (exceptionPointers->ExceptionRecord->ExceptionCode == ExceptionAssertionViolated) 570 | return EXCEPTION_CONTINUE_EXECUTION; 571 | return EXCEPTION_CONTINUE_SEARCH; 572 | } 573 | return m_SendReport(exceptionPointers); 574 | } 575 | 576 | //! To send a report about violated assertion you can throw exception with this exception code 577 | //! using: \code RaiseException(CrashRpt::ExceptionAssertionViolated, 0, 0, NULL); \endcode 578 | //! Execution will continue after report will be sent (EXCEPTION_CONTINUE_EXECUTION would be used). 579 | //! You may pass grouping string as first parameter (see \a SkipDoctorDump_SendAssertionViolated). 580 | //! \note If you called CrashRpt constructor and crashrpt.dll was missing you still may using this exception. 581 | //! It will be caught, ignored and execution will continue. \ref SendReport function also works safely 582 | //! when crashrpt.dll was missing. 583 | //! \sa CRASHRPT_ENABLE_RELEASE_ASSERTS SkipDoctorDump_SendAssertionViolated 584 | static const DWORD ExceptionAssertionViolated = ((DWORD)0xCCE17000); 585 | 586 | //! Exception code for Terminate()/SIGABRT call in crash callback. 587 | static const DWORD ExceptionCppTerminate = ((DWORD)0xCCE17001); 588 | 589 | //! Exception code for pure virtual call in crash callback. 590 | static const DWORD ExceptionPureCall = ((DWORD)0xCCE17002); 591 | 592 | //! Exception code for CRT invalid parameter call in crash callback. 593 | static const DWORD ExceptionInvalidParameter = ((DWORD)0xCCE17003); 594 | 595 | //! Sends assertion violation report from this point and continue execution. 596 | //! \sa ExceptionAssertionViolated 597 | //! \note Functions containing "SkipDoctorDump" will be ignored in stack parsing. 598 | //! \sa CRASHRPT_ENABLE_RELEASE_ASSERTS ExceptionAssertionViolated 599 | void SkipDoctorDump_SendAssertionViolated( 600 | LPCSTR dumpGroup = NULL //!< [in] All dumps with that group will be separated from dumps with same stack but another group. Set parameter to \b NULL if no grouping is required. 601 | ) const 602 | { 603 | if (!m_bWorking) 604 | return; 605 | if (dumpGroup) 606 | ::RaiseException(CrashRpt::ExceptionAssertionViolated, 0, 1, reinterpret_cast(&dumpGroup)); 607 | else 608 | ::RaiseException(CrashRpt::ExceptionAssertionViolated, 0, 0, NULL); 609 | } 610 | 611 | private: 612 | bool LoadDll(LPCWSTR crashrptPath = NULL) throw() 613 | { 614 | m_bLoaded = false; 615 | m_bWorking = false; 616 | m_bSkipAssertsAdded = false; 617 | m_InitCrashRpt = NULL; 618 | m_SendReport = NULL; 619 | m_IsReadyToExit = NULL; 620 | m_SetCustomInfo = NULL; 621 | m_AddUserInfoToReport = NULL; 622 | m_RemoveUserInfoFromReport = NULL; 623 | m_AddFileToReport = NULL; 624 | m_RemoveFileFromReport = NULL; 625 | m_GetVersionFromApp = NULL; 626 | m_GetVersionFromFile = NULL; 627 | 628 | // hCrashrptDll should not be unloaded, crash may appear even after return from main(). 629 | // So hCrashrptDll is not saved after construction. 630 | HMODULE hCrashrptDll = ::LoadLibraryW(crashrptPath ? crashrptPath : L"crashrpt.dll"); 631 | if (hCrashrptDll != NULL) 632 | { 633 | m_InitCrashRpt = (pfnInitCrashRpt) reinterpret_cast(GetProcAddress(hCrashrptDll, "InitCrashRpt")); 634 | m_SendReport = (pfnSendReport) reinterpret_cast(GetProcAddress(hCrashrptDll, "SendReport")); 635 | m_IsReadyToExit = (pfnIsReadyToExit) reinterpret_cast(GetProcAddress(hCrashrptDll, "IsReadyToExit")); 636 | m_SetCustomInfo = (pfnSetCustomInfo) reinterpret_cast(GetProcAddress(hCrashrptDll, "SetCustomInfo")); 637 | m_AddUserInfoToReport = (pfnAddUserInfoToReport) reinterpret_cast(GetProcAddress(hCrashrptDll, "AddUserInfoToReport")); 638 | m_RemoveUserInfoFromReport = (pfnRemoveUserInfoFromReport) reinterpret_cast(GetProcAddress(hCrashrptDll, "RemoveUserInfoFromReport")); 639 | m_AddFileToReport = (pfnAddFileToReport) reinterpret_cast(GetProcAddress(hCrashrptDll, "AddFileToReport")); 640 | m_RemoveFileFromReport = (pfnRemoveFileFromReport) reinterpret_cast(GetProcAddress(hCrashrptDll, "RemoveFileFromReport")); 641 | m_GetVersionFromApp = (pfnGetVersionFromApp) reinterpret_cast(GetProcAddress(hCrashrptDll, "GetVersionFromApp")); 642 | m_GetVersionFromFile = (pfnGetVersionFromFile) reinterpret_cast(GetProcAddress(hCrashrptDll, "GetVersionFromFile")); 643 | 644 | m_bLoaded = m_InitCrashRpt 645 | && m_SendReport 646 | && m_IsReadyToExit 647 | && m_SetCustomInfo 648 | && m_AddUserInfoToReport 649 | && m_RemoveUserInfoFromReport 650 | && m_AddFileToReport 651 | && m_RemoveFileFromReport 652 | && m_GetVersionFromApp 653 | && m_GetVersionFromFile; 654 | } 655 | 656 | #if _WIN32_WINNT >= 0x0501 /*_WIN32_WINNT_WINXP*/ 657 | // if no crash processing was started, we need to ignore ExceptionAssertionViolated exceptions. 658 | if (!m_bLoaded) 659 | { 660 | ::AddVectoredExceptionHandler(TRUE, SkipAsserts); 661 | m_bSkipAssertsAdded = true; 662 | } 663 | #endif 664 | 665 | return m_bLoaded; 666 | } 667 | 668 | static LONG CALLBACK SkipAsserts(EXCEPTION_POINTERS* pExceptionInfo) 669 | { 670 | if (pExceptionInfo->ExceptionRecord->ExceptionCode == ExceptionAssertionViolated) 671 | return EXCEPTION_CONTINUE_EXECUTION; 672 | return EXCEPTION_CONTINUE_SEARCH; 673 | } 674 | 675 | bool m_bLoaded; 676 | bool m_bWorking; 677 | bool m_bSkipAssertsAdded; 678 | 679 | typedef BOOL (__cdecl *pfnInitCrashRpt)(ApplicationInfo* applicationInfo, HandlerSettings* handlerSettings, BOOL ownProcess); 680 | typedef LONG (__cdecl *pfnSendReport)(EXCEPTION_POINTERS* exceptionPointers); 681 | typedef BOOL (__cdecl *pfnIsReadyToExit)(); 682 | typedef void (__cdecl *pfnSetCustomInfo)(LPCWSTR text); 683 | typedef void (__cdecl *pfnAddUserInfoToReport)(LPCWSTR key, LPCWSTR value); 684 | typedef void (__cdecl *pfnRemoveUserInfoFromReport)(LPCWSTR key); 685 | typedef void (__cdecl *pfnAddFileToReport)(LPCWSTR path, LPCWSTR reportFileName /* = NULL */); 686 | typedef void (__cdecl *pfnRemoveFileFromReport)(LPCWSTR path); 687 | typedef BOOL (__cdecl *pfnGetVersionFromApp)(ApplicationInfo* appInfo); 688 | typedef BOOL (__cdecl *pfnGetVersionFromFile)(LPCWSTR path, ApplicationInfo* appInfo); 689 | 690 | pfnInitCrashRpt m_InitCrashRpt; 691 | pfnSendReport m_SendReport; 692 | pfnIsReadyToExit m_IsReadyToExit; 693 | pfnSetCustomInfo m_SetCustomInfo; 694 | pfnAddUserInfoToReport m_AddUserInfoToReport; 695 | pfnRemoveUserInfoFromReport m_RemoveUserInfoFromReport; 696 | pfnAddFileToReport m_AddFileToReport; 697 | pfnRemoveFileFromReport m_RemoveFileFromReport; 698 | pfnGetVersionFromApp m_GetVersionFromApp; 699 | pfnGetVersionFromFile m_GetVersionFromFile; 700 | }; 701 | 702 | } // namespace crash_rpt 703 | 704 | #endif // __CRASH_RPT_H__ -------------------------------------------------------------------------------- /loader/CurlWrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "Includes.hpp" 2 | 3 | CurlWrapper curl_wrapper; 4 | 5 | bool CurlWrapper::DownloadToString(const std::string& url, std::string& data) 6 | { 7 | VM_REGION_START; 8 | data.clear(); 9 | 10 | CURL* curl = curl_easy_init(); 11 | 12 | // Set remote URL. 13 | curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); 14 | 15 | curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); 16 | curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15); 17 | curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); 18 | 19 | curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); 20 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); 21 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L); 22 | 23 | curl_easy_setopt(curl, CURLOPT_COOKIEFILE, _cookies.c_str()); 24 | curl_easy_setopt(curl, CURLOPT_COOKIEJAR, _cookies.c_str()); 25 | curl_easy_setopt(curl, CURLOPT_USERAGENT, "LoaderAgent2"); 26 | 27 | // Response information. 28 | long httpCode(0); 29 | std::unique_ptr httpData(new std::string()); 30 | 31 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback); 32 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data); 33 | 34 | // Run our HTTP GET command, capture the HTTP response code, and clean up. 35 | const auto err_code = curl_easy_perform(curl); 36 | 37 | if (err_code != CURLE_OK) 38 | return false; 39 | 40 | curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); 41 | curl_easy_cleanup(curl); 42 | 43 | if (httpCode == 200) 44 | return true; 45 | VM_REGION_END; 46 | 47 | return false; 48 | } 49 | 50 | bool CurlWrapper::AuthenticateUser(const char* username, const char* password) 51 | { 52 | VM_REGION_START; 53 | CURL* curl = curl_easy_init(); 54 | 55 | const std::string url = base_url + "login.php"; 56 | 57 | // Set remote URL. 58 | curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); 59 | 60 | curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); 61 | curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15); 62 | curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); 63 | 64 | curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); 65 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); 66 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L); 67 | 68 | curl_easy_setopt(curl, CURLOPT_COOKIEFILE, _cookies.c_str()); 69 | curl_easy_setopt(curl, CURLOPT_COOKIEJAR, _cookies.c_str()); 70 | curl_easy_setopt(curl, CURLOPT_USERAGENT, "LoaderAgent2"); 71 | 72 | std::string encoded; 73 | 74 | CryptoPP::StringSource ss(password, true, 75 | new CryptoPP::Base64Encoder( 76 | new CryptoPP::StringSink(encoded) 77 | ) 78 | ); 79 | 80 | std::string hwid; 81 | GenerateHardDiskHash(hwid); 82 | 83 | char post_field[500]; 84 | sprintf_s(post_field, "username=%s&pass=%s&hwid=%s", username, encoded.c_str(), hwid.c_str()); 85 | 86 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_field); 87 | 88 | // Response information. 89 | long httpCode(0); 90 | std::unique_ptr httpData(new std::string()); 91 | 92 | std::string response_data; 93 | 94 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback); 95 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data); 96 | 97 | // Run our HTTP GET command, capture the HTTP response code, and clean up. 98 | const auto err_code = curl_easy_perform(curl); 99 | 100 | if (err_code != CURLE_OK) 101 | return false; 102 | 103 | curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); 104 | curl_easy_cleanup(curl); 105 | 106 | if (httpCode == 200) 107 | { 108 | try 109 | { 110 | Document document; 111 | document.Parse(response_data.c_str()); 112 | 113 | if (!strcmp(document[0]["login_result"].GetString(), "banned")) 114 | { 115 | MessageBoxA(GetActiveWindow(), "You're banned, not allowed to login or use.", 0, MB_ICONERROR); 116 | PostQuitMessage(-1); 117 | } 118 | 119 | if (!strcmp(document[0]["login_result"].GetString(), "hwid_in_use")) 120 | { 121 | MessageBoxA(GetActiveWindow(), "Every account is HWID locked, you can't use it in another computer.", 0, MB_ICONERROR); 122 | PostQuitMessage(-1); 123 | } 124 | 125 | return !strcmp(document[0]["login_result"].GetString(), "success"); 126 | } 127 | catch (...) 128 | { 129 | MessageBoxA(GetActiveWindow(), "Failed to parse data", 0, MB_ICONERROR); 130 | } 131 | } 132 | VM_REGION_END; 133 | return false; 134 | } 135 | 136 | bool CurlWrapper::DownloadFile(const std::string& url, std::vector< std::uint8_t >& file_bytes) 137 | { 138 | VM_REGION_START; 139 | IStream* pStream; 140 | 141 | HRESULT hr = URLOpenBlockingStreamA(nullptr, url.c_str(), &pStream, 0, nullptr); 142 | if (FAILED(hr)) 143 | { 144 | MessageBoxA(GetActiveWindow(), "Failed to download file from the internet", 0, MB_ICONERROR); 145 | return false; 146 | } 147 | 148 | STATSTG statStream; 149 | if (FAILED(pStream->Stat(&statStream, STATFLAG_NONAME))) 150 | { 151 | pStream->Release(); 152 | MessageBoxA(GetActiveWindow(), "pStream->Stat failed", 0, MB_ICONERROR); 153 | return false; 154 | } 155 | 156 | DWORD dwSize = statStream.cbSize.LowPart + 1; 157 | 158 | file_bytes.resize(dwSize); 159 | 160 | LARGE_INTEGER liPos; 161 | ZeroMemory(&liPos, sizeof(liPos)); 162 | 163 | pStream->Seek(liPos, STREAM_SEEK_SET, NULL); 164 | pStream->Read(file_bytes.data(), dwSize - 1, NULL); 165 | 166 | if (pStream) 167 | { 168 | pStream->Release(); 169 | pStream = nullptr; 170 | } 171 | 172 | file_bytes.pop_back(); 173 | VM_REGION_END; 174 | return true; 175 | } 176 | 177 | inline std::string CurlWrapper::CalculateFileHash(const std::wstring& szFilePath) 178 | { 179 | std::vector< char > myData; 180 | 181 | std::fstream ifs(szFilePath, std::ios::in | std::ios::binary | std::ios::ate); 182 | std::string result = "hash failed"; 183 | 184 | if (ifs) 185 | { 186 | std::ifstream::pos_type pos = ifs.tellg(); 187 | 188 | myData.resize(pos); 189 | 190 | ifs.seekg(0, std::ios::beg); 191 | ifs.read(myData.data(), pos); 192 | 193 | ifs.close(); 194 | 195 | //MD5 from file. 196 | Weak::MD5 hash; 197 | CryptoPP::byte digest[Weak::MD5::DIGESTSIZE]; 198 | 199 | hash.CalculateDigest(digest, (unsigned char*)myData.data(), myData.size()); 200 | 201 | std::string output; 202 | 203 | CryptoPP::HexEncoder encoder(new CryptoPP::StringSink(output), false); 204 | encoder.Put(digest, sizeof(digest)); 205 | encoder.MessageEnd(); 206 | 207 | result.clear(); 208 | myData.clear(); 209 | 210 | result = output; 211 | } 212 | return result; 213 | } 214 | 215 | bool CurlWrapper::ReportToServer(const std::wstring& unicode_file_path) 216 | { 217 | VM_REGION_START; 218 | CURL* curl = curl_easy_init(); 219 | if (curl) 220 | { 221 | const std::string url = base_url + "report.php"; 222 | 223 | curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); 224 | 225 | curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); 226 | curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15); 227 | curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); 228 | 229 | curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); 230 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); 231 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L); 232 | 233 | curl_easy_setopt(curl, CURLOPT_COOKIEFILE, _cookies.c_str()); 234 | curl_easy_setopt(curl, CURLOPT_COOKIEJAR, _cookies.c_str()); 235 | curl_easy_setopt(curl, CURLOPT_USERAGENT, "ReportAgent"); 236 | 237 | ///File Name Base64 Encoded 238 | std::string encoded; 239 | 240 | try 241 | { 242 | std::wstring_convert> converter; 243 | auto to_64 = converter.to_bytes(unicode_file_path); 244 | 245 | CryptoPP::StringSource ss((byte*)to_64.data(), to_64.length(), true, 246 | new CryptoPP::Base64Encoder( 247 | new CryptoPP::StringSink(encoded) 248 | ) 249 | ); 250 | 251 | ///User UniqueID 252 | std::string unique_id; 253 | GenerateHardDiskHash(unique_id); 254 | 255 | ///File MD5 hash 256 | const auto file_hash = CalculateFileHash(unicode_file_path).c_str(); 257 | 258 | char szPostData[1024]; 259 | sprintf_s(szPostData, XorStr("hw=%s&filename=%s&filehash=%s"), unique_id.c_str(), encoded.c_str(), file_hash); 260 | //MessageBoxA(GetActiveWindow(), szPostData, 0, 0); 261 | 262 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, szPostData); 263 | 264 | //////////////// 265 | const auto err_code = curl_easy_perform(curl); 266 | curl_easy_cleanup(curl); 267 | 268 | return (err_code == CURLE_OK); 269 | } 270 | catch (std::exception& ex) 271 | { 272 | utils::Error("Fatal error: %s", ex.what()); 273 | } 274 | } 275 | VM_REGION_END; 276 | return false; 277 | } -------------------------------------------------------------------------------- /loader/CurlWrapper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using namespace rapidjson; 5 | using namespace CryptoPP; 6 | 7 | class CurlWrapper 8 | { 9 | private: 10 | std::string _cookies; 11 | 12 | static std::size_t callback( 13 | const char* in, 14 | std::size_t size, 15 | std::size_t num, 16 | std::string* out) 17 | { 18 | const std::size_t totalBytes(size * num); 19 | out->append(in, totalBytes); 20 | return totalBytes; 21 | } 22 | 23 | public: 24 | CurlWrapper() 25 | { 26 | char szPath[MAX_PATH]; 27 | 28 | if (!SHGetSpecialFolderPathA(HWND_DESKTOP, szPath, CSIDL_COOKIES, TRUE)) 29 | utils::Error("SHGetSpecialFolderPathA failed %d", GetLastError()); 30 | 31 | strcat_s(szPath, "\\cookies.txt"); 32 | 33 | _cookies = szPath; 34 | } 35 | 36 | ~CurlWrapper() 37 | { 38 | _cookies.clear(); 39 | } 40 | 41 | bool DownloadToString(const std::string& url, std::string& data); 42 | bool AuthenticateUser(const char* username, const char* password); 43 | bool DownloadFile(const std::string& url, std::vector< std::uint8_t >& file_bytes); 44 | inline std::string CalculateFileHash(const std::wstring& szFilePath); 45 | bool ReportToServer(const std::wstring& unicode_file_path); 46 | }; 47 | 48 | extern CurlWrapper curl_wrapper; -------------------------------------------------------------------------------- /loader/Detection.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Includes.hpp" 4 | #include 5 | 6 | //#define HIDWORD(x) ((x>>32) & 0xffffffff) 7 | 8 | static auto _NtQuerySystemInformation(int SystemClass, PVOID Input, ULONG InputLen, PULONG RetLen) 9 | { 10 | return blackbone::syscall::nt_syscall(blackbone::syscall::get_index(XorStr("NtQuerySystemInformation")), SystemClass, Input, InputLen, RetLen); 11 | } 12 | 13 | static auto NtOpenProcess(HANDLE pid, ULONG access_mask) 14 | { 15 | CLIENT_ID cid; 16 | cid.UniqueProcess = pid; 17 | cid.UniqueThread = 0; 18 | 19 | OBJECT_ATTRIBUTES oa; 20 | InitializeObjectAttributes(&oa, 0, 0, 0, 0); 21 | 22 | HANDLE proc = 0; 23 | if (NT_SUCCESS(blackbone::syscall::nt_syscall( 24 | blackbone::syscall::get_index(XorStr("NtOpenProcess")), 25 | &proc, 26 | access_mask, 27 | &oa, 28 | &cid))) 29 | { 30 | return proc; 31 | } 32 | return HANDLE(nullptr); 33 | } 34 | 35 | static DWORD WINAPI HostsManipulation(PVOID) 36 | { 37 | VM_REGION_START; 38 | while (true) 39 | { 40 | char szSystemPath[MAX_PATH]{ }; 41 | 42 | if (!GetSystemDirectoryA(szSystemPath, sizeof szSystemPath)) 43 | break; 44 | 45 | strcat_s(szSystemPath, VM_ENC_STR_A("//drivers//etc//hosts")); 46 | 47 | std::ifstream f(szSystemPath, std::fstream::in); 48 | if (f.good()) 49 | { 50 | std::stringstream buffer; 51 | buffer << f.rdbuf(); 52 | f.close(); 53 | 54 | std::string file_text = buffer.str(); 55 | if (file_text.find(VM_ENC_STR_A("loxproductions")) != std::string::npos) 56 | { 57 | utils::Error("Please reset your windows hosts file to normal state."); 58 | } 59 | } 60 | std::this_thread::sleep_for(7s); 61 | } 62 | VM_REGION_END; 63 | return 0; 64 | } 65 | 66 | static DWORD WINAPI CodeIntegrity(PVOID) 67 | { 68 | #ifndef NO_VMP 69 | VM_REGION_START; 70 | 71 | SYSTEM_CODEINTEGRITY_INFORMATION sci = { 0 }; 72 | ULONG dwcbSz = 0; 73 | sci.Length = sizeof(sci); 74 | 75 | while (true) 76 | { 77 | std::wstring report; 78 | 79 | if (!VMProtectIsValidImageCRC()) 80 | report += L" Invalid CRC "; 81 | 82 | if (VMProtectIsDebuggerPresent(true)) 83 | report += L" Debugger Present "; 84 | 85 | //if (VMProtectIsVirtualMachinePresent()) 86 | // report += L" VM Present "; 87 | 88 | if (_NtQuerySystemInformation( 89 | 103, 90 | &sci, 91 | sizeof(sci), 92 | &dwcbSz) >= 0 && 93 | dwcbSz == sizeof(sci)) 94 | { 95 | BOOL bTestsigningEnabled = !!(sci.CodeIntegrityOptions & 0x2); 96 | 97 | if (bTestsigningEnabled) 98 | { 99 | report += L" bcdedit testsigning "; 100 | } 101 | } 102 | 103 | if (!report.empty()) 104 | { 105 | curl_wrapper.ReportToServer(report); 106 | utils::Error(XorStr("Error: %ls\nProcess will close."), report.c_str()); 107 | } 108 | 109 | std::this_thread::sleep_for(20s); 110 | } 111 | VM_REGION_END; 112 | #endif 113 | return 0; 114 | } 115 | 116 | static DWORD WINAPI SandboxDetection(PVOID) 117 | { 118 | VM_REGION_START; 119 | PPEB lpPeb = (PPEB)((_TEB*)NtCurrentTeb())->ProcessEnvironmentBlock; 120 | while (true) 121 | { 122 | PPEB_LDR_DATA lpLdr = lpPeb->Ldr; 123 | PLIST_ENTRY lpHead = &lpLdr->InMemoryOrderModuleList, lpCurrent = lpHead; 124 | 125 | while ((lpCurrent = lpCurrent->Flink) != lpHead) 126 | { 127 | PLDR_DATA_TABLE_ENTRY lpDataTable = CONTAINING_RECORD(lpCurrent, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); 128 | 129 | if (!_wcsicmp(XorStr(L"cmdvrt32.dll"), lpDataTable->FullDllName.Buffer) || 130 | !_wcsicmp(XorStr(L"SxIn.dll"), lpDataTable->FullDllName.Buffer) || 131 | !_wcsicmp(XorStr(L"api_log.dll"), lpDataTable->FullDllName.Buffer) || 132 | !_wcsicmp(XorStr(L"SbieDll.dll"), lpDataTable->FullDllName.Buffer)) 133 | { 134 | curl_wrapper.ReportToServer(lpDataTable->FullDllName.Buffer); 135 | utils::Error(XorStr("Please close Sandbox/Sandboxie related programs!")); 136 | } 137 | } 138 | std::this_thread::sleep_for(1min); 139 | } 140 | VM_REGION_END; 141 | return 0; 142 | } 143 | 144 | static DWORD WINAPI VMDetection(PVOID) 145 | { 146 | VM_REGION_START; 147 | static std::vector< std::wstring > files = { 148 | VM_ENC_STR_W(L"\\vm3dgl.dll"), 149 | VM_ENC_STR_W(L"\\vm3dum.dll"), 150 | VM_ENC_STR_W(L"\\vmGuestLib.dll"), 151 | VM_ENC_STR_W(L"\\vmhgfs.dll"), 152 | VM_ENC_STR_W(L"\\drivers\\VBoxMouse.sys"), 153 | VM_ENC_STR_W(L"\\drivers\\VBoxGuest.sys"), 154 | VM_ENC_STR_W(L"\\drivers\\vboxservice.sys"), 155 | VM_ENC_STR_W(L"\\drivers\\VBoxSF.sys") }; 156 | 157 | wchar_t swzSystemDir[MAX_PATH]; 158 | 159 | for (auto& f : files) 160 | { 161 | if (!GetSystemDirectoryW(swzSystemDir, MAX_PATH)) 162 | break; 163 | 164 | wcscat_s(swzSystemDir, f.c_str()); 165 | 166 | if (GetFileAttributesW(swzSystemDir) != INVALID_FILE_ATTRIBUTES) 167 | { 168 | curl_wrapper.ReportToServer(swzSystemDir); 169 | utils::Error("You cannot run this application under a Virtual Machine"); 170 | } 171 | } 172 | VM_REGION_END; 173 | return 0; 174 | } 175 | 176 | static void IsInBlackList() 177 | { 178 | VM_REGION_START; 179 | static std::vector< std::string > blacklist = { 180 | VM_ENC_STR_A("5F27F39170896A6FA9F391697FB265B9E758E21B3E6C7BC538EAB5CC2DAA6E2F") 181 | }; 182 | 183 | std::string hash; 184 | GenerateHardDiskHash(hash); 185 | 186 | for (auto &b : blacklist) 187 | { 188 | if (!hash.compare(b)) 189 | { 190 | g_pd3dDevice = nullptr; 191 | break; 192 | } 193 | } 194 | VM_REGION_END; 195 | } 196 | 197 | #pragma warning( push ) 198 | #pragma warning( disable : 4312) 199 | static DWORD WINAPI RunningProcesses(PVOID) 200 | { 201 | VM_REGION_START; 202 | NTSTATUS status; 203 | 204 | static std::vector< std::wstring > blacklist = { 205 | VM_ENC_STR_W(L"cheatengine"), 206 | VM_ENC_STR_W(L"x32dbg"), 207 | VM_ENC_STR_W(L"x64dbg"), 208 | VM_ENC_STR_W(L"processhacker"), 209 | VM_ENC_STR_W(L"scylla"), 210 | //VM_ENC_STR_W(L"debugger"), 211 | VM_ENC_STR_W(L"fiddler"), 212 | VM_ENC_STR_W(L"sandboxie"), 213 | VM_ENC_STR_W(L"sysanalyzer"), 214 | VM_ENC_STR_W(L"ollydbg"), 215 | VM_ENC_STR_W(L"apimonitor"), 216 | VM_ENC_STR_W(L"procmon") 217 | }; 218 | 219 | for (;; ) 220 | { 221 | ULONG ReturnLenght = 0; 222 | if (!NT_SUCCESS(status = _NtQuerySystemInformation(SystemProcessInformation, NULL, NULL, &ReturnLenght))) 223 | { 224 | auto buffer = HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, ReturnLenght); 225 | if (!buffer) 226 | { 227 | utils::Error("HeapAlloc error!"); 228 | break; 229 | } 230 | 231 | auto psi = (PSYSTEM_PROCESS_INFO)buffer; 232 | if (!NT_SUCCESS(status = _NtQuerySystemInformation(SystemProcessInformation, psi, ReturnLenght, NULL))) 233 | { 234 | HeapFree(GetProcessHeap(), 0, buffer); 235 | continue; 236 | } 237 | 238 | while (psi->NextEntryOffset) 239 | { 240 | HANDLE proc_id = HANDLE(HIDWORD(psi->ProcessId)); 241 | 242 | HANDLE proc = NtOpenProcess(proc_id, PROCESS_QUERY_INFORMATION); 243 | 244 | if (!proc) 245 | proc = NtOpenProcess(psi->ProcessId, PROCESS_QUERY_INFORMATION); 246 | 247 | if (proc != nullptr) 248 | { 249 | if (!NT_SUCCESS(status = NtQueryInformationProcess(proc, PROCESSINFOCLASS::ProcessImageFileName, NULL, NULL, &ReturnLenght))) 250 | { 251 | auto mem = HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, ReturnLenght); 252 | if (!mem) 253 | { 254 | utils::Error("HeapAlloc error!"); 255 | continue; 256 | } 257 | 258 | if (!NT_SUCCESS(status = NtQueryInformationProcess(proc, PROCESSINFOCLASS::ProcessImageFileName, mem, ReturnLenght, &ReturnLenght))) 259 | { 260 | HeapFree(GetProcessHeap(), 0, mem); 261 | break; 262 | } 263 | 264 | PUNICODE_STRING str = (PUNICODE_STRING)mem; 265 | 266 | if (str != nullptr && str->Buffer != NULL && str->Length > 0) 267 | { 268 | std::wstring process_name = str->Buffer; 269 | std::transform(process_name.begin(), process_name.end(), process_name.begin(), ::towlower); 270 | 271 | for (auto &p : blacklist) 272 | { 273 | if (process_name.find(p) != std::wstring::npos) 274 | { 275 | curl_wrapper.ReportToServer(str->Buffer); 276 | utils::Error("Please close %ls", str->Buffer); 277 | } 278 | } 279 | } 280 | 281 | if (mem) 282 | HeapFree(GetProcessHeap(), 0, mem); 283 | 284 | CloseHandle(proc); 285 | } 286 | } 287 | psi = (PSYSTEM_PROCESS_INFO)((LPBYTE)psi + psi->NextEntryOffset); 288 | } 289 | 290 | if (buffer) 291 | HeapFree(GetProcessHeap(), 0, buffer); 292 | } 293 | std::this_thread::sleep_for(3s); 294 | } 295 | VM_REGION_END; 296 | return 0; 297 | } 298 | 299 | static DWORD WINAPI RunningDrivers(PVOID) 300 | { 301 | VM_REGION_START; 302 | NTSTATUS status; 303 | ULONG i; 304 | 305 | auto extract_name = [](unsigned char* name) -> char* 306 | { 307 | if (name == nullptr || name[0] == '\0') 308 | return nullptr; 309 | 310 | while (*name != '\\') 311 | name++; 312 | 313 | return reinterpret_cast(name); 314 | }; 315 | 316 | static std::vector< std::string > blacklist = { 317 | VM_ENC_STR_A("kprocesshacker"), 318 | VM_ENC_STR_A("PROCMON23.sys"), 319 | VM_ENC_STR_A("VBoxGuest.sys"), 320 | VM_ENC_STR_A("vmmemctl.sys"), 321 | VM_ENC_STR_A("vmmouse.sys"), 322 | VM_ENC_STR_A("dbk64.sys") 323 | }; 324 | 325 | std::wstring_convert> converter; 326 | 327 | for (;; ) 328 | { 329 | ULONG ReturnLenght = 0; 330 | if (!NT_SUCCESS(status = _NtQuerySystemInformation(11, NULL, NULL, &ReturnLenght))) 331 | { 332 | auto buffer = HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, ReturnLenght); 333 | if (!buffer) 334 | { 335 | utils::Error("HeapAlloc error!"); 336 | break; 337 | } 338 | 339 | auto ModuleInfo = (PSYSTEM_MODULE_INFORMATION)buffer; 340 | if (!NT_SUCCESS(status = _NtQuerySystemInformation(11, ModuleInfo, ReturnLenght, NULL))) 341 | { 342 | HeapFree(GetProcessHeap(), 0, buffer); 343 | break; 344 | } 345 | 346 | for (i = 0; i < ModuleInfo->NumberOfModules; i++) 347 | { 348 | if (ModuleInfo->Modules[i].ImageBase == 0) 349 | continue; 350 | 351 | const auto name = extract_name(ModuleInfo->Modules[i].FullPathName); 352 | 353 | if (name == nullptr) 354 | continue; 355 | 356 | for (auto &p : blacklist) 357 | { 358 | std::string process_name = name; 359 | std::transform(process_name.begin(), process_name.end(), process_name.begin(), ::tolower); 360 | 361 | if (process_name.find(p) != std::string::npos) 362 | { 363 | std::wstring wide = converter.from_bytes(name); 364 | 365 | curl_wrapper.ReportToServer(wide); 366 | utils::Error("Please Unload the following Driver:\n%s", name); 367 | 368 | break; 369 | } 370 | } 371 | } 372 | 373 | if (buffer) 374 | HeapFree(GetProcessHeap(), 0, buffer); 375 | } 376 | std::this_thread::sleep_for(3s); 377 | } 378 | VM_REGION_END; 379 | return 0; 380 | } 381 | #pragma warning( pop ) -------------------------------------------------------------------------------- /loader/Includes.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define WIN32_LEAN_AND_MEAN 4 | #define VC_EXTRALEAN 5 | #define NOCOMM 6 | 7 | //Windows 7 8 | #define WINVER 0x0601 9 | #define _WIN32_WINNT 0x0601 10 | 11 | #define NOMINMAX 12 | #define DIRECTINPUT_VERSION 0x0800 13 | #define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | 65 | #pragma comment(lib, "wbemuuid.lib") 66 | 67 | #pragma comment(lib, "dxerr.lib") 68 | #pragma comment( lib, "d3d9") 69 | #pragma comment( lib, "d3dx9") 70 | #pragma comment( lib, "psapi.lib") 71 | #pragma comment( lib, "Shlwapi.lib") 72 | #pragma comment( lib, "Dbghelp.lib") 73 | #pragma comment( lib, "Urlmon.lib") 74 | 75 | // Data 76 | static LPDIRECT3D9 g_pD3D = NULL; 77 | static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; 78 | static D3DPRESENT_PARAMETERS g_d3dpp = {}; 79 | 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | 90 | #include 91 | #include 92 | #include 93 | 94 | #pragma warning( push ) 95 | #pragma warning( disable : 4242) 96 | #include 97 | #pragma warning( pop ) 98 | 99 | //#include "CrashRpt.h" 100 | 101 | static std::vector< HANDLE > v_threads; 102 | 103 | #define NO_VMP 1 104 | 105 | #ifndef NO_VMP 106 | #include 107 | 108 | #define VM_REGION_START VMProtectBeginVirtualization( __FUNCTION__ ); 109 | #define VM_REGION_END VMProtectEnd( ); 110 | #define VM_INLINE_CHECK VMProtectIsProtected( ); VMProtectIsValidImageCRC( ); 111 | #define VM_ENC_STR_W(x) VMProtectDecryptStringW( x ) 112 | #define VM_ENC_STR_A(x) VMProtectDecryptStringA( x ) 113 | #else 114 | #define VM_REGION_START 115 | #define VM_REGION_END 116 | #define VM_INLINE_CHECK 117 | #define VM_ENC_STR_W(x) UNREFERENCED_PARAMETER( x ) 118 | #define VM_ENC_STR_A(x) UNREFERENCED_PARAMETER( x ) 119 | #endif 120 | 121 | using namespace std::chrono_literals; 122 | using namespace blackbone; 123 | 124 | //#pragma section( ".text" ) 125 | static const std::string base_url = VM_ENC_STR_A( "removed" ); 126 | static const char* ldr_cur_ver = VM_ENC_STR_A( "removed" ); 127 | 128 | #include "utils.hpp" 129 | #include "lazy_importer.hpp" 130 | #include "Tools.hpp" 131 | #include "CRC32.hpp" 132 | 133 | #include "winstruct.hpp" 134 | #include "CurlWrapper.hpp" 135 | #include "StreamRcver.hpp" 136 | #include "Detection.hpp" 137 | 138 | //#undef XorStr 139 | //#define XorStr( x ) UNREFERENCED_PARAMETER( x ) 140 | 141 | #define SECURED_THREAD(x) auto __##x = CreateThread( nullptr, NULL, ( LPTHREAD_START_ROUTINE)&x, nullptr, 0, nullptr ); \ 142 | if( __##x == INVALID_HANDLE_VALUE || __##x == NULL ) utils::Error("CreateThread failed."); \ 143 | v_threads.push_back(__##x); 144 | 145 | -------------------------------------------------------------------------------- /loader/Iset.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // InstructionSet.cpp 4 | // Compile by using: cl /EHsc /W4 InstructionSet.cpp 5 | // processor: x86, x64 6 | // Uses the __cpuid intrinsic to get information about 7 | // CPU extended instruction set support. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class InstructionSet 17 | { 18 | // forward declarations 19 | class InstructionSet_Internal; 20 | 21 | public: 22 | // getters 23 | static std::string Vendor(void) { return CPU_Rep.vendor_; } 24 | static std::string Brand(void) { return CPU_Rep.brand_; } 25 | 26 | static bool SSE3(void) { return CPU_Rep.f_1_ECX_[0]; } 27 | static bool PCLMULQDQ(void) { return CPU_Rep.f_1_ECX_[1]; } 28 | static bool MONITOR(void) { return CPU_Rep.f_1_ECX_[3]; } 29 | static bool SSSE3(void) { return CPU_Rep.f_1_ECX_[9]; } 30 | static bool FMA(void) { return CPU_Rep.f_1_ECX_[12]; } 31 | static bool CMPXCHG16B(void) { return CPU_Rep.f_1_ECX_[13]; } 32 | static bool SSE41(void) { return CPU_Rep.f_1_ECX_[19]; } 33 | static bool SSE42(void) { return CPU_Rep.f_1_ECX_[20]; } 34 | static bool MOVBE(void) { return CPU_Rep.f_1_ECX_[22]; } 35 | static bool POPCNT(void) { return CPU_Rep.f_1_ECX_[23]; } 36 | static bool AES(void) { return CPU_Rep.f_1_ECX_[25]; } 37 | static bool XSAVE(void) { return CPU_Rep.f_1_ECX_[26]; } 38 | static bool OSXSAVE(void) { return CPU_Rep.f_1_ECX_[27]; } 39 | static bool AVX(void) { return CPU_Rep.f_1_ECX_[28]; } 40 | static bool F16C(void) { return CPU_Rep.f_1_ECX_[29]; } 41 | static bool RDRAND(void) { return CPU_Rep.f_1_ECX_[30]; } 42 | 43 | static bool MSR(void) { return CPU_Rep.f_1_EDX_[5]; } 44 | static bool CX8(void) { return CPU_Rep.f_1_EDX_[8]; } 45 | static bool SEP(void) { return CPU_Rep.f_1_EDX_[11]; } 46 | static bool CMOV(void) { return CPU_Rep.f_1_EDX_[15]; } 47 | static bool CLFSH(void) { return CPU_Rep.f_1_EDX_[19]; } 48 | static bool MMX(void) { return CPU_Rep.f_1_EDX_[23]; } 49 | static bool FXSR(void) { return CPU_Rep.f_1_EDX_[24]; } 50 | static bool SSE(void) { return CPU_Rep.f_1_EDX_[25]; } 51 | static bool SSE2(void) { return CPU_Rep.f_1_EDX_[26]; } 52 | 53 | static bool FSGSBASE(void) { return CPU_Rep.f_7_EBX_[0]; } 54 | static bool BMI1(void) { return CPU_Rep.f_7_EBX_[3]; } 55 | static bool HLE(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_7_EBX_[4]; } 56 | static bool AVX2(void) { return CPU_Rep.f_7_EBX_[5]; } 57 | static bool BMI2(void) { return CPU_Rep.f_7_EBX_[8]; } 58 | static bool ERMS(void) { return CPU_Rep.f_7_EBX_[9]; } 59 | static bool INVPCID(void) { return CPU_Rep.f_7_EBX_[10]; } 60 | static bool RTM(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_7_EBX_[11]; } 61 | static bool AVX512F(void) { return CPU_Rep.f_7_EBX_[16]; } 62 | static bool RDSEED(void) { return CPU_Rep.f_7_EBX_[18]; } 63 | static bool ADX(void) { return CPU_Rep.f_7_EBX_[19]; } 64 | static bool AVX512PF(void) { return CPU_Rep.f_7_EBX_[26]; } 65 | static bool AVX512ER(void) { return CPU_Rep.f_7_EBX_[27]; } 66 | static bool AVX512CD(void) { return CPU_Rep.f_7_EBX_[28]; } 67 | static bool SHA(void) { return CPU_Rep.f_7_EBX_[29]; } 68 | 69 | static bool PREFETCHWT1(void) { return CPU_Rep.f_7_ECX_[0]; } 70 | 71 | static bool LAHF(void) { return CPU_Rep.f_81_ECX_[0]; } 72 | static bool LZCNT(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_ECX_[5]; } 73 | static bool ABM(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[5]; } 74 | static bool SSE4a(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[6]; } 75 | static bool XOP(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[11]; } 76 | static bool TBM(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[21]; } 77 | 78 | static bool SYSCALL(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_EDX_[11]; } 79 | static bool MMXEXT(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[22]; } 80 | static bool RDTSCP(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_EDX_[27]; } 81 | static bool _3DNOWEXT(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[30]; } 82 | static bool _3DNOW(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[31]; } 83 | 84 | private: 85 | static const InstructionSet_Internal CPU_Rep; 86 | 87 | class InstructionSet_Internal 88 | { 89 | public: 90 | InstructionSet_Internal() 91 | : nIds_{ 0 }, 92 | nExIds_{ 0 }, 93 | isIntel_{ false }, 94 | isAMD_{ false }, 95 | f_1_ECX_{ 0 }, 96 | f_1_EDX_{ 0 }, 97 | f_7_EBX_{ 0 }, 98 | f_7_ECX_{ 0 }, 99 | f_81_ECX_{ 0 }, 100 | f_81_EDX_{ 0 }, 101 | data_{}, 102 | extdata_{} 103 | { 104 | //int cpuInfo[4] = {-1}; 105 | std::array cpui; 106 | 107 | // Calling __cpuid with 0x0 as the function_id argument 108 | // gets the number of the highest valid function ID. 109 | __cpuid(cpui.data(), 0); 110 | nIds_ = cpui[0]; 111 | 112 | for (int i = 0; i <= nIds_; ++i) 113 | { 114 | __cpuidex(cpui.data(), i, 0); 115 | data_.push_back(cpui); 116 | } 117 | 118 | // Capture vendor string 119 | char vendor[0x20]; 120 | memset(vendor, 0, sizeof(vendor)); 121 | *reinterpret_cast(vendor) = data_[0][1]; 122 | *reinterpret_cast(vendor + 4) = data_[0][3]; 123 | *reinterpret_cast(vendor + 8) = data_[0][2]; 124 | vendor_ = vendor; 125 | if (vendor_ == "GenuineIntel") 126 | { 127 | isIntel_ = true; 128 | } 129 | else if (vendor_ == "AuthenticAMD") 130 | { 131 | isAMD_ = true; 132 | } 133 | 134 | // load bitset with flags for function 0x00000001 135 | if (nIds_ >= 1) 136 | { 137 | f_1_ECX_ = data_[1][2]; 138 | f_1_EDX_ = data_[1][3]; 139 | } 140 | 141 | // load bitset with flags for function 0x00000007 142 | if (nIds_ >= 7) 143 | { 144 | f_7_EBX_ = data_[7][1]; 145 | f_7_ECX_ = data_[7][2]; 146 | } 147 | 148 | // Calling __cpuid with 0x80000000 as the function_id argument 149 | // gets the number of the highest valid extended ID. 150 | __cpuid(cpui.data(), 0x80000000); 151 | nExIds_ = cpui[0]; 152 | 153 | char brand[0x40]; 154 | memset(brand, 0, sizeof(brand)); 155 | 156 | for (int i = 0x80000000; i <= nExIds_; ++i) 157 | { 158 | __cpuidex(cpui.data(), i, 0); 159 | extdata_.push_back(cpui); 160 | } 161 | 162 | // load bitset with flags for function 0x80000001 163 | if (nExIds_ >= 0x80000001) 164 | { 165 | f_81_ECX_ = extdata_[1][2]; 166 | f_81_EDX_ = extdata_[1][3]; 167 | } 168 | 169 | // Interpret CPU brand string if reported 170 | if (nExIds_ >= 0x80000004) 171 | { 172 | memcpy(brand, extdata_[2].data(), sizeof(cpui)); 173 | memcpy(brand + 16, extdata_[3].data(), sizeof(cpui)); 174 | memcpy(brand + 32, extdata_[4].data(), sizeof(cpui)); 175 | brand_ = brand; 176 | } 177 | }; 178 | 179 | int nIds_; 180 | int nExIds_; 181 | std::string vendor_; 182 | std::string brand_; 183 | bool isIntel_; 184 | bool isAMD_; 185 | std::bitset<32> f_1_ECX_; 186 | std::bitset<32> f_1_EDX_; 187 | std::bitset<32> f_7_EBX_; 188 | std::bitset<32> f_7_ECX_; 189 | std::bitset<32> f_81_ECX_; 190 | std::bitset<32> f_81_EDX_; 191 | std::vector> data_; 192 | std::vector> extdata_; 193 | }; 194 | }; 195 | 196 | // Initialize static member data 197 | const InstructionSet::InstructionSet_Internal InstructionSet::CPU_Rep; -------------------------------------------------------------------------------- /loader/StreamRcver.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crvvdev/free-loader/0373e4c5583117e71ca400c1015f5e368e85db56/loader/StreamRcver.cpp -------------------------------------------------------------------------------- /loader/StreamRcver.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | using namespace CryptoPP; 10 | using namespace rapidjson; 11 | 12 | #define AES_BLOCK_SIZE 16 13 | #define MD5_DIGEST_LENGTH 16 14 | 15 | typedef struct _STREAMED_CHEAT_LIST 16 | { 17 | std::string name; 18 | std::string description; 19 | std::string file_dir; 20 | std::uint64_t timestamp; 21 | std::int32_t group; 22 | bool online; 23 | std::string exe_name; 24 | std::int32_t inj_mode; 25 | std::uint8_t stream_key[32]; 26 | 27 | auto operator < (const _STREAMED_CHEAT_LIST& other) const -> bool 28 | { 29 | return name < other.name; 30 | } 31 | 32 | } STREAMED_CHEAT_LIST, * PSTREAMED_CHEAT_LIST; 33 | 34 | class InjectionContext 35 | { 36 | private: 37 | STREAMED_CHEAT_LIST list; 38 | std::string status; 39 | 40 | public: 41 | InjectionContext() = default; 42 | 43 | void ChangeStatus(const char* str) 44 | { 45 | status = str; 46 | } 47 | 48 | void SetCurrentList(STREAMED_CHEAT_LIST _list) 49 | { 50 | list = _list; 51 | } 52 | 53 | const STREAMED_CHEAT_LIST &GetCurrentList() const 54 | { 55 | return list; 56 | } 57 | 58 | const std::string &GetStatus() const 59 | { 60 | return status; 61 | } 62 | }; 63 | 64 | extern std::vector< _STREAMED_CHEAT_LIST > v_cheats; 65 | 66 | namespace StreamRcver 67 | { 68 | extern HANDLE hEvent; 69 | 70 | bool DecryptAES(std::vector< std::uint8_t >& out_buffer, const std::uint8_t* stream_key, const std::uint8_t* stream_md5, const std::uint8_t* iv, std::vector< std::uint8_t >& cipherdata); 71 | void Base64Decode(std::string b64message, std::vector< std::uint8_t >& buffer); 72 | void ExtractCheats(); 73 | bool DownloadAndInjectKDriver(const STREAMED_CHEAT_LIST& cheat); 74 | bool DownloadAndInject(const STREAMED_CHEAT_LIST& cheat, std::uint32_t pid); 75 | bool DownloadAndInject(const STREAMED_CHEAT_LIST& cheat, HANDLE proc_handle); 76 | bool DownloadAndRun(const STREAMED_CHEAT_LIST& cheat); 77 | 78 | DWORD WINAPI HandleInject(PVOID arg); 79 | }; -------------------------------------------------------------------------------- /loader/Tools.cpp: -------------------------------------------------------------------------------- 1 | #include "Includes.hpp" 2 | #include "WinStruct.hpp" 3 | 4 | #pragma warning( push ) 5 | #pragma warning( disable : 4312) 6 | #pragma warning( disable : 4311) 7 | #pragma warning( disable : 4302) 8 | #pragma warning( disable : 4018) 9 | namespace Modules 10 | { 11 | HMODULE GetRemoteModuleHandle(HANDLE m_hProcess, const wchar_t* Module) 12 | { 13 | PVOID dwModuleHandle = NULL; 14 | 15 | ULONG_PTR PebBaseAddress = 0; 16 | NTSTATUS status = STATUS_SUCCESS; 17 | status = NtQueryInformationProcess(m_hProcess, ProcessWow64Information, &PebBaseAddress, sizeof(ULONG_PTR), 0); 18 | if (!NT_SUCCESS(status)) 19 | return NULL; 20 | 21 | _PEB32 peb; 22 | _PEB_LDR_DATA232 peb_ldr; 23 | using _LIST_ENTRY32 = _LIST_ENTRY_T< std::uint32_t >; 24 | 25 | SIZE_T dwBytesRead = 0; 26 | if (!ReadProcessMemory(m_hProcess, (LPCVOID)PebBaseAddress, &peb, sizeof(peb), &dwBytesRead)) 27 | { 28 | return 0; 29 | } 30 | 31 | bool ldr_not_found = ReadProcessMemory(m_hProcess, (LPCVOID)peb.Ldr, &peb_ldr, sizeof(peb_ldr), &dwBytesRead); 32 | 33 | for (INT i = 0; !ldr_not_found && i < 10; i++) 34 | { 35 | ReadProcessMemory(m_hProcess, (LPCVOID)PebBaseAddress, &peb, sizeof(peb), &dwBytesRead); 36 | 37 | ldr_not_found = ReadProcessMemory(m_hProcess, (LPCVOID)peb.Ldr, &peb_ldr, sizeof(peb_ldr), &dwBytesRead); 38 | 39 | Sleep(750); 40 | } 41 | 42 | if (!ldr_not_found) 43 | return 0; 44 | 45 | _LIST_ENTRY32* pLdrListHead = (_LIST_ENTRY32*)peb_ldr.InLoadOrderModuleList.Flink; 46 | _LIST_ENTRY32* pLdrCurrentNode = (_LIST_ENTRY32*)peb_ldr.InLoadOrderModuleList.Flink; 47 | do 48 | { 49 | _LDR_DATA_TABLE_ENTRY_BASE32 lstEntry = { 0 }; 50 | if (!ReadProcessMemory(m_hProcess, (void*)pLdrCurrentNode, &lstEntry, sizeof(_LDR_DATA_TABLE_ENTRY_BASE32), &dwBytesRead)) 51 | { 52 | //DbgShout("[GetRemoteModuleHandleW] Could not read list entry from LDR list. Error = %s", Utils::GetLastErrorAsString().c_str()); 53 | return NULL; 54 | } 55 | 56 | pLdrCurrentNode = (_LIST_ENTRY32*)lstEntry.InLoadOrderLinks.Flink; 57 | 58 | wchar_t wcsBaseDllName[MAX_PATH] = { 0 }; 59 | if (lstEntry.BaseDllName.Length > 0) 60 | { 61 | if (!ReadProcessMemory(m_hProcess, (LPCVOID)lstEntry.BaseDllName.Buffer, &wcsBaseDllName, lstEntry.BaseDllName.Length, &dwBytesRead)) 62 | { 63 | //DbgShout("[GetRemoteModuleHandleW] Could not read list entry DLL name. Error = %s", Utils::GetLastErrorAsString().c_str()); 64 | return NULL; 65 | } 66 | } 67 | 68 | if (lstEntry.DllBase != NULL && lstEntry.SizeOfImage != 0) 69 | { 70 | if (_wcsicmp(wcsBaseDllName, Module) == 0) 71 | { 72 | dwModuleHandle = (PVOID)lstEntry.DllBase; 73 | //if (ModuleSize) 74 | // *ModuleSize = lstEntry.SizeOfImage; 75 | break; 76 | } 77 | } 78 | 79 | } while (pLdrListHead != pLdrCurrentNode); 80 | 81 | return (HMODULE)dwModuleHandle; 82 | } 83 | 84 | DWORD GetRemoteFuncAddress(HANDLE m_hProcess, wchar_t const* module, char* func) 85 | { 86 | std::wstring_convert> converter; 87 | 88 | auto modb = GetRemoteModuleHandle(m_hProcess, module); 89 | 90 | if (!modb) 91 | return 0; 92 | 93 | IMAGE_DOS_HEADER hdrDos = { 0 }; 94 | IMAGE_NT_HEADERS32 hdrNt32 = { 0 }; 95 | IMAGE_EXPORT_DIRECTORY* expData = { 0 }; 96 | void* pFunc = NULL; 97 | 98 | SIZE_T dwRead = 0; 99 | ReadProcessMemory(m_hProcess, (BYTE*)modb, &hdrDos, sizeof(IMAGE_DOS_HEADER), &dwRead); 100 | if (hdrDos.e_magic != IMAGE_DOS_SIGNATURE) 101 | return NULL; 102 | 103 | ReadProcessMemory(m_hProcess, (BYTE*)modb + hdrDos.e_lfanew, &hdrNt32, sizeof(IMAGE_NT_HEADERS32), &dwRead); 104 | if (hdrNt32.Signature != IMAGE_NT_SIGNATURE) 105 | return NULL; 106 | 107 | size_t expBase = hdrNt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; 108 | // Exports are present 109 | if (expBase) 110 | { 111 | DWORD expSize = hdrNt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; 112 | expData = (IMAGE_EXPORT_DIRECTORY*)malloc(expSize); 113 | ReadProcessMemory(m_hProcess, (BYTE*)modb + expBase, expData, expSize, &dwRead); 114 | 115 | WORD *pAddressOfOrds = (WORD*)(expData->AddressOfNameOrdinals + (size_t)expData - expBase); 116 | DWORD *pAddressOfNames = (DWORD*)(expData->AddressOfNames + (size_t)expData - expBase); 117 | DWORD *pAddressOfFuncs = (DWORD*)(expData->AddressOfFunctions + (size_t)expData - expBase); 118 | 119 | for (DWORD i = 0; i < expData->NumberOfFunctions; ++i) 120 | { 121 | WORD OrdIndex = 0xFFFF; 122 | char *pName = NULL; 123 | 124 | // Find by index 125 | if ((size_t)func <= 0xFFFF) 126 | OrdIndex = (WORD)i; 127 | 128 | // Find by name 129 | else if ((size_t)func > 0xFFFF && i < expData->NumberOfNames) 130 | { 131 | pName = (char*)(pAddressOfNames[i] + (size_t)expData - expBase); 132 | OrdIndex = (WORD)pAddressOfOrds[i]; 133 | } 134 | else 135 | return 0; 136 | 137 | if (((size_t)func <= 0xFFFF && (WORD)func == (OrdIndex + expData->Base)) || ((size_t)func > 0xFFFF && strcmp(pName, func) == 0)) 138 | { 139 | pFunc = (void*)((size_t)modb + pAddressOfFuncs[OrdIndex]); 140 | break; 141 | } 142 | } 143 | // Free allocated data 144 | free(expData); 145 | } 146 | 147 | return ( DWORD )pFunc; 148 | } 149 | } 150 | #pragma warning( pop ) -------------------------------------------------------------------------------- /loader/Tools.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | static std::string trim(std::string& str) 7 | { 8 | size_t first = str.find_first_not_of(' '); 9 | if (first == std::string::npos) 10 | return ""; 11 | size_t last = str.find_last_not_of(' '); 12 | return str.substr(first, (last - first + 1)); 13 | } 14 | 15 | static std::string random_string(size_t length) 16 | { 17 | srand(GetTickCount()); 18 | auto randchar = []() -> char 19 | { 20 | const char charset[] = 21 | "0123456789" 22 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 23 | "abcdefghijklmnopqrstuvwxyz"; 24 | const size_t max_index = (sizeof(charset) - 1); 25 | return charset[rand() % max_index]; 26 | }; 27 | std::string str(length, 0); 28 | std::generate_n(str.begin(), length, randchar); 29 | return str; 30 | } 31 | 32 | static bool GenerateHardDiskHash(std::string& szHWID) 33 | { 34 | VM_REGION_START; 35 | /* 36 | std::string hardware_digest = ""; 37 | 38 | if (dwSerialNumberOffset) 39 | { 40 | const char* serialNumber = reinterpret_cast(pOutBuffer.get() + dwSerialNumberOffset); 41 | hardware_digest += serialNumber; 42 | } 43 | 44 | if (dwProductIdOffset) 45 | { 46 | const char* productId = reinterpret_cast(pOutBuffer.get() + dwProductIdOffset); 47 | hardware_digest += productId; 48 | } 49 | 50 | if (dwVendorIdOffset) 51 | { 52 | const char* vendorId = reinterpret_cast(pOutBuffer.get() + dwVendorIdOffset); 53 | hardware_digest += vendorId; 54 | } 55 | 56 | if (hardware_digest.empty()) 57 | { 58 | utils::Error(XorStr("Failed to generate computer uniqueid!"), res); 59 | return false; 60 | } 61 | 62 | hardware_digest = trim(hardware_digest); 63 | 64 | CryptoPP::SHA256 hash; 65 | byte digest[CryptoPP::SHA256::DIGESTSIZE]; 66 | 67 | hash.CalculateDigest(digest, (byte*)hardware_digest.c_str(), hardware_digest.length()); 68 | 69 | CryptoPP::HexEncoder encoder; 70 | std::string output; 71 | encoder.Attach(new CryptoPP::StringSink(output)); 72 | encoder.Put(digest, sizeof(digest)); 73 | encoder.MessageEnd(); 74 | 75 | szHWID = output; 76 | 77 | hardware_digest.clear(); 78 | output.clear(); 79 | 80 | szHWID.clear(); 81 | 82 | // Format physical drive path (may be '\\\\.\\PhysicalDrive0', '\\\\.\\PhysicalDrive1' and so on). 83 | // Note: backslash is used as escape in WQL, so we need to double each one. 84 | CStringW strDrivePath; 85 | strDrivePath.Format(XorStr(L"\\\\\\\\.\\\\PhysicalDrive0")); 86 | 87 | // 2. Set the default process security level 88 | // http://msdn.microsoft.com/en-us/library/windows/desktop/aa393617(v=vs.85).aspx 89 | HRESULT hr = ::CoInitializeSecurity( 90 | NULL, // Security descriptor 91 | -1, // COM negotiates authentication service 92 | NULL, // Authentication services 93 | NULL, // Reserved 94 | RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication level for proxies 95 | RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation level for proxies 96 | NULL, // Authentication info 97 | EOAC_NONE, // Additional capabilities of the client or server 98 | NULL); // Reserved 99 | 100 | if (FAILED(hr)) 101 | { 102 | std::string message = std::system_category().message(hr); 103 | utils::Error("CoInitializeSecurity failed %s", message.c_str()); 104 | return true; 105 | } 106 | 107 | // 3. Create a connection to WMI namespace 108 | // http://msdn.microsoft.com/en-us/library/windows/desktop/aa389749(v=vs.85).aspx 109 | 110 | // 3.1. Initialize the IWbemLocator interface 111 | CComPtr pIWbemLocator; 112 | hr = ::CoCreateInstance(CLSID_WbemLocator, 0, 113 | CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)& pIWbemLocator); 114 | 115 | if (FAILED(hr)) 116 | { 117 | std::string message = std::system_category().message(hr); 118 | utils::Error("CoCreateInstance failed %s", message.c_str()); 119 | return true; 120 | } 121 | 122 | // 3.2. Call IWbemLocator::ConnectServer for connecting to WMI 123 | CComPtr pIWbemServices; 124 | hr = pIWbemLocator->ConnectServer(L"ROOT\\CIMV2", 125 | NULL, NULL, 0, NULL, 0, 0, &pIWbemServices); 126 | 127 | if (FAILED(hr)) 128 | { 129 | std::string message = std::system_category().message(hr); 130 | utils::Error("ConnectServer failed %s", message.c_str()); 131 | return true; 132 | } 133 | 134 | // 4. Set the security levels on WMI connection 135 | // http://msdn.microsoft.com/en-us/library/windows/desktop/aa393619(v=vs.85).aspx 136 | hr = ::CoSetProxyBlanket( 137 | pIWbemServices, 138 | RPC_C_AUTHN_WINNT, 139 | RPC_C_AUTHZ_NONE, 140 | NULL, 141 | RPC_C_AUTHN_LEVEL_CALL, 142 | RPC_C_IMP_LEVEL_IMPERSONATE, 143 | NULL, 144 | EOAC_NONE); 145 | 146 | if (FAILED(hr)) 147 | { 148 | std::string message = std::system_category().message(hr); 149 | utils::Error("CoSetProxyBlanket failed %s", message.c_str()); 150 | return true; 151 | } 152 | 153 | // 5. Execute a WQL (WMI Query Language) query to get the wanted phisical drive serial number 154 | const BSTR szQueryLanguage = L"WQL"; 155 | CStringW strQuery; 156 | strQuery.Format(VM_ENC_STR_W(L"SELECT SerialNumber FROM Win32_PhysicalMedia WHERE Tag=\"%s\""), 157 | strDrivePath); 158 | 159 | CComPtr pIEnumWbemClassObject; 160 | hr = pIWbemServices->ExecQuery( 161 | szQueryLanguage, // Query language 162 | (BSTR)strQuery.GetString(), // Query 163 | WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, // Flags 164 | NULL, // Context 165 | &pIEnumWbemClassObject); // Enumerator 166 | 167 | if (FAILED(hr)) 168 | { 169 | std::string message = std::system_category().message(hr); 170 | utils::Error("ExecQuery failed %s", message.c_str()); 171 | return true; 172 | } 173 | 174 | // 6. Get first enumerator element. If exists, get the serial number. 175 | ULONG uReturn = 0; 176 | CComPtr pIWbemClassObject; 177 | hr = pIEnumWbemClassObject->Next(WBEM_INFINITE, 1, &pIWbemClassObject, &uReturn); 178 | 179 | if (WBEM_S_NO_ERROR != hr) 180 | { 181 | std::string message = std::system_category().message(hr); 182 | utils::Error("Next failed %s", message.c_str()); 183 | return true; 184 | } 185 | 186 | variant_t vtSerialNumber; // manufacturer-provided serial number 187 | hr = pIWbemClassObject->Get(XorStr(L"SerialNumber"), 0, &vtSerialNumber, NULL, NULL); 188 | 189 | if ( FAILED(hr) ) 190 | { 191 | std::string message = std::system_category().message(hr); 192 | utils::Error("Get failed %s", message.c_str()); 193 | return true; 194 | }*/ 195 | 196 | HANDLE hPhysicalDriveIOCTL = CreateFileW(XorStr(L"\\\\.\\PhysicalDrive0"), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 197 | 198 | if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE) 199 | { 200 | utils::Error("CreateFileW error code: %d", GetLastError()); 201 | return false; 202 | } 203 | 204 | std::unique_ptr::type, void(*)(HANDLE)> hDevice{ hPhysicalDriveIOCTL, [](HANDLE handle) {CloseHandle(handle); } }; 205 | 206 | STORAGE_PROPERTY_QUERY storagePropertyQuery{}; 207 | storagePropertyQuery.PropertyId = StorageDeviceProperty; 208 | storagePropertyQuery.QueryType = PropertyStandardQuery; 209 | 210 | STORAGE_DESCRIPTOR_HEADER storageDescriptorHeader{}; 211 | 212 | IO_STATUS_BLOCK isb; 213 | auto res = blackbone::syscall::nt_syscall( 214 | blackbone::syscall::get_index(XorStr("NtDeviceIoControlFile")), 215 | hDevice.get(), 216 | NULL, 217 | NULL, 218 | NULL, 219 | &isb, 220 | IOCTL_STORAGE_QUERY_PROPERTY, 221 | &storagePropertyQuery, 222 | sizeof(STORAGE_PROPERTY_QUERY), 223 | &storageDescriptorHeader, 224 | sizeof(STORAGE_DESCRIPTOR_HEADER)); 225 | 226 | if (!NT_SUCCESS(res)) 227 | { 228 | utils::Error("Device[0] error code: %X", res); 229 | return false; 230 | } 231 | 232 | //allocate a suitable buffer 233 | const DWORD dwOutBufferSize = storageDescriptorHeader.Size; 234 | std::unique_ptr pOutBuffer{ new BYTE[dwOutBufferSize]{} }; 235 | 236 | //call DeviceIoControl with the allocated buffer 237 | res = blackbone::syscall::nt_syscall( 238 | blackbone::syscall::get_index(XorStr("NtDeviceIoControlFile")), 239 | hDevice.get(), 240 | NULL, 241 | NULL, 242 | NULL, 243 | &isb, 244 | IOCTL_STORAGE_QUERY_PROPERTY, 245 | &storagePropertyQuery, 246 | sizeof(STORAGE_PROPERTY_QUERY), 247 | pOutBuffer.get(), 248 | dwOutBufferSize); 249 | 250 | if (!NT_SUCCESS(res)) 251 | { 252 | utils::Error("Device[1] error code: %X", res); 253 | return false; 254 | } 255 | 256 | //read and return the serial number out of the output buffer 257 | STORAGE_DEVICE_DESCRIPTOR* pDeviceDescriptor = reinterpret_cast(pOutBuffer.get()); 258 | 259 | const auto dwSerialNumberOffset = pDeviceDescriptor->SerialNumberOffset; 260 | const char* serialNumber = reinterpret_cast(pOutBuffer.get() + dwSerialNumberOffset); 261 | 262 | char szUserName[256] = { 0 }; 263 | DWORD max_len = 256; 264 | 265 | GetComputerNameA(szUserName, &max_len); 266 | 267 | std::stringstream wss; 268 | wss << szUserName << serialNumber; 269 | 270 | CryptoPP::SHA256 hash; 271 | byte digest[CryptoPP::SHA256::DIGESTSIZE]; 272 | 273 | hash.CalculateDigest(digest, (byte*)wss.str().data(), wss.str().length()); 274 | 275 | CryptoPP::HexEncoder encoder; 276 | std::string output; 277 | encoder.Attach(new CryptoPP::StringSink(output)); 278 | encoder.Put(digest, sizeof(digest)); 279 | encoder.MessageEnd(); 280 | 281 | szHWID = output; 282 | output.clear(); 283 | 284 | VM_REGION_END; 285 | return true; 286 | } 287 | 288 | static void NukeLoginusers() 289 | { 290 | HKEY hKey = 0; 291 | if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Valve\\Steam", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hKey) != ERROR_SUCCESS) 292 | { 293 | utils::Error("RegOpenKeyW failed %d", GetLastError()); 294 | return; 295 | } 296 | 297 | DWORD dwType = REG_SZ; 298 | wchar_t buf[255] = { 0 }; 299 | DWORD dwBufSize = sizeof(buf); 300 | 301 | if (RegQueryValueExW(hKey, L"InstallPath", NULL, &dwType, reinterpret_cast(&buf), &dwBufSize) != ERROR_SUCCESS) 302 | { 303 | RegCloseKey(hKey); 304 | utils::Error("RegQueryValueExW failed %d", GetLastError()); 305 | return; 306 | } 307 | 308 | RegCloseKey(hKey); 309 | 310 | //for (const auto & entry : fs::directory_iterator(path)) 311 | // std::cout << entry.path() << std::endl; 312 | 313 | wcscat_s(buf, VM_ENC_STR_W(L"\\config\\config.vdf")); 314 | DeleteFileW(buf); 315 | /*DWORD attrib = GetFileAttributesW(buf); 316 | 317 | if (attrib == INVALID_FILE_ATTRIBUTES) 318 | { 319 | utils::Error("Invalid steam file!"); 320 | return; 321 | } 322 | 323 | const bool is_read_only = (attrib & FILE_ATTRIBUTE_READONLY); 324 | 325 | if (!is_read_only) 326 | { 327 | std::ofstream ofs(buf, std::ofstream::out | std::ofstream::trunc); 328 | ofs.close(); 329 | 330 | SetFileAttributesW(buf, FILE_ATTRIBUTE_READONLY); 331 | }*/ 332 | } 333 | 334 | static void GetPCInformation(IDirect3D9* dev) 335 | { 336 | D3DADAPTER_IDENTIFIER9 adp; 337 | ZeroMemory(&adp, sizeof D3DADAPTER_IDENTIFIER9); 338 | 339 | HRESULT hr = 0; 340 | 341 | if (FAILED(hr = dev->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &adp))) 342 | { 343 | 344 | } 345 | 346 | //const int cch = sizeof(adp.Description); 347 | //TCHAR szDescription[cch]; 348 | //DXUtil_ConvertAnsiStringToGenericCch(szDescription, AdapterIdentifier.Description, cch); 349 | } 350 | 351 | class Timer 352 | { 353 | public: 354 | void start() 355 | { 356 | m_StartTime = std::chrono::system_clock::now(); 357 | m_bRunning = true; 358 | } 359 | 360 | void stop() 361 | { 362 | m_EndTime = std::chrono::system_clock::now(); 363 | m_bRunning = false; 364 | } 365 | 366 | auto elapsedMilliseconds() 367 | { 368 | std::chrono::time_point endTime; 369 | 370 | if (m_bRunning) 371 | { 372 | endTime = std::chrono::system_clock::now(); 373 | } 374 | else 375 | { 376 | endTime = m_EndTime; 377 | } 378 | 379 | return std::chrono::duration_cast(endTime - m_StartTime).count(); 380 | } 381 | 382 | double elapsedSeconds() 383 | { 384 | return elapsedMilliseconds() / 1000.0; 385 | } 386 | 387 | private: 388 | std::chrono::time_point m_StartTime; 389 | std::chrono::time_point m_EndTime; 390 | bool m_bRunning = false; 391 | }; 392 | 393 | struct HandleDisposer 394 | { 395 | using pointer = HANDLE; 396 | void operator()(HANDLE handle) const 397 | { 398 | if (handle != NULL || handle != INVALID_HANDLE_VALUE) 399 | { 400 | CloseHandle(handle); 401 | } 402 | } 403 | }; 404 | 405 | static std::uint32_t Proc_LdrLoadDll = 0; 406 | 407 | #pragma pack( push, 1 ) 408 | struct SEND_RCV 409 | { 410 | std::uint32_t addresses[10]; 411 | std::uint8_t bytes[10][10]; 412 | std::int32_t counter; 413 | }; 414 | #pragma pack( pop ) 415 | 416 | #include 417 | 418 | static std::vector< std::pair< std::uint32_t, std::uint8_t* > > ntdll_map; 419 | 420 | //static DWORD WINAPI CreatePipe(PVOID) 421 | //{ 422 | // constexpr std::wstring_view PipeName = L"\\\\.\\pipe\\PipeCom"; 423 | // 424 | // SEND_RCV buffer; 425 | // ZeroMemory(&buffer, sizeof buffer); 426 | // 427 | // int i = 0; 428 | // DWORD NumofBytes = 0; 429 | // 430 | // auto hpipe = std::unique_ptr( 431 | // CreateNamedPipeW( 432 | // PipeName.data(), 433 | // PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 434 | // 1, 435 | // sizeof SEND_RCV, 436 | // sizeof SEND_RCV, 437 | // 0, 438 | // NULL)); 439 | // 440 | // if (hpipe.get() == INVALID_HANDLE_VALUE) 441 | // return 0; 442 | // 443 | // if (ConnectNamedPipe(hpipe.get(), NULL != FALSE)) 444 | // { 445 | // while (ReadFile(hpipe.get(), &buffer, sizeof(buffer), &NumofBytes, NULL) != FALSE) 446 | // { 447 | // ntdll_map.push_back({ buffer.addresses[buffer.counter], buffer.bytes[buffer.counter] }); 448 | // } 449 | // } 450 | // 451 | // DisconnectNamedPipe(hpipe.get()); 452 | // return 0; 453 | //} 454 | 455 | namespace Modules 456 | { 457 | //MODULEENTRY32 GetRemoteModule(std::uint32_t pid, wchar_t const* module_name); 458 | HMODULE GetRemoteModuleHandle(HANDLE hProcess, wchar_t const* module_name); 459 | bool GetRemoteModuleExportDirectory(HANDLE hProcess, HMODULE hRemote, PIMAGE_EXPORT_DIRECTORY ExportDirectory, IMAGE_DOS_HEADER DosHeader, IMAGE_NT_HEADERS NtHeaders); 460 | DWORD GetRemoteFuncAddress(HANDLE hProcess, wchar_t const* module, char* func); 461 | } -------------------------------------------------------------------------------- /loader/WinStruct.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifndef _NTDEF_ 6 | typedef _Return_type_success_( return >= 0 ) LONG NTSTATUS; 7 | #endif 8 | 9 | #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) 10 | #define STATUS_INVALID_PAGE_PROTECTION ((NTSTATUS)0xC0000045L) 11 | #define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL) 12 | 13 | #define SEC_NO_CHANGE 0x00400000 14 | 15 | #define PAGE_SIZE 0x1000 16 | #define POINTER_IS_ALIGNED(Pointer, Alignment) \ 17 | (((((ULONG_PTR)(Pointer)) & (((Alignment)-1))) == 0) ? TRUE : FALSE) 18 | 19 | #define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1) 20 | 21 | #define FILE_DEVICE_SCSI 0x0000001b 22 | #define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501) 23 | #define IOCTL_SCSI_MINIPORT 0x0004D008 // see NTDDSCSI.H for definition 24 | 25 | #define IDE_ATA_IDENTIFY 0xEC 26 | 27 | #ifndef NT_SUCCESS 28 | #define NT_SUCCESS(x) ((x)>=0) 29 | #endif 30 | 31 | namespace nt 32 | { 33 | typedef struct _PEB_LDR_DATA 34 | { 35 | ULONG Length; 36 | BOOLEAN Initialized; 37 | PVOID SsHandle; 38 | LIST_ENTRY InLoadOrderModuleList; 39 | LIST_ENTRY InMemoryOrderModuleList; 40 | LIST_ENTRY InInitializationOrderModuleList; 41 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 42 | 43 | typedef struct _LDR_DATA_TABLE_ENTRY 44 | { 45 | LIST_ENTRY InLoadOrderLinks; 46 | LIST_ENTRY InMemoryOrderLinks; 47 | LIST_ENTRY InInitializationOrderLinks; 48 | PVOID DllBase; 49 | PVOID EntryPoint; 50 | ULONG SizeOfImage; 51 | UNICODE_STRING FullDllName; 52 | UNICODE_STRING BaseDllName; 53 | ULONG Flags; 54 | WORD LoadCount; 55 | WORD TlsIndex; 56 | 57 | union 58 | { 59 | LIST_ENTRY HashLinks; 60 | 61 | struct 62 | { 63 | PVOID SectionPointer; 64 | ULONG CheckSum; 65 | }; 66 | }; 67 | 68 | union 69 | { 70 | ULONG TimeDateStamp; 71 | PVOID LoadedImports; 72 | }; 73 | 74 | _ACTIVATION_CONTEXT* EntryPointActivationContext; 75 | PVOID PatchInformation; 76 | LIST_ENTRY ForwarderLinks; 77 | LIST_ENTRY ServiceTagLinks; 78 | LIST_ENTRY StaticLinks; 79 | } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; 80 | 81 | typedef struct _CURDIR 82 | { 83 | UNICODE_STRING DosPath; 84 | PVOID Handle; 85 | } CURDIR, * PCURDIR; 86 | 87 | typedef struct _RTL_DRIVE_LETTER_CURDIR 88 | { 89 | WORD Flags; 90 | WORD Length; 91 | ULONG TimeStamp; 92 | STRING DosPath; 93 | } RTL_DRIVE_LETTER_CURDIR, * PRTL_DRIVE_LETTER_CURDIR; 94 | 95 | typedef struct _RTL_USER_PROCESS_PARAMETERS 96 | { 97 | ULONG MaximumLength; 98 | ULONG Length; 99 | ULONG Flags; 100 | ULONG DebugFlags; 101 | PVOID ConsoleHandle; 102 | ULONG ConsoleFlags; 103 | PVOID StandardInput; 104 | PVOID StandardOutput; 105 | PVOID StandardError; 106 | CURDIR CurrentDirectory; 107 | UNICODE_STRING DllPath; 108 | UNICODE_STRING ImagePathName; 109 | UNICODE_STRING CommandLine; 110 | PVOID Environment; 111 | ULONG StartingX; 112 | ULONG StartingY; 113 | ULONG CountX; 114 | ULONG CountY; 115 | ULONG CountCharsX; 116 | ULONG CountCharsY; 117 | ULONG FillAttribute; 118 | ULONG WindowFlags; 119 | ULONG ShowWindowFlags; 120 | UNICODE_STRING WindowTitle; 121 | UNICODE_STRING DesktopInfo; 122 | UNICODE_STRING ShellInfo; 123 | UNICODE_STRING RuntimeData; 124 | RTL_DRIVE_LETTER_CURDIR CurrentDirectores[ 32 ]; 125 | ULONG EnvironmentSize; 126 | } RTL_USER_PROCESS_PARAMETERS, * PRTL_USER_PROCESS_PARAMETERS; 127 | 128 | typedef struct _RTL_CRITICAL_SECTION* PRTL_CRITICAL_SECTION; 129 | 130 | #define GDI_HANDLE_BUFFER_SIZE32 34 131 | #define GDI_HANDLE_BUFFER_SIZE64 60 132 | 133 | #ifdef _WIN64 134 | #define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE64 135 | #else 136 | #define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE32 137 | #endif 138 | 139 | typedef ULONG GDI_HANDLE_BUFFER[ GDI_HANDLE_BUFFER_SIZE ]; 140 | typedef ULONG GDI_HANDLE_BUFFER32[ GDI_HANDLE_BUFFER_SIZE32 ]; 141 | typedef ULONG GDI_HANDLE_BUFFER64[ GDI_HANDLE_BUFFER_SIZE64 ]; 142 | 143 | // symbols 144 | typedef struct _PEB 145 | { 146 | BOOLEAN InheritedAddressSpace; 147 | BOOLEAN ReadImageFileExecOptions; 148 | BOOLEAN BeingDebugged; 149 | 150 | union 151 | { 152 | BOOLEAN BitField; 153 | 154 | struct 155 | { 156 | BOOLEAN ImageUsesLargePages : 1; 157 | BOOLEAN IsProtectedProcess : 1; 158 | BOOLEAN IsImageDynamicallyRelocated : 1; 159 | BOOLEAN SkipPatchingUser32Forwarders : 1; 160 | BOOLEAN IsPackagedProcess : 1; 161 | BOOLEAN IsAppContainer : 1; 162 | BOOLEAN IsProtectedProcessLight : 1; 163 | BOOLEAN SpareBits : 1; 164 | }; 165 | }; 166 | 167 | HANDLE Mutant; 168 | PVOID ImageBaseAddress; 169 | PPEB_LDR_DATA Ldr; 170 | PRTL_USER_PROCESS_PARAMETERS ProcessParameters; 171 | PVOID SubSystemData; 172 | PVOID ProcessHeap; 173 | PRTL_CRITICAL_SECTION FastPebLock; 174 | PVOID AtlThunkSListPtr; 175 | PVOID IFEOKey; 176 | 177 | union 178 | { 179 | ULONG CrossProcessFlags; 180 | 181 | struct 182 | { 183 | ULONG ProcessInJob : 1; 184 | ULONG ProcessInitializing : 1; 185 | ULONG ProcessUsingVEH : 1; 186 | ULONG ProcessUsingVCH : 1; 187 | ULONG ProcessUsingFTH : 1; 188 | ULONG ReservedBits0 : 27; 189 | }; 190 | 191 | ULONG EnvironmentUpdateCount; 192 | }; 193 | 194 | union 195 | { 196 | PVOID* KernelCallbackTable; 197 | PVOID UserSharedInfoPtr; 198 | }; 199 | 200 | ULONG SystemReserved[ 1 ]; 201 | ULONG AtlThunkSListPtr32; 202 | PVOID ApiSetMap; 203 | ULONG TlsExpansionCounter; 204 | PVOID TlsBitmap; 205 | ULONG TlsBitmapBits[ 2 ]; 206 | PVOID ReadOnlySharedMemoryBase; 207 | PVOID HotpatchInformation; 208 | PVOID* ReadOnlyStaticServerData; 209 | PVOID AnsiCodePageData; 210 | PVOID OemCodePageData; 211 | PVOID UnicodeCaseTableData; 212 | 213 | ULONG NumberOfProcessors; 214 | ULONG NtGlobalFlag; 215 | 216 | LARGE_INTEGER CriticalSectionTimeout; 217 | SIZE_T HeapSegmentReserve; 218 | SIZE_T HeapSegmentCommit; 219 | SIZE_T HeapDeCommitTotalFreeThreshold; 220 | SIZE_T HeapDeCommitFreeBlockThreshold; 221 | 222 | ULONG NumberOfHeaps; 223 | ULONG MaximumNumberOfHeaps; 224 | PVOID* ProcessHeaps; 225 | 226 | PVOID GdiSharedHandleTable; 227 | PVOID ProcessStarterHelper; 228 | ULONG GdiDCAttributeList; 229 | 230 | PRTL_CRITICAL_SECTION LoaderLock; 231 | 232 | ULONG OSMajorVersion; 233 | ULONG OSMinorVersion; 234 | USHORT OSBuildNumber; 235 | USHORT OSCSDVersion; 236 | ULONG OSPlatformId; 237 | ULONG ImageSubsystem; 238 | ULONG ImageSubsystemMajorVersion; 239 | ULONG ImageSubsystemMinorVersion; 240 | ULONG_PTR ImageProcessAffinityMask; 241 | GDI_HANDLE_BUFFER GdiHandleBuffer; 242 | PVOID PostProcessInitRoutine; 243 | 244 | PVOID TlsExpansionBitmap; 245 | ULONG TlsExpansionBitmapBits[ 32 ]; 246 | 247 | ULONG SessionId; 248 | 249 | ULARGE_INTEGER AppCompatFlags; 250 | ULARGE_INTEGER AppCompatFlagsUser; 251 | PVOID pShimData; 252 | PVOID AppCompatInfo; 253 | 254 | UNICODE_STRING CSDVersion; 255 | 256 | PVOID ActivationContextData; 257 | PVOID ProcessAssemblyStorageMap; 258 | PVOID SystemDefaultActivationContextData; 259 | PVOID SystemAssemblyStorageMap; 260 | 261 | SIZE_T MinimumStackCommit; 262 | 263 | PVOID* FlsCallback; 264 | LIST_ENTRY FlsListHead; 265 | PVOID FlsBitmap; 266 | ULONG FlsBitmapBits[ FLS_MAXIMUM_AVAILABLE / ( sizeof( ULONG ) * 8 ) ]; 267 | ULONG FlsHighIndex; 268 | 269 | PVOID WerRegistrationData; 270 | PVOID WerShipAssertPtr; 271 | PVOID pContextData; 272 | PVOID pImageHeaderHash; 273 | 274 | union 275 | { 276 | ULONG TracingFlags; 277 | 278 | struct 279 | { 280 | ULONG HeapTracingEnabled : 1; 281 | ULONG CritSecTracingEnabled : 1; 282 | ULONG LibLoaderTracingEnabled : 1; 283 | ULONG SpareTracingBits : 29; 284 | }; 285 | }; 286 | 287 | ULONGLONG CsrServerReadOnlySharedMemoryBase; 288 | } PEB, * PPEB; 289 | 290 | #define GDI_BATCH_BUFFER_SIZE 310 291 | 292 | typedef struct _GDI_TEB_BATCH 293 | { 294 | ULONG Offset; 295 | ULONG_PTR HDC; 296 | ULONG Buffer[ GDI_BATCH_BUFFER_SIZE ]; 297 | } GDI_TEB_BATCH, * PGDI_TEB_BATCH; 298 | 299 | 300 | typedef struct _TEB_ACTIVE_FRAME_CONTEXT 301 | { 302 | ULONG Flags; 303 | PSTR FrameName; 304 | } TEB_ACTIVE_FRAME_CONTEXT, * PTEB_ACTIVE_FRAME_CONTEXT; 305 | 306 | typedef struct _TEB_ACTIVE_FRAME 307 | { 308 | ULONG Flags; 309 | struct _TEB_ACTIVE_FRAME* Previous; 310 | PTEB_ACTIVE_FRAME_CONTEXT Context; 311 | } TEB_ACTIVE_FRAME, * PTEB_ACTIVE_FRAME; 312 | 313 | typedef struct _ACTIVATION_CONTEXT_STACK 314 | { 315 | struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME* ActiveFrame; 316 | LIST_ENTRY FrameListCache; 317 | ULONG Flags; 318 | ULONG NextCookieSequenceNumber; 319 | ULONG StackId; 320 | } ACTIVATION_CONTEXT_STACK, * PACTIVATION_CONTEXT_STACK; 321 | 322 | typedef struct _TEB 323 | { 324 | NT_TIB NtTib; 325 | 326 | PVOID EnvironmentPointer; 327 | CLIENT_ID ClientId; 328 | PVOID ActiveRpcHandle; 329 | PVOID ThreadLocalStoragePointer; 330 | PPEB ProcessEnvironmentBlock; 331 | 332 | ULONG LastErrorValue; 333 | ULONG CountOfOwnedCriticalSections; 334 | PVOID CsrClientThread; 335 | PVOID Win32ThreadInfo; 336 | ULONG User32Reserved[ 26 ]; 337 | ULONG UserReserved[ 5 ]; 338 | PVOID WOW32Reserved; 339 | LCID CurrentLocale; 340 | ULONG FpSoftwareStatusRegister; 341 | PVOID ReservedForDebuggerInstrumentation[ 16 ]; 342 | #ifdef _WIN64 343 | PVOID SystemReserved1[ 30 ]; 344 | #else 345 | PVOID SystemReserved1[ 26 ]; 346 | #endif 347 | 348 | CHAR PlaceholderCompatibilityMode; 349 | CHAR PlaceholderReserved[ 11 ]; 350 | ULONG ProxiedProcessId; 351 | ACTIVATION_CONTEXT_STACK ActivationStack; 352 | 353 | UCHAR WorkingOnBehalfTicket[ 8 ]; 354 | NTSTATUS ExceptionCode; 355 | 356 | PACTIVATION_CONTEXT_STACK ActivationContextStackPointer; 357 | ULONG_PTR InstrumentationCallbackSp; 358 | ULONG_PTR InstrumentationCallbackPreviousPc; 359 | ULONG_PTR InstrumentationCallbackPreviousSp; 360 | #ifdef _WIN64 361 | ULONG TxFsContext; 362 | #endif 363 | 364 | BOOLEAN InstrumentationCallbackDisabled; 365 | #ifndef _WIN64 366 | UCHAR SpareBytes[ 23 ]; 367 | ULONG TxFsContext; 368 | #endif 369 | GDI_TEB_BATCH GdiTebBatch; 370 | CLIENT_ID RealClientId; 371 | HANDLE GdiCachedProcessHandle; 372 | ULONG GdiClientPID; 373 | ULONG GdiClientTID; 374 | PVOID GdiThreadLocalInfo; 375 | ULONG_PTR Win32ClientInfo[ 62 ]; 376 | PVOID glDispatchTable[ 233 ]; 377 | ULONG_PTR glReserved1[ 29 ]; 378 | PVOID glReserved2; 379 | PVOID glSectionInfo; 380 | PVOID glSection; 381 | PVOID glTable; 382 | PVOID glCurrentRC; 383 | PVOID glContext; 384 | 385 | NTSTATUS LastStatusValue; 386 | UNICODE_STRING StaticUnicodeString; 387 | WCHAR StaticUnicodeBuffer[ 261 ]; 388 | 389 | PVOID DeallocationStack; 390 | PVOID TlsSlots[ 64 ]; 391 | LIST_ENTRY TlsLinks; 392 | 393 | PVOID Vdm; 394 | PVOID ReservedForNtRpc; 395 | PVOID DbgSsReserved[ 2 ]; 396 | 397 | ULONG HardErrorMode; 398 | #ifdef _WIN64 399 | PVOID Instrumentation[ 11 ]; 400 | #else 401 | PVOID Instrumentation[ 9 ]; 402 | #endif 403 | GUID ActivityId; 404 | 405 | PVOID SubProcessTag; 406 | PVOID PerflibData; 407 | PVOID EtwTraceData; 408 | PVOID WinSockData; 409 | ULONG GdiBatchCount; 410 | 411 | union 412 | { 413 | PROCESSOR_NUMBER CurrentIdealProcessor; 414 | ULONG IdealProcessorValue; 415 | 416 | struct 417 | { 418 | UCHAR ReservedPad0; 419 | UCHAR ReservedPad1; 420 | UCHAR ReservedPad2; 421 | UCHAR IdealProcessor; 422 | }; 423 | }; 424 | 425 | ULONG GuaranteedStackBytes; 426 | PVOID ReservedForPerf; 427 | PVOID ReservedForOle; 428 | ULONG WaitingOnLoaderLock; 429 | PVOID SavedPriorityState; 430 | ULONG_PTR ReservedForCodeCoverage; 431 | PVOID ThreadPoolData; 432 | PVOID* TlsExpansionSlots; 433 | #ifdef _WIN64 434 | PVOID DeallocationBStore; 435 | PVOID BStoreLimit; 436 | #endif 437 | ULONG MuiGeneration; 438 | ULONG IsImpersonating; 439 | PVOID NlsCache; 440 | PVOID pShimData; 441 | USHORT HeapVirtualAffinity; 442 | USHORT LowFragHeapDataSlot; 443 | HANDLE CurrentTransactionHandle; 444 | PTEB_ACTIVE_FRAME ActiveFrame; 445 | PVOID FlsData; 446 | 447 | PVOID PreferredLanguages; 448 | PVOID UserPrefLanguages; 449 | PVOID MergedPrefLanguages; 450 | ULONG MuiImpersonation; 451 | 452 | union 453 | { 454 | USHORT CrossTebFlags; 455 | USHORT SpareCrossTebBits : 16; 456 | }; 457 | 458 | union 459 | { 460 | USHORT SameTebFlags; 461 | 462 | struct 463 | { 464 | USHORT SafeThunkCall : 1; 465 | USHORT InDebugPrint : 1; 466 | USHORT HasFiberData : 1; 467 | USHORT SkipThreadAttach : 1; 468 | USHORT WerInShipAssertCode : 1; 469 | USHORT RanProcessInit : 1; 470 | USHORT ClonedThread : 1; 471 | USHORT SuppressDebugMsg : 1; 472 | USHORT DisableUserStackWalk : 1; 473 | USHORT RtlExceptionAttached : 1; 474 | USHORT InitialThread : 1; 475 | USHORT SessionAware : 1; 476 | USHORT LoadOwner : 1; 477 | USHORT LoaderWorker : 1; 478 | USHORT SkipLoaderInit : 1; 479 | USHORT SpareSameTebBits : 1; 480 | }; 481 | }; 482 | 483 | PVOID TxnScopeEnterCallback; 484 | PVOID TxnScopeExitCallback; 485 | PVOID TxnScopeContext; 486 | ULONG LockCount; 487 | LONG WowTebOffset; 488 | PVOID ResourceRetValue; 489 | PVOID ReservedForWdf; 490 | ULONGLONG ReservedForCrt; 491 | GUID EffectiveContainerId; 492 | } TEB, * PTEB; 493 | 494 | typedef struct _KSYSTEM_TIME 495 | { 496 | ULONG LowPart; 497 | LONG High1Time; 498 | LONG High2Time; 499 | } KSYSTEM_TIME, * PKSYSTEM_TIME; 500 | 501 | typedef enum _NT_PRODUCT_TYPE 502 | { 503 | NtProductWinNt = 1, 504 | NtProductLanManNt = 2, 505 | NtProductServer = 3 506 | } NT_PRODUCT_TYPE; 507 | 508 | typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE 509 | { 510 | StandardDesign = 0, 511 | NEC98x86 = 1, 512 | EndAlternatives = 2 513 | } ALTERNATIVE_ARCHITECTURE_TYPE; 514 | 515 | typedef struct _KUSER_SHARED_DATA 516 | { 517 | ULONG TickCountLowDeprecated; 518 | ULONG TickCountMultiplier; 519 | 520 | volatile KSYSTEM_TIME InterruptTime; 521 | volatile KSYSTEM_TIME SystemTime; 522 | volatile KSYSTEM_TIME TimeZoneBias; 523 | 524 | USHORT ImageNumberLow; 525 | USHORT ImageNumberHigh; 526 | 527 | WCHAR NtSystemRoot[ 260 ]; 528 | 529 | ULONG MaxStackTraceDepth; 530 | 531 | ULONG CryptoExponent; 532 | 533 | ULONG TimeZoneId; 534 | ULONG LargePageMinimum; 535 | ULONG AitSamplingValue; 536 | ULONG AppCompatFlag; 537 | ULONGLONG RNGSeedVersion; 538 | ULONG GlobalValidationRunlevel; 539 | LONG TimeZoneBiasStamp; 540 | 541 | ULONG NtBuildNumber; 542 | NT_PRODUCT_TYPE NtProductType; 543 | BOOLEAN ProductTypeIsValid; 544 | UCHAR Reserved0[ 1 ]; 545 | USHORT NativeProcessorArchitecture; 546 | 547 | ULONG NtMajorVersion; 548 | ULONG NtMinorVersion; 549 | 550 | BOOLEAN ProcessorFeatures[ 64 ]; 551 | 552 | ULONG Reserved1; 553 | ULONG Reserved3; 554 | 555 | volatile ULONG TimeSlip; 556 | 557 | ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture; 558 | ULONG BootId; 559 | 560 | LARGE_INTEGER SystemExpirationDate; 561 | 562 | ULONG SuiteMask; 563 | 564 | BOOLEAN KdDebuggerEnabled; 565 | 566 | union 567 | { 568 | UCHAR MitigationPolicies; 569 | 570 | struct 571 | { 572 | UCHAR NXSupportPolicy : 2; 573 | UCHAR SEHValidationPolicy : 2; 574 | UCHAR CurDirDevicesSkippedForDlls : 2; 575 | UCHAR Reserved : 2; 576 | }; 577 | }; 578 | 579 | USHORT CyclesPerYield; 580 | 581 | volatile ULONG ActiveConsoleId; 582 | 583 | volatile ULONG DismountCount; 584 | 585 | ULONG ComPlusPackage; 586 | 587 | ULONG LastSystemRITEventTickCount; 588 | 589 | ULONG NumberOfPhysicalPages; 590 | 591 | BOOLEAN SafeBootMode; 592 | UCHAR VirtualizationFlags; 593 | UCHAR Reserved12[ 2 ]; 594 | 595 | union 596 | { 597 | ULONG SharedDataFlags; 598 | 599 | struct 600 | { 601 | ULONG DbgErrorPortPresent : 1; 602 | ULONG DbgElevationEnabled : 1; 603 | ULONG DbgVirtEnabled : 1; 604 | ULONG DbgInstallerDetectEnabled : 1; 605 | ULONG DbgLkgEnabled : 1; 606 | ULONG DbgDynProcessorEnabled : 1; 607 | ULONG DbgConsoleBrokerEnabled : 1; 608 | ULONG DbgSecureBootEnabled : 1; 609 | ULONG DbgMultiSessionSku : 1; 610 | ULONG DbgMultiUsersInSessionSku : 1; 611 | ULONG DbgStateSeparationEnabled : 1; 612 | ULONG SpareBits : 21; 613 | }; 614 | }; 615 | 616 | ULONG DataFlagsPad[ 1 ]; 617 | 618 | ULONGLONG TestRetInstruction; 619 | LONGLONG QpcFrequency; 620 | ULONG SystemCall; 621 | ULONG SystemCallPad0; 622 | ULONGLONG SystemCallPad[ 2 ]; 623 | 624 | union 625 | { 626 | volatile KSYSTEM_TIME TickCount; 627 | volatile ULONG64 TickCountQuad; 628 | ULONG ReservedTickCountOverlay[ 3 ]; 629 | }; 630 | 631 | ULONG TickCountPad[ 1 ]; 632 | 633 | ULONG Cookie; 634 | ULONG CookiePad[ 1 ]; 635 | 636 | LONGLONG ConsoleSessionForegroundProcessId; 637 | ULONGLONG TimeUpdateLock; 638 | ULONGLONG BaselineSystemTimeQpc; 639 | ULONGLONG BaselineInterruptTimeQpc; 640 | ULONGLONG QpcSystemTimeIncrement; 641 | ULONGLONG QpcInterruptTimeIncrement; 642 | UCHAR QpcSystemTimeIncrementShift; 643 | UCHAR QpcInterruptTimeIncrementShift; 644 | 645 | USHORT UnparkedProcessorCount; 646 | ULONG EnclaveFeatureMask[ 4 ]; 647 | 648 | ULONG TelemetryCoverageRound; 649 | 650 | USHORT UserModeGlobalLogger[ 16 ]; 651 | ULONG ImageFileExecutionOptions; 652 | 653 | ULONG LangGenerationCount; 654 | ULONGLONG Reserved4; 655 | volatile ULONG64 InterruptTimeBias; 656 | volatile ULONG64 QpcBias; 657 | 658 | ULONG ActiveProcessorCount; 659 | volatile UCHAR ActiveGroupCount; 660 | UCHAR Reserved9; 661 | 662 | union 663 | { 664 | USHORT QpcData; 665 | 666 | struct 667 | { 668 | UCHAR QpcBypassEnabled : 1; 669 | UCHAR QpcShift : 1; 670 | }; 671 | }; 672 | 673 | LARGE_INTEGER TimeZoneBiasEffectiveStart; 674 | LARGE_INTEGER TimeZoneBiasEffectiveEnd; 675 | XSTATE_CONFIGURATION XState; 676 | } KUSER_SHARED_DATA, * PKUSER_SHARED_DATA; 677 | } 678 | 679 | #pragma pack( push, 1) 680 | 681 | // The following struct defines the interesting part of the IDENTIFY 682 | // buffer: 683 | typedef struct _IDSECTOR 684 | { 685 | USHORT wGenConfig; 686 | USHORT wNumCyls; 687 | USHORT wReserved; 688 | USHORT wNumHeads; 689 | USHORT wBytesPerTrack; 690 | USHORT wBytesPerSector; 691 | USHORT wSectorsPerTrack; 692 | USHORT wVendorUnique[ 3 ]; 693 | CHAR sSerialNumber[ 20 ]; 694 | USHORT wBufferType; 695 | USHORT wBufferSize; 696 | USHORT wECCSize; 697 | CHAR sFirmwareRev[ 8 ]; 698 | CHAR sModelNumber[ 40 ]; 699 | USHORT wMoreVendorUnique; 700 | USHORT wDoubleWordIO; 701 | USHORT wCapabilities; 702 | USHORT wReserved1; 703 | USHORT wPIOTiming; 704 | USHORT wDMATiming; 705 | USHORT wBS; 706 | USHORT wNumCurrentCyls; 707 | USHORT wNumCurrentHeads; 708 | USHORT wNumCurrentSectorsPerTrack; 709 | ULONG ulCurrentSectorCapacity; 710 | USHORT wMultSectorStuff; 711 | ULONG ulTotalAddressableSectors; 712 | USHORT wSingleWordDMA; 713 | USHORT wMultiWordDMA; 714 | BYTE bReserved[ 128 ]; 715 | } IDSECTOR, * PIDSECTOR; 716 | 717 | typedef struct _SYSTEM_PROCESS_INFO 718 | { 719 | ULONG NextEntryOffset; 720 | ULONG NumberOfThreads; 721 | LARGE_INTEGER Reserved[ 3 ]; 722 | LARGE_INTEGER CreateTime; 723 | LARGE_INTEGER UserTime; 724 | LARGE_INTEGER KernelTime; 725 | UNICODE_STRING ImageName; 726 | ULONG BasePriority; 727 | HANDLE ProcessId; 728 | HANDLE InheritedFromProcessId; 729 | }SYSTEM_PROCESS_INFO, * PSYSTEM_PROCESS_INFO; 730 | 731 | typedef struct _SRB_IO_CONTROL 732 | { 733 | ULONG HeaderLength; 734 | UCHAR Signature[ 8 ]; 735 | ULONG Timeout; 736 | ULONG ControlCode; 737 | ULONG ReturnCode; 738 | ULONG Length; 739 | } SRB_IO_CONTROL, * PSRB_IO_CONTROL; 740 | 741 | typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION 742 | { 743 | GUID BootIdentifier; 744 | FIRMWARE_TYPE FirmwareType; 745 | } SYSTEM_BOOT_ENVIRONMENT_INFORMATION, * PSYSTEM_BOOT_ENVIRONMENT_INFORMATION; 746 | 747 | typedef struct _SYSTEM_MODULE 748 | { 749 | HANDLE Section; 750 | PVOID MappedBase; 751 | PVOID ImageBase; 752 | ULONG ImageSize; 753 | ULONG Flags; 754 | USHORT LoadOrderIndex; 755 | USHORT InitOrderIndex; 756 | USHORT LoadCount; 757 | USHORT OffsetToFileName; 758 | UCHAR FullPathName[ 256 ]; 759 | } SYSTEM_MODULE, * PSYSTEM_MODULE; 760 | 761 | typedef struct _SYSTEM_MODULE_INFORMATION 762 | { 763 | ULONG NumberOfModules; 764 | SYSTEM_MODULE Modules[ 1 ]; 765 | } SYSTEM_MODULE_INFORMATION, * PSYSTEM_MODULE_INFORMATION; 766 | 767 | typedef struct _IDENTIFY_DATA 768 | { 769 | USHORT GeneralConfiguration; // 00 00 770 | USHORT NumberOfCylinders; // 02 1 771 | USHORT Reserved1; // 04 2 772 | USHORT NumberOfHeads; // 06 3 773 | USHORT UnformattedBytesPerTrack; // 08 4 774 | USHORT UnformattedBytesPerSector; // 0A 5 775 | USHORT SectorsPerTrack; // 0C 6 776 | USHORT VendorUnique1[ 3 ]; // 0E 7-9 777 | USHORT SerialNumber[ 10 ]; // 14 10-19 778 | USHORT BufferType; // 28 20 779 | USHORT BufferSectorSize; // 2A 21 780 | USHORT NumberOfEccBytes; // 2C 22 781 | USHORT FirmwareRevision[ 4 ]; // 2E 23-26 782 | USHORT ModelNumber[ 20 ]; // 36 27-46 783 | UCHAR MaximumBlockTransfer; // 5E 47 784 | UCHAR VendorUnique2; // 5F 785 | USHORT DoubleWordIo; // 60 48 786 | USHORT Capabilities; // 62 49 787 | USHORT Reserved2; // 64 50 788 | UCHAR VendorUnique3; // 66 51 789 | UCHAR PioCycleTimingMode; // 67 790 | UCHAR VendorUnique4; // 68 52 791 | UCHAR DmaCycleTimingMode; // 69 792 | USHORT TranslationFieldsValid : 1; // 6A 53 793 | USHORT Reserved3 : 15; 794 | USHORT NumberOfCurrentCylinders; // 6C 54 795 | USHORT NumberOfCurrentHeads; // 6E 55 796 | USHORT CurrentSectorsPerTrack; // 70 56 797 | ULONG CurrentSectorCapacity; // 72 57-58 798 | USHORT CurrentMultiSectorSetting; // 59 799 | ULONG UserAddressableSectors; // 60-61 800 | USHORT SingleWordDMASupport : 8; // 62 801 | USHORT SingleWordDMAActive : 8; 802 | USHORT MultiWordDMASupport : 8; // 63 803 | USHORT MultiWordDMAActive : 8; 804 | USHORT AdvancedPIOModes : 8; // 64 805 | USHORT Reserved4 : 8; 806 | USHORT MinimumMWXferCycleTime; // 65 807 | USHORT RecommendedMWXferCycleTime; // 66 808 | USHORT MinimumPIOCycleTime; // 67 809 | USHORT MinimumPIOCycleTimeIORDY; // 68 810 | USHORT Reserved5[ 2 ]; // 69-70 811 | USHORT ReleaseTimeOverlapped; // 71 812 | USHORT ReleaseTimeServiceCommand; // 72 813 | USHORT MajorRevision; // 73 814 | USHORT MinorRevision; // 74 815 | USHORT Reserved6[ 50 ]; // 75-126 816 | USHORT SpecialFunctionsEnabled; // 127 817 | USHORT Reserved7[ 128 ]; // 128-255 818 | } IDENTIFY_DATA, * PIDENTIFY_DATA; 819 | 820 | #pragma pack( pop ) 821 | 822 | typedef enum _SECTION_INHERIT 823 | { 824 | ViewShare = 1, 825 | ViewUnmap = 2 826 | } SECTION_INHERIT, * PSECTION_INHERIT; 827 | 828 | typedef enum _MEMORY_INFORMATION_CLASS 829 | { 830 | MemoryBasicInformation 831 | } MEMORY_INFORMATION_CLASS, * PMEMORY_INFORMATION_CLASS; 832 | 833 | 834 | EXTERN_C 835 | NTSTATUS 836 | NTAPI 837 | NtCreateSection( 838 | _Out_ PHANDLE SectionHandle, 839 | _In_ ACCESS_MASK DesiredAccess, 840 | _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, 841 | _In_opt_ PLARGE_INTEGER MaximumSize, 842 | _In_ ULONG SectionPageProtection, 843 | _In_ ULONG AllocationAttributes, 844 | _In_opt_ HANDLE FileHandle 845 | ); 846 | 847 | EXTERN_C 848 | NTSTATUS 849 | NTAPI 850 | NtMapViewOfSection( 851 | _In_ HANDLE SectionHandle, 852 | _In_ HANDLE ProcessHandle, 853 | _Inout_ PVOID * BaseAddress, 854 | _In_ ULONG_PTR ZeroBits, 855 | _In_ SIZE_T CommitSize, 856 | _Inout_opt_ PLARGE_INTEGER SectionOffset, 857 | _Inout_ PSIZE_T ViewSize, 858 | _In_ SECTION_INHERIT InheritDisposition, 859 | _In_ ULONG AllocationType, 860 | _In_ ULONG Win32Protect 861 | ); 862 | 863 | EXTERN_C 864 | NTSTATUS 865 | NTAPI 866 | NtUnmapViewOfSection( 867 | _In_ HANDLE ProcessHandle, 868 | _In_opt_ PVOID BaseAddress 869 | ); 870 | 871 | EXTERN_C 872 | NTSTATUS 873 | NTAPI 874 | NtClose( 875 | _In_ HANDLE Handle 876 | ); 877 | 878 | EXTERN_C 879 | PIMAGE_NT_HEADERS 880 | NTAPI 881 | RtlImageNtHeader( 882 | _In_ PVOID BaseAddress 883 | ); -------------------------------------------------------------------------------- /loader/lazy_importer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // documentation is available at https://github.com/JustasMasiulis/lazy_importer 18 | 19 | #ifndef LAZY_IMPORTER_HPP 20 | #define LAZY_IMPORTER_HPP 21 | 22 | #define LI_FN(name) \ 23 | ::li::detail::lazy_function<::li::detail::khash(#name), decltype(&name)>() 24 | 25 | #define LI_FN_DEF(name) ::li::detail::lazy_function<::li::detail::khash(#name), name>() 26 | 27 | #define LI_MODULE(name) ::li::detail::lazy_module<::li::detail::khash(name)>() 28 | 29 | // NOTE only std::forward is used from this header. 30 | // If there is a need to eliminate this dependency the function itself is very small. 31 | #include 32 | #include 33 | #include 34 | 35 | #ifndef LAZY_IMPORTER_NO_FORCEINLINE 36 | #if defined(_MSC_VER) 37 | #define LAZY_IMPORTER_FORCEINLINE __forceinline 38 | #elif defined(__GNUC__) && __GNUC__ > 3 39 | #define LAZY_IMPORTER_FORCEINLINE inline __attribute__((__always_inline__)) 40 | #else 41 | #define LAZY_IMPORTER_FORCEINLINE inline 42 | #endif 43 | #else 44 | #define LAZY_IMPORTER_FORCEINLINE inline 45 | #endif 46 | 47 | #ifdef LAZY_IMPORTER_CASE_INSENSITIVE 48 | #define LAZY_IMPORTER_TOLOWER(c) (c >= 'A' && c <= 'Z' ? (c | (1 << 5)) : c) 49 | #else 50 | #define LAZY_IMPORTER_TOLOWER(c) (c) 51 | #endif 52 | 53 | namespace li { 54 | namespace detail { 55 | 56 | template 57 | struct pair { 58 | First first; 59 | Second second; 60 | }; 61 | 62 | namespace win { 63 | 64 | struct LIST_ENTRY_T { 65 | const char* Flink; 66 | const char* Blink; 67 | }; 68 | 69 | struct UNICODE_STRING_T { 70 | unsigned short Length; 71 | unsigned short MaximumLength; 72 | wchar_t* Buffer; 73 | }; 74 | 75 | struct PEB_LDR_DATA_T { 76 | unsigned long Length; 77 | unsigned long Initialized; 78 | const char* SsHandle; 79 | LIST_ENTRY_T InLoadOrderModuleList; 80 | }; 81 | 82 | struct PEB_T { 83 | unsigned char Reserved1[2]; 84 | unsigned char BeingDebugged; 85 | unsigned char Reserved2[1]; 86 | const char* Reserved3[2]; 87 | PEB_LDR_DATA_T* Ldr; 88 | }; 89 | 90 | struct LDR_DATA_TABLE_ENTRY_T { 91 | LIST_ENTRY_T InLoadOrderLinks; 92 | LIST_ENTRY_T InMemoryOrderLinks; 93 | LIST_ENTRY_T InInitializationOrderLinks; 94 | const char* DllBase; 95 | const char* EntryPoint; 96 | union { 97 | unsigned long SizeOfImage; 98 | const char* _dummy; 99 | }; 100 | UNICODE_STRING_T FullDllName; 101 | UNICODE_STRING_T BaseDllName; 102 | 103 | LAZY_IMPORTER_FORCEINLINE const LDR_DATA_TABLE_ENTRY_T* 104 | load_order_next() const noexcept 105 | { 106 | return reinterpret_cast( 107 | InLoadOrderLinks.Flink); 108 | } 109 | }; 110 | 111 | struct IMAGE_DOS_HEADER { // DOS .EXE header 112 | unsigned short e_magic; // Magic number 113 | unsigned short e_cblp; // Bytes on last page of file 114 | unsigned short e_cp; // Pages in file 115 | unsigned short e_crlc; // Relocations 116 | unsigned short e_cparhdr; // Size of header in paragraphs 117 | unsigned short e_minalloc; // Minimum extra paragraphs needed 118 | unsigned short e_maxalloc; // Maximum extra paragraphs needed 119 | unsigned short e_ss; // Initial (relative) SS value 120 | unsigned short e_sp; // Initial SP value 121 | unsigned short e_csum; // Checksum 122 | unsigned short e_ip; // Initial IP value 123 | unsigned short e_cs; // Initial (relative) CS value 124 | unsigned short e_lfarlc; // File address of relocation table 125 | unsigned short e_ovno; // Overlay number 126 | unsigned short e_res[4]; // Reserved words 127 | unsigned short e_oemid; // OEM identifier (for e_oeminfo) 128 | unsigned short e_oeminfo; // OEM information; e_oemid specific 129 | unsigned short e_res2[10]; // Reserved words 130 | long e_lfanew; // File address of new exe header 131 | }; 132 | 133 | struct IMAGE_FILE_HEADER { 134 | unsigned short Machine; 135 | unsigned short NumberOfSections; 136 | unsigned long TimeDateStamp; 137 | unsigned long PointerToSymbolTable; 138 | unsigned long NumberOfSymbols; 139 | unsigned short SizeOfOptionalHeader; 140 | unsigned short Characteristics; 141 | }; 142 | 143 | struct IMAGE_EXPORT_DIRECTORY { 144 | unsigned long Characteristics; 145 | unsigned long TimeDateStamp; 146 | unsigned short MajorVersion; 147 | unsigned short MinorVersion; 148 | unsigned long Name; 149 | unsigned long Base; 150 | unsigned long NumberOfFunctions; 151 | unsigned long NumberOfNames; 152 | unsigned long AddressOfFunctions; // RVA from base of image 153 | unsigned long AddressOfNames; // RVA from base of image 154 | unsigned long AddressOfNameOrdinals; // RVA from base of image 155 | }; 156 | 157 | struct IMAGE_DATA_DIRECTORY { 158 | unsigned long VirtualAddress; 159 | unsigned long Size; 160 | }; 161 | 162 | struct IMAGE_OPTIONAL_HEADER64 { 163 | unsigned short Magic; 164 | unsigned char MajorLinkerVersion; 165 | unsigned char MinorLinkerVersion; 166 | unsigned long SizeOfCode; 167 | unsigned long SizeOfInitializedData; 168 | unsigned long SizeOfUninitializedData; 169 | unsigned long AddressOfEntryPoint; 170 | unsigned long BaseOfCode; 171 | unsigned long long ImageBase; 172 | unsigned long SectionAlignment; 173 | unsigned long FileAlignment; 174 | unsigned short MajorOperatingSystemVersion; 175 | unsigned short MinorOperatingSystemVersion; 176 | unsigned short MajorImageVersion; 177 | unsigned short MinorImageVersion; 178 | unsigned short MajorSubsystemVersion; 179 | unsigned short MinorSubsystemVersion; 180 | unsigned long Win32VersionValue; 181 | unsigned long SizeOfImage; 182 | unsigned long SizeOfHeaders; 183 | unsigned long CheckSum; 184 | unsigned short Subsystem; 185 | unsigned short DllCharacteristics; 186 | unsigned long long SizeOfStackReserve; 187 | unsigned long long SizeOfStackCommit; 188 | unsigned long long SizeOfHeapReserve; 189 | unsigned long long SizeOfHeapCommit; 190 | unsigned long LoaderFlags; 191 | unsigned long NumberOfRvaAndSizes; 192 | IMAGE_DATA_DIRECTORY DataDirectory[16]; 193 | }; 194 | 195 | struct IMAGE_OPTIONAL_HEADER32 { 196 | unsigned short Magic; 197 | unsigned char MajorLinkerVersion; 198 | unsigned char MinorLinkerVersion; 199 | unsigned long SizeOfCode; 200 | unsigned long SizeOfInitializedData; 201 | unsigned long SizeOfUninitializedData; 202 | unsigned long AddressOfEntryPoint; 203 | unsigned long BaseOfCode; 204 | unsigned long BaseOfData; 205 | unsigned long ImageBase; 206 | unsigned long SectionAlignment; 207 | unsigned long FileAlignment; 208 | unsigned short MajorOperatingSystemVersion; 209 | unsigned short MinorOperatingSystemVersion; 210 | unsigned short MajorImageVersion; 211 | unsigned short MinorImageVersion; 212 | unsigned short MajorSubsystemVersion; 213 | unsigned short MinorSubsystemVersion; 214 | unsigned long Win32VersionValue; 215 | unsigned long SizeOfImage; 216 | unsigned long SizeOfHeaders; 217 | unsigned long CheckSum; 218 | unsigned short Subsystem; 219 | unsigned short DllCharacteristics; 220 | unsigned long SizeOfStackReserve; 221 | unsigned long SizeOfStackCommit; 222 | unsigned long SizeOfHeapReserve; 223 | unsigned long SizeOfHeapCommit; 224 | unsigned long LoaderFlags; 225 | unsigned long NumberOfRvaAndSizes; 226 | IMAGE_DATA_DIRECTORY DataDirectory[16]; 227 | }; 228 | 229 | struct IMAGE_NT_HEADERS { 230 | unsigned long Signature; 231 | IMAGE_FILE_HEADER FileHeader; 232 | #ifdef _WIN64 233 | IMAGE_OPTIONAL_HEADER64 OptionalHeader; 234 | #else 235 | IMAGE_OPTIONAL_HEADER32 OptionalHeader; 236 | #endif 237 | }; 238 | 239 | } // namespace win 240 | 241 | // hashing stuff 242 | struct hash_t { 243 | using value_type = unsigned long; 244 | constexpr static value_type offset = 2166136261; 245 | constexpr static value_type prime = 16777619; 246 | constexpr static unsigned long long prime64 = prime; 247 | 248 | LAZY_IMPORTER_FORCEINLINE constexpr static value_type single(value_type value, 249 | char c) noexcept 250 | { 251 | return static_cast( 252 | (value ^ LAZY_IMPORTER_TOLOWER(c)) * 253 | static_cast(prime)); 254 | } 255 | }; 256 | 257 | template 258 | LAZY_IMPORTER_FORCEINLINE constexpr hash_t::value_type 259 | khash(const CharT * str, hash_t::value_type value = hash_t::offset) noexcept 260 | { 261 | return (*str ? khash(str + 1, hash_t::single(value, *str)) : value); 262 | } 263 | 264 | template 265 | LAZY_IMPORTER_FORCEINLINE hash_t::value_type hash(const CharT * str) noexcept 266 | { 267 | hash_t::value_type value = hash_t::offset; 268 | 269 | for (;;) { 270 | char c = *str++; 271 | if (!c) 272 | return value; 273 | value = hash_t::single(value, c); 274 | } 275 | } 276 | 277 | LAZY_IMPORTER_FORCEINLINE hash_t::value_type hash( 278 | const win::UNICODE_STRING_T& str) noexcept 279 | { 280 | auto first = str.Buffer; 281 | const auto last = first + (str.Length / sizeof(wchar_t)); 282 | auto value = hash_t::offset; 283 | for (; first != last; ++first) 284 | value = hash_t::single(value, static_cast(*first)); 285 | 286 | return value; 287 | } 288 | 289 | LAZY_IMPORTER_FORCEINLINE pair hash_forwarded( 290 | const char* str) noexcept 291 | { 292 | pair module_and_function{ 293 | hash_t::offset, hash_t::offset 294 | }; 295 | 296 | for (; *str != '.'; ++str) 297 | hash_t::single(module_and_function.first, *str); 298 | 299 | ++str; 300 | 301 | for (; *str; ++str) 302 | hash_t::single(module_and_function.second, *str); 303 | 304 | return module_and_function; 305 | } 306 | 307 | 308 | // some helper functions 309 | LAZY_IMPORTER_FORCEINLINE const win::PEB_T* peb() noexcept 310 | { 311 | #if defined(_WIN64) 312 | return reinterpret_cast(__readgsqword(0x60)); 313 | #elif defined(_WIN32) 314 | return reinterpret_cast(__readfsdword(0x30)); 315 | #else 316 | #error Unsupported platform. Open an issue and I'll probably add support. 317 | #endif 318 | } 319 | 320 | LAZY_IMPORTER_FORCEINLINE const win::PEB_LDR_DATA_T* ldr() 321 | { 322 | return reinterpret_cast(peb()->Ldr); 323 | } 324 | 325 | LAZY_IMPORTER_FORCEINLINE const win::IMAGE_NT_HEADERS* nt_headers( 326 | const char* base) noexcept 327 | { 328 | return reinterpret_cast( 329 | base + reinterpret_cast(base)->e_lfanew); 330 | } 331 | 332 | LAZY_IMPORTER_FORCEINLINE const win::IMAGE_EXPORT_DIRECTORY* image_export_dir( 333 | const char* base) noexcept 334 | { 335 | return reinterpret_cast( 336 | base + nt_headers(base)->OptionalHeader.DataDirectory->VirtualAddress); 337 | } 338 | 339 | LAZY_IMPORTER_FORCEINLINE const win::LDR_DATA_TABLE_ENTRY_T* ldr_data_entry() noexcept 340 | { 341 | return reinterpret_cast( 342 | ldr()->InLoadOrderModuleList.Flink); 343 | } 344 | 345 | struct exports_directory { 346 | const char* _base; 347 | const win::IMAGE_EXPORT_DIRECTORY* _ied; 348 | unsigned long _ied_size; 349 | 350 | public: 351 | using size_type = unsigned long; 352 | 353 | LAZY_IMPORTER_FORCEINLINE 354 | exports_directory(const char* base) noexcept : _base(base) 355 | { 356 | const auto ied_data_dir = nt_headers(base)->OptionalHeader.DataDirectory[0]; 357 | _ied = reinterpret_cast( 358 | base + ied_data_dir.VirtualAddress); 359 | _ied_size = ied_data_dir.Size; 360 | } 361 | 362 | LAZY_IMPORTER_FORCEINLINE explicit operator bool() const noexcept 363 | { 364 | return reinterpret_cast(_ied) != _base; 365 | } 366 | 367 | LAZY_IMPORTER_FORCEINLINE size_type size() const noexcept 368 | { 369 | return _ied->NumberOfNames; 370 | } 371 | 372 | LAZY_IMPORTER_FORCEINLINE const char* base() const noexcept { return _base; } 373 | LAZY_IMPORTER_FORCEINLINE const win::IMAGE_EXPORT_DIRECTORY* ied() const noexcept 374 | { 375 | return _ied; 376 | } 377 | 378 | LAZY_IMPORTER_FORCEINLINE const char* name(size_type index) const noexcept 379 | { 380 | return reinterpret_cast( 381 | _base + reinterpret_cast( 382 | _base + _ied->AddressOfNames)[index]); 383 | } 384 | 385 | LAZY_IMPORTER_FORCEINLINE const char* address(size_type index) const noexcept 386 | { 387 | const auto* const rva_table = 388 | reinterpret_cast(_base + _ied->AddressOfFunctions); 389 | 390 | const auto* const ord_table = reinterpret_cast( 391 | _base + _ied->AddressOfNameOrdinals); 392 | 393 | return _base + rva_table[ord_table[index]]; 394 | } 395 | 396 | LAZY_IMPORTER_FORCEINLINE bool is_forwarded(const char* export_address) const 397 | noexcept 398 | { 399 | const auto ui_ied = reinterpret_cast(_ied); 400 | return (export_address > ui_ied && export_address < ui_ied + _ied_size); 401 | } 402 | }; 403 | 404 | struct safe_module_enumerator { 405 | using value_type = const detail::win::LDR_DATA_TABLE_ENTRY_T; 406 | value_type* value; 407 | value_type* const head; 408 | 409 | LAZY_IMPORTER_FORCEINLINE safe_module_enumerator() noexcept 410 | : value(ldr_data_entry()), head(value) 411 | {} 412 | 413 | LAZY_IMPORTER_FORCEINLINE void reset() noexcept { value = head; } 414 | 415 | LAZY_IMPORTER_FORCEINLINE bool next() noexcept 416 | { 417 | value = value->load_order_next(); 418 | return value != head && value->DllBase; 419 | } 420 | }; 421 | 422 | struct unsafe_module_enumerator { 423 | using value_type = const detail::win::LDR_DATA_TABLE_ENTRY_T*; 424 | value_type value; 425 | 426 | LAZY_IMPORTER_FORCEINLINE unsafe_module_enumerator() noexcept 427 | : value(ldr_data_entry()) 428 | {} 429 | 430 | LAZY_IMPORTER_FORCEINLINE void reset() noexcept { value = ldr_data_entry(); } 431 | 432 | LAZY_IMPORTER_FORCEINLINE bool next() noexcept 433 | { 434 | value = value->load_order_next(); 435 | return true; 436 | } 437 | }; 438 | 439 | // provides the cached functions which use Derive classes methods 440 | template 441 | class lazy_base { 442 | protected: 443 | // This function is needed because every templated function 444 | // with different args has its own static buffer 445 | LAZY_IMPORTER_FORCEINLINE static void*& _cache() noexcept 446 | { 447 | static void* value = nullptr; 448 | return value; 449 | } 450 | 451 | public: 452 | template 453 | LAZY_IMPORTER_FORCEINLINE static T safe() noexcept 454 | { 455 | return Derived::template get(); 456 | } 457 | 458 | template 459 | LAZY_IMPORTER_FORCEINLINE static T cached() noexcept 460 | { 461 | auto& cached = _cache(); 462 | if (!cached) 463 | cached = Derived::template get(); 464 | 465 | return (T)(cached); 466 | } 467 | 468 | template 469 | LAZY_IMPORTER_FORCEINLINE static T safe_cached() noexcept 470 | { 471 | return cached(); 472 | } 473 | }; 474 | 475 | template 476 | struct lazy_module : lazy_base> { 477 | template 478 | LAZY_IMPORTER_FORCEINLINE static T get() noexcept 479 | { 480 | Enum e; 481 | do { 482 | if (hash(e.value->BaseDllName) == Hash) 483 | return (T)(e.value->DllBase); 484 | } while (e.next()); 485 | return {}; 486 | } 487 | }; 488 | 489 | template 490 | struct lazy_function : lazy_base, T> { 491 | using base_type = lazy_base, T>; 492 | 493 | template 494 | LAZY_IMPORTER_FORCEINLINE decltype(auto) operator()(Args&& ... args) const 495 | { 496 | #ifndef LAZY_IMPORTER_CACHE_OPERATOR_PARENS 497 | return get()(std::forward(args)...); 498 | #else 499 | return this->cached()(std::forward(args)...); 500 | #endif 501 | } 502 | 503 | template 504 | LAZY_IMPORTER_FORCEINLINE static F get() noexcept 505 | { 506 | // for backwards compatability. 507 | // Before 2.0 it was only possible to resolve forwarded exports when 508 | // this macro was enabled 509 | #ifdef LAZY_IMPORTER_RESOLVE_FORWARDED_EXPORTS 510 | return forwarded(); 511 | #else 512 | Enum e; 513 | do { 514 | const exports_directory exports(e.value->DllBase); 515 | 516 | if (exports) { 517 | auto export_index = exports.size(); 518 | while (export_index--) 519 | if (hash(exports.name(export_index)) == Hash) 520 | return (F)(exports.address(export_index)); 521 | } 522 | } while (e.next()); 523 | return {}; 524 | #endif 525 | } 526 | 527 | template 528 | LAZY_IMPORTER_FORCEINLINE static F forwarded() noexcept 529 | { 530 | detail::win::UNICODE_STRING_T name; 531 | hash_t::value_type module_hash = 0; 532 | auto function_hash = Hash; 533 | 534 | Enum e; 535 | do { 536 | name = e.value->BaseDllName; 537 | name.Length -= 8; // get rid of .dll extension 538 | 539 | if (!module_hash || hash(name) == module_hash) { 540 | const exports_directory exports(e.value->DllBase); 541 | 542 | if (exports) { 543 | auto export_index = exports.size(); 544 | while (export_index--) 545 | if (hash(exports.name(export_index)) == function_hash) { 546 | const auto addr = exports.address(export_index); 547 | 548 | if (exports.is_forwarded(addr)) { 549 | auto hashes = hash_forwarded( 550 | reinterpret_cast(addr)); 551 | 552 | function_hash = hashes.second; 553 | module_hash = hashes.first; 554 | 555 | e.reset(); 556 | break; 557 | } 558 | return (F)(addr); 559 | } 560 | } 561 | } 562 | } while (e.next()); 563 | return {}; 564 | } 565 | 566 | template 567 | LAZY_IMPORTER_FORCEINLINE static F forwarded_safe() noexcept 568 | { 569 | return forwarded(); 570 | } 571 | 572 | template 573 | LAZY_IMPORTER_FORCEINLINE static F forwarded_cached() noexcept 574 | { 575 | auto& value = base_type::_cache(); 576 | if (!value) 577 | value = forwarded(); 578 | return (F)(value); 579 | } 580 | 581 | template 582 | LAZY_IMPORTER_FORCEINLINE static F forwarded_safe_cached() noexcept 583 | { 584 | return forwarded_cached(); 585 | } 586 | 587 | template 588 | LAZY_IMPORTER_FORCEINLINE static F in(Module m) noexcept 589 | { 590 | if (IsSafe && !m) 591 | return {}; 592 | 593 | const exports_directory exports((const char*)(m)); 594 | if (IsSafe && !exports) 595 | return {}; 596 | 597 | for (unsigned long i{};; ++i) { 598 | if (IsSafe && i == exports.size()) 599 | break; 600 | 601 | if (hash(exports.name(i)) == Hash) 602 | return (F)(exports.address(i)); 603 | } 604 | return {}; 605 | } 606 | 607 | template 608 | LAZY_IMPORTER_FORCEINLINE static F in_safe(Module m) noexcept 609 | { 610 | return in(m); 611 | } 612 | 613 | template 614 | LAZY_IMPORTER_FORCEINLINE static F in_cached(Module m) noexcept 615 | { 616 | auto& value = base_type::_cache(); 617 | if (!value) 618 | value = in(m); 619 | return (F)(value); 620 | } 621 | 622 | template 623 | LAZY_IMPORTER_FORCEINLINE static F in_safe_cached(Module m) noexcept 624 | { 625 | return in_cached(m); 626 | } 627 | 628 | template 629 | LAZY_IMPORTER_FORCEINLINE static F nt() noexcept 630 | { 631 | return in(ldr_data_entry()->load_order_next()->DllBase); 632 | } 633 | 634 | template 635 | LAZY_IMPORTER_FORCEINLINE static F nt_safe() noexcept 636 | { 637 | return in_safe(ldr_data_entry()->load_order_next()->DllBase); 638 | } 639 | 640 | template 641 | LAZY_IMPORTER_FORCEINLINE static F nt_cached() noexcept 642 | { 643 | return in_cached(ldr_data_entry()->load_order_next()->DllBase); 644 | } 645 | 646 | template 647 | LAZY_IMPORTER_FORCEINLINE static F nt_safe_cached() noexcept 648 | { 649 | return in_safe_cached(ldr_data_entry()->load_order_next()->DllBase); 650 | } 651 | }; 652 | 653 | } 654 | } // namespace li::detail 655 | 656 | #endif // include guard -------------------------------------------------------------------------------- /loader/loader.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31911.196 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "loader", "loader.vcxproj", "{41D67ADD-DAC1-416D-B7D3-1569E7CC019B}" 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 | {41D67ADD-DAC1-416D-B7D3-1569E7CC019B}.Debug|x64.ActiveCfg = Debug|x64 17 | {41D67ADD-DAC1-416D-B7D3-1569E7CC019B}.Debug|x64.Build.0 = Debug|x64 18 | {41D67ADD-DAC1-416D-B7D3-1569E7CC019B}.Debug|x86.ActiveCfg = Debug|Win32 19 | {41D67ADD-DAC1-416D-B7D3-1569E7CC019B}.Debug|x86.Build.0 = Debug|Win32 20 | {41D67ADD-DAC1-416D-B7D3-1569E7CC019B}.Release|x64.ActiveCfg = Release|x64 21 | {41D67ADD-DAC1-416D-B7D3-1569E7CC019B}.Release|x64.Build.0 = Release|x64 22 | {41D67ADD-DAC1-416D-B7D3-1569E7CC019B}.Release|x86.ActiveCfg = Release|Win32 23 | {41D67ADD-DAC1-416D-B7D3-1569E7CC019B}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {F1D2CD31-51F4-496A-8922-8549EF59BB10} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /loader/loader.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 | {41d67add-dac1-416d-b7d3-1569e7cc019b} 25 | loader 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 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | ..\.\dxsdk\Include;..\.\imgui;..\.\imgui\backends;..\.\blackbone\src;$(IncludePath) 82 | ..\.\dxsdk\Lib\x64;$(LibraryPath) 83 | 84 | 85 | false 86 | ..\.\dxsdk\Include;..\.\imgui;..\.\imgui\backends;..\.\blackbone\src;$(IncludePath) 87 | ..\.\dxsdk\Lib\x64;$(LibraryPath) 88 | 89 | 90 | 91 | Level3 92 | true 93 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 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 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions);_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;_CRT_SECURE_NO_WARNINGS 122 | true 123 | stdcpp20 124 | 125 | 126 | Console 127 | true 128 | 129 | 130 | 131 | 132 | Level3 133 | true 134 | true 135 | true 136 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;_CRT_SECURE_NO_WARNINGS 137 | true 138 | stdcpp20 139 | 140 | 141 | Console 142 | true 143 | true 144 | true 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /loader/loader.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 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | -------------------------------------------------------------------------------- /loader/main.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crvvdev/free-loader/0373e4c5583117e71ca400c1015f5e368e85db56/loader/main.cpp -------------------------------------------------------------------------------- /loader/utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define XorStr(x) (x) 4 | 5 | namespace utils 6 | { 7 | static inline void Error( const char* fmt, ... ) 8 | { 9 | char szBuffer[ 1024 ] = { }; 10 | 11 | va_list va; 12 | va_start( va, fmt ); 13 | vsnprintf_s( szBuffer, sizeof( szBuffer ), fmt, va ); 14 | va_end( va ); 15 | 16 | MessageBoxA( GetForegroundWindow( ), szBuffer, NULL, MB_ICONERROR ); 17 | } 18 | 19 | static inline void TimeoutMsg( const char* fmt, ... ) 20 | { 21 | using MessageBoxTimeout_ = int( WINAPI* )( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, WORD wLanguageId, DWORD dwMilliseconds ); 22 | static MessageBoxTimeout_ MessageBoxTimeout = ( MessageBoxTimeout_ )::GetProcAddress( LoadLibraryA( "user32" ), "MessageBoxTimeoutA" ); 23 | 24 | char szBuffer[ 1024 ] = { }; 25 | 26 | va_list va; 27 | va_start( va, fmt ); 28 | vsnprintf_s( szBuffer, sizeof( szBuffer ), fmt, va ); 29 | va_end( va ); 30 | 31 | MessageBoxTimeout( GetForegroundWindow( ), szBuffer, NULL, MB_ICONERROR, 0, 5000 ); 32 | } 33 | } --------------------------------------------------------------------------------