From d2ca8de3e673dce1bb1a200167e4626ba5d22181 Mon Sep 17 00:00:00 2001 From: Paul Tarter Date: Fri, 17 Nov 2023 15:00:22 -0500 Subject: [PATCH] attempt to blackbox link in cpp through a static lib, backup file works --- .../FileDeleteRecordPluginDriver.cpp | 34 +-- .../FileDeleteRecordPluginDriver.vcxproj | 9 +- C/STrace.sln | 15 + C/STraceCLI/STraceCLI.cpp | 13 +- C/Utils/Utils.cpp | 280 ++++++++++++++++++ C/Utils/Utils.h | 5 + C/Utils/Utils.vcxproj | 168 +++++++++++ C/Utils/Utils.vcxproj.filters | 27 ++ 8 files changed, 520 insertions(+), 31 deletions(-) create mode 100644 C/Utils/Utils.cpp create mode 100644 C/Utils/Utils.h create mode 100644 C/Utils/Utils.vcxproj create mode 100644 C/Utils/Utils.vcxproj.filters diff --git a/C/FileDeleteRecordPluginDriver/FileDeleteRecordPluginDriver.cpp b/C/FileDeleteRecordPluginDriver/FileDeleteRecordPluginDriver.cpp index 7d6a789..efa9e53 100644 --- a/C/FileDeleteRecordPluginDriver/FileDeleteRecordPluginDriver.cpp +++ b/C/FileDeleteRecordPluginDriver/FileDeleteRecordPluginDriver.cpp @@ -3,9 +3,10 @@ #include "interface.h" -#include "utils.h" +#include "..\Utils\Utils.h" const unsigned long PLUGIN_POOL_TAG = 'LEDS'; +const wchar_t* backup_directory = L"\\??\\C:\\deleted"; #pragma warning(disable: 6011) PluginApis g_Apis; @@ -86,31 +87,6 @@ void PrintStackTrace(CallerInfo& callerinfo) { } } - - -OBJECT_NAME_INFORMATION* getFilePathFromHandle(HANDLE hFile) { - ULONG dwSize = 0; - OBJECT_NAME_INFORMATION* pObjectName = nullptr; - NTSTATUS status = ZwQueryObject(hFile, (OBJECT_INFORMATION_CLASS)1 /*ObjectNameInformation*/, pObjectName, 0, &dwSize); - if (dwSize) - { - pObjectName = (OBJECT_NAME_INFORMATION*)ExAllocatePoolWithTag(NonPagedPoolNx, dwSize, PLUGIN_POOL_TAG); - if (pObjectName) { - status = ZwQueryObject(hFile, (OBJECT_INFORMATION_CLASS)1 /*ObjectNameInformation*/, pObjectName, dwSize, &dwSize); - } - } - - if (status == STATUS_SUCCESS && pObjectName) { - return pObjectName; - } - - if (pObjectName) { - ExFreePoolWithTag(pObjectName, PLUGIN_POOL_TAG); - pObjectName = nullptr; - } - return nullptr; -} - extern "C" __declspec(dllexport) void StpCallbackEntry(ULONG64 pService, ULONG32 probeId, MachineState & ctx, CallerInfo & callerinfo) { //LOG_INFO("[ENTRY] %s[0x%x](%d) Id: %d Parameters: [%d]\r\n", callerinfo.processName, callerinfo.processId, callerinfo.isWow64 ? 32 : 64, pService, probeId, ctx.paramCount); @@ -129,9 +105,9 @@ extern "C" __declspec(dllexport) void StpCallbackEntry(ULONG64 pService, ULONG32 if (pFilePath) { LOG_INFO("File %wZ deleted\r\n", pFilePath->Name); - //backupFile((wchar_t*)backup_directory, pFilePath->Name, hFile); - //ExFreePoolWithTag(pFilePath, PLUGIN_POOL_TAG); - //pFilePath = nullptr; + backupFile((wchar_t*)backup_directory, pFilePath->Name, hFile); + ExFreePoolWithTag(pFilePath, PLUGIN_POOL_TAG); + pFilePath = nullptr; LOG_INFO("File Backup Complete\r\n"); } else { diff --git a/C/FileDeleteRecordPluginDriver/FileDeleteRecordPluginDriver.vcxproj b/C/FileDeleteRecordPluginDriver/FileDeleteRecordPluginDriver.vcxproj index db436d8..82d35e1 100644 --- a/C/FileDeleteRecordPluginDriver/FileDeleteRecordPluginDriver.vcxproj +++ b/C/FileDeleteRecordPluginDriver/FileDeleteRecordPluginDriver.vcxproj @@ -92,10 +92,13 @@ false false stdcpp20 - _WIN64;_AMD64_;AMD64;ENABLE_LOG;%(PreprocessorDefinitions) + KERNEL_MODE;_WIN64;_AMD64_;AMD64;ENABLE_LOG;%(PreprocessorDefinitions) + false DriverEntry + %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;Utils.lib + $(outdir) @@ -107,9 +110,13 @@ false Default stdcpp20 + KERNEL_MODE;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions) + false DriverEntry + %(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;Utils.lib + $(outdir) diff --git a/C/STrace.sln b/C/STrace.sln index 4372585..e58276f 100644 --- a/C/STrace.sln +++ b/C/STrace.sln @@ -7,6 +7,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "STrace", "STrace\STrace.vcx ProjectSection(ProjectDependencies) = postProject {4349310C-30F9-48A9-9AE7-13D181F958B5} = {4349310C-30F9-48A9-9AE7-13D181F958B5} {C09F1082-CDCA-4320-AB91-CC3EAB12560C} = {C09F1082-CDCA-4320-AB91-CC3EAB12560C} + {D237889B-F553-478C-857A-A6BF4B883AE9} = {D237889B-F553-478C-857A-A6BF4B883AE9} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "STraceCLI", "STraceCLI\STraceCLI.vcxproj", "{4349310C-30F9-48A9-9AE7-13D181F958B5}" @@ -21,6 +22,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AddNewEtwEventPlugin", "Add EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FileDeleteRecordPluginDriver", "FileDeleteRecordPluginDriver\FileDeleteRecordPluginDriver.vcxproj", "{CD47158C-73E3-4197-AE90-92DC38D8BC0E}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Utils", "Utils\Utils.vcxproj", "{D237889B-F553-478C-857A-A6BF4B883AE9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -127,6 +130,18 @@ Global {CD47158C-73E3-4197-AE90-92DC38D8BC0E}.Release|x86.ActiveCfg = Release|x64 {CD47158C-73E3-4197-AE90-92DC38D8BC0E}.Release|x86.Build.0 = Release|x64 {CD47158C-73E3-4197-AE90-92DC38D8BC0E}.Release|x86.Deploy.0 = Release|x64 + {D237889B-F553-478C-857A-A6BF4B883AE9}.Debug|ARM64.ActiveCfg = Debug|x64 + {D237889B-F553-478C-857A-A6BF4B883AE9}.Debug|ARM64.Build.0 = Debug|x64 + {D237889B-F553-478C-857A-A6BF4B883AE9}.Debug|x64.ActiveCfg = Debug|x64 + {D237889B-F553-478C-857A-A6BF4B883AE9}.Debug|x64.Build.0 = Debug|x64 + {D237889B-F553-478C-857A-A6BF4B883AE9}.Debug|x86.ActiveCfg = Debug|Win32 + {D237889B-F553-478C-857A-A6BF4B883AE9}.Debug|x86.Build.0 = Debug|Win32 + {D237889B-F553-478C-857A-A6BF4B883AE9}.Release|ARM64.ActiveCfg = Release|x64 + {D237889B-F553-478C-857A-A6BF4B883AE9}.Release|ARM64.Build.0 = Release|x64 + {D237889B-F553-478C-857A-A6BF4B883AE9}.Release|x64.ActiveCfg = Release|x64 + {D237889B-F553-478C-857A-A6BF4B883AE9}.Release|x64.Build.0 = Release|x64 + {D237889B-F553-478C-857A-A6BF4B883AE9}.Release|x86.ActiveCfg = Release|Win32 + {D237889B-F553-478C-857A-A6BF4B883AE9}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/C/STraceCLI/STraceCLI.cpp b/C/STraceCLI/STraceCLI.cpp index e330253..5764fa5 100644 --- a/C/STraceCLI/STraceCLI.cpp +++ b/C/STraceCLI/STraceCLI.cpp @@ -10,6 +10,7 @@ #include HANDLE g_Driver; +SC_HANDLE g_Scm; std::filesystem::path AskForFile() { wchar_t szFileName[MAX_PATH] = { 0 }; @@ -99,11 +100,21 @@ int main() printf("[+] Opening driver\n"); g_Driver = CreateFileW(L"\\\\.\\STrace", GENERIC_ALL, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0); if (g_Driver == INVALID_HANDLE_VALUE) { - printf("[!] Handle open to driver failed\n"); + printf("[!] Handle open to driver failed: %d\n", GetLastError()); return 1; } printf("[+] Driver Opened Successfully\n"); + printf("[+] Opening Service Manager\n"); + g_Scm = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (NULL == g_Scm) + { + printf("[!] OpenServiceManager failed with: %d\n", GetLastError()); + return 1; + } + printf("[+] Service Manager Opened Successfully\n"); + + while (true) { std::cout << "Input command: load, unload, exit" << std::endl; std::string input; diff --git a/C/Utils/Utils.cpp b/C/Utils/Utils.cpp new file mode 100644 index 0000000..6d8e997 --- /dev/null +++ b/C/Utils/Utils.cpp @@ -0,0 +1,280 @@ +#include "..\FileDeleteRecordPlugin\Interface.h" +#include "..\FileDeleteRecordPlugin\KernelApis.h" +#include "..\FileDeleteRecordPlugin\config.h" +#include "..\FileDeleteRecordPlugin\string.h" + +#include +#include +#include +#include + +#include "Utils.h" + +template +int string_printf(String& str, T printer, Args&&... args) { + char tmp[512] = { 0 }; + + int size = printer(tmp, sizeof(tmp), std::forward(args)...); + if (size < 0) { + return -1; + } + + str += (char*)tmp; + return size; +} + +using hash_t = std::uint64_t; + +consteval uint64_t fnv1a_imp(uint64_t h, const char* s) +{ + return (*s == 0) ? h : + fnv1a_imp((h ^ static_cast(*s)) * 1099511628211ull, s + 1); +} + +consteval uint64_t fnv1a(const char* s) +{ + return fnv1a_imp(14695981039346656037ull, s); +} + +// Abuse template instantion rules to generate a unique name for a given type. Each template is a unique function in C++. +// Then, convert that string to a numeric hash. Stable for the lifetime of the application, may change between compilations. +template +consteval uint64_t get_type_id() { + return fnv1a(__FUNCSIG__); +} + +// given a typedef, match the arg list and convert each arg to a typeid. Store results in an array. +template +struct arg_types {}; + +template +struct arg_types { + static constexpr std::array value = { get_type_id()... }; +}; + +// msvc doesn't implement a constructor for std::span from iterators. This does that... +template +constexpr auto make_span(It begin, It end) { + return std::span>>(&(*begin), std::distance(begin, end)); +} + +template +class FinalAction { +public: + FinalAction(Func f) :FinalActionFunc(std::move(f)) {} + ~FinalAction() + { + FinalActionFunc(); + } +private: + Func FinalActionFunc; + + /*Uses RAII to call a final function on destruction + C++ 11 version of java's finally (kindof)*/ +}; + +template +FinalAction finally(F f) { + return FinalAction(f); +} + +template +T FnCast(uint64_t fnToCast, T pFnCastTo) { + PH_UNUSED(pFnCastTo); + return (T)fnToCast; +} + +template +T FnCast(void* fnToCast, T pFnCastTo) { + PH_UNUSED(pFnCastTo); + return (T)fnToCast; +} + +// analog of dtrace_copyin. Given a pointer to a usermode structure, safely read that structure in. +// Dtrace returns a pointer to that result. We can be slightly nicer and give a copy of the value exactly. +template +std::remove_pointer_t readUserArg(T2 pUserAddress, PluginApis pApis) { + std::remove_pointer_t tmp = { 0 }; + pApis.pTraceAccessMemory(&tmp, (uint64_t)pUserAddress, sizeof(tmp), 1, TRUE); + return tmp; +} + +bool createFile(PUNICODE_STRING filePath, PHANDLE hFileOut) { + *hFileOut = INVALID_HANDLE_VALUE; + + OBJECT_ATTRIBUTES attrs = { 0 }; + InitializeObjectAttributes(&attrs, filePath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); + + IO_STATUS_BLOCK IoStatus; + NTSTATUS Status = ZwCreateFile(hFileOut, + FILE_WRITE_DATA | SYNCHRONIZE, + &attrs, + &IoStatus, + NULL, + FILE_ATTRIBUTE_SYSTEM, + FILE_SHARE_READ, + FILE_OPEN_IF, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, + NULL, + 0); + return Status == STATUS_SUCCESS; +} + +bool openFile(PUNICODE_STRING filePath, PHANDLE hFileOut) { + *hFileOut = INVALID_HANDLE_VALUE; + + OBJECT_ATTRIBUTES attrs = { 0 }; + InitializeObjectAttributes(&attrs, filePath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); + + IO_STATUS_BLOCK IoStatus; + NTSTATUS Status = ZwOpenFile(hFileOut, + FILE_READ_DATA | SYNCHRONIZE, + &attrs, + &IoStatus, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE + ); + return Status == STATUS_SUCCESS; +} + +// backupFileName must begin with a slash, or be a filepath with slashes +bool __stdcall backupFile(PWSTR backupDir, UNICODE_STRING backupFileName, HANDLE hFileSource) { + if (!backupFileName.Buffer || backupFileName.Length <= sizeof(wchar_t)) + return false; + + // scan backwards until first slash + PWCHAR fileName = backupFileName.Buffer + (backupFileName.Length - sizeof(wchar_t)); + size_t fileNameLen = 0; + while (*fileName != L'\\') { + fileName--; + fileNameLen++; + } + + UNICODE_STRING backupPath = { 0 }; + backupPath.Length = (USHORT)(wcslen(backupDir) * sizeof(wchar_t)); + backupPath.MaximumLength = (USHORT)(backupPath.Length + (fileNameLen * sizeof(wchar_t))); + backupPath.Buffer = (PWSTR)ExAllocatePoolWithTag(NonPagedPoolNx, backupPath.MaximumLength, POOL_TAG); + memcpy(backupPath.Buffer, backupDir, backupPath.Length); + + NTSTATUS status = RtlAppendUnicodeToString(&backupPath, fileName); + if (status != STATUS_SUCCESS) + return false; + + HANDLE hFileCopy = INVALID_HANDLE_VALUE; + auto close_handles = finally([&] { + if (hFileCopy != INVALID_HANDLE_VALUE) { + ZwClose(hFileCopy); + } + }); + + if (!createFile(&backupPath, &hFileCopy)) + return false; + + LARGE_INTEGER pos = { 0 }; + IO_STATUS_BLOCK iosb = { 0 }; + + LARGE_INTEGER pos_write = { 0 }; + IO_STATUS_BLOCK iosb_write = { 0 }; + + while (true) { + char pBuf[512] = { 0 }; + status = ZwReadFile( + hFileSource, + NULL, NULL, NULL, + &iosb, + pBuf, (ULONG)sizeof(pBuf), + &pos, + NULL + ); + + if (status == STATUS_END_OF_FILE) { + if (iosb.Information == 0) { + break; + } + } + + if (status != STATUS_SUCCESS) { + break; + } + + status = ZwWriteFile(hFileCopy, + NULL, NULL, NULL, + &iosb_write, + pBuf, (ULONG)sizeof(pBuf), + &pos_write, + NULL + ); + + if (iosb_write.Status != STATUS_SUCCESS) { + break; + } + + if (status != STATUS_SUCCESS) { + break; + } + + pos.QuadPart += iosb.Information; + pos_write.QuadPart += iosb_write.Information; + } + return true; +} + +VOID NTAPI FreeUnicodeString(PUNICODE_STRING UnicodeString, ULONG Tag) +{ + if (UnicodeString->Buffer) + { + ExFreePoolWithTag(UnicodeString->Buffer, Tag); + } +} + +NTSTATUS DuplicateUnicodeString(PCUNICODE_STRING SourceString, PUNICODE_STRING DestinationString, ULONG Tag) +{ + if (SourceString == NULL || DestinationString == NULL || + SourceString->Length > SourceString->MaximumLength || + (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL)) + { + return STATUS_INVALID_PARAMETER; + } + + if (SourceString->Length == 0) + { + DestinationString->Length = 0; + DestinationString->MaximumLength = 0; + DestinationString->Buffer = NULL; + } + else { + UINT DestMaxLength = SourceString->Length; + + DestinationString->Buffer = (PWSTR)ExAllocatePoolWithTag(NonPagedPoolNx, DestMaxLength, Tag); + if (DestinationString->Buffer == NULL) + return STATUS_NO_MEMORY; + + memcpy(DestinationString->Buffer, SourceString->Buffer, SourceString->Length); + DestinationString->Length = SourceString->Length; + DestinationString->MaximumLength = DestMaxLength; + } + return STATUS_SUCCESS; +} + +OBJECT_NAME_INFORMATION* __stdcall getFilePathFromHandle(HANDLE hFile) { + ULONG dwSize = 0; + OBJECT_NAME_INFORMATION* pObjectName = nullptr; + NTSTATUS status = ZwQueryObject(hFile, ObjectNameInformation, pObjectName, 0, &dwSize); + if (dwSize) + { + pObjectName = (OBJECT_NAME_INFORMATION*)ExAllocatePoolWithTag(NonPagedPoolNx, dwSize, POOL_TAG); + if (pObjectName) { + status = ZwQueryObject(hFile, ObjectNameInformation, pObjectName, dwSize, &dwSize); + } + } + + if (status == STATUS_SUCCESS && pObjectName) { + return pObjectName; + } + + if (pObjectName) { + ExFreePoolWithTag(pObjectName, POOL_TAG); + pObjectName = nullptr; + } + return nullptr; +} \ No newline at end of file diff --git a/C/Utils/Utils.h b/C/Utils/Utils.h new file mode 100644 index 0000000..8758ff3 --- /dev/null +++ b/C/Utils/Utils.h @@ -0,0 +1,5 @@ +#pragma once + + +extern "C" bool __stdcall backupFile(PWSTR backupDir, UNICODE_STRING backupFileName, HANDLE hFileSource); +extern "C" OBJECT_NAME_INFORMATION * __stdcall getFilePathFromHandle(HANDLE hFile); \ No newline at end of file diff --git a/C/Utils/Utils.vcxproj b/C/Utils/Utils.vcxproj new file mode 100644 index 0000000..2f2256d --- /dev/null +++ b/C/Utils/Utils.vcxproj @@ -0,0 +1,168 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {d237889b-f553-478c-857a-a6bf4b883ae9} + Utils + 10.0 + + + + StaticLibrary + true + v143 + Unicode + + + StaticLibrary + false + v143 + true + Unicode + + + StaticLibrary + true + v143 + Unicode + + + StaticLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Use + pch.h + + + + + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Use + pch.h + + + + + true + true + true + + + + + Level3 + false + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + NotUsing + pch.h + MultiThreadedDebug + false + stdcpp20 + ProgramDatabase + /kernel %(AdditionalOptions) + Default + false + + + + + true + + + true + + + + + Level3 + true + true + false + NDEBUG;_LIB;%(PreprocessorDefinitions) + true + NotUsing + pch.h + MultiThreaded + false + stdcpp20 + /kernel %(AdditionalOptions) + false + + + + + true + true + true + + + true + + + + + + + + + + + + \ No newline at end of file diff --git a/C/Utils/Utils.vcxproj.filters b/C/Utils/Utils.vcxproj.filters new file mode 100644 index 0000000..e53c4ac --- /dev/null +++ b/C/Utils/Utils.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file