├── .gitignore ├── LICENSE ├── MiniDumper.sln ├── MiniDumper ├── MemoryMgr.h ├── MiniDumper.rc ├── MiniDumper.vcxproj ├── MiniDumper.vcxproj.filters ├── dllmain.cpp └── resource.h └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | [Nn]ormal/ 14 | [Nn]ightly/ 15 | [Mm]aster/ 16 | output/ 17 | symbols/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # MSTest test Results 26 | [Tt]est[Rr]esult*/ 27 | [Bb]uild[Ll]og.* 28 | 29 | #NUNIT 30 | *.VisualState.xml 31 | TestResult.xml 32 | 33 | *.cso 34 | *_i.c 35 | *_p.c 36 | *_i.h 37 | *.ilk 38 | *.meta 39 | *.obj 40 | *.pch 41 | *.pdb 42 | *.pgc 43 | *.pgd 44 | *.rsp 45 | *.sbr 46 | *.tlb 47 | *.tli 48 | *.tlh 49 | *.tmp 50 | *.tmp_proj 51 | *.log 52 | *.vspscc 53 | *.vssscc 54 | .builds 55 | *.pidb 56 | *.svclog 57 | *.scc 58 | 59 | # Chutzpah Test files 60 | _Chutzpah* 61 | 62 | # Visual C++ cache files 63 | ipch/ 64 | .vs/ 65 | *.aps 66 | *.ncb 67 | *.opensdf 68 | *.sdf 69 | *.db 70 | *.opendb 71 | *.cachefile 72 | 73 | # Visual Studio profiler 74 | *.psess 75 | *.vsp 76 | *.vspx 77 | 78 | # TFS 2012 Local Workspace 79 | $tf/ 80 | 81 | # Guidance Automation Toolkit 82 | *.gpState 83 | 84 | # ReSharper is a .NET coding add-in 85 | _ReSharper*/ 86 | *.[Rr]e[Ss]harper 87 | *.DotSettings.user 88 | 89 | # JustCode is a .NET coding addin-in 90 | .JustCode 91 | 92 | # TeamCity is a build add-in 93 | _TeamCity* 94 | 95 | # DotCover is a Code Coverage Tool 96 | *.dotCover 97 | 98 | # NCrunch 99 | *.ncrunch* 100 | _NCrunch_* 101 | .*crunch*.local.xml 102 | 103 | # MightyMoose 104 | *.mm.* 105 | AutoTest.Net/ 106 | 107 | # Web workbench (sass) 108 | .sass-cache/ 109 | 110 | # Installshield output folder 111 | [Ee]xpress/ 112 | 113 | # DocProject is a documentation generator add-in 114 | DocProject/buildhelp/ 115 | DocProject/Help/*.HxT 116 | DocProject/Help/*.HxC 117 | DocProject/Help/*.hhc 118 | DocProject/Help/*.hhk 119 | DocProject/Help/*.hhp 120 | DocProject/Help/Html2 121 | DocProject/Help/html 122 | 123 | # Click-Once directory 124 | publish/ 125 | 126 | # Publish Web Output 127 | *.[Pp]ublish.xml 128 | *.azurePubxml 129 | 130 | # NuGet Packages Directory 131 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 132 | #packages/* 133 | ## TODO: If the tool you use requires repositories.config, also uncomment the next line 134 | #!packages/repositories.config 135 | 136 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 137 | # This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) 138 | !packages/build/ 139 | 140 | # Windows Azure Build Output 141 | csx/ 142 | *.build.csdef 143 | 144 | # Windows Store app package directory 145 | AppPackages/ 146 | 147 | # Others 148 | sql/ 149 | *.Cache 150 | ClientBin/ 151 | [Ss]tyle[Cc]op.* 152 | ~$* 153 | *~ 154 | *.dbmdl 155 | *.dbproj.schemaview 156 | *.pfx 157 | *.publishsettings 158 | node_modules/ 159 | 160 | # RIA/Silverlight projects 161 | Generated_Code/ 162 | 163 | # Backup & report files from converting an old project file to a newer 164 | # Visual Studio version. Backup files are not needed, because we have git ;-) 165 | _UpgradeReport_Files/ 166 | Backup*/ 167 | UpgradeLog*.XML 168 | UpgradeLog*.htm 169 | 170 | # SQL Server files 171 | App_Data/*.mdf 172 | App_Data/*.ldf 173 | 174 | # Business Intelligence projects 175 | *.rdl.data 176 | *.bim.layout 177 | *.bim_*.settings 178 | 179 | # Microsoft Fakes 180 | FakesAssemblies/ 181 | 182 | # ========================= 183 | # Windows detritus 184 | # ========================= 185 | 186 | # Windows image file caches 187 | Thumbs.db 188 | ehthumbs.db 189 | 190 | # Folder config file 191 | Desktop.ini 192 | 193 | # Recycle Bin used on file shares 194 | $RECYCLE.BIN/ 195 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Adrian Zdanowicz (Silent) 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 | -------------------------------------------------------------------------------- /MiniDumper.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 15 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MiniDumper", "MiniDumper\MiniDumper.vcxproj", "{D153FD38-5711-4CA4-872A-B12CE1046E7E}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {D153FD38-5711-4CA4-872A-B12CE1046E7E}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {D153FD38-5711-4CA4-872A-B12CE1046E7E}.Debug|Win32.Build.0 = Debug|Win32 14 | {D153FD38-5711-4CA4-872A-B12CE1046E7E}.Release|Win32.ActiveCfg = Release|Win32 15 | {D153FD38-5711-4CA4-872A-B12CE1046E7E}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /MiniDumper/MemoryMgr.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEMORYMGR 2 | #define __MEMORYMGR 3 | 4 | // Switches: 5 | // _MEMORY_NO_CRT - don't include anything "complex" like ScopedUnprotect or memset 6 | // _MEMORY_DECLS_ONLY - don't include anything but macroes 7 | 8 | #define WRAPPER __declspec(naked) 9 | #define DEPRECATED __declspec(deprecated) 10 | #define EAXJMP(a) { _asm mov eax, a _asm jmp eax } 11 | #define VARJMP(a) { _asm jmp a } 12 | #define WRAPARG(a) ((int)a) 13 | 14 | #define NOVMT __declspec(novtable) 15 | #define SETVMT(a) *((uintptr_t*)this) = (uintptr_t)a 16 | 17 | #ifndef _MEMORY_DECLS_ONLY 18 | 19 | #define WIN32_LEAN_AND_MEAN 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #ifndef _MEMORY_NO_CRT 26 | #include 27 | #include 28 | #endif 29 | 30 | enum 31 | { 32 | PATCH_CALL, 33 | PATCH_JUMP 34 | }; 35 | 36 | template 37 | inline AT DynBaseAddress(AT address) 38 | { 39 | return (ptrdiff_t)GetModuleHandle(nullptr) - 0x400000 + address; 40 | } 41 | 42 | namespace Memory 43 | { 44 | template 45 | inline void Patch(AT address, T value) 46 | {*(T*)address = value; } 47 | 48 | #ifndef _MEMORY_NO_CRT 49 | template 50 | inline void Patch(AT address, std::initializer_list list ) 51 | { 52 | uint8_t* const addr = (uint8_t*)address; 53 | std::copy( list.begin(), list.end(), stdext::make_checked_array_iterator(addr, list.size()) ); 54 | } 55 | #endif 56 | 57 | template 58 | inline void Nop(AT address, size_t count) 59 | #ifndef _MEMORY_NO_CRT 60 | { memset((void*)address, 0x90, count); } 61 | #else 62 | { do { 63 | *(uint8_t*)address++ = 0x90; 64 | } while ( --count != 0 ); } 65 | #endif 66 | 67 | template 68 | inline void WriteOffsetValue(AT address, Var var) 69 | { 70 | union member_cast 71 | { 72 | intptr_t addr; 73 | Var varPtr; 74 | } cast; 75 | static_assert( sizeof(cast.addr) == sizeof(cast.varPtr), "member_cast failure!" ); 76 | cast.varPtr = var; 77 | 78 | intptr_t dstAddr = (intptr_t)address; 79 | *(int32_t*)dstAddr = static_cast(cast.addr - dstAddr - 4); 80 | } 81 | 82 | template 83 | inline void ReadOffsetValue(AT address, Var& var) 84 | { 85 | union member_cast 86 | { 87 | intptr_t addr; 88 | Var varPtr; 89 | } cast; 90 | static_assert( sizeof(cast.addr) == sizeof(cast.varPtr), "member_cast failure!" ); 91 | 92 | intptr_t srcAddr = (intptr_t)address; 93 | cast.addr = srcAddr + 4 + *(int32_t*)srcAddr; 94 | var = cast.varPtr; 95 | } 96 | 97 | template 98 | inline void InjectHook(AT address, Func hook) 99 | { 100 | WriteOffsetValue( (intptr_t)address + 1, hook ); 101 | } 102 | 103 | template 104 | inline void InjectHook(AT address, Func hook, unsigned int nType) 105 | { 106 | *(uint8_t*)address = nType == PATCH_JUMP ? 0xE9 : 0xE8; 107 | InjectHook(address, hook); 108 | } 109 | 110 | template 111 | inline void ReadCall(AT address, Func& func) 112 | { 113 | ReadOffsetValue( (intptr_t)address+1, func ); 114 | } 115 | 116 | template 117 | inline void* ReadCallFrom(AT address, ptrdiff_t offset = 0) 118 | { 119 | uintptr_t addr; 120 | ReadCall( address, addr ); 121 | return reinterpret_cast( addr + offset ); 122 | } 123 | 124 | #ifndef _MEMORY_NO_CRT 125 | inline bool MemEquals(uintptr_t address, std::initializer_list val) 126 | { 127 | const uint8_t* mem = reinterpret_cast(address); 128 | return std::equal( val.begin(), val.end(), stdext::make_checked_array_iterator(mem, val.size()) ); 129 | } 130 | #endif 131 | 132 | template 133 | inline AT Verify(AT address, uintptr_t expected) 134 | { 135 | assert( uintptr_t(address) == expected ); 136 | return address; 137 | } 138 | 139 | namespace DynBase 140 | { 141 | template 142 | inline void Patch(AT address, T value) 143 | { 144 | Memory::Patch(DynBaseAddress(address), value); 145 | } 146 | 147 | #ifndef _MEMORY_NO_CRT 148 | template 149 | inline void Patch(AT address, std::initializer_list list ) 150 | { 151 | Memory::Patch(DynBaseAddress(address), std::move(list)); 152 | } 153 | #endif 154 | 155 | template 156 | inline void Nop(AT address, size_t count) 157 | { 158 | Memory::Nop(DynBaseAddress(address), count); 159 | } 160 | 161 | template 162 | inline void InjectHook(AT address, HT hook) 163 | { 164 | Memory::InjectHook(DynBaseAddress(address), hook); 165 | } 166 | 167 | template 168 | inline void InjectHook(AT address, HT hook, unsigned int nType) 169 | { 170 | Memory::InjectHook(DynBaseAddress(address), hook, nType); 171 | } 172 | 173 | template 174 | inline void ReadCall(AT address, Func& func) 175 | { 176 | Memory::ReadCall(DynBaseAddress(address), func); 177 | } 178 | 179 | template 180 | inline void* ReadCallFrom(AT address, ptrdiff_t offset = 0) 181 | { 182 | return Memory::ReadCallFrom(DynBaseAddress(address), offset); 183 | } 184 | 185 | #ifndef _MEMORY_NO_CRT 186 | inline bool MemEquals(uintptr_t address, std::initializer_list val) 187 | { 188 | return Memory::MemEquals(DynBaseAddress(address), std::move(val)); 189 | } 190 | 191 | template 192 | inline AT Verify(AT address, uintptr_t expected) 193 | { 194 | return Memory::Verify(address, DynBaseAddress(expected)); 195 | } 196 | #endif 197 | }; 198 | 199 | namespace VP 200 | { 201 | template 202 | inline void Patch(AT address, T value) 203 | { 204 | DWORD dwProtect[2]; 205 | VirtualProtect((void*)address, sizeof(T), PAGE_EXECUTE_READWRITE, &dwProtect[0]); 206 | Memory::Patch( address, value ); 207 | VirtualProtect((void*)address, sizeof(T), dwProtect[0], &dwProtect[1]); 208 | } 209 | 210 | #ifndef _MEMORY_NO_CRT 211 | template 212 | inline void Patch(AT address, std::initializer_list list ) 213 | { 214 | DWORD dwProtect[2]; 215 | VirtualProtect((void*)address, list.size(), PAGE_EXECUTE_READWRITE, &dwProtect[0]); 216 | Memory::Patch(address, std::move(list)); 217 | VirtualProtect((void*)address, list.size(), dwProtect[0], &dwProtect[1]); 218 | } 219 | #endif 220 | 221 | template 222 | inline void Nop(AT address, size_t count) 223 | { 224 | DWORD dwProtect[2]; 225 | VirtualProtect((void*)address, count, PAGE_EXECUTE_READWRITE, &dwProtect[0]); 226 | Memory::Nop( address, count ); 227 | VirtualProtect((void*)address, count, dwProtect[0], &dwProtect[1]); 228 | } 229 | 230 | template 231 | inline void InjectHook(AT address, HT hook) 232 | { 233 | DWORD dwProtect[2]; 234 | 235 | VirtualProtect((void*)((DWORD_PTR)address + 1), 4, PAGE_EXECUTE_READWRITE, &dwProtect[0]); 236 | Memory::InjectHook( address, hook ); 237 | VirtualProtect((void*)((DWORD_PTR)address + 1), 4, dwProtect[0], &dwProtect[1]); 238 | } 239 | 240 | template 241 | inline void InjectHook(AT address, HT hook, unsigned int nType) 242 | { 243 | DWORD dwProtect[2]; 244 | 245 | VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect[0]); 246 | Memory::InjectHook( address, hook, nType ); 247 | VirtualProtect((void*)address, 5, dwProtect[0], &dwProtect[1]); 248 | } 249 | 250 | template 251 | inline void ReadCall(AT address, Func& func) 252 | { 253 | Memory::ReadCall(address, func); 254 | } 255 | 256 | template 257 | inline void* ReadCallFrom(AT address, ptrdiff_t offset = 0) 258 | { 259 | return Memory::ReadCallFrom(address, offset); 260 | } 261 | 262 | #ifndef _MEMORY_NO_CRT 263 | inline bool MemEquals(uintptr_t address, std::initializer_list val) 264 | { 265 | return Memory::MemEquals(address, std::move(val)); 266 | } 267 | #endif 268 | 269 | template 270 | inline AT Verify(AT address, uintptr_t expected) 271 | { 272 | return Memory::Verify(address, expected); 273 | } 274 | 275 | namespace DynBase 276 | { 277 | template 278 | inline void Patch(AT address, T value) 279 | { 280 | VP::Patch(DynBaseAddress(address), value); 281 | } 282 | 283 | #ifndef _MEMORY_NO_CRT 284 | template 285 | inline void Patch(AT address, std::initializer_list list ) 286 | { 287 | VP::Patch(DynBaseAddress(address), std::move(list)); 288 | } 289 | #endif 290 | 291 | template 292 | inline void Nop(AT address, size_t count) 293 | { 294 | VP::Nop(DynBaseAddress(address), count); 295 | } 296 | 297 | template 298 | inline void InjectHook(AT address, HT hook) 299 | { 300 | VP::InjectHook(DynBaseAddress(address), hook); 301 | } 302 | 303 | template 304 | inline void InjectHook(AT address, HT hook, unsigned int nType) 305 | { 306 | VP::InjectHook(DynBaseAddress(address), hook, nType); 307 | } 308 | 309 | template 310 | inline void ReadCall(AT address, Func& func) 311 | { 312 | Memory::ReadCall(DynBaseAddress(address), func); 313 | } 314 | 315 | template 316 | inline void* ReadCallFrom(AT address, ptrdiff_t offset = 0) 317 | { 318 | Memory::ReadCallFrom(DynBaseAddress(address), offset); 319 | } 320 | 321 | #ifndef _MEMORY_NO_CRT 322 | inline bool MemEquals(uintptr_t address, std::initializer_list val) 323 | { 324 | return Memory::MemEquals(DynBaseAddress(address), std::move(val)); 325 | } 326 | #endif 327 | 328 | template 329 | inline AT Verify(AT address, uintptr_t expected) 330 | { 331 | return Memory::Verify(address, DynBaseAddress(expected)); 332 | } 333 | 334 | }; 335 | }; 336 | }; 337 | 338 | #ifndef _MEMORY_NO_CRT 339 | 340 | #include 341 | #include 342 | #include 343 | 344 | namespace ScopedUnprotect 345 | { 346 | class Unprotect 347 | { 348 | public: 349 | ~Unprotect() 350 | { 351 | for ( auto& it : m_queriedProtects ) 352 | { 353 | DWORD dwOldProtect; 354 | VirtualProtect( std::get<0>(it), std::get<1>(it), std::get<2>(it), &dwOldProtect ); 355 | } 356 | } 357 | 358 | protected: 359 | Unprotect() = default; 360 | 361 | void UnprotectRange( DWORD_PTR BaseAddress, SIZE_T Size ) 362 | { 363 | SIZE_T QueriedSize = 0; 364 | while ( QueriedSize < Size ) 365 | { 366 | MEMORY_BASIC_INFORMATION MemoryInf; 367 | DWORD dwOldProtect; 368 | 369 | VirtualQuery( (LPCVOID)(BaseAddress + QueriedSize), &MemoryInf, sizeof(MemoryInf) ); 370 | if ( MemoryInf.State == MEM_COMMIT && (MemoryInf.Type & MEM_IMAGE) != 0 && 371 | (MemoryInf.Protect & (PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY|PAGE_READWRITE|PAGE_WRITECOPY)) == 0 ) 372 | { 373 | const bool wasExecutable = (MemoryInf.Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ)) != 0; 374 | VirtualProtect( MemoryInf.BaseAddress, MemoryInf.RegionSize, wasExecutable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &dwOldProtect ); 375 | m_queriedProtects.emplace_front( MemoryInf.BaseAddress, MemoryInf.RegionSize, MemoryInf.Protect ); 376 | } 377 | QueriedSize += MemoryInf.RegionSize; 378 | } 379 | } 380 | 381 | private: 382 | std::forward_list< std::tuple< LPVOID, SIZE_T, DWORD > > m_queriedProtects; 383 | }; 384 | 385 | class Section : public Unprotect 386 | { 387 | public: 388 | Section( HINSTANCE hInstance, const char* name ) 389 | { 390 | PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)hInstance + ((PIMAGE_DOS_HEADER)hInstance)->e_lfanew); 391 | PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(ntHeader); 392 | 393 | DWORD_PTR VirtualAddress = DWORD_PTR(-1); 394 | SIZE_T VirtualSize = SIZE_T(-1); 395 | for ( SIZE_T i = 0, j = ntHeader->FileHeader.NumberOfSections; i < j; ++i, ++pSection ) 396 | { 397 | if ( strncmp( (const char*)pSection->Name, name, IMAGE_SIZEOF_SHORT_NAME ) == 0 ) 398 | { 399 | VirtualAddress = (DWORD_PTR)hInstance + pSection->VirtualAddress; 400 | VirtualSize = pSection->Misc.VirtualSize; 401 | m_locatedSection = true; 402 | break; 403 | } 404 | } 405 | 406 | if ( VirtualAddress == DWORD_PTR(-1) ) 407 | return; 408 | 409 | UnprotectRange( VirtualAddress, VirtualSize ); 410 | }; 411 | 412 | bool SectionLocated() const { return m_locatedSection; } 413 | 414 | private: 415 | bool m_locatedSection = false; 416 | }; 417 | 418 | class FullModule : public Unprotect 419 | { 420 | public: 421 | FullModule( HINSTANCE hInstance ) 422 | { 423 | PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)hInstance + ((PIMAGE_DOS_HEADER)hInstance)->e_lfanew); 424 | UnprotectRange( (DWORD_PTR)hInstance, ntHeader->OptionalHeader.SizeOfImage ); 425 | } 426 | }; 427 | 428 | inline std::unique_ptr UnprotectSectionOrFullModule( HINSTANCE hInstance, const char* name ) 429 | { 430 | std::unique_ptr
section = std::make_unique
( hInstance, name ); 431 | if ( !section->SectionLocated() ) 432 | { 433 | return std::make_unique( hInstance ); 434 | } 435 | return section; 436 | } 437 | }; 438 | 439 | #endif 440 | 441 | #endif 442 | 443 | #endif -------------------------------------------------------------------------------- /MiniDumper/MiniDumper.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CookiePLMonster/MiniDumper/a991b16a54bd231cd03875cfdf712b2aac34511f/MiniDumper/MiniDumper.rc -------------------------------------------------------------------------------- /MiniDumper/MiniDumper.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {D153FD38-5711-4CA4-872A-B12CE1046E7E} 15 | MiniDumper 16 | 17 | 18 | 19 | DynamicLibrary 20 | true 21 | Unicode 22 | v141_xp 23 | 24 | 25 | DynamicLibrary 26 | false 27 | true 28 | Unicode 29 | v141_xp 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | .asi 43 | 44 | 45 | .asi 46 | 47 | 48 | 49 | Level4 50 | Disabled 51 | MultiThreadedDebug 52 | /Zc:threadSafeInit- %(AdditionalOptions) 53 | 54 | 55 | true 56 | dbghelp.lib;%(AdditionalDependencies) 57 | Windows 58 | 59 | 60 | 61 | 62 | Level4 63 | MaxSpeed 64 | true 65 | true 66 | true 67 | MultiThreaded 68 | /Zc:threadSafeInit- %(AdditionalOptions) 69 | NDEBUG;%(PreprocessorDefinitions) 70 | 71 | 72 | false 73 | true 74 | true 75 | dbghelp.lib;%(AdditionalDependencies) 76 | Windows 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /MiniDumper/MiniDumper.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;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 | 23 | 24 | Header Files 25 | 26 | 27 | 28 | 29 | Resource Files 30 | 31 | 32 | -------------------------------------------------------------------------------- /MiniDumper/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include "MemoryMgr.h" 7 | 8 | #define INCLUDE_MESSAGEBOX 0 9 | 10 | LONG WINAPI CustomUnhandledExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo) 11 | { 12 | // step 1: write minidump 13 | #if INCLUDE_MESSAGEBOX 14 | wchar_t error[1024]; 15 | wchar_t errorCode[1024]; 16 | #endif 17 | wchar_t modulename[MAX_PATH]; 18 | wchar_t filename[MAX_PATH]; 19 | wchar_t timestamp[128]; 20 | __time64_t time; 21 | struct tm ltime; 22 | HANDLE hFile; 23 | HWND hWnd; 24 | 25 | const wchar_t* modulenameptr; 26 | if ( GetModuleFileNameW( GetModuleHandle(NULL), modulename, _countof(modulename)) != 0 ) 27 | { 28 | modulenameptr = wcsrchr(modulename, '\\') + 1; 29 | } 30 | else 31 | { 32 | modulenameptr = L"err.err"; 33 | } 34 | 35 | _time64(&time); 36 | _localtime64_s(<ime, &time); 37 | wcsftime(timestamp, _countof(timestamp), L"%Y%m%d%H%M%S", <ime); 38 | swprintf_s(filename, L"%s.%s.dmp", modulenameptr, timestamp); 39 | #if INCLUDE_MESSAGEBOX 40 | swprintf_s(error, L"A minidump has been written to %s.", filename); 41 | #endif 42 | 43 | //CreateDirectoryA("minidumps", NULL); 44 | hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 45 | 46 | if (hFile != INVALID_HANDLE_VALUE) 47 | { 48 | MINIDUMP_EXCEPTION_INFORMATION ex; 49 | memset(&ex, 0, sizeof(ex)); 50 | ex.ThreadId = GetCurrentThreadId(); 51 | ex.ExceptionPointers = ExceptionInfo; 52 | ex.ClientPointers = TRUE; 53 | 54 | if (FAILED(MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpWithDataSegs, &ex, NULL, NULL))) 55 | { 56 | #if INCLUDE_MESSAGEBOX 57 | swprintf_s(error, L"An error (0x%X) occurred during writing %s.", GetLastError(), filename); 58 | #endif 59 | } 60 | 61 | CloseHandle(hFile); 62 | } 63 | else 64 | { 65 | #if INCLUDE_MESSAGEBOX 66 | swprintf_s(error, L"An error (0x%X) occurred during creating %s.", GetLastError(), filename); 67 | #endif 68 | } 69 | 70 | // step 2: exit the application 71 | #if INCLUDE_MESSAGEBOX 72 | swprintf_s(errorCode, L"Fatal error (0x%08X) at 0x%08X.\n%s", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress, error); 73 | #endif 74 | ShowCursor(TRUE); 75 | hWnd = FindWindowW(0, L""); 76 | SetForegroundWindow(hWnd); 77 | #if INCLUDE_MESSAGEBOX 78 | ShowCursor(TRUE); 79 | MessageBoxW(NULL, errorCode, L"MiniDumper", MB_ICONERROR | MB_OK ); 80 | hWnd = FindWindowW(0, L""); 81 | SetForegroundWindow(hWnd); 82 | #endif 83 | 84 | return EXCEPTION_CONTINUE_SEARCH; 85 | } 86 | 87 | BOOL APIENTRY DllMain( HMODULE hModule, 88 | DWORD ul_reason_for_call, 89 | LPVOID lpReserved 90 | ) 91 | { 92 | if ( ul_reason_for_call == DLL_PROCESS_ATTACH ) 93 | { 94 | SetUnhandledExceptionFilter(CustomUnhandledExceptionFilter); 95 | 96 | // Now stub out CustomUnhandledExceptionFilter so NO ONE ELSE can set it! 97 | Memory::VP::Patch( &SetUnhandledExceptionFilter, { 0xC2, 0x04, 0x00 } ); 98 | } 99 | 100 | return TRUE; 101 | } -------------------------------------------------------------------------------- /MiniDumper/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by vbdec.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MiniDumper 2 | 3 | Generic in-process plugin for producing crash dumps from application crashes. 4 | 5 | This repository serves mainly as a source repository for [modupdater](https://github.com/ThirteenAG/modupdater), 6 | so MiniDumper can auto-update itself. 7 | --------------------------------------------------------------------------------