PE-sieve
Scans all running processes. Recognizes and dumps a variety of potentially malicious implants (replaced/implanted PEs, shellcodes, hooks, in-memory patches).
Loading...
Searching...
No Matches
artefact_scanner.h
Go to the documentation of this file.
1#pragma once
2
3#include <windows.h>
4#include <psapi.h>
5#include <map>
6
7#include <peconv.h>
11#include "process_details.h"
12
13#define INVALID_OFFSET (-1)
14#define PE_NOT_FOUND 0
15
16namespace pesieve {
17
18 bool is_valid_file_hdr(BYTE *loadedData, size_t loadedSize, BYTE *hdr_ptr, DWORD charact);
19 bool is_valid_section(BYTE *loadedData, size_t loadedSize, BYTE *hdr_ptr, DWORD charact);
20
23 public:
24 static const size_t JSON_LEVEL = 1;
25
37
38 bool hasNtHdrs()
39 {
41 }
42
44 {
45 return (secHdrsOffset != INVALID_OFFSET);
46 }
47
48 ULONGLONG peImageBase()
49 {
51 return INVALID_OFFSET;
52 }
53 return this->peBaseOffset + this->regionStart;
54 }
55
56 ULONGLONG dropPeBase(const ULONGLONG offset_with_pe_base) const
57 {
58 if (peBaseOffset == INVALID_OFFSET || offset_with_pe_base == INVALID_OFFSET) {
59 return INVALID_OFFSET;
60 }
61 if (offset_with_pe_base < peBaseOffset) {
62 return INVALID_OFFSET;
63 }
64 return offset_with_pe_base - peBaseOffset;
65 }
66
67 const virtual bool fieldsToJSON(std::stringstream &outs, size_t level, const pesieve::t_json_level &jdetails)
68 {
69 OUT_PADDED(outs, level, "\"pe_base_offset\" : ");
70 outs << "\"" << std::hex << peBaseOffset << "\"";
71 if (hasNtHdrs()) {
72 outs << ",\n";
73 OUT_PADDED(outs, level, "\"nt_file_hdr\" : ");
74 outs << "\"" << std::hex << ntFileHdrsOffset << "\"";
75 }
76 outs << ",\n";
77 OUT_PADDED(outs, level, "\"sections_hdrs\" : ");
78 outs << "\"" << std::hex << secHdrsOffset << "\"";
79 outs << ",\n";
80 OUT_PADDED(outs, level, "\"sections_count\" : ");
81 outs << std::dec << secCount;
82 outs << ",\n";
83#ifdef _DEBUG
84 OUT_PADDED(outs, level, "\"calculated_image_size\" : ");
85 outs << std::hex << this->calculatedImgSize;
86 outs << ",\n";
87#endif
88 OUT_PADDED(outs, level, "\"is_dll\" : ");
89 outs << std::dec << isDll;
90 outs << ",\n";
91 OUT_PADDED(outs, level, "\"is_64_bit\" : ");
92 outs << std::dec << this->is64bit;
93 return true;
94 }
95
96 const virtual bool toJSON(std::stringstream &outs, size_t level, const pesieve::t_json_level &jdetails)
97 {
98 OUT_PADDED(outs, level, "\"pe_artefacts\" : {\n");
99 fieldsToJSON(outs, level + 1, jdetails);
100 outs << "\n";
101 OUT_PADDED(outs, level, "}");
102 return true;
103 }
104
105 LONGLONG regionStart;
106 size_t peBaseOffset; //offset from the regionStart (PE may not start at the first page of the region)
107 size_t ntFileHdrsOffset; //offset from the regionStart
108 size_t secHdrsOffset; //offset from the regionStart
109 size_t secCount;
112 bool isDll;
114 };
115
118 {
119 public:
120 ArtefactScanReport(HMODULE _module, size_t _moduleSize, t_scan_status status, PeArtefacts &peArt)
121 : WorkingSetScanReport(_module, _moduleSize, status),
122 artefacts(peArt),
123 initialRegionSize(_moduleSize)
124 {
125 is_executable = true;
126 protection = 0;
127 has_pe = true;
128 has_shellcode = false;
129
130 size_t total_region_size = peArt.calculatedImgSize + peArt.peBaseOffset;
131 if (total_region_size > this->moduleSize) {
132 this->moduleSize = total_region_size;
133 }
134 }
135
136 const virtual void fieldsToJSON(std::stringstream &outs, size_t level, const pesieve::t_json_level &jdetails)
137 {
138 WorkingSetScanReport::fieldsToJSON(outs, level, jdetails);
139 outs << ",\n";
140 artefacts.toJSON(outs, level, jdetails);
141 }
142
143 const virtual bool toJSON(std::stringstream &outs, size_t level, const pesieve::t_json_level &jdetails)
144 {
145 OUT_PADDED(outs, level, "\"workingset_scan\" : {\n");
146 fieldsToJSON(outs, level + 1, jdetails);
147 outs << "\n";
148 OUT_PADDED(outs, level, "}");
149 return true;
150 }
151
154 };
155
158 public:
159
160 static size_t calcImgSize(HANDLE processHandle, HMODULE modBaseAddr, BYTE* headerBuffer, size_t headerBufferSize, IMAGE_SECTION_HEADER *hdr_ptr = NULL);
161
162 ArtefactScanner(HANDLE _procHndl, const process_details _proc_details, MemPageData &_memPageData, ProcessScanReport& _process_report)
163 : ProcessFeatureScanner(_procHndl), pDetails(_proc_details),
164 processReport(_process_report), isProcess64bit(false),
165 memPage(_memPageData), prevMemPage(nullptr), artPagePtr(nullptr)
166 {
167 isProcess64bit = pesieve::util::is_process_64bit(this->processHandle);
168 }
169
171 {
173 }
174
176
177 protected:
179 {
180 public:
181 ArtefactsMapping(MemPageData &_memPage, bool _is64bit) :
182 memPage(_memPage)
183 {
185 dos_hdr = nullptr;
186 nt_file_hdr = nullptr;
187 sec_hdr = nullptr;
188 isMzPeFound = false;
189 sec_count = 0;
190 is64bit = _is64bit;
191 }
192
193 bool foundAny()
194 {
195 if (sec_hdr || nt_file_hdr) {
196 return true;
197 }
198 return false;
199 }
200
201 size_t getScore() const
202 {
203 size_t score = 0;
204 if (sec_hdr) {
205 score++;
206 if (sec_count > 1) score += 2;
207 }
208 if (nt_file_hdr) score += 2;
209 if (dos_hdr) score++;
210 return score;
211 }
212
213 bool operator < (const ArtefactsMapping& map2) const {
214 return getScore() < map2.getScore();
215 }
216
218 this->pe_image_base = other.pe_image_base;
219 this->dos_hdr = other.dos_hdr;
220 this->nt_file_hdr = other.nt_file_hdr;
221 this->sec_hdr = other.sec_hdr;
222 this->sec_count = other.sec_count;
223 this->isMzPeFound = other.isMzPeFound;
224 this->is64bit = other.is64bit;
225 return *this;
226 }
227
229 ULONGLONG pe_image_base;
230 IMAGE_DOS_HEADER *dos_hdr;
231 IMAGE_FILE_HEADER* nt_file_hdr;
232 IMAGE_SECTION_HEADER* sec_hdr;
233 size_t sec_count;
236 };
237
239 {
240 delete this->prevMemPage;
241 this->prevMemPage = nullptr;
242 this->artPagePtr = nullptr;
243 }
244
245 bool hasShellcode(HMODULE region_start, size_t region_size, PeArtefacts &peArt);
246
247 bool findMzPe(ArtefactsMapping &mapping, const size_t search_offset);
248 bool setMzPe(ArtefactsMapping &mapping, IMAGE_DOS_HEADER* _dos_hdr);
249 bool setSecHdr(ArtefactsMapping &mapping, IMAGE_SECTION_HEADER* _sec_hdr);
250 bool setNtFileHdr(ArtefactScanner::ArtefactsMapping &aMap, IMAGE_FILE_HEADER* _nt_hdr);
251 PeArtefacts *generateArtefacts(ArtefactsMapping &aMap);
252
253 PeArtefacts* findArtefacts(MemPageData &memPage, size_t start_offset);
254 PeArtefacts* findInPrevPages(ULONGLONG addr_start, ULONGLONG addr_stop);
255
256 ULONGLONG _findMZoffset(MemPageData &memPage, LPVOID hdr_ptr);
257 ULONGLONG calcPeBase(MemPageData &memPage, LPVOID hdr_ptr);
258 size_t calcImageSize(MemPageData &memPage, IMAGE_SECTION_HEADER *hdr_ptr, ULONGLONG pe_image_base);
259
260 IMAGE_FILE_HEADER* findNtFileHdr(MemPageData &memPage, const size_t start_offset, size_t stop_offset = INVALID_OFFSET);
261
262 bool _validateSecRegions(MemPageData &memPage, LPVOID sec_hdr, size_t sec_count, ULONGLONG pe_image_base, bool is_virtual);
263 bool _validateSecRegions(MemPageData &memPage, LPVOID sec_hdr, size_t sec_count);
264 BYTE* _findSecByPatterns(BYTE *search_ptr, const size_t max_search_size);
265 IMAGE_SECTION_HEADER* findSecByPatterns(MemPageData &memPageData, const size_t max_search_size, const size_t search_offset);
266
267 IMAGE_DOS_HEADER* findMzPeHeader(MemPageData &memPage, const size_t search_offset);
268 IMAGE_DOS_HEADER* _findDosHdrByPatterns(BYTE *search_ptr, const size_t max_search_size);
269 IMAGE_DOS_HEADER* findDosHdrByPatterns(MemPageData &memPage, const size_t start_offset, size_t stop_offset = INVALID_OFFSET);
270
273 MemPageData *artPagePtr; //pointer to the page where the artefacts were found: either to memPage or to prevMemPage
277 };
278
279}; //namespace pe-sieve
#define INVALID_OFFSET
#define PE_NOT_FOUND
A report from the artefacts scan, generated by ArtefactScanner.
virtual const void fieldsToJSON(std::stringstream &outs, size_t level, const pesieve::t_json_level &jdetails)
ArtefactScanReport(HMODULE _module, size_t _moduleSize, t_scan_status status, PeArtefacts &peArt)
virtual const bool toJSON(std::stringstream &outs, size_t level, const pesieve::t_json_level &jdetails)
bool operator<(const ArtefactsMapping &map2) const
ArtefactsMapping & operator=(const ArtefactsMapping &other)
ArtefactsMapping(MemPageData &_memPage, bool _is64bit)
A scanner for detection of artefacts related to PE implants in the process workingset.
ProcessScanReport & processReport
virtual ArtefactScanReport * scanRemote()
bool hasShellcode(HMODULE region_start, size_t region_size, PeArtefacts &peArt)
size_t calcImageSize(MemPageData &memPage, IMAGE_SECTION_HEADER *hdr_ptr, ULONGLONG pe_image_base)
ULONGLONG _findMZoffset(MemPageData &memPage, LPVOID hdr_ptr)
ArtefactScanner(HANDLE _procHndl, const process_details _proc_details, MemPageData &_memPageData, ProcessScanReport &_process_report)
bool findMzPe(ArtefactsMapping &mapping, const size_t search_offset)
IMAGE_SECTION_HEADER * findSecByPatterns(MemPageData &memPageData, const size_t max_search_size, const size_t search_offset)
ULONGLONG calcPeBase(MemPageData &memPage, LPVOID hdr_ptr)
const process_details pDetails
bool setMzPe(ArtefactsMapping &mapping, IMAGE_DOS_HEADER *_dos_hdr)
bool setNtFileHdr(ArtefactScanner::ArtefactsMapping &aMap, IMAGE_FILE_HEADER *_nt_hdr)
IMAGE_DOS_HEADER * _findDosHdrByPatterns(BYTE *search_ptr, const size_t max_search_size)
bool setSecHdr(ArtefactsMapping &mapping, IMAGE_SECTION_HEADER *_sec_hdr)
bool _validateSecRegions(MemPageData &memPage, LPVOID sec_hdr, size_t sec_count, ULONGLONG pe_image_base, bool is_virtual)
IMAGE_FILE_HEADER * findNtFileHdr(MemPageData &memPage, const size_t start_offset, size_t stop_offset=INVALID_OFFSET)
PeArtefacts * findArtefacts(MemPageData &memPage, size_t start_offset)
IMAGE_DOS_HEADER * findDosHdrByPatterns(MemPageData &memPage, const size_t start_offset, size_t stop_offset=INVALID_OFFSET)
static size_t calcImgSize(HANDLE processHandle, HMODULE modBaseAddr, BYTE *headerBuffer, size_t headerBufferSize, IMAGE_SECTION_HEADER *hdr_ptr=NULL)
PeArtefacts * findInPrevPages(ULONGLONG addr_start, ULONGLONG addr_stop)
PeArtefacts * generateArtefacts(ArtefactsMapping &aMap)
IMAGE_DOS_HEADER * findMzPeHeader(MemPageData &memPage, const size_t search_offset)
BYTE * _findSecByPatterns(BYTE *search_ptr, const size_t max_search_size)
A report about the PE artefact detected in the workingset.
virtual const bool fieldsToJSON(std::stringstream &outs, size_t level, const pesieve::t_json_level &jdetails)
virtual const bool toJSON(std::stringstream &outs, size_t level, const pesieve::t_json_level &jdetails)
ULONGLONG dropPeBase(const ULONGLONG offset_with_pe_base) const
static const size_t JSON_LEVEL
A base class for all the scanners checking appropriate process' features.
The report aggregating the results of the performed scan.
Definition scan_report.h:19
A report from the working set scan, generated by WorkingSetScanner.
virtual const void fieldsToJSON(std::stringstream &outs, size_t level, const pesieve::t_json_level &jdetails)
#define OUT_PADDED(stream, field_size, str)
Definition format_util.h:12
bool is_process_64bit(IN HANDLE process)
bool is_valid_file_hdr(BYTE *loadedData, size_t loadedSize, BYTE *hdr_ptr, DWORD charact)
bool is_valid_section(BYTE *loadedData, size_t loadedSize, BYTE *hdr_ptr, DWORD charact)
enum pesieve::module_scan_status t_scan_status