diff --git a/params_info/pe_sieve_params_info.cpp b/params_info/pe_sieve_params_info.cpp index d291ddf9..47e4b6b1 100644 --- a/params_info/pe_sieve_params_info.cpp +++ b/params_info/pe_sieve_params_info.cpp @@ -153,11 +153,11 @@ std::string pesieve::translate_json_level(const pesieve::t_json_level &mode) { switch (mode) { case pesieve::JSON_BASIC: - return "basic"; + return "basic (default)"; case pesieve::JSON_DETAILS: - return "details #1 (list patches)"; + return "details #1 (medium)"; case pesieve::JSON_DETAILS2: - return "details #2 (list patches: extended)"; + return "details #2 (verbose)"; } return ""; } diff --git a/scanners/thread_scanner.cpp b/scanners/thread_scanner.cpp index 797949ab..bd4e17b5 100644 --- a/scanners/thread_scanner.cpp +++ b/scanners/thread_scanner.cpp @@ -306,17 +306,16 @@ bool pesieve::ThreadScanner::checkReturnAddrIntegrity(IN const std::vector &call_stack, IN OUT ctx_details& cDetails, OUT IN std::set &shcCandidates) +size_t pesieve::ThreadScanner::_analyzeCallStack(IN OUT ctx_details& cDetails, OUT IN std::set &shcCandidates) { size_t processedCntr = 0; cDetails.is_managed = false; - cDetails.stackFramesCount = call_stack.size(); cDetails.is_ret_in_frame = false; #ifdef _SHOW_THREAD_INFO - std::cout << "\n" << "Stack frame Size: " << std::dec << call_stack.size() << "\n===\n"; + std::cout << "\n" << "Stack frame Size: " << std::dec << cDetails.callStack.size() << "\n===\n"; #endif //_SHOW_THREAD_INFO - for (auto itr = call_stack.rbegin(); itr != call_stack.rend() ;++itr, ++processedCntr) { + for (auto itr = cDetails.callStack.rbegin(); itr != cDetails.callStack.rend() ;++itr, ++processedCntr) { const ULONGLONG next_return = *itr; if (cDetails.ret_on_stack == next_return) { cDetails.is_ret_in_frame = true; @@ -362,6 +361,15 @@ size_t pesieve::ThreadScanner::_analyzeCallStack(IN const std::vector return processedCntr; } +size_t pesieve::ThreadScanner::analyzeCallStackInfo(IN OUT ThreadScanReport& my_report) +{ + const size_t analyzedCount = _analyzeCallStack(my_report.cDetails, my_report.shcCandidates); + if (!my_report.cDetails.is_managed) { + my_report.cDetails.is_ret_as_syscall = checkReturnAddrIntegrity(my_report.cDetails.callStack); + } + return analyzedCount; +} + size_t pesieve::ThreadScanner::fillCallStackInfo(IN HANDLE hProcess, IN HANDLE hThread, IN LPVOID ctx, IN OUT ThreadScanReport& my_report) { // do it in a new thread to prevent stucking... @@ -391,31 +399,22 @@ size_t pesieve::ThreadScanner::fillCallStackInfo(IN HANDLE hProcess, IN HANDLE h if (!args.is_ok) { return 0; } - my_report.callStack = args.callStack; + my_report.cDetails.callStack = args.callStack; return args.callStack.size(); } -size_t pesieve::ThreadScanner::analyzeCallStackInfo(IN OUT ThreadScanReport& my_report) -{ - const size_t analyzedCount = _analyzeCallStack(my_report.callStack, my_report.cDetails, my_report.shcCandidates); - if (!my_report.cDetails.is_managed) { - my_report.cDetails.is_ret_as_syscall = checkReturnAddrIntegrity(my_report.callStack); +namespace pesieve { + template + bool read_return_ptr(IN HANDLE hProcess, IN OUT ctx_details& cDetails) { + PTR_T ret_addr = 0; + cDetails.ret_on_stack = 0; + if (peconv::read_remote_memory(hProcess, (LPVOID)cDetails.rsp, (BYTE*)&ret_addr, sizeof(ret_addr)) == sizeof(ret_addr)) { + cDetails.ret_on_stack = (ULONGLONG)ret_addr; + return true; + } + return false; } - return analyzedCount; -} - -template -bool read_return_ptr(IN HANDLE hProcess, IN OUT ctx_details& cDetails) { - PTR_T ret_addr = 0; - cDetails.ret_on_stack = 0; - if (peconv::read_remote_memory(hProcess, (LPVOID)cDetails.rsp, (BYTE*)&ret_addr, sizeof(ret_addr)) == sizeof(ret_addr)) { - cDetails.ret_on_stack = (ULONGLONG)ret_addr; - return true; - } - return false; -} - - +}; //namespace pesieve bool pesieve::ThreadScanner::fetchThreadCtxDetails(IN HANDLE hProcess, IN HANDLE hThread, OUT ThreadScanReport& my_report) { @@ -610,14 +609,12 @@ bool pesieve::ThreadScanner::scanRemoteThreadCtx(HANDLE hThread, ThreadScanRepor my_report.status = SCAN_NOT_SUSPICIOUS; return false; } - if (!is_ok) { + if (!is_ok || !analyzeCallStackInfo(my_report)) { // could not fetch the thread context and information my_report.status = SCAN_ERROR; return false; } - analyzeCallStackInfo(my_report); - my_report.stack_ptr = cDetails.rsp; bool isModified = false; bool is_unnamed = !isAddrInNamedModule(cDetails.rip); @@ -692,7 +689,7 @@ bool pesieve::ThreadScanner::scanRemoteThreadCtx(HANDLE hThread, ThreadScanRepor } if (hasEmptyGUI && - cDetails.stackFramesCount == 1 + cDetails.callStack.size() == 1 && this->info.is_extended && info.ext.state == Waiting && info.ext.wait_reason == UserRequest) { my_report.indicators.insert(THI_SUS_CALLSTACK_CORRUPT); @@ -743,14 +740,14 @@ ThreadScanReport* pesieve::ThreadScanner::scanRemote() } } } - if (!should_scan_context(info)) { - return my_report; - } if (this->info.is_extended) { 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; } + if (!should_scan_context(info)) { + return my_report; + } // proceed with detailed checks: HANDLE hThread = OpenThread( THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | SYNCHRONIZE, diff --git a/scanners/thread_scanner.h b/scanners/thread_scanner.h index fc5c8784..f21aac06 100644 --- a/scanners/thread_scanner.h +++ b/scanners/thread_scanner.h @@ -7,6 +7,7 @@ #include "../utils/process_symbols.h" #include "../stats/stats.h" #include "../stats/entropy_stats.h" +#include namespace pesieve { @@ -46,11 +47,10 @@ namespace pesieve { bool is_ret_as_syscall; bool is_ret_in_frame; bool is_managed; // does it contain .NET modules - size_t stackFramesCount; + std::vector callStack; _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_as_syscall(false), is_ret_in_frame(false), - stackFramesCount(0), is_managed(false) { } @@ -87,6 +87,29 @@ namespace pesieve { { } + const virtual void callstackToJSON(std::stringstream& outs, size_t level, const pesieve::t_json_level& jdetails) + { + OUT_PADDED(outs, level, "\"stack_ptr\" : "); + outs << "\"" << std::hex << stack_ptr << "\""; + if (cDetails.callStack.size()) { + outs << ",\n"; + OUT_PADDED(outs, level, "\"frames_count\" : "); + outs << std::dec << cDetails.callStack.size(); + if (jdetails >= JSON_DETAILS) { + outs << ",\n"; + OUT_PADDED(outs, level, "\"frames\" : ["); + for (auto itr = cDetails.callStack.begin(); itr != cDetails.callStack.end(); ++itr) { + if (itr != cDetails.callStack.begin()) { + outs << ", "; + } + const ULONGLONG addr = *itr; + outs << "\"" << std::hex << addr << "\""; + } + outs << "]"; + } + } + } + const virtual void fieldsToJSON(std::stringstream &outs, size_t level, const pesieve::t_json_level &jdetails) { ModuleScanReport::_toJSON(outs, level); @@ -105,13 +128,10 @@ namespace pesieve { outs << "]"; if (stack_ptr) { outs << ",\n"; - OUT_PADDED(outs, level, "\"stack_ptr\" : "); - outs << "\"" << std::hex << stack_ptr << "\""; - } - if (callStack.size()) { - outs << ",\n"; - OUT_PADDED(outs, level, "\"frames_count\" : "); - outs << std::dec << callStack.size(); + OUT_PADDED(outs, level, "\"callstack\" : {\n"); + callstackToJSON(outs, level + 1, jdetails); + outs << "\n"; + OUT_PADDED(outs, level, "}"); } if (thread_state != THREAD_STATE_UNKNOWN) { outs << ",\n"; @@ -158,13 +178,11 @@ namespace pesieve { ULONGLONG susp_addr; DWORD protection; ULONGLONG stack_ptr; - //size_t frames_count; DWORD thread_state; DWORD thread_wait_reason; DWORD thread_wait_time; ctx_details cDetails; - std::vector callStack; std::set shcCandidates; std::set indicators; @@ -197,7 +215,7 @@ namespace pesieve { size_t fillCallStackInfo(IN HANDLE hProcess, IN HANDLE hThread, IN LPVOID ctx, IN OUT ThreadScanReport& my_report); size_t analyzeCallStackInfo(IN OUT ThreadScanReport& my_report); - size_t _analyzeCallStack(IN const std::vector& call_stack, IN OUT ctx_details& cDetails, OUT IN std::set& shcCandidates); + size_t _analyzeCallStack(IN OUT ctx_details& cDetails, OUT IN std::set& shcCandidates); bool checkReturnAddrIntegrity(IN const std::vector& callStack);