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#include "peconv/logger.h"
7
8// Check if gaps between sections are typical for Virtual Alignment.
9// Returns true if confirmed, false if not confirmed. False result can also mean that data was invalid/insufficient to decide.
10bool is_virtual_padding(const BYTE* pe_buffer, size_t pe_size)
11{
12 const size_t r_align = peconv::get_sec_alignment((PBYTE)pe_buffer, true);
13 if (r_align == 0) return false;
14
15 size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
16 if (sections_count < 2) return false;
17
18 bool is_valid_padding = false;
19 for (size_t i = 1; i < sections_count; i++) {
20 PIMAGE_SECTION_HEADER sec1 = peconv::get_section_hdr(pe_buffer, pe_size, i-1);
21 PIMAGE_SECTION_HEADER sec2 = peconv::get_section_hdr(pe_buffer, pe_size, i);
22 if (!sec1 || !sec2) continue; //skip if fetching any of the sections failed
23
24 if (sec1->SizeOfRawData == 0) continue; //skip empty sections
25
26 const DWORD sec1_end_offset = sec1->VirtualAddress + sec1->SizeOfRawData;
27 if (sec2->VirtualAddress == sec1_end_offset) continue;
28
29 if (sec2->VirtualAddress < sec1_end_offset) {
30 LOG_ERROR("Invalid size of the section: 0x%llx vs 0x%llx", (unsigned long long)sec2->VirtualAddress, (unsigned long long)sec1_end_offset);
31 return false;
32 }
33 const size_t diff = sec2->VirtualAddress - sec1_end_offset;
34 if (diff < r_align) continue; //to small to determine
35
36 BYTE* sec1_end_ptr = (BYTE*)((ULONGLONG)pe_buffer + sec1_end_offset);
37 if (!peconv::validate_ptr((const LPVOID)pe_buffer, pe_size, sec1_end_ptr, diff)) {
38 LOG_ERROR("Invalid pointer to the section at offset: 0x%llx", (unsigned long long)sec1_end_offset);
39 return false;
40 }
41 if (peconv::is_padding(sec1_end_ptr, diff, 0)) {
42 is_valid_padding = true;
43 }
44 else {
45 return false;
46 }
47 }
48 return is_valid_padding;
49}
50
51// Check if the gap between the end of headers and the first section is typical for Virtual Alignment.
52// Returns true if confirmed, false if not confirmed. False result can also mean that data was invalid/insufficient to decide.
53bool is_hdr_virtual_align(const BYTE* pe_buffer, size_t pe_size)
54{
55 const size_t v_align = peconv::get_sec_alignment((PBYTE)pe_buffer, false);
56 if (peconv::get_hdrs_size(pe_buffer) >= v_align) {
57 //undetermined for such case
58 return false;
59 }
60 //walk through sections and check their sizes
61 size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
62 if (sections_count == 0) return false;
63 for (size_t i = 0; i < sections_count; i++) {
64 PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(pe_buffer, pe_size, i);
65 if (!sec || sec->PointerToRawData == 0 || sec->SizeOfRawData == 0) {
66 continue; // check next
67 }
68 if (sec->PointerToRawData >= v_align) continue;
69
70 size_t diff = v_align - sec->PointerToRawData;
71 BYTE* sec_raw_ptr = (BYTE*)((ULONGLONG)pe_buffer + sec->PointerToRawData);
72 if (!peconv::validate_ptr((const LPVOID)pe_buffer, pe_size, sec_raw_ptr, diff)) {
73 return false;
74 }
75 if (peconv::is_padding(sec_raw_ptr, diff, 0)) {
76 return true;
77 }
78 }
79 return false;
80}
81
82bool is_sec_hdrs_erased(IN const BYTE* pe_buffer, IN size_t pe_size, bool is_raw)
83{
84 const size_t count = peconv::get_sections_count(pe_buffer, pe_size);
85 for (size_t i = 0; i < count; i++) {
86 const IMAGE_SECTION_HEADER* hdr = peconv::get_section_hdr(pe_buffer, pe_size, i);
87 if (!hdr) continue;
88 if (is_raw) {
89 if (hdr->PointerToRawData != 0) return false;
90 }
91 else {
92 if (hdr->VirtualAddress != 0) return false;
93 }
94 }
95 return true;
96}
97
98bool peconv::is_pe_raw_eq_virtual(IN const BYTE* pe_buffer, IN size_t pe_size)
99{
100 const size_t count = peconv::get_sections_count(pe_buffer, pe_size);
101 for (size_t i = 0; i < count; i++) {
102 const IMAGE_SECTION_HEADER* hdr = peconv::get_section_hdr(pe_buffer, pe_size, i);
103 if (!hdr) continue;
104
105 if (hdr->VirtualAddress != hdr->PointerToRawData) {
106 return false;
107 }
108 }
109 return true;
110}
111
112bool is_pe_mapped(IN const BYTE* pe_buffer, IN size_t pe_size)
113{
114 size_t v_score = 0;
115 if (peconv::has_valid_import_table((const PBYTE)pe_buffer, pe_size)) {
116 LOG_INFO("Valid Import Table found.");
117 v_score++;
118 }
119 if (peconv::has_valid_relocation_table((const PBYTE)pe_buffer, pe_size)) {
120 LOG_INFO("Valid Relocations Table found.");
121 v_score++;
122 }
123 if (is_hdr_virtual_align(pe_buffer, pe_size)) {
124 LOG_INFO("Header virtual alignment OK.");
125 v_score++;
126 }
127 LOG_INFO("TOTAL v_score: %zu.", v_score);
128 if (v_score > 0) {
129 return true;
130 }
131 return false;
132}
133
134bool peconv::is_pe_raw(IN const BYTE* pe_buffer, IN size_t pe_size)
135{
136 if (peconv::get_sections_count(pe_buffer, pe_size) == 0) {
137 return true;
138 }
139 if (is_pe_mapped(pe_buffer, pe_size)) {
140 // it has artefacts typical for a PE in a virtual alignment
141 return false;
142 }
143 if (is_sec_hdrs_erased(pe_buffer, pe_size, true)) {
144 LOG_INFO("Raw alignment is erased.");
145 // the raw alignment of the sections is erased
146 return false;
147 }
148 return true;
149}
150
151// checks if any sections has been expanded in the memory
152bool peconv::is_pe_expanded(IN const BYTE* pe_buffer, IN size_t pe_size)
153{
154 //walk through sections and check their sizes
155 size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
156 for (size_t i = 0; i < sections_count; i++) {
157 PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(pe_buffer, pe_size, i);
158 if (is_section_expanded(pe_buffer, pe_size, sec)) {
159 return true;
160 }
161 }
162 return false;
163}
164
165// checks if the section's content in memory is bigger than in the raw format
166bool peconv::is_section_expanded(IN const BYTE* pe_buffer, IN size_t pe_size, IN const PIMAGE_SECTION_HEADER sec)
167{
168 if (!sec) return false;
169
170 size_t sec_vsize = peconv::get_virtual_sec_size(pe_buffer, sec, true);
171 size_t sec_rsize = sec->SizeOfRawData;
172
173 if (sec_rsize >= sec_vsize) return false;
174 size_t diff = sec_vsize - sec_rsize;
175
176 BYTE* sec_raw_end_ptr = (BYTE*)((ULONGLONG)pe_buffer + sec->VirtualAddress + sec_rsize);
177 if (!peconv::validate_ptr((const LPVOID)pe_buffer, pe_size, sec_raw_end_ptr, diff)) {
178 return false;
179 }
180 if (!is_padding(sec_raw_end_ptr, diff, 0)) {
181 //this is not padding: non-zero content detected
182 return true;
183 }
184 return false;
185}
Parsing and filling the Import Table.
Compile-time configurable logging macros for peconv.
#define LOG_INFO(fmt,...)
Definition: logger.h:74
#define LOG_ERROR(fmt,...)
Definition: logger.h:60
bool has_valid_import_table(const PBYTE modulePtr, size_t moduleSize, size_t max_count=0)
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)
Definition: buffer_util.cpp:9
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:106
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:192
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_sec_hdrs_erased(IN const BYTE *pe_buffer, IN size_t pe_size, bool is_raw)
bool is_pe_mapped(IN const BYTE *pe_buffer, IN size_t pe_size)
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.