diff --git a/etw_listener.cpp b/etw_listener.cpp index 7f9bfce..7379406 100644 --- a/etw_listener.cpp +++ b/etw_listener.cpp @@ -208,9 +208,10 @@ void runHHinNewThread(t_hh_params args) HHScanReport* report = hhunter.scan(); if (report) { - if (!g_hh_args.quiet || report->countSuspicious()) { + // in this mode only suspicious will be reported + if (!g_hh_args.quiet || report->countReports(pesieve::SHOW_SUSPICIOUS)) { const std::lock_guard lock(g_stdOutMutex); - hhunter.summarizeScan(report); + hhunter.summarizeScan(report, pesieve::SHOW_SUSPICIOUS); } else { hhunter.writeToLog(report); diff --git a/hh_params.cpp b/hh_params.cpp index 7e7e749..6fe29f3 100644 --- a/hh_params.cpp +++ b/hh_params.cpp @@ -10,6 +10,7 @@ void hh_params::init() pesieve_args.quiet = true; pesieve_args.no_hooks = true; + pesieve_args.results_filter = pesieve::SHOW_SUSPICIOUS; suspend_suspicious = false; kill_suspicious = false; @@ -48,4 +49,4 @@ hh_params& hh_params::operator=(const hh_params& other) this->ignored_names_list = other.ignored_names_list; return *this; -} \ No newline at end of file +} diff --git a/hh_report.cpp b/hh_report.cpp index b49dd59..e95b309 100644 --- a/hh_report.cpp +++ b/hh_report.cpp @@ -15,44 +15,51 @@ std::cout.fill(' '); \ if (field_size) stream << std::setw(field_size) << ' '; \ stream << str; -bool is_suspicious_process(pesieve::t_report report) -{ - if (report.suspicious) { - return true; - } - return false; -} bool HHScanReport::appendReport(pesieve::t_report &scan_report, const std::wstring &img_name) { pidToReport[scan_report.pid] = scan_report; pidToName[scan_report.pid] = img_name; - if (is_suspicious_process(scan_report)) { + if (scan_report.suspicious) { this->suspicious.push_back(scan_report.pid); } + if (scan_report.errors == pesieve::ERROR_SCAN_FAILURE) { + this->failed.push_back(scan_report.pid); + } return true; } -size_t HHScanReport::reportsToString(std::wstringstream& stream, bool suspiciousOnly) +size_t HHScanReport::reportsToString(std::wstringstream& stream, const pesieve::t_results_filter rfilter) { size_t printed = 0; size_t counter = 0; - size_t scannedCount = pidToReport.size(); - if (suspiciousOnly) { - scannedCount = suspicious.size(); - } + size_t scannedCount = countReports(rfilter); + if (!scannedCount) { return printed; } + const size_t max_len = size_t(std::floor(std::log10(double(scannedCount))) + 1) % 100; for (auto itr = this->pidToReport.begin(); itr != pidToReport.end(); ++itr) { + bool isFailed = false; DWORD pid = itr->first; - if (suspiciousOnly) { - pesieve::t_report rep = itr->second; + pesieve::t_report rep = itr->second; + if ((rfilter & pesieve::SHOW_SUSPICIOUS) == 0) { if (!rep.suspicious) continue; } + if (rep.errors == pesieve::ERROR_SCAN_FAILURE) { + isFailed = true; + } + + if (isFailed && (rfilter & pesieve::SHOW_ERRORS) == 0) { + continue; // do not display failed + } stream << L"[" << std::setw(max_len) << counter++ << L"]: PID: " << std::dec << pid << L", "; - stream << L"Name: " << this->pidToName[pid] << L"\n"; + stream << L"Name: " << this->pidToName[pid]; + if (isFailed) { + stream << L" : FAILED"; + } + stream << L"\n"; printed++; } return printed; @@ -114,7 +121,7 @@ size_t HHScanReport::toJSON(std::wstringstream &stream, const t_hh_params ¶m OUT_PADDED(stream, level, L"{\n"); level++; //summary: - const size_t suspicious_count = countSuspicious(); + const size_t suspicious_count = countReports(pesieve::SHOW_SUSPICIOUS); size_t all_count = 0; OUT_PADDED(stream, level, L"\"scan_date_time\" : "); stream << std::dec << L"\"" << util::strtime(this->startTime) << L"\"" << L",\n"; @@ -123,7 +130,9 @@ size_t HHScanReport::toJSON(std::wstringstream &stream, const t_hh_params ¶m OUT_PADDED(stream, level, L"\"scan_time_ms\" : "); stream << std::dec << getScanTime() << L",\n"; OUT_PADDED(stream, level, L"\"scanned_count\" : "); - stream << std::dec << countTotal() << L",\n"; + stream << std::dec << countTotal(true) << L",\n"; + OUT_PADDED(stream, level, L"\"failed_count\" : "); + stream << std::dec << countReports(pesieve::SHOW_ERRORS) << L",\n"; OUT_PADDED(stream, level, L"\"suspicious_count\" : "); stream << std::dec << suspicious_count; if (suspicious_count > 0) { @@ -152,7 +161,7 @@ void print_scantime(STR_STREAM& stream, size_t timeInMs) } } -void HHScanReport::toString(std::wstringstream &stream, bool suspiciousOnly) +void HHScanReport::toString(std::wstringstream &stream, const pesieve::t_results_filter rfilter) { //summary: stream << L"--------" << std::endl; @@ -161,14 +170,22 @@ void HHScanReport::toString(std::wstringstream &stream, bool suspiciousOnly) stream << L"Finished scan in: "; print_scantime(stream, getScanTime()); stream << L"\n"; - stream << L"[*] Total scanned: " << std::dec << countTotal() << L"\n"; - if (!suspiciousOnly && countTotal() > 0) { + const size_t scannedCount = countReports(pesieve::SHOW_SUCCESSFUL_ONLY); + stream << L"[*] Total scanned: " << std::dec << scannedCount << L"\n"; + if ((rfilter & pesieve::SHOW_NOT_SUSPICIOUS) && scannedCount > 0) { stream << L"[+] List of scanned: \n"; - reportsToString(stream, false); + reportsToString(stream, pesieve::SHOW_SUCCESSFUL_ONLY); } - stream << L"[*] Total suspicious: " << std::dec << countSuspicious() << L"\n"; - if (countSuspicious() > 0) { - stream << L"[+] List of suspicious: \n"; - reportsToString(stream, true); + if (rfilter & pesieve::SHOW_SUSPICIOUS) { + const size_t count = countReports(pesieve::SHOW_SUSPICIOUS); + stream << L"[*] Total suspicious: " << std::dec << count << L"\n"; + if (count > 0) { + stream << L"[+] List of suspicious: \n"; + reportsToString(stream, pesieve::SHOW_SUSPICIOUS); + } + } + if (rfilter & pesieve::SHOW_ERRORS) { + const size_t count = countReports(pesieve::SHOW_ERRORS); + stream << L"[*] Total failed: " << std::dec << count << L"\n"; } } diff --git a/hh_report.h b/hh_report.h index c9b09b3..50abf5b 100644 --- a/hh_report.h +++ b/hh_report.h @@ -36,20 +36,40 @@ public: bool appendReport(pesieve::t_report &scan_report, const std::wstring &img_name); - size_t countSuspicious() const + size_t countReports(const pesieve::t_results_filter rfilter) const { - return suspicious.size(); + if (rfilter == pesieve::SHOW_NONE) { + return 0; + } + if (rfilter == pesieve::SHOW_ALL) { + return countTotal(false); + } + if (rfilter == pesieve::SHOW_SUCCESSFUL_ONLY) { + return countTotal(true); + } + size_t total = 0; + if (rfilter & pesieve::SHOW_ERRORS) { + total += failed.size(); + } + if (rfilter & pesieve::SHOW_SUSPICIOUS) { + total += suspicious.size(); + } + return total; } - size_t countTotal() const + size_t countTotal(bool successfulOnly = true) const { - return pidToReport.size(); + size_t total = pidToReport.size(); + if (successfulOnly) { + total -= failed.size(); + } + return total; } - void toString(std::wstringstream &stream, bool suspiciousOnly = true); + void toString(std::wstringstream &stream, const pesieve::t_results_filter rfilter); protected: - size_t reportsToString(std::wstringstream &stream, bool suspiciousOnly = true); + size_t reportsToString(std::wstringstream &stream, const pesieve::t_results_filter rfilter); size_t toJSON(std::wstringstream &stream, const t_hh_params ¶ms); size_t reportsToJSON(std::wstringstream &stream, size_t level, const t_hh_params ¶ms); @@ -63,6 +83,6 @@ protected: std::map pidToReport; std::map pidToName; std::vector suspicious; - + std::vector failed; friend class HHScanner; }; diff --git a/hh_scanner.cpp b/hh_scanner.cpp index 414b009..905a8f2 100644 --- a/hh_scanner.cpp +++ b/hh_scanner.cpp @@ -17,7 +17,7 @@ #include #include -#define PID_FIELD_SIZE 4 +#define PID_FIELD_SIZE 8 using namespace pesieve; @@ -309,8 +309,9 @@ t_single_scan_status HHScanner::scanNextProcess(DWORD pid, WCHAR* exe_file, HHSc } if (!hh_args.quiet) { const std::lock_guard stdOutLock(g_stdOutMutex); - std::cout << ">> Scanning PID: " << std::setw(PID_FIELD_SIZE) << std::dec << pid; - std::wcout << " : " << exe_file; + std::wcout << ">> Scanning PID: " + << std::setw(PID_FIELD_SIZE) << std::dec << pid + << " : " << exe_file; if (is_process_wow64) { std::cout << " : 32b"; @@ -350,22 +351,21 @@ bool HHScanner::writeToLog(HHScanReport* hh_report) return false; } - const bool suspiciousOnly = false; std::wstringstream stream; - hh_report->toString(stream, suspiciousOnly); + hh_report->toString(stream, pesieve::SHOW_ALL); static std::mutex logMutx; const std::lock_guard lock(logMutx); return files_util::write_to_file("hollows_hunter.log", stream.str(), true); } -void HHScanner::summarizeScan(HHScanReport *hh_report, bool suspiciousOnly) +void HHScanner::summarizeScan(HHScanReport *hh_report, const pesieve::t_results_filter rfilter) { if (!hh_report) return; std::wstringstream summary_str; if (!this->hh_args.json_output) { - hh_report->toString(summary_str, suspiciousOnly); + hh_report->toString(summary_str, rfilter); std::wcout << summary_str.rdbuf(); } else { @@ -375,7 +375,7 @@ void HHScanner::summarizeScan(HHScanReport *hh_report, bool suspiciousOnly) if (hh_args.pesieve_args.out_filter != OUT_NO_DIR) { //file the same report into the directory with dumps: - if (hh_report->suspicious.size()) { + if (hh_report->countReports(rfilter)) { std::string report_path = files_util::join_path(this->outDir, "summary.json"); static std::mutex summaryMutx; diff --git a/hh_scanner.h b/hh_scanner.h index 1e74b26..8d32756 100644 --- a/hh_scanner.h +++ b/hh_scanner.h @@ -31,7 +31,7 @@ public: HHScanReport* scan(); bool writeToLog(HHScanReport* hh_report); - void summarizeScan(HHScanReport *hh_report, bool suspiciousOnly = true); + void summarizeScan(HHScanReport* hh_report, const pesieve::t_results_filter rfilter); protected: void printScanRoundStats(size_t found, size_t ignored_count, size_t not_matched_count); diff --git a/main.cpp b/main.cpp index 1c03d70..0e88a0a 100644 --- a/main.cpp +++ b/main.cpp @@ -65,18 +65,18 @@ t_pesieve_res deploy_scan() else { HHScanner hhunter(g_hh_args); - do { - HHScanReport *report = hhunter.scan(); - if (report) { - hhunter.summarizeScan(report); - if (report->countSuspicious() > 0) { - scan_res = PESIEVE_DETECTED; + do { + HHScanReport *report = hhunter.scan(); + if (report) { + hhunter.summarizeScan(report, g_hh_args.pesieve_args.results_filter); + if (report->countReports(pesieve::SHOW_SUSPICIOUS) > 0) { + scan_res = PESIEVE_DETECTED; + } + delete report; + } + if (!HHScanner::isScannerCompatibile()) { + compatibility_alert(); } - delete report; - } - if (!HHScanner::isScannerCompatibile()) { - compatibility_alert(); - } } while (g_hh_args.loop_scanning); } return scan_res; diff --git a/params_info/params.h b/params_info/params.h index 90bbe3f..d844ece 100644 --- a/params_info/params.h +++ b/params_info/params.h @@ -39,6 +39,7 @@ using namespace pesieve; //output options: #define PARAM_QUIET "quiet" #define PARAM_OUT_FILTER "ofilter" +#define PARAM_RESULTS_FILTER "report" #define PARAM_SUSPEND "suspend" #define PARAM_KILL "kill" #define PARAM_UNIQUE_DIR "uniqd" @@ -169,6 +170,18 @@ public: } } + enumParam = new EnumParam(PARAM_RESULTS_FILTER, "result_type", false); + if (enumParam) { + this->addParam(enumParam); + this->setInfo(PARAM_RESULTS_FILTER, "Define what type of results are reported."); + for (size_t i = SHOW_SUSPICIOUS; i < SHOW_FILTERS_COUNT; i++) { + t_results_filter mode = (t_results_filter)(i); + std::string info = translate_results_filter(mode); + if (info.empty()) continue; + enumParam->addEnumValue(mode, results_filter_to_id(i), info); + } + } + this->addParam(new StringListParam(PARAM_MODULES_IGNORE, false, PARAM_LIST_SEPARATOR)); { std::stringstream ss1; @@ -289,6 +302,7 @@ public: this->addParamToGroup(PARAM_JSON, str_group); this->addParamToGroup(PARAM_JSON_LVL, str_group); this->addParamToGroup(PARAM_OUT_FILTER, str_group); + this->addParamToGroup(PARAM_RESULTS_FILTER, str_group); this->addParamToGroup(PARAM_LOG, str_group); this->addParamToGroup(PARAM_UNIQUE_DIR, str_group); @@ -464,6 +478,7 @@ protected: { copyVal(PARAM_IMP_REC, ps.imprec_mode); copyVal(PARAM_OUT_FILTER, ps.out_filter); + copyVal(PARAM_RESULTS_FILTER, ps.results_filter); fillStringParam(PARAM_MODULES_IGNORE, ps.modules_ignored); diff --git a/params_info/pe_sieve_params_info.cpp b/params_info/pe_sieve_params_info.cpp index efc5842..4c82d6e 100644 --- a/params_info/pe_sieve_params_info.cpp +++ b/params_info/pe_sieve_params_info.cpp @@ -14,7 +14,7 @@ std::string translate_dump_mode(const DWORD dump_mode) case pesieve::PE_DUMP_REALIGN: return "realigned raw (converted raw format to be the same as virtual)"; } - return "undefined"; + return ""; } std::string translate_out_filter(const pesieve::t_output_filter o_filter) @@ -27,7 +27,33 @@ std::string translate_out_filter(const pesieve::t_output_filter o_filter) case pesieve::OUT_NO_DIR: return "don't dump any files"; } - return "undefined"; + return ""; +} + +std::string translate_results_filter(const pesieve::t_results_filter r_filter) +{ + switch (r_filter) { + case pesieve::SHOW_SUSPICIOUS: + return "only suspicious (default)"; + case pesieve::SHOW_SUSPICIOUS_AND_ERRORS: + return "suspicious and errors"; + case pesieve::SHOW_ALL: + return "all scanned"; + } + return ""; +} + +std::string results_filter_to_id(const DWORD r_filter) +{ + switch (r_filter) { + case pesieve::SHOW_SUSPICIOUS: + return "S"; + case pesieve::SHOW_SUSPICIOUS_AND_ERRORS: + return "SE"; + case pesieve::SHOW_ALL: + return "L"; + } + return ""; } std::string translate_imprec_mode(const pesieve::t_imprec_mode imprec_mode) @@ -46,7 +72,7 @@ std::string translate_imprec_mode(const pesieve::t_imprec_mode imprec_mode) case pesieve::PE_IMPREC_REBUILD2: return "build the ImportTable from scratch, basing on the found IATs:\n\t use all found blocks (aggressive mode)"; } - return "undefined"; + return ""; } std::string translate_iat_scan_mode(const pesieve::t_iat_scan_mode mode) @@ -61,7 +87,7 @@ std::string translate_iat_scan_mode(const pesieve::t_iat_scan_mode mode) case pesieve::PE_IATS_UNFILTERED: return "unfiltered: scan for IAT Hooks, report all"; } - return "undefined"; + return ""; } std::string translate_dotnet_policy(const pesieve::t_dotnet_policy &mode) @@ -78,7 +104,7 @@ std::string translate_dotnet_policy(const pesieve::t_dotnet_policy &mode) case pesieve::PE_DNET_SKIP_ALL: return "skip all the above (mapping, shellcodes, hooks)"; } - return "undefined"; + return ""; } std::string translate_json_level(const pesieve::t_json_level &mode) @@ -91,10 +117,9 @@ std::string translate_json_level(const pesieve::t_json_level &mode) case pesieve::JSON_DETAILS2: return "details #2 (list patches: extended)"; } - return "undefined"; + return ""; } - std::string shellc_mode_mode_to_id(const pesieve::t_shellc_mode& mode) { switch (mode) { @@ -124,7 +149,7 @@ std::string translate_shellc_mode(const pesieve::t_shellc_mode& mode) case pesieve::SHELLC_PATTERNS_AND_STATS: return "detect shellcodes by patterns and stats (both match)"; } - return "undefined"; + return ""; } std::string translate_obfusc_mode(const pesieve::t_obfusc_mode& mode) @@ -139,7 +164,7 @@ std::string translate_obfusc_mode(const pesieve::t_obfusc_mode& mode) case pesieve::OBFUSC_ANY: return "detect any: possible strong or weak encryption"; } - return "undefined"; + return ""; } std::string obfusc_mode_mode_to_id(const pesieve::t_obfusc_mode& mode) @@ -171,7 +196,7 @@ std::string translate_data_mode(const pesieve::t_data_scan_mode& mode) case pesieve::PE_DATA_SCAN_INACCESSIBLE_ONLY: return "scan inaccessible pages, but exclude other non-executable;\n\t works in reflection mode (/refl) only"; } - return "undefined"; + return ""; } std::string dump_mode_to_id(const DWORD dump_mode) diff --git a/params_info/pe_sieve_params_info.h b/params_info/pe_sieve_params_info.h index e885418..7177ac3 100644 --- a/params_info/pe_sieve_params_info.h +++ b/params_info/pe_sieve_params_info.h @@ -5,6 +5,8 @@ std::string translate_dump_mode(const DWORD dump_mode); std::string translate_out_filter(const pesieve::t_output_filter o_filter); +std::string translate_results_filter(const pesieve::t_results_filter r_filter); +std::string results_filter_to_id(const DWORD r_filter); std::string translate_imprec_mode(const pesieve::t_imprec_mode imprec_mode); std::string translate_iat_scan_mode(const pesieve::t_iat_scan_mode mode); std::string translate_dotnet_policy(const pesieve::t_dotnet_policy &mode); diff --git a/pe-sieve b/pe-sieve index 35bfd85..0fb3836 160000 --- a/pe-sieve +++ b/pe-sieve @@ -1 +1 @@ -Subproject commit 35bfd851c0da1130cf831c4761f9ebaa9f0f4d83 +Subproject commit 0fb38363bd6109f561256dc48ca2ba12ac813653