20 if (!peconv::validate_ptr(loadedData, loadedSize, field,
sizeof(BYTE))) {
23 return size_t((ULONG_PTR)field - (ULONG_PTR)loadedData);
28 size_t opt_hdr_size = nt_file_hdr->SizeOfOptionalHeader;
29 if (opt_hdr_size == 0) {
31 bool is64bit = (nt_file_hdr->Machine == IMAGE_FILE_MACHINE_AMD64) ?
true :
false;
32 opt_hdr_size = is64bit ?
sizeof(IMAGE_OPTIONAL_HEADER64) :
sizeof(IMAGE_OPTIONAL_HEADER32);
34 const size_t headers_size = opt_hdr_size +
sizeof(IMAGE_FILE_HEADER);
35 size_t nt_offset =
calc_offset(memPage, nt_file_hdr);
36 size_t sec_hdr_offset = headers_size + nt_offset;
37 return sec_hdr_offset;
42 size_t sec_hdr_offset =
calc_offset(memPage, first_sec);
46 size_t opt_hdr_size = is64bit ?
sizeof(IMAGE_OPTIONAL_HEADER64) :
sizeof(IMAGE_OPTIONAL_HEADER32);
47 const size_t headers_size = opt_hdr_size +
sizeof(IMAGE_FILE_HEADER);
48 size_t nt_offset = sec_hdr_offset - headers_size;
54 if (!_sec_hdr)
return false;
55 if (!nt_file_hdr)
return false;
59 if (sec_offset_hdrs != sec_offset) {
60 std::cout << std::hex <<
"sec_offset_hdrs: " << sec_offset_hdrs <<
" vs: " << sec_offset <<
"\n";
69 if (!loadedData || !hdr_ptr) {
73 IMAGE_SECTION_HEADER* curr_sec = hdr_ptr;
75 if (!
is_valid_section(loadedData, loadedSize, (BYTE*)curr_sec, IMAGE_SCN_MEM_READ)) {
85 IMAGE_SECTION_HEADER*
get_first_section(BYTE *loadedData,
size_t loadedSize, IMAGE_SECTION_HEADER *hdr_ptr)
87 IMAGE_SECTION_HEADER* prev_sec = hdr_ptr;
89 if (!
is_valid_section(loadedData, loadedSize, (BYTE*)prev_sec, IMAGE_SCN_MEM_READ)) {
85 IMAGE_SECTION_HEADER*
get_first_section(BYTE *loadedData,
size_t loadedSize, IMAGE_SECTION_HEADER *hdr_ptr) {
…}
104 PIMAGE_SECTION_HEADER hdr_candidate = (PIMAGE_SECTION_HEADER) hdr_ptr;
105 if (!peconv::validate_ptr(loadedData, loadedSize, hdr_candidate,
sizeof(IMAGE_SECTION_HEADER))) {
109 if (hdr_candidate->PointerToRelocations != 0
110 || hdr_candidate->NumberOfRelocations != 0
111 || hdr_candidate->PointerToLinenumbers != 0)
116 if (charact != 0 && (hdr_candidate->Characteristics & charact) == 0) {
132 const BYTE mz_sig[] =
"MZ\x90";
134 BYTE *min_search =
memPage.getLoadedData();
135 BYTE *start_ptr = min_search + hdrs_offset -
sizeof(mz_sig);
138 for (BYTE *search_ptr = start_ptr; search_ptr >= min_search && space > 0; search_ptr--, space--) {
139 if ((search_ptr[0] == mz_sig[0] && search_ptr[1] == mz_sig[1] )
140 && (search_ptr[2] == mz_sig[2] || search_ptr[2] == 0))
154 return memPage.region_start + found_mz;
167 return memPage.region_start + dos_offset;
171 size_t full_pages = hdrs_offset /
PAGE_SIZE;
179 hdr_ptr = peconv::get_section_hdr(headerBuffer, headerBufferSize, 0);
180 if (!hdr_ptr)
return peconv::fetch_region_size(
processHandle, (PBYTE)modBaseAddr);
185 const ULONGLONG main_base = peconv::fetch_alloc_base(
processHandle, (PBYTE)modBaseAddr);
186 for (IMAGE_SECTION_HEADER* curr_sec = hdr_ptr; ; curr_sec++)
189 if (!
is_valid_section(headerBuffer, headerBufferSize, (BYTE*)curr_sec, 0)) {
192 if (curr_sec->Misc.VirtualSize == 0 || curr_sec->VirtualAddress == 0) {
196 const DWORD sec_rva = curr_sec->VirtualAddress;
198 MEMORY_BASIC_INFORMATION page_info = { 0 };
199 if (!peconv::fetch_region_info(
processHandle, (PBYTE)((ULONG_PTR)modBaseAddr + sec_rva), page_info)) {
202 if ((ULONG_PTR)page_info.AllocationBase != main_base) {
205 std::cout <<
"[!] Mismatch: region_base : " << std::hex << page_info.AllocationBase <<
" while main base: " << main_base <<
"\n";
209 if (page_info.Type == 0 || page_info.Protect == 0) {
212 if ((page_info.State & MEM_COMMIT) == 0) {
215 if (sec_rva > max_addr) {
220 size_t last_sec_size = peconv::fetch_region_size(
processHandle, (PBYTE)((ULONG_PTR)modBaseAddr + max_addr));
221 size_t total_size = max_addr + last_sec_size;
223 std::cout <<
"Image: " << std::hex << (ULONGLONG)modBaseAddr <<
" Size:" << std::hex << total_size <<
" max_addr: " << max_addr << std::endl;
236 BYTE* data =
memPage.getLoadedData();
237 if (!data)
return nullptr;
239 BYTE *search_ptr = data + start_offset;
240 BYTE *max_search = search_ptr + hdrs_offset;
242 size_t max_search_size = max_search - search_ptr;
243 if (!
memPage.validatePtr(search_ptr, max_search_size)) {
247 const bool is_dos_valid =
memPage.validatePtr(dos_hdr,
sizeof(IMAGE_DOS_HEADER));
260 const size_t patterns_count = 2;
261 const size_t pattern_size = 14;
262 BYTE stub_patterns[patterns_count][pattern_size] = {
264 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4,
265 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C,
269 0xBA, 0x10, 0x00, 0x0E, 0x1F, 0xB4,
270 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C,
275 const size_t dos_hdr_size =
sizeof(IMAGE_DOS_HEADER);
277 BYTE *stub_ptr =
nullptr;
278 IMAGE_DOS_HEADER *dos_ptr =
nullptr;
279 for (
size_t i = 0; i < patterns_count; i++) {
280 BYTE *pattern = stub_patterns[i];
281 stub_ptr =
find_pattern(search_ptr, max_search_size, pattern, pattern_size);
285 size_t offset_to_bgn =
sizeof(IMAGE_DOS_HEADER);
286 if ((ULONG_PTR)stub_ptr < offset_to_bgn) {
289 dos_ptr = (IMAGE_DOS_HEADER*)((ULONG_PTR)stub_ptr - offset_to_bgn);
290 if (!peconv::validate_ptr(search_ptr, max_search_size, dos_ptr,
sizeof(IMAGE_DOS_HEADER))) {
300 if (!sec_hdr || !sec_count) {
303 MEMORY_BASIC_INFORMATION module_start_info = { 0 };
304 if (!peconv::fetch_region_info(
processHandle, (BYTE*)pe_image_base, module_start_info)) {
307 IMAGE_SECTION_HEADER* curr_sec = (IMAGE_SECTION_HEADER*)sec_hdr;
309 for (
size_t i = 0; i < sec_count; i++, curr_sec++) {
310 if (curr_sec->VirtualAddress == 0)
continue;
312 ULONG sec_start = is_virtual ? curr_sec->VirtualAddress : curr_sec->PointerToRawData;
313 ULONGLONG last_sec_addr = pe_image_base + sec_start;
315 MEMORY_BASIC_INFORMATION page_info = { 0 };
316 if (!peconv::fetch_region_info(
processHandle, (BYTE*)last_sec_addr, page_info)) {
318 std::cout << std::hex << last_sec_addr <<
" couldn't fetch module info" << std::endl;
322 if (page_info.AllocationBase != module_start_info.AllocationBase) {
324 std::cout <<
"[-] SecBase mismatch: ";
325 if (curr_sec->Name) {
326 std::cout << curr_sec->Name;
328 std::cout << std::hex << i <<
" section: " << last_sec_addr <<
" alloc base: " << page_info.AllocationBase <<
" with module base: " << module_start_info.AllocationBase << std::endl;
338 if (!
memPage.getLoadedData() || !sec_hdr) {
342 bool has_non_zero =
false;
344 IMAGE_SECTION_HEADER* curr_sec = (IMAGE_SECTION_HEADER*)sec_hdr;
345 for (
size_t i = 0; i < sec_count; i++, curr_sec++) {
346 if (curr_sec->VirtualAddress && curr_sec->Misc.VirtualSize) {
350 if (!has_non_zero)
return false;
359 std::cout <<
"[-] Raw failed!\n";
362 std::cout <<
"[+] Raw OK!\n";
368 std::cout <<
"[+] Virtual OK!\n";
379 const DWORD charact = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
381 char sec_name[] =
".text";
382 BYTE *hdr_ptr =
find_pattern(search_ptr, max_search_size, (BYTE*)sec_name, strlen(sec_name));
392 const size_t patterns_count = 2;
393 const size_t pattern_size =
sizeof(
DWORD) * 4;
394 BYTE charact_patterns[patterns_count][pattern_size] = {
396 0x00, 0x00, 0x00, 0x00,
397 0x00, 0x00, 0x00, 0x00,
398 0x00, 0x00, 0x00, 0x00,
399 0x20, 0x00, 0x00, 0x60
402 0x00, 0x00, 0x00, 0x00,
403 0x00, 0x00, 0x00, 0x00,
404 0x00, 0x00, 0x00, 0x00,
405 0x40, 0x00, 0x00, 0xC0
409 for (
size_t i = 0; i < patterns_count; i++) {
410 BYTE *sec_ending = charact_patterns[i];
411 const size_t sec_ending_size = pattern_size;
412 hdr_ptr =
find_pattern(search_ptr, max_search_size, sec_ending, sec_ending_size);
416 size_t offset_to_bgn =
sizeof(IMAGE_SECTION_HEADER) - sec_ending_size;
417 hdr_ptr -= offset_to_bgn;
418 if (!peconv::validate_ptr(search_ptr, max_search_size, hdr_ptr,
sizeof(IMAGE_SECTION_HEADER))) {
430 BYTE *search_ptr = search_offset +
memPage.getLoadedData();
431 if (!
memPage.validatePtr(search_ptr, max_search_size)) {
446 const ULONGLONG diff = (ULONGLONG)first_sec - (ULONGLONG)
memPage.getLoadedData();
447 std::cout <<
"[!] section header: " << std::hex << (ULONGLONG)
memPage.region_start <<
" hdr at: " << diff <<
" : validation failed!\n";
451 return (IMAGE_SECTION_HEADER*)first_sec;
456 IMAGE_FILE_HEADER* hdr_candidate = (IMAGE_FILE_HEADER*)hdr_ptr;
457 if (!peconv::validate_ptr(loadedData, loadedSize, hdr_candidate,
sizeof(IMAGE_FILE_HEADER))) {
461 if (hdr_candidate->NumberOfSections > 100) {
464 if (hdr_candidate->NumberOfSymbols != 0 || hdr_candidate->PointerToSymbolTable != 0) {
468 size_t opt_hdr_size = 0;
469 if (hdr_candidate->Machine == IMAGE_FILE_MACHINE_I386) {
470 opt_hdr_size =
sizeof(IMAGE_OPTIONAL_HEADER32);
472 else if (hdr_candidate->Machine == IMAGE_FILE_MACHINE_AMD64) {
473 opt_hdr_size =
sizeof(IMAGE_OPTIONAL_HEADER64);
479 if (hdr_candidate->SizeOfOptionalHeader >
PAGE_SIZE) {
482 if (!peconv::validate_ptr(loadedData, loadedSize, hdr_candidate,
483 sizeof(IMAGE_FILE_HEADER) + opt_hdr_size))
487 if (hdr_candidate->SizeOfOptionalHeader == opt_hdr_size) {
491 if (charact != 0 && (hdr_candidate->Characteristics & charact) == 0) {
499 BYTE*
const loadedData =
memPage.getLoadedData();
500 size_t const loadedSize =
memPage.getLoadedSize();
503 if (!loadedData)
return nullptr;
507 stop_offset = loadedSize;
510 if (stop_offset > loadedSize) {
511 stop_offset = loadedSize;
515 || start_offset >= loadedSize || stop_offset <= start_offset)
520 BYTE* search_ptr = loadedData + start_offset;
521 size_t search_size = loadedSize - start_offset;
529 WORD archs[ARCHS_COUNT] = { 0 };
530 archs[ARCH_32B] = IMAGE_FILE_MACHINE_I386;
531 archs[ARCH_64B] = IMAGE_FILE_MACHINE_AMD64;
533 BYTE *arch_ptr =
nullptr;
535 for (my_arch = ARCH_32B; my_arch < ARCHS_COUNT; my_arch++) {
536 arch_ptr =
find_pattern(search_ptr, search_size, (BYTE*)&archs[my_arch],
sizeof(WORD), max_iter);
545 DWORD charact = IMAGE_FILE_EXECUTABLE_IMAGE;
546 if (my_arch == ARCH_32B) {
547 charact |= IMAGE_FILE_32BIT_MACHINE;
550 charact |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
556 return reinterpret_cast<IMAGE_FILE_HEADER*
>(arch_ptr);
565 if (
memPage.getLoadedSize() <= search_offset) {
568 const size_t scan_size =
memPage.getLoadedSize() - search_offset;
569 BYTE* buffer_ptr =
memPage.getLoadedData() + search_offset;
570 if (!
memPage.validatePtr(buffer_ptr, scan_size)) {
573 const size_t minimal_size =
sizeof(IMAGE_DOS_HEADER)
574 +
sizeof(IMAGE_FILE_HEADER)
575 +
sizeof(IMAGE_OPTIONAL_HEADER32);
578 for (
size_t i = 0; i < scan_size; i++) {
579 const size_t remaining_size = scan_size - i;
580 if (remaining_size < minimal_size) {
583 const BYTE* pe_candidate = buffer_ptr + i;
584 BYTE *nt_hdr = peconv::get_nt_hdrs(pe_candidate, remaining_size);
585 if (nt_hdr !=
nullptr) {
587 return (IMAGE_DOS_HEADER*)(pe_candidate);
610 if (!_dos_hdr)
return false;
617 IMAGE_NT_HEADERS32* pe_hdrs = (IMAGE_NT_HEADERS32*)((ULONGLONG)_dos_hdr + _dos_hdr->e_lfanew);
628 if (_sec_hdr ==
nullptr)
return false;
648 if (suggested_nt_offset !=
INVALID_OFFSET && (sec_hdr_offset >= suggested_nt_offset)) {
665 if (!_nt_hdr)
return false;
676 aMap.
sec_hdr = (IMAGE_SECTION_HEADER*)((ULONGLONG)loadedData + sec_hdr_offset);
683 std::cout <<
"[WARNING] Sections header misaligned with FileHeader." << std::endl;
736 if (!_memPage.
load()) {
742 for (
size_t min_offset = start_offset; min_offset < _memPage.
getLoadedSize(); min_offset++)
750 min_offset = (dos_offset !=
INVALID_OFFSET) ? dos_offset : min_offset;
752 std::cout << std::hex <<
"Page: " << aMap.
memPage.
start_va <<
" Found DOS Header at: " << dos_offset <<
"\n";
757 std::cout << std::hex <<
"Page: " << aMap.
memPage.
start_va <<
" Searching NT Header at: " << min_offset <<
"\n";
768 min_offset = nt_offset;
772 if (max_section_search + min_offset <= _memPage.
getLoadedSize()) {
773 max_section_search += min_offset;
779 if (max_section_search > min_offset) {
780 const size_t diff = max_section_search - min_offset;
788 const size_t sections_area_size = aMap.
sec_count *
sizeof(IMAGE_SECTION_HEADER);
789 min_offset = (sec_offset + sections_area_size);
791 std::cout <<
"Setting minOffset to SecHdr end offset: " << std::hex << min_offset <<
"\n";
800 IMAGE_NT_HEADERS32 *nt_ptr = (IMAGE_NT_HEADERS32*)((ULONG_PTR)aMap.
dos_hdr + aMap.
dos_hdr->e_lfanew);
803 std::cout <<
"Found PE offset: " << std::hex << aMap.
dos_hdr->e_lfanew <<
" NT offset: " << nt_offset <<
"\n";
814 bestMapping = (bestMapping < aMap) ? aMap : bestMapping;
823 min_offset = nt_offset;
826 min_offset = sec_offset;
840 ULONGLONG next_addr = addr_stop -
PAGE_SIZE;
842 if (next_addr < addr_start) {
845 const size_t area_size = size_t(addr_stop - next_addr);
846 if (this->
processReport.hasModuleContaining((ULONGLONG)next_addr, area_size)) {
864 bool is_shellcode =
false;
881 ULONGLONG region_start =
memPage.region_start;
885 if (!peArt && (region_start >
memPage.alloc_base)) {
896 const size_t region_size = size_t(
memPage.region_end - region_start);
A report from the artefacts scan, generated by ArtefactScanner.
IMAGE_SECTION_HEADER * sec_hdr
IMAGE_FILE_HEADER * nt_file_hdr
IMAGE_DOS_HEADER * dos_hdr
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)
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)
MemPageData * prevMemPage
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)
size_t getLoadedSize(bool trimmed=false)
const PBYTE getLoadedData(bool trimmed=false)
bool validatePtr(const LPVOID field_bgn, size_t field_size)
ULONGLONG start_va
VA that was requested. May not be beginning of the region.
A report about the PE artefact detected in the workingset.
bool validate_hdrs_alignment(MemPageData &memPage, IMAGE_FILE_HEADER *nt_file_hdr, IMAGE_SECTION_HEADER *_sec_hdr)
size_t calc_offset(MemPageData &memPage, LPVOID field)
IMAGE_SECTION_HEADER * get_first_section(BYTE *loadedData, size_t loadedSize, IMAGE_SECTION_HEADER *hdr_ptr)
size_t calc_nt_hdr_offset(MemPageData &memPage, IMAGE_SECTION_HEADER *first_sec, bool is64bit=true)
BYTE * find_pattern(BYTE *buffer, size_t buf_size, BYTE *pattern_buf, size_t pattern_size, size_t max_iter=0)
DWORD(__stdcall *_PssCaptureSnapshot)(HANDLE ProcessHandle
size_t count_section_hdrs(BYTE *loadedData, size_t loadedSize, IMAGE_SECTION_HEADER *hdr_ptr)
size_t calc_sec_hdrs_offset(MemPageData &memPage, IMAGE_FILE_HEADER *nt_file_hdr)
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)