/* ____________________________________________________________________________________________________ | _______ _____ __ _ _______ _______ _______ | | | | | | | | \ | |______ | |_____| | | | | | |_____| | \_| |______ | | | | |__________________________________________________________________________________________________| | Moneta ~ Usermode memory scanner & malware hunter | |--------------------------------------------------------------------------------------------------| | https://www.forrest-orr.net/post/masking-malicious-memory-artifacts-part-ii-insights-from-moneta | |--------------------------------------------------------------------------------------------------| | Author: Forrest Orr - 2020 | |--------------------------------------------------------------------------------------------------| | Contact: forrest.orr@protonmail.com | |--------------------------------------------------------------------------------------------------| | Licensed under GNU GPLv3 | |__________________________________________________________________________________________________| | ## Features | | | | ~ Query the memory attributes of any accessible process(es). | | ~ Identify private, mapped and image memory. | | ~ Correlate regions of memory to their underlying file on disks. | | ~ Identify PE headers and sections corresponding to image memory. | | ~ Identify modified regions of mapped image memory. | | ~ Identify abnormal memory attributes indicative of malware. | | ~ Create memory dumps of user-specified memory ranges | | ~ Calculate memory permission/type statistics | |__________________________________________________________________________________________________| */ #include "StdAfx.h" #include "Memory.hpp" #include "Interface.hpp" #include "Ioc.hpp" #include "Statistics.hpp" using namespace std; using namespace Memory; void PermissionRecord::UpdateMap(vector SubregionRecords) { for (vector::const_iterator RecordItr = SubregionRecords.begin(); RecordItr != SubregionRecords.end(); ++RecordItr) { if (!PermissionMap->count((*RecordItr)->GetBasic()->Type)) { PermissionMap->insert(make_pair((*RecordItr)->GetBasic()->Type, map())); } map& CountMap = PermissionMap->at((*RecordItr)->GetBasic()->Type); uint32_t PagePermissions[] = { PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY, PAGE_WRITECOPY, PAGE_EXECUTE, PAGE_NOACCESS }; for (uint32_t dwX = 0; dwX < (sizeof(PagePermissions) / sizeof(uint32_t)); dwX++) { if (!CountMap.count(PagePermissions[dwX])) { CountMap.insert(make_pair(PagePermissions[dwX], 0)); } if (((*RecordItr)->GetBasic()->Protect & PagePermissions[dwX])) { CountMap[PagePermissions[dwX]]++; this->TotalRegions++; } } } } PermissionRecord::PermissionRecord(vector SubregionRecords) : PermissionMap(new map>()) { UpdateMap(SubregionRecords); } void PermissionRecord::ShowRecords() const { Interface::Log(Interface::VerbosityLevel::Surface, "\r\nMemory statistics\r\n"); for (map>::const_iterator Itr = PermissionMap->begin(); Itr != PermissionMap->end(); ++Itr) { int32_t nTotalRegions = 0, nX = 0; for (map::const_iterator Itr2 = Itr->second.begin(); Itr2 != Itr->second.end(); ++Itr2) { nTotalRegions += Itr2->second; } Interface::Log(Interface::VerbosityLevel::Surface, " %ws [%d total]\r\n", Subregion::TypeSymbol(Itr->first), nTotalRegions); // Total regions for the current memory type only for (map::const_iterator Itr2 = Itr->second.begin(); Itr2 != Itr->second.end(); ++Itr2, nX++) { if (!nX) { Interface::Log(Interface::VerbosityLevel::Surface, " |__ "); } else { Interface::Log(Interface::VerbosityLevel::Surface, " | "); } switch (Itr2->first) { case PAGE_READONLY: Interface::Log(Interface::VerbosityLevel::Surface, "PAGE_READONLY: %d (%f%%)", Itr2->second, static_cast(Itr2->second) / nTotalRegions * 100.0); break; case PAGE_READWRITE: Interface::Log(Interface::VerbosityLevel::Surface, "PAGE_READWRITE: %d (%f%%)", Itr2->second, static_cast(Itr2->second) / nTotalRegions * 100.0); break; case PAGE_EXECUTE_READ: Interface::Log(Interface::VerbosityLevel::Surface, "PAGE_EXECUTE_READ: %d (%f%%)", Itr2->second, static_cast(Itr2->second) / nTotalRegions * 100.0); break; case PAGE_EXECUTE_READWRITE: Interface::Log(Interface::VerbosityLevel::Surface, "PAGE_EXECUTE_READWRITE: %d (%f%%)", Itr2->second, static_cast(Itr2->second) / nTotalRegions * 100.0); break; case PAGE_EXECUTE_WRITECOPY: Interface::Log(Interface::VerbosityLevel::Surface, "PAGE_EXECUTE_WRITECOPY: %d (%f%%)", Itr2->second, static_cast(Itr2->second) / nTotalRegions * 100.0); break; case PAGE_WRITECOPY: Interface::Log(Interface::VerbosityLevel::Surface, "PAGE_WRITECOPY: %d (%f%%)", Itr2->second, static_cast(Itr2->second) / nTotalRegions * 100.0); break; case PAGE_EXECUTE: Interface::Log(Interface::VerbosityLevel::Surface, "PAGE_EXECUTE: %d (%f%%)", Itr2->second, static_cast(Itr2->second) / nTotalRegions * 100.0); break; case PAGE_NOACCESS: Interface::Log(Interface::VerbosityLevel::Surface, "PAGE_NOACCESS: %d (%f%%)", Itr2->second, static_cast(Itr2->second) / nTotalRegions * 100.0); break; default: Interface::Log(Interface::VerbosityLevel::Surface, "0x%08x: %d (%f%%)", Itr2->first, Itr2->second, static_cast(Itr2->second) / nTotalRegions * 100.0); break; } Interface::Log(Interface::VerbosityLevel::Surface, "\r\n"); } } } void IocRecord::ShowRecords() const { if (this->TotalIoc) { int32_t nX = 0; Interface::Log(Interface::VerbosityLevel::Surface, "\r\IOC statistics [%d total]\r\n", this->TotalIoc); for (map::const_iterator Itr = this->RecordMap->begin(); Itr != this->RecordMap->end(); ++Itr, nX++) { if (!nX) { Interface::Log(Interface::VerbosityLevel::Surface, "|__ "); } else { Interface::Log(Interface::VerbosityLevel::Surface, " | "); } Interface::Log(Interface::VerbosityLevel::Surface, "%ws: %d (%f%%)\r\n", Ioc::GetDescription((Ioc::Type)Itr->first).c_str(), Itr->second, static_cast(Itr->second) / this->TotalIoc * 100.0); } } } void IocRecord::UpdateMap(vector* Records) { for (vector::const_iterator ListItr = Records->begin(); ListItr != Records->end(); ++ListItr) { if (!this->RecordMap->count((*ListItr)->GetType())) { this->RecordMap->insert(make_pair((*ListItr)->GetType(), 1)); } else { (*this->RecordMap)[(*ListItr)->GetType()]++; } this->TotalIoc++; } } IocRecord::IocRecord(vector* Records) : RecordMap(new map()) { this->UpdateMap(Records); }