libPeConv
A library to load, manipulate, dump PE files.
Loading...
Searching...
No Matches
pe_mode_detector.cpp
Go to the documentation of this file.
2#include "peconv/util.h"
4#include "peconv/relocate.h"
5
6#ifdef _DEBUG
7#include <iostream>
8#endif
9
10// Check if gaps between sections are typical for Virtual Alignment.
11// Returns true if confirmed, false if not confirmed. False result can also mean that data was invalid/insufficient to decide.
12bool is_virtual_padding(const BYTE* pe_buffer, size_t pe_size)
13{
14 const size_t r_align = peconv::get_sec_alignment((PBYTE)pe_buffer, true);
15
16 size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
17 if (sections_count < 2) return false;
18
19 bool is_valid_padding = false;
20 for (size_t i = 1; i < sections_count; i += 2) {
21 PIMAGE_SECTION_HEADER sec1 = peconv::get_section_hdr(pe_buffer, pe_size, i-1);
22 PIMAGE_SECTION_HEADER sec2 = peconv::get_section_hdr(pe_buffer, pe_size, i);
23 if (!sec1 || !sec2) continue; //skip if fetching any of the sections failed
24
25 if (sec1->SizeOfRawData == 0) continue; //skip empty sections
26
27 const DWORD sec1_end_offset = sec1->VirtualAddress + sec1->SizeOfRawData;
28 if (sec2->VirtualAddress == sec1_end_offset) continue;
29
30 if (sec2->VirtualAddress < sec1_end_offset) {
31 //std::cout << "Invalid size of the section: " << std::hex << sec2->VirtualAddress << " vs "<< sec1_end_offset << std::endl;
32 return false;
33 }
34 const size_t diff = sec2->VirtualAddress - sec1_end_offset;
35 if (diff < r_align) continue; //to small to determine
36
37 BYTE* sec1_end_ptr = (BYTE*)((ULONGLONG)pe_buffer + sec1_end_offset);
38 if (!peconv::validate_ptr((const LPVOID)pe_buffer, pe_size, sec1_end_ptr, diff)) {
39 //std::cout << "Invalid pointer to the section\n";
40 return false;
41 }
42 if (peconv::is_padding(sec1_end_ptr, diff, 0)) {
43 is_valid_padding = true;
44 }
45 else {
46 return false;
47 }
48 }
49 return is_valid_padding;
50}
51
52// Check if the gap between the end of headers and the first section is typical for Virtual Alignment.
53// Returns true if confirmed, false if not confirmed. False result can also mean that data was invalid/insufficient to decide.
54bool is_hdr_virtual_align(const BYTE* pe_buffer, size_t pe_size)
55{
56 const size_t v_align = peconv::get_sec_alignment((PBYTE)pe_buffer, false);
57 if (peconv::get_hdrs_size(pe_buffer) >= v_align) {
58 //undetermined for such case
59 return false;
60 }
61 //walk through sections and check their sizes
62 size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
63 if (sections_count == 0) return false;
64 for (size_t i = 0; i < sections_count; i++) {
65 PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(pe_buffer, pe_size, i);
66 if (!sec || sec->PointerToRawData == 0 || sec->SizeOfRawData == 0) {
67 continue; // check next
68 }
69 if (sec->PointerToRawData >= v_align) continue;
70
71 size_t diff = v_align - sec->PointerToRawData;
72 BYTE* sec_raw_ptr = (BYTE*)((ULONGLONG)pe_buffer + sec->PointerToRawData);
73 if (!peconv::validate_ptr((const LPVOID)pe_buffer, pe_size, sec_raw_ptr, diff)) {
74 return false;
75 }
76 if (peconv::is_padding(sec_raw_ptr, diff, 0)) {
77 return true;
78 }
79 }
80 return false;
81}
82
83bool sec_hdrs_erased(IN const BYTE* pe_buffer, IN size_t pe_size, bool is_raw)
84{
85 const size_t count = peconv::get_sections_count(pe_buffer, pe_size);
86 for (size_t i = 0; i < count; i++) {
87 const IMAGE_SECTION_HEADER* hdr = peconv::get_section_hdr(pe_buffer, pe_size, i);
88 if (!hdr) continue;
89 if (is_raw) {
90 if (hdr->PointerToRawData != 0) return false;
91 }
92 else {
93 if (hdr->VirtualAddress != 0) return false;
94 }
95 }
96 return true;
97}
98
99bool peconv::is_pe_raw_eq_virtual(IN const BYTE* pe_buffer, IN size_t pe_size)
100{
101 const size_t count = peconv::get_sections_count(pe_buffer, pe_size);
102 for (size_t i = 0; i < count; i++) {
103 const IMAGE_SECTION_HEADER* hdr = peconv::get_section_hdr(pe_buffer, pe_size, i);
104 if (!hdr) continue;
105
106 if (hdr->VirtualAddress != hdr->PointerToRawData) {
107 return false;
108 }
109 }
110 return true;
111}
112
113bool is_pe_mapped(IN const BYTE* pe_buffer, IN size_t pe_size)
114{
115 size_t v_score = 0;
116 if (peconv::has_valid_import_table((const PBYTE)pe_buffer, pe_size)) {
117#ifdef _DEBUG
118 std::cout << "Valid Import Table found" << std::endl;
119#endif
120 v_score++;
121 }
122 if (peconv::has_valid_relocation_table((const PBYTE)pe_buffer, pe_size)) {
123#ifdef _DEBUG
124 std::cout << "Valid Relocations Table found" << std::endl;
125#endif
126 v_score++;
127 }
128 if (is_hdr_virtual_align(pe_buffer, pe_size)) {
129#ifdef _DEBUG
130 std::cout << "Header virtual align OK" << std::endl;
131#endif
132 v_score++;
133 }
134#ifdef _DEBUG
135 std::cout << "TOTAL v_score: " << std::dec << v_score << std::endl;
136#endif
137 if (v_score > 0) {
138 return true;
139 }
140 return false;
141}
142
143bool peconv::is_pe_raw(IN const BYTE* pe_buffer, IN size_t pe_size)
144{
145 if (peconv::get_sections_count(pe_buffer, pe_size) == 0) {
146 return true;
147 }
148 if (is_pe_mapped(pe_buffer, pe_size)) {
149 // it has artefacts typical for a PE in a virtual alignment
150 return false;
151 }
152 if (sec_hdrs_erased(pe_buffer, pe_size, true)) {
153#ifdef _DEBUG
154 std::cout << "Raw alignment is erased\n";
155#endif
156 // the raw alignment of the sections is erased
157 return false;
158 }
159 return true;
160}
161
162// checks if any sections has been expanded in the memory
163bool peconv::is_pe_expanded(IN const BYTE* pe_buffer, IN size_t pe_size)
164{
165 //walk through sections and check their sizes
166 size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
167 for (size_t i = 0; i < sections_count; i++) {
168 PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(pe_buffer, pe_size, i);
169 if (is_section_expanded(pe_buffer, pe_size, sec)) {
170 return true;
171 }
172 }
173 return false;
174}
175
176// checks if the section's content in memory is bigger than in the raw format
177bool peconv::is_section_expanded(IN const BYTE* pe_buffer, IN size_t pe_size, IN const PIMAGE_SECTION_HEADER sec)
178{
179 if (!sec) return false;
180
181 size_t sec_vsize = peconv::get_virtual_sec_size(pe_buffer, sec, true);
182 size_t sec_rsize = sec->SizeOfRawData;
183
184 if (sec_rsize >= sec_vsize) return false;
185 size_t diff = sec_vsize - sec_rsize;
186
187 BYTE* sec_raw_end_ptr = (BYTE*)((ULONGLONG)pe_buffer + sec->VirtualAddress + sec_rsize);
188 if (!peconv::validate_ptr((const LPVOID)pe_buffer, pe_size, sec_raw_end_ptr, diff)) {
189 return false;
190 }
191 if (!is_padding(sec_raw_end_ptr, diff, 0)) {
192 //this is not padding: non-zero content detected
193 return true;
194 }
195 return false;
196}
Parsing and filling the Import Table.
bool has_valid_import_table(const PBYTE modulePtr, size_t moduleSize)
bool is_section_expanded(IN const BYTE *pe_buffer, IN size_t pe_size, IN const PIMAGE_SECTION_HEADER sec)
DWORD get_virtual_sec_size(IN const BYTE *pe_hdr, IN const PIMAGE_SECTION_HEADER sec_hdr, IN bool rounded)
bool is_pe_raw(IN const BYTE *pe_buffer, IN size_t pe_size)
bool validate_ptr(IN const void *buffer_bgn, IN size_t buffer_size, IN const void *field_bgn, IN size_t field_size)
PIMAGE_SECTION_HEADER get_section_hdr(IN const BYTE *pe_buffer, IN const size_t buffer_size, IN size_t section_num)
bool is_padding(const BYTE *cave_ptr, size_t cave_size, const BYTE padding_char)
Definition util.cpp:100
DWORD get_sec_alignment(IN const BYTE *modulePtr, IN bool is_raw)
bool is_pe_raw_eq_virtual(IN const BYTE *pe_buffer, IN size_t pe_size)
size_t get_sections_count(IN const BYTE *buffer, IN const size_t buffer_size)
bool is_pe_expanded(IN const BYTE *pe_buffer, IN size_t pe_size)
DWORD get_hdrs_size(IN const BYTE *pe_buffer)
bool has_valid_relocation_table(IN const PBYTE modulePtr, IN const size_t moduleSize)
Definition relocate.cpp:185
bool is_hdr_virtual_align(const BYTE *pe_buffer, size_t pe_size)
bool is_virtual_padding(const BYTE *pe_buffer, size_t pe_size)
bool is_pe_mapped(IN const BYTE *pe_buffer, IN size_t pe_size)
bool sec_hdrs_erased(IN const BYTE *pe_buffer, IN size_t pe_size, bool is_raw)
Detecting in which mode is the PE in the supplied buffer (i.e. raw, virtual). Analyzes PE features ty...
Operating on PE file's relocations table.
Miscellaneous utility functions.