mirror of
https://github.com/hasherezade/hollows_hunter.git
synced 2026-10-11 21:49:55 +00:00
[FEATURE] Added new parameter: report allowing to regulate what results are included in the report (Issue #21)
This commit is contained in:
+3
-2
@@ -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<std::mutex> lock(g_stdOutMutex);
|
||||
hhunter.summarizeScan(report);
|
||||
hhunter.summarizeScan(report, pesieve::SHOW_SUSPICIOUS);
|
||||
}
|
||||
else {
|
||||
hhunter.writeToLog(report);
|
||||
|
||||
+2
-1
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+43
-26
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
+27
-7
@@ -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<DWORD, pesieve::t_report> pidToReport;
|
||||
std::map<DWORD, std::wstring> pidToName;
|
||||
std::vector<DWORD> suspicious;
|
||||
|
||||
std::vector<DWORD> failed;
|
||||
friend class HHScanner;
|
||||
};
|
||||
|
||||
+8
-8
@@ -17,7 +17,7 @@
|
||||
#include <paramkit.h>
|
||||
#include <mutex>
|
||||
|
||||
#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<std::mutex> 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<std::mutex> 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;
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<EnumParam>(PARAM_IMP_REC, ps.imprec_mode);
|
||||
copyVal<EnumParam>(PARAM_OUT_FILTER, ps.out_filter);
|
||||
copyVal<EnumParam>(PARAM_RESULTS_FILTER, ps.results_filter);
|
||||
|
||||
fillStringParam(PARAM_MODULES_IGNORE, ps.modules_ignored);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
+1
-1
Submodule pe-sieve updated: 35bfd851c0...0fb38363bd
Reference in New Issue
Block a user