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)) {
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";
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))
152 ULONGLONG found_mz = _findMZoffset(memPage, sec_hdr);
157 size_t hdrs_offset =
calc_offset(memPage, sec_hdr);
164 IMAGE_DOS_HEADER *dos_hdr = findDosHdrByPatterns(memPage, search_start, hdrs_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;
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)) {
246 IMAGE_DOS_HEADER* dos_hdr = _findDosHdrByPatterns(search_ptr, max_search_size);
247 const bool is_dos_valid = memPage.
validatePtr(dos_hdr,
sizeof(IMAGE_DOS_HEADER));
256 if (!memPage.load()) {
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;
341 ULONGLONG pe_image_base = this->calcPeBase(memPage, 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;
353 bool is_ok = _validateSecRegions(memPage, sec_hdr, sec_count, pe_image_base,
true);
356 is_ok = _validateSecRegions(memPage, sec_hdr, sec_count, pe_image_base,
false);
359 std::cout <<
"[-] Raw failed!\n";
362 std::cout <<
"[+] Raw OK!\n";
368 std::cout <<
"[+] Virtual OK!\n";
376 if (!memPage.load()) {
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))) {
431 if (!memPage.
validatePtr(search_ptr, max_search_size)) {
434 BYTE *hdr_ptr = _findSecByPatterns(search_ptr, max_search_size);
444 if (!_validateSecRegions(memPage, first_sec, count)) {
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) {
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);
562 if (!memPage.
load()) {
568 const size_t scan_size = memPage.
getLoadedSize() - search_offset;
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);
595 IMAGE_DOS_HEADER* dos_hdr = findMzPeHeader(aMap.
memPage, search_offset);
602 if (setMzPe(aMap, dos_hdr)) {
610 if (!_dos_hdr)
return false;
617 IMAGE_NT_HEADERS32* pe_hdrs = (IMAGE_NT_HEADERS32*)((ULONGLONG)_dos_hdr + _dos_hdr->e_lfanew);
622 setNtFileHdr(aMap, &pe_hdrs->FileHeader);
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;
728 aMap.
is64bit = this->isProcess64bit;
736 if (!_memPage.
load()) {
742 for (
size_t min_offset = start_offset; min_offset < _memPage.
getLoadedSize(); min_offset++)
748 if (findMzPe(aMap, 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";
760 setNtFileHdr(aMap, nt_hdr);
768 min_offset = nt_offset;
772 if (max_section_search + min_offset <= _memPage.
getLoadedSize()) {
773 max_section_search += min_offset;
777 if (!setSecHdr(aMap, aMap.
sec_hdr)) {
779 if (max_section_search > min_offset) {
780 const size_t diff = max_section_search - min_offset;
781 IMAGE_SECTION_HEADER *sec_hdr = findSecByPatterns(_memPage, diff, min_offset);
782 setSecHdr(aMap, sec_hdr);
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";
798 aMap.
dos_hdr = findDosHdrByPatterns(aMap.
memPage, start, sec_offset);
800 IMAGE_NT_HEADERS32 *nt_ptr = (IMAGE_NT_HEADERS32*)((ULONG_PTR)aMap.
dos_hdr + aMap.
dos_hdr->e_lfanew);
802 const size_t nt_offset =
calc_offset(memPage, nt_ptr);
803 std::cout <<
"Found PE offset: " << std::hex << aMap.
dos_hdr->e_lfanew <<
" NT offset: " << nt_offset <<
"\n";
806 setNtFileHdr(aMap, &nt_ptr->FileHeader);
811 if (!setSecHdr(aMap, aMap.
sec_hdr)) {
814 bestMapping = (bestMapping < aMap) ? aMap : bestMapping;
823 min_offset = nt_offset;
826 min_offset = sec_offset;
833 return generateArtefacts(bestMapping);
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)) {
850 this->prevMemPage =
new MemPageData(this->processHandle, this->pDetails.isReflection, next_addr, addr_stop);
851 peArt = findArtefacts(*prevMemPage, 0);
855 next_addr -= (this->prevMemPage->region_start -
PAGE_SIZE);
864 bool is_shellcode =
false;
881 ULONGLONG region_start = memPage.region_start;
882 this->artPagePtr = &memPage;
885 if (!peArt && (region_start > memPage.alloc_base)) {
886 peArt = findInPrevPages(memPage.alloc_base, memPage.region_start);
888 this->artPagePtr = prevMemPage;
889 region_start = prevMemPage->region_start;
896 const size_t region_size = size_t(memPage.region_end - region_start);
900 my_report->
has_shellcode = hasShellcode((HMODULE)region_start, region_size, *peArt);
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
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)
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)
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)