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
headers_scanner.cpp
Go to the documentation of this file.
1#include "headers_scanner.h"
2#include <peconv.h>
3
4using namespace pesieve;
5
7{
9 std::cerr << "[-] Module not initialized" << std::endl;
10 return nullptr;
11 }
13 std::cerr << "[-] Failed to read the module header" << std::endl;
14 return nullptr;
15 }
16
18
19 BYTE hdr_buffer1[peconv::MAX_HEADER_SIZE] = { 0 };
20 memcpy(hdr_buffer1, remoteModData.headerBuffer, peconv::MAX_HEADER_SIZE);
21 my_report->is64 = peconv::is64bit(hdr_buffer1);
22 my_report->isDotNetModule = moduleData.isDotNet();
23
24 size_t hdrs_size = peconv::get_hdrs_size(hdr_buffer1);
25 if (hdrs_size > peconv::MAX_HEADER_SIZE) {
26 hdrs_size = peconv::MAX_HEADER_SIZE;
27 }
28
29 BYTE hdr_buffer2[peconv::MAX_HEADER_SIZE] = { 0 };
31
32 // some .NET modules overwrite their own headers, so at this point they should be excluded from the comparison
33 const DWORD ep1 = peconv::get_entry_point_rva(hdr_buffer1);
34 const DWORD ep2 = peconv::get_entry_point_rva(hdr_buffer2);
35 if (ep1 != ep2) {
36 my_report->epModified = true;
37 }
38 const DWORD arch1 = peconv::get_nt_hdr_architecture(hdr_buffer1);
39 const DWORD arch2 = peconv::get_nt_hdr_architecture(hdr_buffer2);
40 if (arch1 != arch2) {
41 // this often happend in .NET modules
42 //if there is an architecture mismatch it may indicate that a different version of the app was loaded (possibly legit)
43 my_report->archMismatch = true;
44 }
45
46 //normalize before comparing:
47 peconv::update_image_base(hdr_buffer1, 0);
48 peconv::update_image_base(hdr_buffer2, 0);
49
50 zeroUnusedFields(hdr_buffer1, hdrs_size);
51 zeroUnusedFields(hdr_buffer2, hdrs_size);
52
53 //compare:
56 return my_report;
57 }
58 //modifications detected, now find more details:
59 my_report->dosHdrModified = isDosHdrModified(hdr_buffer1, hdr_buffer2, hdrs_size);
60 my_report->fileHdrModified = isFileHdrModified(hdr_buffer1, hdr_buffer2, hdrs_size);
61 my_report->ntHdrModified = isNtHdrModified(hdr_buffer1, hdr_buffer2, hdrs_size);
62 my_report->secHdrModified = isSecHdrModified(hdr_buffer1, hdr_buffer2, hdrs_size);
63
64 if (moduleData.isDotNet()) {
65 const bool dotNetFileHdrModif = isFileHdrModified(hdr_buffer1, hdr_buffer2, hdrs_size, my_report->archMismatch);
66#ifdef _DEBUG
67 std::cout << "[#] .NET module detected as SUSPICIOUS\n";
68#endif
69 if (!my_report->isHdrReplaced()
70 && !my_report->dosHdrModified
72 && (my_report->epModified || (my_report->archMismatch && my_report->ntHdrModified))
73 )
74 {
75 //.NET modules may overwrite some parts of their own headers
76#ifdef _DEBUG
77 std::cout << "[#] Filtered out modifications typical for .NET files, setting as not suspicious\n";
78#endif
80 return my_report;
81 }
82 }
83 my_report->status = SCAN_SUSPICIOUS;
84 return my_report;
85}
86
87bool pesieve::HeadersScanner::zeroUnusedFields(PBYTE hdr_buffer, size_t hdrs_size)
88{
89 bool is_modified = false;
90 const size_t section_num = peconv::get_sections_count(hdr_buffer, hdrs_size);
91
92 for (size_t i = 0; i < section_num; i++) {
93 PIMAGE_SECTION_HEADER sec_hdr = peconv::get_section_hdr(hdr_buffer, hdrs_size, i);
94 if (sec_hdr == nullptr) continue;
95
96 if (sec_hdr->SizeOfRawData == 0) {
97 sec_hdr->PointerToRawData = 0;
98 is_modified = true;
99 }
100 }
101 return is_modified;
102}
103
104bool pesieve::HeadersScanner::isDosHdrModified(const PBYTE hdr_buffer1, const PBYTE hdr_buffer2, const size_t hdrs_size)
105{
106 if (hdrs_size < sizeof(IMAGE_DOS_HEADER)) { //should never happen
107 return false;
108 }
111 if (memcmp(hdr1, hdr2, sizeof(IMAGE_DOS_HEADER)) != 0) {
112 return true;
113 }
114
115 LONG new_hdr = hdr2->e_lfanew;
116 if (memcmp(hdr1, hdr2, new_hdr) != 0) {
117 return true;
118 }
119 return false;
120}
121
122bool pesieve::HeadersScanner::isSecHdrModified(const PBYTE hdr_buffer1, const PBYTE hdr_buffer2, const size_t hdrs_size)
123{
124 size_t section_num1 = peconv::get_sections_count(hdr_buffer1, hdrs_size);
125 size_t section_num2 = peconv::get_sections_count(hdr_buffer2, hdrs_size);
126 if (section_num1 != section_num2) {
127 return true;
128 }
129
130 for (size_t i = 0; i < section_num1; i++) {
131 PIMAGE_SECTION_HEADER sec_hdr1 = peconv::get_section_hdr(hdr_buffer1, hdrs_size, i);
132 PIMAGE_SECTION_HEADER sec_hdr2 = peconv::get_section_hdr(hdr_buffer2, hdrs_size, i);
133 if (!sec_hdr1 && !sec_hdr2) {
134 continue;
135 }
136 else if (!sec_hdr1 || !sec_hdr2) {
137 return true; //modified
138 }
139
140 if (sec_hdr1->VirtualAddress != sec_hdr2->VirtualAddress) {
141 return true;
142 }
143 if (sec_hdr1->Misc.VirtualSize != sec_hdr2->Misc.VirtualSize) {
144 return true;
145 }
146 if (sec_hdr1->PointerToRawData != sec_hdr2->PointerToRawData) {
147 return true;
148 }
149 }
150 return false;
151}
152
153bool pesieve::HeadersScanner::isFileHdrModified(const PBYTE hdr_buffer1, const PBYTE hdr_buffer2, const size_t hdrs_size, bool mask_arch_mismatch)
154{
155 const IMAGE_FILE_HEADER *file_hdr1 = peconv::get_file_hdr(hdr_buffer1, hdrs_size);
156 const IMAGE_FILE_HEADER *file_hdr2 = peconv::get_file_hdr(hdr_buffer2, hdrs_size);
157
158 if (!file_hdr1 && !file_hdr2) return false;
159 if (!file_hdr1 || !file_hdr2) return true;
160
161 if (memcmp(file_hdr1, file_hdr2, sizeof(IMAGE_FILE_HEADER)) == 0) {
162 return false;
163 }
164 if (mask_arch_mismatch) {
165 if (file_hdr1->Machine == file_hdr2->Machine
166 && file_hdr1->Characteristics == file_hdr2->Characteristics
167 && file_hdr1->NumberOfSections == file_hdr2->NumberOfSections
168 && file_hdr1->TimeDateStamp == file_hdr2->TimeDateStamp
169 && file_hdr1->SizeOfOptionalHeader != file_hdr2->SizeOfOptionalHeader)
170 {
171 // only the SizeOfOptionalHeader has changed
172 return false;
173 }
174 }
175 return true;
176}
177
178bool pesieve::HeadersScanner::isNtHdrModified(const PBYTE hdr_buffer1, const PBYTE hdr_buffer2, const size_t hdrs_size)
179{
180 const bool is64 = peconv::is64bit(hdr_buffer1);
181 if (peconv::is64bit(hdr_buffer2) != is64) {
182 return true;
183 }
184 const BYTE *nt1 = peconv::get_nt_hdrs(hdr_buffer1, hdrs_size);
185 const BYTE *nt2 = peconv::get_nt_hdrs(hdr_buffer2, hdrs_size);
186 if (!nt1 && !nt2) return false;
187 if (!nt1 || !nt2) return true;
188
189 const size_t nt_hdr_size = is64 ? sizeof(IMAGE_NT_HEADERS64) : sizeof(IMAGE_NT_HEADERS32);
190 if (memcmp(nt1, nt2, nt_hdr_size) == 0) {
191 return false;
192 }
193 return true;
194}
A report from the headers scan, generated by HeadersScanner.
virtual HeadersScanReport * scanRemote()
RemoteModuleData & remoteModData
BYTE headerBuffer[peconv::MAX_HEADER_SIZE]
size_t fill_iat(BYTE *vBuf, size_t vBufSize, IN const peconv::ExportsMapper *exportsMap, IN OUT IATBlock &iat, IN ThunkFoundCallback *callback)
Definition iat_finder.h:31