From 392263e32c96930a9d6c3690ddcd702ff19e0fc9 Mon Sep 17 00:00:00 2001 From: hasherezade Date: Sun, 8 Sep 2024 11:12:56 -0700 Subject: [PATCH 1/6] [FEATURE] In Thread Scanner: retrieve last called syscall --- CMakeLists.txt | 2 + pe_sieve.cpp | 2 + scanners/thread_scanner.cpp | 6 +++ utils/syscall_extractor.cpp | 101 ++++++++++++++++++++++++++++++++++++ utils/syscall_extractor.h | 38 ++++++++++++++ utils/threads_util.cpp | 24 +++++++-- utils/threads_util.h | 6 ++- 7 files changed, 175 insertions(+), 4 deletions(-) create mode 100644 utils/syscall_extractor.cpp create mode 100644 utils/syscall_extractor.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4722fd0ba..f90461fb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,6 +161,7 @@ set (utils_srcs utils/process_reflection.cpp utils/console_color.cpp utils/strings_util.cpp + utils/syscall_extractor.cpp ) set (utils_hdrs @@ -182,6 +183,7 @@ set (utils_hdrs utils/custom_mutex.h utils/custom_buffer.h utils/process_symbols.h + utils/syscall_extractor.h ) set (params_info_hdrs diff --git a/pe_sieve.cpp b/pe_sieve.cpp index 00fb1c9ed..17e285395 100644 --- a/pe_sieve.cpp +++ b/pe_sieve.cpp @@ -15,11 +15,13 @@ #include "color_scheme.h" #include "utils/artefacts_util.h" +#include "utils/syscall_extractor.h" using namespace pesieve; using namespace pesieve::util; pesieve::PatternMatcher g_Matcher; +pesieve::SyscallTable g_SyscallTable; namespace pesieve { void check_access_denied(DWORD processID) diff --git a/scanners/thread_scanner.cpp b/scanners/thread_scanner.cpp index 100c284d1..507d03649 100644 --- a/scanners/thread_scanner.cpp +++ b/scanners/thread_scanner.cpp @@ -5,6 +5,9 @@ #include "../utils/ntddk.h" #include "../stats/stats.h" #include "../utils/process_symbols.h" +#include "../utils/syscall_extractor.h" + +extern pesieve::SyscallTable g_SyscallTable; #define ENTROPY_TRESHOLD 3.0 //#define NO_ENTROPY_CHECK @@ -345,6 +348,9 @@ void pesieve::ThreadScanner::printThreadInfo(const pesieve::util::thread_info& t if (threadi.is_extended) { std::cout << std::hex << "\tSysStart: "; printResolvedAddr(threadi.ext.sys_start_addr); + if (threadi.last_syscall != INVALID_SYSCALL) { + std::cout << "\tLast Syscall: " << std::hex << threadi.last_syscall << " func: " << g_SyscallTable.getSyscallName(threadi.last_syscall) << std::endl; + } std::cout << "\tState: [" << ThreadScanReport::translate_thread_state(threadi.ext.state) << "]"; if (threadi.ext.state == Waiting) { std::cout << " Reason: [" << ThreadScanReport::translate_wait_reason(threadi.ext.wait_reason) << "] Time: " << threadi.ext.wait_time; diff --git a/utils/syscall_extractor.cpp b/utils/syscall_extractor.cpp new file mode 100644 index 000000000..c8a062100 --- /dev/null +++ b/utils/syscall_extractor.cpp @@ -0,0 +1,101 @@ +#include "syscall_extractor.h" + +#include +#include // include libPeConv header +#include +#include "process_util.h" + +namespace pesieve { + namespace util { + + bool isSyscallFunc(const std::string& funcName) + { + std::string prefix("Nt"); + if (funcName.size() < (prefix.size() + 1)) { + return false; + } + if (funcName.compare(0, prefix.size(), prefix) != 0) { + return false; + } + char afterPrefix = funcName.at(prefix.size()); + if (afterPrefix >= 'A' && afterPrefix <= 'Z') { + // the name of the function after the Nt prefix will start in uppercase, + // syscalls are in functions like: NtUserSetWindowLongPtr, but not: NtdllDefWindowProc_A + return true; + } + return false; + } + + size_t extract_syscalls(BYTE* pe_buf, size_t pe_size, std::map& syscallToName, size_t startID = 0) + { + std::vector names_list; + if (!peconv::get_exported_names(pe_buf, names_list)) { + return 0; + } + + std::map sys_functions; + for (auto itr = names_list.begin(); itr != names_list.end(); ++itr) { + std::string funcName = *itr; + if (isSyscallFunc(funcName)) { + ULONG_PTR va = (ULONG_PTR)peconv::get_exported_func(pe_buf, funcName.c_str()); + if (!va) continue; + + DWORD rva = DWORD(va - (ULONG_PTR)pe_buf); + sys_functions[rva] = funcName; + } + } + size_t id = startID; + for (auto itr = sys_functions.begin(); itr != sys_functions.end(); ++itr) { + std::string funcName = itr->second; + syscallToName[id++] = funcName; + } + return id; + } + + size_t extract_from_dll(IN const std::string& path, size_t startSyscallID, OUT std::map& syscallToName) + { + size_t bufsize = 0; + BYTE* buffer = peconv::load_pe_module(path.c_str(), bufsize, false, false); + + if (!buffer) { + std::cerr << "Failed to load the PE: " << path << "\n"; + return 0; + } + + size_t extracted_count = extract_syscalls(buffer, bufsize, syscallToName, startSyscallID); + peconv::free_pe_buffer(buffer); + + if (!extracted_count) { + std::cerr << "No syscalls extracted from: " << path << "\n"; + } + return extracted_count; + } + + }; //namespace util + +}; //namespace pesieve + +size_t pesieve::util::extract_syscall_table(OUT std::map& syscallToName) +{ + PVOID old_val = NULL; + pesieve::util::wow64_disable_fs_redirection(&old_val); + + std::stringstream outs; + size_t extracted_count = 0; + + char ntdll_path[MAX_PATH] = { 0 }; + ExpandEnvironmentStringsA("%SystemRoot%\\system32\\ntdll.dll", ntdll_path, MAX_PATH); + extracted_count += extract_from_dll(ntdll_path, 0, syscallToName); + + char win32u_path[MAX_PATH] = { 0 }; + ExpandEnvironmentStringsA("%SystemRoot%\\system32\\win32u.dll", win32u_path, MAX_PATH); + extracted_count += extract_from_dll(win32u_path, 0x1000, syscallToName); + + pesieve::util::wow64_revert_fs_redirection(&old_val); + + if (!extracted_count) { + std::cerr << "Failed to extract syscalls.\n"; + return 0; + } + return syscallToName.size(); +} diff --git a/utils/syscall_extractor.h b/utils/syscall_extractor.h new file mode 100644 index 000000000..6b131e107 --- /dev/null +++ b/utils/syscall_extractor.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include + +namespace pesieve { + namespace util { + size_t extract_syscall_table(OUT std::map& syscallToName); + }; //namespace util + + struct SyscallTable { + + SyscallTable() + { + util::extract_syscall_table(this->syscallToName); + std::cout << "Extracted syscalls: " << syscallToName.size() << "\n"; + } + + bool isReady() + { + return syscallToName.size() ? true : false; + } + + std::string getSyscallName(DWORD id) + { + auto itr = syscallToName.find(id); + if (itr != syscallToName.end()) { + return itr->second; + } + return ""; + } + + std::map syscallToName; + }; //struct SyscallTable + +}; // namespace pesieve diff --git a/utils/threads_util.cpp b/utils/threads_util.cpp index 1719a2fa2..53cb375b5 100644 --- a/utils/threads_util.cpp +++ b/utils/threads_util.cpp @@ -9,9 +9,18 @@ #include #endif + namespace pesieve { namespace util { + // Thread info structures: + typedef struct _THREAD_LAST_SYSCALL_INFORMATION + { + PVOID FirstArgument; + USHORT SystemCallNumber; + } THREAD_LAST_SYSCALL_INFORMATION, * PTHREAD_LAST_SYSCALL_INFORMATION; + + bool query_thread_details(IN DWORD tid, OUT pesieve::util::thread_info& info) { static auto mod = GetModuleHandleA("ntdll.dll"); @@ -20,10 +29,12 @@ namespace pesieve { static auto pNtQueryInformationThread = reinterpret_cast(GetProcAddress(mod, "NtQueryInformationThread")); if (!pNtQueryInformationThread) return false; - DWORD thAccess = THREAD_QUERY_INFORMATION; + const DWORD thAccess = THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT; HANDLE hThread = OpenThread(thAccess, 0, tid); - if (!hThread) return false; - + if (!hThread) { + hThread = OpenThread(THREAD_QUERY_INFORMATION, 0, tid); + if (!hThread) return false; + } bool isOk = false; ULONG returnedLen = 0; LPVOID startAddr = 0; @@ -33,6 +44,13 @@ namespace pesieve { info.start_addr = (ULONGLONG)startAddr; isOk = true; } + returnedLen = 0; + THREAD_LAST_SYSCALL_INFORMATION syscallInfo = { 0 }; + status = pNtQueryInformationThread(hThread, ThreadLastSystemCall, &syscallInfo, sizeof(syscallInfo), &returnedLen); + if (status == 0 && returnedLen == sizeof(syscallInfo)) { + info.last_syscall = syscallInfo.SystemCallNumber; + isOk = true; + } CloseHandle(hThread); return isOk; } diff --git a/utils/threads_util.h b/utils/threads_util.h index cbc0a1277..44ce86395 100644 --- a/utils/threads_util.h +++ b/utils/threads_util.h @@ -3,6 +3,8 @@ #include #include +#define INVALID_SYSCALL (-1) + namespace pesieve { namespace util { @@ -35,12 +37,13 @@ namespace pesieve { { DWORD tid; ULONGLONG start_addr; + DWORD last_syscall; bool is_extended; thread_info_ext ext; _thread_info(DWORD _tid = 0) : tid(_tid), - start_addr(0), + start_addr(0), last_syscall(INVALID_SYSCALL), is_extended(false) { } @@ -49,6 +52,7 @@ namespace pesieve { { this->tid = other.tid; this->start_addr = other.start_addr; + this->last_syscall = other.last_syscall; this->is_extended = other.is_extended; this->ext = other.ext; } From 1e26a55bab57308f13963191915df2dbc0457f0e Mon Sep 17 00:00:00 2001 From: hasherezade Date: Sun, 8 Sep 2024 11:50:07 -0700 Subject: [PATCH 2/6] [FEATURE] Compare last syscall with the callstack end --- scanners/thread_scanner.cpp | 19 ++++++++++++++++++- utils/process_symbols.h | 16 ++++++++++++++++ utils/syscall_extractor.h | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/scanners/thread_scanner.cpp b/scanners/thread_scanner.cpp index 507d03649..f58bbec5b 100644 --- a/scanners/thread_scanner.cpp +++ b/scanners/thread_scanner.cpp @@ -244,7 +244,24 @@ size_t pesieve::ThreadScanner::fillCallStackInfo(IN HANDLE hProcess, IN HANDLE h #ifdef _SHOW_THREAD_INFO std::cout << "\n=== TID " << std::dec << GetThreadId(hThread) << " ===\n"; #endif //_SHOW_THREAD_INFO - return analyzeCallStack(args.callStack, cDetails); + size_t analyzedCount = analyzeCallStack(args.callStack, cDetails); + + + if (this->info.last_syscall != INVALID_SYSCALL) { + std::string syscallFuncName = g_SyscallTable.getSyscallName(this->info.last_syscall); + + auto itr = args.callStack.begin(); + ULONGLONG lastCalled = *itr; + std::string lastFuncCalled = symbols ? symbols->funcNameFromAddr(lastCalled) : ""; + if (!g_SyscallTable.isSameSyscallFunc(syscallFuncName, lastFuncCalled)) { + std::cout << "#### " << syscallFuncName << " VS " << lastFuncCalled; + std::cout << " DIFFERENT"; + std::cout << std::endl; + } + + + } + return analyzedCount; } template diff --git a/utils/process_symbols.h b/utils/process_symbols.h index 594f81327..272c5e3b8 100644 --- a/utils/process_symbols.h +++ b/utils/process_symbols.h @@ -39,6 +39,22 @@ class ProcessSymbolsManager //--- + std::string funcNameFromAddr(const ULONG_PTR addr) + { + if (!isInit) return ""; + + CHAR buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME] = { 0 }; + PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + + DWORD64 Displacement = 0; + if (!SymFromAddr(hProcess, addr, &Displacement, pSymbol)) { + return ""; + } + return pSymbol->Name; + } + bool dumpSymbolInfo(const ULONG_PTR addr) { if (!isInit) return false; diff --git a/utils/syscall_extractor.h b/utils/syscall_extractor.h index 6b131e107..a67c4cafd 100644 --- a/utils/syscall_extractor.h +++ b/utils/syscall_extractor.h @@ -12,10 +12,42 @@ namespace pesieve { struct SyscallTable { + static bool isSameSyscallFunc(std::string func1, std::string func2) + { + if (func1 == func2) return true; + + std::string prefix1 = func1.substr(0, 2); + std::string prefix2 = func2.substr(0, 2); + + if ((prefix1 == "Zw" || prefix1 == "Nt") && (prefix2 == "Zw" || prefix2 == "Nt")) { + std::string body1 = func1.substr(2); + std::string body2 = func2.substr(2); + if (body1 == body2) { + return true; + } + if (body1.length() == body2.length()) { + return false; + } + // the difference may be in the suffix + std::string* smaller_ptr = body1.length() < body2.length() ? &body1 : &body2; + size_t smaller_size = smaller_ptr->length(); + if (body1.substr(0, smaller_size) == body2.substr(0, smaller_size)) { + std::string* bigger_ptr = body1.length() > body2.length() ? &body1 : &body2; + std::string suffix = bigger_ptr->substr(smaller_size); + if (suffix == "32") { + return true; + } + } + } + return false; + } + SyscallTable() { util::extract_syscall_table(this->syscallToName); +#ifdef _DEBUG std::cout << "Extracted syscalls: " << syscallToName.size() << "\n"; +#endif } bool isReady() From 388d1dd824682e27f92e5a8ae03bc38f4141d067 Mon Sep 17 00:00:00 2001 From: hasherezade Date: Sun, 8 Sep 2024 12:22:32 -0700 Subject: [PATCH 3/6] [WIP] Show discrepencies: thread stack vs syscall --- scanners/thread_scanner.cpp | 47 +++++++++++++++++++++++-------------- scanners/thread_scanner.h | 1 + 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/scanners/thread_scanner.cpp b/scanners/thread_scanner.cpp index f58bbec5b..e9a0f8358 100644 --- a/scanners/thread_scanner.cpp +++ b/scanners/thread_scanner.cpp @@ -156,6 +156,34 @@ std::string ThreadScanReport::translate_thread_state(DWORD thread_state) //--- +bool pesieve::ThreadScanner::checkCallStackIntegrity(IN const std::vector callStack) +{ + if (this->info.last_syscall == INVALID_SYSCALL || !symbols || !callStack.size()) { + return true; // skip the check + } + std::string syscallFuncName = g_SyscallTable.getSyscallName(this->info.last_syscall); + + ULONGLONG lastCalled = *callStack.begin(); + std::string lastFuncCalled = symbols->funcNameFromAddr(lastCalled); + + if (this->info.ext.wait_reason == Suspended && callStack.size() == 1 && lastFuncCalled == "RtlUserThreadStart" && this->info.last_syscall == 0) { + return true; //normal for suspended threads + } + if (g_SyscallTable.isSameSyscallFunc(syscallFuncName, lastFuncCalled)) return true; + + std::cout << "\n#### TID=" << std::dec <dumpSymbolInfo(next_return); + std::cout << "\t"; + printResolvedAddr(next_return); + } + std::cout << std::endl; + return false; +} + size_t pesieve::ThreadScanner::analyzeCallStack(IN const std::vector call_stack, IN OUT ctx_details& cDetails) { size_t processedCntr = 0; @@ -244,23 +272,8 @@ size_t pesieve::ThreadScanner::fillCallStackInfo(IN HANDLE hProcess, IN HANDLE h #ifdef _SHOW_THREAD_INFO std::cout << "\n=== TID " << std::dec << GetThreadId(hThread) << " ===\n"; #endif //_SHOW_THREAD_INFO - size_t analyzedCount = analyzeCallStack(args.callStack, cDetails); - - - if (this->info.last_syscall != INVALID_SYSCALL) { - std::string syscallFuncName = g_SyscallTable.getSyscallName(this->info.last_syscall); - - auto itr = args.callStack.begin(); - ULONGLONG lastCalled = *itr; - std::string lastFuncCalled = symbols ? symbols->funcNameFromAddr(lastCalled) : ""; - if (!g_SyscallTable.isSameSyscallFunc(syscallFuncName, lastFuncCalled)) { - std::cout << "#### " << syscallFuncName << " VS " << lastFuncCalled; - std::cout << " DIFFERENT"; - std::cout << std::endl; - } - - - } + const size_t analyzedCount = analyzeCallStack(args.callStack, cDetails); + checkCallStackIntegrity(args.callStack); return analyzedCount; } diff --git a/scanners/thread_scanner.h b/scanners/thread_scanner.h index 7dfc1cfc8..d70facb31 100644 --- a/scanners/thread_scanner.h +++ b/scanners/thread_scanner.h @@ -143,6 +143,7 @@ namespace pesieve { bool fetchThreadCtxDetails(IN HANDLE hProcess, IN HANDLE hThread, OUT ctx_details& c); size_t fillCallStackInfo(IN HANDLE hProcess, IN HANDLE hThread, IN LPVOID ctx, IN OUT ctx_details& cDetails); size_t analyzeCallStack(IN const std::vector stack_frame, IN OUT ctx_details& cDetails); + bool checkCallStackIntegrity(IN const std::vector stack_frame); bool fillAreaStats(ThreadScanReport* my_report); bool reportSuspiciousAddr(ThreadScanReport* my_report, ULONGLONG susp_addr); From 7173a46b695c13305dfe38a3f562c7f5b33ab528 Mon Sep 17 00:00:00 2001 From: hasherezade Date: Sun, 8 Sep 2024 14:39:28 -0700 Subject: [PATCH 4/6] [FEATURE] Check and report thread return address integrity --- scanners/thread_scanner.cpp | 70 ++++++++++++++++++++++++------------- scanners/thread_scanner.h | 6 ++-- stats/entropy_stats.h | 4 +-- 3 files changed, 51 insertions(+), 29 deletions(-) diff --git a/scanners/thread_scanner.cpp b/scanners/thread_scanner.cpp index e9a0f8358..44f503aa2 100644 --- a/scanners/thread_scanner.cpp +++ b/scanners/thread_scanner.cpp @@ -53,6 +53,19 @@ namespace pesieve { } }; +bool get_page_details(HANDLE processHandle, LPVOID start_va, MEMORY_BASIC_INFORMATION& page_info) +{ + size_t page_info_size = sizeof(MEMORY_BASIC_INFORMATION); + const SIZE_T out = VirtualQueryEx(processHandle, (LPCVOID)start_va, &page_info, page_info_size); + const bool is_read = (out == page_info_size) ? true : false; + const DWORD error = is_read ? ERROR_SUCCESS : GetLastError(); + if (error != ERROR_SUCCESS) { + //nothing to read + return false; + } + return true; +} + DWORD WINAPI enum_stack_thread(LPVOID lpParam) { t_stack_enum_params* args = static_cast(lpParam); @@ -156,21 +169,26 @@ std::string ThreadScanReport::translate_thread_state(DWORD thread_state) //--- -bool pesieve::ThreadScanner::checkCallStackIntegrity(IN const std::vector callStack) +bool pesieve::ThreadScanner::checkReturnAddrIntegrity(IN const std::vector& callStack) { - if (this->info.last_syscall == INVALID_SYSCALL || !symbols || !callStack.size()) { + if (this->info.last_syscall == INVALID_SYSCALL || !symbols || !callStack.size() || !info.is_extended) { return true; // skip the check } - std::string syscallFuncName = g_SyscallTable.getSyscallName(this->info.last_syscall); + const std::string syscallFuncName = g_SyscallTable.getSyscallName(this->info.last_syscall); - ULONGLONG lastCalled = *callStack.begin(); - std::string lastFuncCalled = symbols->funcNameFromAddr(lastCalled); + const ULONGLONG lastCalled = *callStack.begin(); + const std::string lastFuncCalled = symbols->funcNameFromAddr(lastCalled); + if (SyscallTable::isSameSyscallFunc(syscallFuncName, lastFuncCalled)) { + return true; + } if (this->info.ext.wait_reason == Suspended && callStack.size() == 1 && lastFuncCalled == "RtlUserThreadStart" && this->info.last_syscall == 0) { return true; //normal for suspended threads } - if (g_SyscallTable.isSameSyscallFunc(syscallFuncName, lastFuncCalled)) return true; - + if (syscallFuncName == "NtCallbackReturn") { + const ScannedModule* mod = modulesInfo.findModuleContaining(lastCalled); + if (mod && mod->getModName() == "win32u.dll") return true; + } std::cout << "\n#### TID=" << std::dec <info.is_extended && info.ext.state == Waiting - && !cDetails.is_ret_in_frame) + const bool hasEmptyGUI = has_empty_gui_info(tid); + + if (this->info.is_extended && info.ext.state == Waiting && !cDetails.is_ret_in_frame) { const ULONGLONG ret_addr = cDetails.ret_on_stack; is_shc = isAddrInShellcode(ret_addr); @@ -530,11 +538,23 @@ bool pesieve::ThreadScanner::scanRemoteThreadCtx(HANDLE hThread, ThreadScanRepor } } - const bool hasEmptyGUI = has_empty_gui_info(tid); + // other indicators of stack being corrupt: + + bool isStackCorrupt = false; + + if (this->info.is_extended && !cDetails.is_managed && !cDetails.is_ret_as_syscall) + { + isStackCorrupt = true; + } + if (hasEmptyGUI && cDetails.stackFramesCount == 1 && this->info.is_extended && info.ext.state == Waiting && info.ext.wait_reason == UserRequest) { + isStackCorrupt = true; + } + + if (isStackCorrupt) { my_report->thread_state = info.ext.state; my_report->thread_wait_reason = info.ext.wait_reason; my_report->thread_wait_time = info.ext.wait_time; diff --git a/scanners/thread_scanner.h b/scanners/thread_scanner.h index d70facb31..dda45dd4c 100644 --- a/scanners/thread_scanner.h +++ b/scanners/thread_scanner.h @@ -10,6 +10,7 @@ namespace pesieve { + //! A report from the thread scan, generated by ThreadScanner class ThreadScanReport : public ModuleScanReport { @@ -100,13 +101,14 @@ namespace pesieve { ULONGLONG rbp; ULONGLONG last_ret; // the last return address on the stack ULONGLONG ret_on_stack; // the last return address stored on the stack + bool is_ret_as_syscall; bool is_ret_in_frame; bool is_managed; // does it contain .NET modules size_t stackFramesCount; std::set shcCandidates; _ctx_details(bool _is64b = false, ULONGLONG _rip = 0, ULONGLONG _rsp = 0, ULONGLONG _rbp = 0, ULONGLONG _ret_addr = 0) - : is64b(_is64b), rip(_rip), rsp(_rsp), rbp(_rbp), last_ret(_ret_addr), ret_on_stack(0), is_ret_in_frame(false), + : is64b(_is64b), rip(_rip), rsp(_rsp), rbp(_rbp), last_ret(_ret_addr), ret_on_stack(0), is_ret_as_syscall(false), is_ret_in_frame(false), stackFramesCount(0), is_managed(false) { @@ -143,7 +145,7 @@ namespace pesieve { bool fetchThreadCtxDetails(IN HANDLE hProcess, IN HANDLE hThread, OUT ctx_details& c); size_t fillCallStackInfo(IN HANDLE hProcess, IN HANDLE hThread, IN LPVOID ctx, IN OUT ctx_details& cDetails); size_t analyzeCallStack(IN const std::vector stack_frame, IN OUT ctx_details& cDetails); - bool checkCallStackIntegrity(IN const std::vector stack_frame); + bool checkReturnAddrIntegrity(IN const std::vector& callStack); bool fillAreaStats(ThreadScanReport* my_report); bool reportSuspiciousAddr(ThreadScanReport* my_report, ULONGLONG susp_addr); diff --git a/stats/entropy_stats.h b/stats/entropy_stats.h index d8183a7c0..60ca58bab 100644 --- a/stats/entropy_stats.h +++ b/stats/entropy_stats.h @@ -32,11 +32,9 @@ namespace pesieve { entropy = stats::calcShannonEntropy(histogram, area_size); } - std::map histogram; double entropy; protected: - const virtual void fieldsToJSON(std::stringstream& outs, size_t level) { OUT_PADDED(outs, level, "\"area_start\" : "); @@ -49,6 +47,8 @@ namespace pesieve { outs << std::dec << entropy; } + std::map histogram; + friend class AreaStatsCalculator; }; // AreaStats From b2ac6afa6a4521502c567943b71f49f65790a8cc Mon Sep 17 00:00:00 2001 From: hasherezade Date: Sun, 8 Sep 2024 14:54:24 -0700 Subject: [PATCH 5/6] [FEATURE] Added one more exclusion case to the return integrity check --- scanners/thread_scanner.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scanners/thread_scanner.cpp b/scanners/thread_scanner.cpp index 44f503aa2..2f5760554 100644 --- a/scanners/thread_scanner.cpp +++ b/scanners/thread_scanner.cpp @@ -185,6 +185,11 @@ bool pesieve::ThreadScanner::checkReturnAddrIntegrity(IN const std::vectorinfo.ext.wait_reason == Suspended && callStack.size() == 1 && lastFuncCalled == "RtlUserThreadStart" && this->info.last_syscall == 0) { return true; //normal for suspended threads } + if (this->info.ext.wait_reason == UserRequest && syscallFuncName == "NtWaitForSingleObject") { + if (lastFuncCalled.rfind("NtQuery", 0) == 0 || lastFuncCalled.rfind("ZwQuery", 0) == 0) { + return true; + } + } if (syscallFuncName == "NtCallbackReturn") { const ScannedModule* mod = modulesInfo.findModuleContaining(lastCalled); if (mod && mod->getModName() == "win32u.dll") return true; From 5ac79e7ed82a9e3595a911d88a6eb2ef10606f76 Mon Sep 17 00:00:00 2001 From: hasherezade Date: Sun, 8 Sep 2024 15:05:02 -0700 Subject: [PATCH 6/6] [VERSION] 0.3.9.8 --- pe_sieve_ver_short.h | 4 ++-- scanners/thread_scanner.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pe_sieve_ver_short.h b/pe_sieve_ver_short.h index 6133a2639..3f97cf0df 100644 --- a/pe_sieve_ver_short.h +++ b/pe_sieve_ver_short.h @@ -3,6 +3,6 @@ #define PESIEVE_MAJOR_VERSION 0 #define PESIEVE_MINOR_VERSION 3 #define PESIEVE_MICRO_VERSION 9 -#define PESIEVE_PATCH_VERSION 7 +#define PESIEVE_PATCH_VERSION 8 -#define PESIEVE_VERSION_STR "0.3.9.7" +#define PESIEVE_VERSION_STR "0.3.9.8" diff --git a/scanners/thread_scanner.cpp b/scanners/thread_scanner.cpp index 2f5760554..41d7e6524 100644 --- a/scanners/thread_scanner.cpp +++ b/scanners/thread_scanner.cpp @@ -194,6 +194,7 @@ bool pesieve::ThreadScanner::checkReturnAddrIntegrity(IN const std::vectorgetModName() == "win32u.dll") return true; } +#ifdef _SHOW_THREAD_INFO std::cout << "\n#### TID=" << std::dec <