· 6 months ago · Mar 17, 2025, 05:05 PM
1==++ Here's the full source for (file 1/3) "main.cpp"::: ++==
2```main.cpp
3#define STRICT
4#define WIN32_LEAN_AND_MEAN
5#define DEBUG_OUTPUT(format, ...) \
6 do { \
7 OUTPUT("[DEBUG] %ls:%d - " format "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__); \
8 } while(0)
9#ifndef OUTPUT
10#define OUTPUT(format, ...) wprintf(L##format, ##__VA_ARGS__)
11#endif
12#include <Windows.h>
13#include <winternl.h>
14#include <CommCtrl.h>
15#include <commdlg.h>
16#include <string>
17#include <strsafe.h>
18#include <sstream>
19#include <iomanip>
20#include <stdio.h>
21#include <vector>
22#include <shellapi.h>
23//#include "helpers.h"
24#include "PEHeaders.h"
25#include "resource.h"
26
27
28std::wstring AnsiToWide(const char* str) {
29 if (!str) return L"";
30 int size = MultiByteToWideChar(CP_ACP, 0, str, -1, nullptr, 0);
31 if (size <= 0) return L"";
32 std::vector<wchar_t> buf(size);
33 MultiByteToWideChar(CP_ACP, 0, str, -1, buf.data(), size);
34 return std::wstring(buf.data());
35}
36
37std::wstring Utf8ToWide(const char* str) {
38 if (!str) return L"";
39 int size = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0);
40 if (size <= 0) return L"";
41 std::vector<wchar_t> buf(size);
42 MultiByteToWideChar(CP_UTF8, 0, str, -1, buf.data(), size);
43 return std::wstring(buf.data());
44}
45
46#pragma comment(lib, "comctl32.lib")
47
48//namespace was here
49
50// Window defines
51#define WINDOW_CLASS_NAME L"PEAnalyzerWindow"
52#define OUTPUT(format, ...) AppendToOutput(L##format, ##__VA_ARGS__)
53#define WINDOW_WIDTH 1024
54#define WINDOW_HEIGHT 768
55#define EDIT_MARGIN 10
56
57// Global variables
58HWND g_hMainWindow = NULL;
59HWND g_hEditControl = NULL;
60HWND g_hStatusBar = NULL;
61HWND g_hProgressBar = NULL;
62HFONT g_hFont = NULL;
63std::wstringstream g_OutputText;
64std::vector<wchar_t> g_OutputBuffer;
65std::wstring tempBuffer;
66WCHAR filePathW[MAX_PATH];
67bool g_FileLoaded = false;
68
69// Resource parsing constants
70static const wchar_t* RESOURCE_TYPES[] = {
71 L"Unknown", L"Cursor", L"Bitmap", L"Icon",
72 L"Menu", L"Dialog", L"String", L"FontDir",
73 L"Font", L"Accelerator", L"RCData", L"MessageTable",
74 L"GroupCursor", L"GroupIcon", L"Version", L"DlgInclude"
75};
76
77//adding structs here now
78
79enum class FileValidationResult {
80 Valid,
81 InvalidPath,
82 FileNotFound,
83 AccessDenied,
84 UnsupportedType
85};
86
87// Forward declarations for global functions
88void UpdateEditControl();
89void AppendToOutput(const wchar_t* format, ...);
90void SetStatusText(const wchar_t* text);
91void ShowProgress(int percentage);
92void OpenFileDialog(HWND hwnd);
93void AnalyzePEFile(const wchar_t* filePathW);
94//analyzepefile 4wd func
95HANDLE GetFileContent(const wchar_t* lpFilePath);
96void OpenFileDialog(HWND hwnd); // Add these in the global scope, before any namespace declarations
97
98// GUI-related forward declarations
99LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
100LRESULT CALLBACK EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam,
101 LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
102void CreateMainWindow(HINSTANCE hInstance);
103void InitializeControls(HWND hwnd);
104void AddMenus(HWND hwnd);
105//void SetStatusText(const wchar_t* text);
106//void ShowProgress(int percentage);
107//void UpdateEditControl();
108DWORD GetFileSizeCustom(const wchar_t* filePath);
109
110//bool Is64BitPE(PIMAGE_NT_HEADERS pNtHeaders);
111
112
113//using namespace std;
114//using namespace PEParser;
115//using namespace PEHelpers;
116
117//namespace PEParser {
118
119//struct PEAnalyzer; // Forward declaration
120class FileMapper;
121FileValidationResult ValidatePEFile(const wchar_t* filePath);
122bool InitializePEAnalyzer(PEAnalyzer& analyzer, const wchar_t* filePath);
123//class FileValidationResult ValidatePEFile(const wchar_t* filePath);
124void ParseSections(const PEAnalyzer& analyzer); //forwarddeclare parse+ bring namespace up
125void ParseImportDirectory(const PEAnalyzer& analyzer);
126void ParseExportDirectory(const PEAnalyzer& analyzer);
127void ParseResourceDirectory(const PEAnalyzer& analyzer);
128void ParseDebugDirectory(const PEAnalyzer& analyzer);
129void AnalyzeHeaders(const PEAnalyzer& analyzer);
130void AnalyzeDataDirectories(const PEAnalyzer& analyzer);
131//bool InitializePEAnalyzer(PEAnalyzer& analyzer, const wchar_t* filePath);
132
133//newglobals
134void ParseNTHeader64(const PEAnalyzer& analyzer);
135void ParseNTHeader32(const PEAnalyzer& analyzer);
136void ParseImportFunctions32(const PEAnalyzer& analyzer, PIMAGE_IMPORT_DESCRIPTOR pImportDesc);
137void ParseImportFunctions64(const PEAnalyzer& analyzer, PIMAGE_IMPORT_DESCRIPTOR pImportDesc);
138void ParseExportedFunctions(const PEAnalyzer& analyzer, PIMAGE_EXPORT_DIRECTORY pExportDir,
139 PDWORD pFunctions, PDWORD pNames, PWORD pOrdinals);
140void ProcessResourceDirectory(
141 PIMAGE_RESOURCE_DIRECTORY resDir,
142 int level,
143 const wchar_t* type,
144 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
145 const PEAnalyzer& analyzer);
146void ProcessNamedResourceEntry(const IMAGE_RESOURCE_DIRECTORY_ENTRY& entry,
147 int level, PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
148 const PEAnalyzer& analyzer);
149void ProcessIdResourceEntry(const IMAGE_RESOURCE_DIRECTORY_ENTRY& entry,
150 int level, const wchar_t* type,
151 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
152 const PEAnalyzer& analyzer);
153void ProcessResourceSubdirectory(const IMAGE_RESOURCE_DIRECTORY_ENTRY& entry,
154 int level, const wchar_t* type,
155 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
156 const PEAnalyzer& analyzer);
157void ProcessResourceData(const IMAGE_RESOURCE_DIRECTORY_ENTRY& entry,
158 int level, const wchar_t* type,
159 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
160 const PEAnalyzer& analyzer);
161void ProcessDebugEntry(const IMAGE_DEBUG_DIRECTORY& debugEntry, const PEAnalyzer& analyzer);
162void ProcessRSDSDebugInfo(const IMAGE_DEBUG_DIRECTORY& debugEntry, DWORD* pCVHeader,
163 const PEAnalyzer& analyzer);
164void ProcessCodeViewDebugInfo(const IMAGE_DEBUG_DIRECTORY& debugEntry, const PEAnalyzer& analyzer);
165void ProcessNB10DebugInfo(const IMAGE_DEBUG_DIRECTORY& debugEntry, DWORD* pCVHeader,
166 const PEAnalyzer& analyzer);
167//void ParseImportDirectory(const PEAnalyzer& analyzer);
168//void ParseExportDirectory(const PEAnalyzer& analyzer);
169//DWORD GetFileSizeCustom(const wchar_t* filePath);
170//endnewglobals
171
172//using namespace std;
173//using namespace PEHelpers;
174//struct was here
175
176
177// File mapping helper class
178class FileMapper {
179private:
180 HANDLE hFile;
181 HANDLE hMapping;
182 LPVOID lpView;
183
184public:
185 FileMapper() : hFile(INVALID_HANDLE_VALUE), hMapping(nullptr), lpView(nullptr) {}
186 ~FileMapper() { Cleanup(); }
187
188 void Cleanup() {
189 if (lpView) {
190 UnmapViewOfFile(lpView);
191 lpView = nullptr;
192 }
193 if (hMapping) {
194 CloseHandle(hMapping);
195 hMapping = nullptr;
196 }
197 if (hFile != INVALID_HANDLE_VALUE) {
198 CloseHandle(hFile);
199 hFile = INVALID_HANDLE_VALUE;
200 }
201 }
202
203 bool Initialize(const wchar_t* path) {
204 Cleanup();
205
206 hFile = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
207 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
208 if (hFile == INVALID_HANDLE_VALUE) {
209 OUTPUT("[-] Failed to open file\n");
210 return false;
211 }
212
213 LARGE_INTEGER fileSize;
214 if (!GetFileSizeEx(hFile, &fileSize)) {
215 OUTPUT("[-] Failed to get file size\n");
216 Cleanup();
217 return false;
218 }
219
220 // Create mapping without SEC_IMAGE first
221 hMapping = CreateFileMappingW(hFile, nullptr, PAGE_READONLY,
222 fileSize.HighPart, fileSize.LowPart, nullptr);
223 if (!hMapping) {
224 OUTPUT("[-] Failed to create file mapping\n");
225 Cleanup();
226 return false;
227 }
228
229 lpView = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
230 if (!lpView) {
231 OUTPUT("[-] Failed to map view of file\n");
232 Cleanup();
233 return false;
234 }
235
236 return true;
237 }
238
239 LPVOID GetView() const { return lpView; }
240};
241
242FileValidationResult ValidatePEFile(const wchar_t* filePath) {
243 if (!filePath || wcslen(filePath) == 0) {
244 OUTPUT("[-] Null or empty file path\n");
245 return FileValidationResult::InvalidPath;
246 }
247
248 // Check file extension
249 const wchar_t* ext = wcsrchr(filePath, L'.');
250 if (!ext || (wcscmp(ext, L".exe") != 0 && wcscmp(ext, L".dll") != 0)) {
251 OUTPUT("[-] Unsupported file type. Only .exe and .dll are supported\n");
252 return FileValidationResult::UnsupportedType;
253 }
254
255 // Detailed file access check
256 HANDLE hFile = CreateFileW(
257 filePath,
258 GENERIC_READ,
259 FILE_SHARE_READ | FILE_SHARE_WRITE,
260 NULL,
261 OPEN_EXISTING,
262 FILE_ATTRIBUTE_NORMAL,
263 NULL
264 );
265
266 if (hFile == INVALID_HANDLE_VALUE) {
267 DWORD error = GetLastError();
268 switch (error) {
269 case ERROR_FILE_NOT_FOUND:
270 OUTPUT("[-] File not found: %ls\n", filePath);
271 return FileValidationResult::FileNotFound;
272 case ERROR_ACCESS_DENIED:
273 OUTPUT("[-] Access denied. Check file permissions: %ls\n", filePath);
274 return FileValidationResult::AccessDenied;
275 default:
276 OUTPUT("[-] File open error %d: %ls\n", error, filePath);
277 return FileValidationResult::InvalidPath;
278 }
279 }
280
281 // Additional checks
282 LARGE_INTEGER fileSize;
283 if (!GetFileSizeEx(hFile, &fileSize)) {
284 CloseHandle(hFile);
285 OUTPUT("[-] Cannot determine file size\n");
286 return FileValidationResult::InvalidPath;
287 }
288
289 CloseHandle(hFile);
290 return FileValidationResult::Valid;
291}
292
293// Initialization function
294bool InitializePEAnalyzer(PEAnalyzer& analyzer, const wchar_t* filePath) {
295 FileValidationResult validationResult = ValidatePEFile(filePath);
296 if (validationResult != FileValidationResult::Valid) {
297 OUTPUT("[-] File validation failed with code: %d\n", static_cast<int>(validationResult));
298 return false;
299 }
300
301 /*if (!analyzer.lpFileContent) {
302 OUTPUT("[-] No file content available\n");
303 return false;
304 }*/ //chatgpt4omitted
305
306 analyzer.pMapper = new FileMapper();
307 if (!analyzer.pMapper->Initialize(filePath)) {
308 OUTPUT("[-] Failed to map file. Detailed error in FileMapper\n");
309 return false;
310 }
311
312 analyzer.lpFileContent = analyzer.pMapper->GetView();
313 analyzer.fileSize = GetFileSizeCustom(filePath);
314 if (!analyzer.lpFileContent) {
315 OUTPUT("[-] Memory mapping failed\n");
316 return false;
317 }
318
319 // Validate DOS Header
320 analyzer.pDosHeader = static_cast<PIMAGE_DOS_HEADER>(analyzer.lpFileContent);
321 if (!IsSafeToRead(analyzer, analyzer.pDosHeader, sizeof(IMAGE_DOS_HEADER)) ||
322 analyzer.pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
323 OUTPUT("[-] Invalid DOS signature: 0x%X (Expected 0x%X)\n",
324 analyzer.pDosHeader->e_magic, IMAGE_DOS_SIGNATURE);
325 return false;
326 }
327
328 // Validate NT Header Offset
329 if (analyzer.pDosHeader->e_lfanew >= analyzer.fileSize ||
330 analyzer.pDosHeader->e_lfanew < sizeof(IMAGE_DOS_HEADER)) {
331 OUTPUT("[-] Invalid e_lfanew value: 0x%X\n", analyzer.pDosHeader->e_lfanew);
332 return false;
333 }
334
335 /* // Comprehensive PE signature validation
336 if (!analyzer.lpFileContent || analyzer.fileSize == 0) {
337 OUTPUT("[-] Memory mapping failed or file size is zero\n");
338 return false;
339 }
340
341 // Add bounds checking
342 if (analyzer.fileSize < sizeof(IMAGE_DOS_HEADER)) {
343 OUTPUT("[-] File too small to contain DOS header\n");
344 return false;
345 }
346
347 // DOS Header validation with extensive checks
348 analyzer.pDosHeader = static_cast<PIMAGE_DOS_HEADER>(analyzer.lpFileContent);
349
350 // Validate DOS header
351 //if (!IsSafeToRead(analyzer, analyzer.pDosHeader, sizeof(IMAGE_DOS_HEADER))) {
352 // OUTPUT("[-] Invalid DOS header access\n");
353 return false;
354 //}
355
356 // More robust DOS signature check
357 if (analyzer.pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
358 OUTPUT("[-] Invalid DOS signature: 0x%X (Expected 0x%X)\n",
359 analyzer.pDosHeader->e_magic, IMAGE_DOS_SIGNATURE);
360 return false;
361 }
362
363 // Validate e_lfanew with more checks
364 if (analyzer.pDosHeader->e_lfanew >= analyzer.fileSize ||
365 analyzer.pDosHeader->e_lfanew < sizeof(IMAGE_DOS_HEADER)) {
366 OUTPUT("[-] Invalid e_lfanew value: 0x%X\n", analyzer.pDosHeader->e_lfanew);
367 return false;
368 } */ //chatgpt4omitted
369
370 /*analyzer.lpFileContent = mapper.GetView();
371 if (!analyzer.lpFileContent) {
372 OUTPUT("[-] Failed to get file view. Memory mapping issue.\n");
373 return false;
374 }
375
376 analyzer.fileSize = GetFileSizeCustom(filePath);
377 if (!analyzer.fileSize) {
378 OUTPUT("[-] Unable to determine file size. File might be empty.\n");
379 return false;
380 }*/
381
382 // Validate file content
383 /*if (analyzer.fileSize < sizeof(IMAGE_DOS_HEADER)) {
384 OUTPUT("[-] File too small to be a valid PE\n");
385 return false;
386 }
387
388 analyzer.pDosHeader = static_cast<PIMAGE_DOS_HEADER>(analyzer.lpFileContent);
389 if (!analyzer.pDosHeader || analyzer.pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
390 OUTPUT("[-] Invalid DOS signature\n");
391 return false;
392 }
393
394 // Validate e_lfanew
395 if (analyzer.pDosHeader->e_lfanew >= analyzer.fileSize ||
396 analyzer.pDosHeader->e_lfanew < sizeof(IMAGE_DOS_HEADER)) {
397 OUTPUT("[-] Invalid e_lfanew value\n");
398 return false;
399 }*/
400
401 // Validate NT Headers
402 LONG ntHeaderOffset = analyzer.pDosHeader->e_lfanew;
403 auto pNtHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(
404 static_cast<BYTE*>(analyzer.lpFileContent) + ntHeaderOffset);
405
406 if (!IsSafeToRead(analyzer, pNtHeaders, sizeof(IMAGE_NT_HEADERS)) ||
407 pNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
408 OUTPUT("[-] Invalid NT signature: 0x%X (Expected 0x%X)\n",
409 pNtHeaders->Signature, IMAGE_NT_SIGNATURE);
410 return false;
411 }
412
413 /* // Validate NT Headers location
414 LONG ntHeaderOffset = analyzer.pDosHeader->e_lfanew;
415 if (ntHeaderOffset <= 0 ||
416 ntHeaderOffset >= analyzer.fileSize ||
417 ntHeaderOffset < sizeof(IMAGE_DOS_HEADER)) {
418 OUTPUT("[-] Invalid NT Headers offset: 0x%X\n", ntHeaderOffset);
419 return false;
420 }
421
422 // NT Headers signature validation
423 auto pNtHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(
424 static_cast<BYTE*>(analyzer.lpFileContent) + ntHeaderOffset);
425
426 if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
427 OUTPUT("[-] Invalid NT signature: 0x%X (Expected 0x%X)\n",
428 pNtHeaders->Signature,
429 IMAGE_NT_SIGNATURE);
430 return false;
431 } */ //chatgpt4omitted
432
433 /*if (IsBadReadPtr(pNtHeaders, sizeof(IMAGE_NT_HEADERS)) ||
434 pNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
435 OUTPUT("[-] Invalid NT signature\n");
436 return false;
437 }*/
438
439 // Determine architecture with additional safety checks
440 // Determine Architecture
441 /* WORD magicNumber = pNtHeaders->OptionalHeader.Magic;
442 analyzer.is64Bit = (magicNumber == IMAGE_NT_OPTIONAL_HDR64_MAGIC);
443 if (analyzer.is64Bit) {
444 analyzer.pNtHeaders64 = reinterpret_cast<PIMAGE_NT_HEADERS64>(pNtHeaders);
445 analyzer.pNtHeaders32 = nullptr;
446 }
447 else {
448 analyzer.pNtHeaders32 = reinterpret_cast<PIMAGE_NT_HEADERS32>(pNtHeaders);
449 analyzer.pNtHeaders64 = nullptr;
450 }*/ //chatgpt4omitted
451
452 // Determine Architecture
453 WORD magicNumber = pNtHeaders->OptionalHeader.Magic;
454 analyzer.is64Bit = (magicNumber == IMAGE_NT_OPTIONAL_HDR64_MAGIC);
455 if (analyzer.is64Bit) {
456 analyzer.pNtHeaders64 = reinterpret_cast<PIMAGE_NT_HEADERS64>(pNtHeaders);
457 analyzer.pNtHeaders32 = nullptr;
458 }
459 else {
460 analyzer.pNtHeaders32 = reinterpret_cast<PIMAGE_NT_HEADERS32>(pNtHeaders);
461 analyzer.pNtHeaders64 = nullptr;
462 }
463
464 return true;
465}
466
467
468// return true;
469//}
470/* catch (const std::exception& ex) {
471 OUTPUT("[-] Initialization error: %s\n", ex.what());
472 return false;
473}
474catch (...) {
475 OUTPUT("[-] Unknown initialization error\n");
476 return false;
477}
478} */ //chatgpt4omitted
479
480// Helper function for file size
481DWORD GetFileSizeCustom(const wchar_t* filePath) {
482 HANDLE hFile = CreateFileW(filePath, GENERIC_READ, FILE_SHARE_READ,
483 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
484 if (hFile == INVALID_HANDLE_VALUE) return 0;
485
486 DWORD fileSize = ::GetFileSize(hFile, nullptr);
487 CloseHandle(hFile);
488 return fileSize;
489} //removing other not this duplicate
490
491// Main analysis function
492void AnalyzePEFile(const wchar_t* filePathW) {
493 if (!filePathW || wcslen(filePathW) == 0) {
494 OUTPUT("[-] Invalid file path\n");
495 SetStatusText(L"Invalid file path!");
496 ShowProgress(0);
497 return;
498 }
499
500
501 /* // Check file extension
502 const wchar_t* ext = wcsrchr(filePathW, L'.');
503 if (!ext || (wcscmp(ext, L".exe") != 0 && wcscmp(ext, L".dll") != 0)) {
504 OUTPUT("[-] Unsupported file type. Use .exe or .dll\n");
505 SetStatusText(L"Unsupported file type!");
506 ShowProgress(0);
507 return;
508 } */
509
510 /* // Check if file exists
511 HANDLE hFile = CreateFileW(filePathW, GENERIC_READ, FILE_SHARE_READ,
512 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
513 if (hFile == INVALID_HANDLE_VALUE) {
514 DWORD error = GetLastError();
515 OUTPUT("[-] Cannot open file. Error code: %d\n", error);
516 SetStatusText(L"Failed to open file!");
517 ShowProgress(0);
518 return;
519 }
520 CloseHandle(hFile); */
521
522 // Reset and prepare for analysis
523 g_OutputText.str(L"");
524 g_OutputText.clear();
525 UpdateEditControl();
526
527 OUTPUT("[+] Starting PE Analysis for: %ls\n\n", filePathW);
528 SetStatusText(L"Analyzing PE File...");
529 ShowProgress(10);
530 //ShowProgress(10);
531
532 PEAnalyzer analyzer;
533 try {
534 if (!InitializePEAnalyzer(analyzer, filePathW)) {
535 OUTPUT("[-] PE Initialization Failed\n");
536 SetStatusText(L"PE Analysis Failed");
537 ShowProgress(0);
538 UpdateEditControl();
539 return;
540 }
541
542 // Add safety check
543 /*if (!analyzer.lpFileContent || !analyzer.pDosHeader) {
544 OUTPUT("[-] Invalid PE file structure\n");
545 SetStatusText(L"Invalid PE File");
546 ShowProgress(0);
547 UpdateEditControl();
548 return;
549 }*/
550
551
552 /* analyzer.lpFileContent = mapper.GetView();
553 analyzer.fileSize = GetFileSizeCustom(filePathW);
554
555 if (!InitializePEAnalyzer(analyzer, filePathW)) {
556 OUTPUT("[-] PE Initialization Failed\n");
557 SetStatusText(L"Analysis Failed - Invalid PE");
558 ShowProgress(0);
559 return;
560 } */ //chatgpt4omitted
561
562 // Detailed logging for architecture
563 OUTPUT("[+] File Architecture: %ls\n", analyzer.is64Bit ? L"64-bit" : L"32-bit");
564
565 // Show initial progress
566 ShowProgress(10);
567 /*
568 // Add null checks before processing
569 if (!analyzer.lpFileContent) {
570 OUTPUT("[-] No file content available\n");
571 SetStatusText(L"Failed to read file content!");
572 ShowProgress(0);
573 return;
574 }
575
576 // Inside AnalyzePEFile, before parsing headers
577 if (analyzer.is64Bit) {
578 if (!PEHelpers::ValidateFileSize(analyzer.pNtHeaders64->OptionalHeader.SizeOfImage, analyzer.fileSize)) {
579 OUTPUT("[-] PE file size mismatch with 64-bit image size!\n");
580 throw std::runtime_error("Invalid file size or PE image");
581 }
582 }
583 else {
584 if (!PEHelpers::ValidateFileSize(analyzer.pNtHeaders32->OptionalHeader.SizeOfImage, analyzer.fileSize)) {
585 OUTPUT("[-] PE file size mismatch with 32-bit image size!\n");
586 throw std::runtime_error("Invalid file size or PE image");
587 }
588 }
589 */
590 // Wrap each analysis step in its own try-catch
591 // Basic headers analysis
592 try {
593 ShowProgress(20);
594 AnalyzeHeaders(analyzer);
595 }
596 catch (const std::exception& ex) {
597 OUTPUT("[-] Header Analysis Error: %ls\n", ex.what());
598 throw; // Re-throw to handle in the outer catch block
599 }
600 //AnalyzeHeaders(analyzer);
601
602 // Data directories
603 try {
604 ShowProgress(30);
605 AnalyzeDataDirectories(analyzer);
606 }
607 catch (const std::exception& ex) {
608 OUTPUT("[-] Data Directories Analysis Error: %ls\n", ex.what());
609 throw; // Re-throw to handle in the outer catch block
610 }
611 //AnalyzeDataDirectories(analyzer);
612
613 // Parse sections
614 try {
615 ShowProgress(40);
616 ParseSections(analyzer);
617 }
618 catch (const std::exception& ex) {
619 OUTPUT("[-] Sections Parsing Error: %ls\n", ex.what());
620 throw; // Re-throw to handle in the outer catch block
621 }
622
623 //ParseSections(analyzer);
624
625 // Parse imports
626 try {
627 ShowProgress(50);
628 ParseImportDirectory(analyzer);
629 }
630 catch (const std::exception& ex) {
631 OUTPUT("[-] Import Directory Parsing Error: %ls\n", ex.what());
632 throw; // Re-throw to handle in the outer catch block
633 }
634 //ParseImportDirectory(analyzer);
635
636 // Parse exports
637 try {
638 ShowProgress(60);
639 ParseExportDirectory(analyzer);
640 }
641 catch (const std::exception& ex) {
642 OUTPUT("[-] Export Directory Parsing Error: %ls\n", ex.what());
643 throw; // Re-throw to handle in the outer catch block
644 }
645 //ParseExportDirectory(analyzer);
646
647 // Parse resources
648 try {
649 ShowProgress(70);
650 ParseResourceDirectory(analyzer);
651 }
652 catch (const std::exception& ex) {
653 OUTPUT("[-] Resource Directory Parsing Error: %ls\n", ex.what());
654 throw; // Re-throw to handle in the outer catch block
655 }
656 //ParseResourceDirectory(analyzer);
657
658 // Parse debug info
659 try {
660 ShowProgress(80);
661 ParseDebugDirectory(analyzer);
662 }
663 catch (const std::exception& ex) {
664 OUTPUT("[-] Debug Directory Parsing Error: %ls\n", ex.what());
665 throw; // Re-throw to handle in the outer catch block
666 }
667 //ParseDebugDirectory(analyzer);
668
669 ShowProgress(100);
670 SetStatusText(L"Analysis Complete");
671
672 // Mark that a file is loaded.
673 g_FileLoaded = true;
674
675 // Enable the "Select All" menu item.
676 HMENU hMenu = GetMenu(g_hMainWindow);
677 HMENU hFileMenu = GetSubMenu(hMenu, 0); // Assuming "File" is the first menu
678 EnableMenuItem(hFileMenu, 2, MF_BYCOMMAND | MF_ENABLED);
679 //EnableMenuItem(hFileMenu, ID_FILE_SELECTALL, MF_BYCOMMAND | MF_ENABLED);
680 DrawMenuBar(g_hMainWindow);
681
682 if (analyzer.pMapper) {
683 delete analyzer.pMapper;
684 analyzer.pMapper = nullptr;
685 }
686 }
687 //}
688 catch (const std::exception& ex) {
689 OUTPUT("[-] Unexpected Exception: %ls\n", ex.what());
690 SetStatusText(L"Analysis Failed");
691 ShowProgress(0);
692 }
693 catch (...) {
694 OUTPUT("[-] Unknown critical error during PE analysis\n");
695 SetStatusText(L"Critical Failure");
696 ShowProgress(0);
697 }
698 /*catch (const std::exception& ex) {
699 OUTPUT("[-] Exception during analysis: %s\n", ex.what());
700 SetStatusText(L"Analysis failed due to error.");
701 ShowProgress(0);
702 return;
703 }*/ //newly commented out
704 /*catch (const std::exception& e) {
705 OUTPUT("[-] Error during analysis: %s\n", e.what());
706 SetStatusText(L"Analysis failed!");
707 }*/
708
709 //ShowWindow(g_hProgressBar, SW_HIDE);
710 // Ensure edit control is updated
711 UpdateEditControl();
712 analyzer.~PEAnalyzer(); // Explicit call to the destructor if not already invoked
713}
714
715//amalgamating parsing funcs here experimental
716
717 // Header analysis function
718void AnalyzeHeaders(const PEAnalyzer& analyzer) {
719 if (!analyzer.lpFileContent || !analyzer.pDosHeader) {
720 throw std::runtime_error("Invalid PE headers");
721 }
722
723 OUTPUT("[+] PE IMAGE INFORMATION\n\n");
724 OUTPUT("[+] Architecture: %ls\n\n", analyzer.is64Bit ? L"x64" : L"x86");
725
726 // Validate DOS Header
727 if (!IsSafeToRead(analyzer, analyzer.pDosHeader, sizeof(IMAGE_DOS_HEADER))) {
728 throw std::runtime_error("Invalid DOS header");
729 }
730
731 // DOS Header
732 OUTPUT("[+] DOS HEADER\n");
733 OUTPUT("\te_magic : 0x%X\n", analyzer.pDosHeader->e_magic);
734 OUTPUT("\te_cblp : 0x%X\n", analyzer.pDosHeader->e_cblp);
735 OUTPUT("\te_cp : 0x%X\n", analyzer.pDosHeader->e_cp);
736 OUTPUT("\te_crlc : 0x%X\n", analyzer.pDosHeader->e_crlc);
737 OUTPUT("\te_cparhdr : 0x%X\n", analyzer.pDosHeader->e_cparhdr);
738 OUTPUT("\te_minalloc : 0x%X\n", analyzer.pDosHeader->e_minalloc);
739 OUTPUT("\te_maxalloc : 0x%X\n", analyzer.pDosHeader->e_maxalloc);
740 OUTPUT("\te_ss : 0x%X\n", analyzer.pDosHeader->e_ss);
741 OUTPUT("\te_sp : 0x%X\n", analyzer.pDosHeader->e_sp);
742 OUTPUT("\te_csum : 0x%X\n", analyzer.pDosHeader->e_csum);
743 OUTPUT("\te_ip : 0x%X\n", analyzer.pDosHeader->e_ip);
744 OUTPUT("\te_cs : 0x%X\n", analyzer.pDosHeader->e_cs);
745 OUTPUT("\te_lfarlc : 0x%X\n", analyzer.pDosHeader->e_lfarlc);
746 OUTPUT("\te_ovno : 0x%X\n", analyzer.pDosHeader->e_ovno);
747 OUTPUT("\te_oemid : 0x%X\n", analyzer.pDosHeader->e_oemid);
748 OUTPUT("\te_oeminfo : 0x%X\n", analyzer.pDosHeader->e_oeminfo);
749 OUTPUT("\te_lfanew : 0x%X\n\n", analyzer.pDosHeader->e_lfanew);
750
751 // Validate NT Headers
752 if (analyzer.is64Bit && analyzer.pNtHeaders64) {
753 ParseNTHeader64(analyzer);
754 }
755 else if (analyzer.pNtHeaders32) {
756 ParseNTHeader32(analyzer);
757 }
758 else {
759 throw std::runtime_error("Invalid NT headers");
760 }
761}
762
763void ParseNTHeader32(const PEAnalyzer& analyzer) {
764 if (!analyzer.pNtHeaders32) {
765 throw std::runtime_error("Invalid NT headers");
766 }
767
768 OUTPUT("[+] NT HEADER (32-bit)\n");
769 OUTPUT("\tSignature: 0x%X\n\n", analyzer.pNtHeaders32->Signature);
770
771 // File Header
772 OUTPUT("[+] FILE HEADER\n");
773 OUTPUT("\tMachine: 0x%X\n", analyzer.pNtHeaders32->FileHeader.Machine);
774 OUTPUT("\tNumberOfSections: 0x%X\n", analyzer.pNtHeaders32->FileHeader.NumberOfSections);
775 OUTPUT("\tTimeDateStamp: 0x%X\n", analyzer.pNtHeaders32->FileHeader.TimeDateStamp);
776 OUTPUT("\tPointerToSymbolTable: 0x%X\n", analyzer.pNtHeaders32->FileHeader.PointerToSymbolTable);
777 OUTPUT("\tNumberOfSymbols: 0x%X\n", analyzer.pNtHeaders32->FileHeader.NumberOfSymbols);
778 OUTPUT("\tSizeOfOptionalHeader: 0x%X\n", analyzer.pNtHeaders32->FileHeader.SizeOfOptionalHeader);
779 OUTPUT("\tCharacteristics: 0x%X\n\n", analyzer.pNtHeaders32->FileHeader.Characteristics);
780
781 // Optional Header
782 OUTPUT("[+] OPTIONAL HEADER\n");
783 OUTPUT("\tMagic: 0x%X\n", analyzer.pNtHeaders32->OptionalHeader.Magic);
784 OUTPUT("\tAddressOfEntryPoint: 0x%X\n", analyzer.pNtHeaders32->OptionalHeader.AddressOfEntryPoint);
785 OUTPUT("\tImageBase: 0x%X\n", analyzer.pNtHeaders32->OptionalHeader.ImageBase);
786 OUTPUT("\tSectionAlignment: 0x%X\n", analyzer.pNtHeaders32->OptionalHeader.SectionAlignment);
787 OUTPUT("\tFileAlignment: 0x%X\n", analyzer.pNtHeaders32->OptionalHeader.FileAlignment);
788 OUTPUT("\tSizeOfImage: 0x%X\n", analyzer.pNtHeaders32->OptionalHeader.SizeOfImage);
789 OUTPUT("\tSizeOfHeaders: 0x%X\n", analyzer.pNtHeaders32->OptionalHeader.SizeOfHeaders);
790 OUTPUT("\tSubsystem: 0x%X\n\n", analyzer.pNtHeaders32->OptionalHeader.Subsystem);
791}
792
793void ParseNTHeader64(const PEAnalyzer& analyzer) {
794 if (!analyzer.pNtHeaders64) {
795 throw std::runtime_error("Invalid NT headers");
796 }
797
798 OUTPUT("[+] NT HEADER (64-bit)\n");
799 OUTPUT("\tSignature: 0x%X\n\n", analyzer.pNtHeaders64->Signature);
800
801 // File Header
802 OUTPUT("[+] FILE HEADER\n");
803 OUTPUT("\tMachine: 0x%X\n", analyzer.pNtHeaders64->FileHeader.Machine);
804 OUTPUT("\tNumberOfSections: 0x%X\n", analyzer.pNtHeaders64->FileHeader.NumberOfSections);
805 OUTPUT("\tTimeDateStamp: 0x%X\n", analyzer.pNtHeaders64->FileHeader.TimeDateStamp);
806 OUTPUT("\tPointerToSymbolTable: 0x%X\n", analyzer.pNtHeaders64->FileHeader.PointerToSymbolTable);
807 OUTPUT("\tNumberOfSymbols: 0x%X\n", analyzer.pNtHeaders64->FileHeader.NumberOfSymbols);
808 OUTPUT("\tSizeOfOptionalHeader: 0x%X\n", analyzer.pNtHeaders64->FileHeader.SizeOfOptionalHeader);
809 OUTPUT("\tCharacteristics: 0x%X\n\n", analyzer.pNtHeaders64->FileHeader.Characteristics);
810
811 // Optional Header
812 OUTPUT("[+] OPTIONAL HEADER\n");
813 OUTPUT("\tMagic: 0x%X\n", analyzer.pNtHeaders64->OptionalHeader.Magic);
814 OUTPUT("\tAddressOfEntryPoint: 0x%X\n", analyzer.pNtHeaders64->OptionalHeader.AddressOfEntryPoint);
815 OUTPUT("\tImageBase: 0x%llX\n", analyzer.pNtHeaders64->OptionalHeader.ImageBase);
816 OUTPUT("\tSectionAlignment: 0x%X\n", analyzer.pNtHeaders64->OptionalHeader.SectionAlignment);
817 OUTPUT("\tFileAlignment: 0x%X\n", analyzer.pNtHeaders64->OptionalHeader.FileAlignment);
818 OUTPUT("\tSizeOfImage: 0x%X\n", analyzer.pNtHeaders64->OptionalHeader.SizeOfImage);
819 OUTPUT("\tSizeOfHeaders: 0x%X\n", analyzer.pNtHeaders64->OptionalHeader.SizeOfHeaders);
820 OUTPUT("\tSubsystem: 0x%X\n\n", analyzer.pNtHeaders64->OptionalHeader.Subsystem);
821}
822//}
823
824 //russianheat (clipped peanalyzefile() code here)
825
826
827 // Data Directories analysis
828void AnalyzeDataDirectories(const PEAnalyzer& analyzer) {
829 OUTPUT("[+] DATA DIRECTORIES\n");
830 const IMAGE_DATA_DIRECTORY* dataDirectories = analyzer.is64Bit ?
831 analyzer.pNtHeaders64->OptionalHeader.DataDirectory :
832 analyzer.pNtHeaders32->OptionalHeader.DataDirectory;
833
834 for (int i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) {
835 if (dataDirectories[i].VirtualAddress != 0) {
836 OUTPUT("\t%ls:\n", PEHelpers::GetDataDirectoryName(i).c_str());
837 OUTPUT("\t\tVirtualAddress: 0x%X\n", dataDirectories[i].VirtualAddress);
838 OUTPUT("\t\tSize: 0x%X\n", dataDirectories[i].Size);
839 }
840 }
841 OUTPUT("\n");
842}
843
844// Safe memory check helper
845template<typename T>
846bool IsSafeToRead(const PEAnalyzer& analyzer, const T* ptr, size_t size) {
847 if (!ptr) return false;
848 DWORD_PTR start = reinterpret_cast<DWORD_PTR>(analyzer.lpFileContent);
849 DWORD_PTR end = start + analyzer.fileSize;
850 DWORD_PTR ptrAddr = reinterpret_cast<DWORD_PTR>(ptr);
851 return (ptrAddr >= start && (ptrAddr + size) <= end);
852}
853
854// Section parsing with safety checks
855void ParseSections(const PEAnalyzer& analyzer) {
856 OUTPUT("[+] SECTION HEADERS\n");
857
858 PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(
859 analyzer.is64Bit ?
860 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders64) :
861 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders32));
862
863 WORD numberOfSections = analyzer.is64Bit ?
864 analyzer.pNtHeaders64->FileHeader.NumberOfSections :
865 analyzer.pNtHeaders32->FileHeader.NumberOfSections;
866
867 if (!IsSafeToRead(analyzer, pSection,
868 sizeof(IMAGE_SECTION_HEADER) * numberOfSections)) {
869 throw std::runtime_error("Invalid section headers");
870 }
871
872 for (WORD i = 0; i < numberOfSections; i++, pSection++) {
873 char sectionName[IMAGE_SIZEOF_SHORT_NAME + 1] = {};
874 memcpy(sectionName, pSection->Name, IMAGE_SIZEOF_SHORT_NAME);
875
876 // Sanitize section name
877 for (int j = 0; j < IMAGE_SIZEOF_SHORT_NAME; j++) {
878 if (!isprint(static_cast<unsigned char>(sectionName[j]))) {
879 sectionName[j] = '\0';
880 break;
881 }
882 }
883
884 // Output section information
885 OUTPUT("\tSECTION: %ls\n", AnsiToWide(sectionName).c_str());
886 OUTPUT("\t\tVirtualSize: 0x%X\n", pSection->Misc.VirtualSize);
887 OUTPUT("\t\tVirtualAddress: 0x%X\n", pSection->VirtualAddress);
888 OUTPUT("\t\tSizeOfRawData: 0x%X\n", pSection->SizeOfRawData);
889 OUTPUT("\t\tPointerToRawData: 0x%X\n", pSection->PointerToRawData);
890 OUTPUT("\t\tPointerToRelocations: 0x%X\n", pSection->PointerToRelocations);
891 OUTPUT("\t\tPointerToLinenumbers: 0x%X\n", pSection->PointerToLinenumbers);
892 OUTPUT("\t\tNumberOfRelocations: 0x%X\n", pSection->NumberOfRelocations);
893 OUTPUT("\t\tNumberOfLinenumbers: 0x%X\n", pSection->NumberOfLinenumbers);
894 OUTPUT("\t\tCharacteristics: 0x%X %ls\n\n",
895 pSection->Characteristics,
896 PEHelpers::GetSectionProtection(pSection->Characteristics).c_str());
897 }
898} //end of parsesection here
899
900 // Import Directory parsing with safety checks
901void ParseImportDirectory(const PEAnalyzer& analyzer) {
902 const auto& importDir = analyzer.is64Bit ?
903 analyzer.pNtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] :
904 analyzer.pNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
905
906 if (!importDir.VirtualAddress || !importDir.Size) {
907 OUTPUT("\n[-] No import directory found.\n");
908 return;
909 }
910
911 OUTPUT("\n[+] IMPORT DIRECTORY (%ls)\n", analyzer.is64Bit ? L"64-bit" : L"32-bit");
912
913 auto pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)PEHelpers::GetRvaPtr(
914 importDir.VirtualAddress,
915 IMAGE_FIRST_SECTION(analyzer.is64Bit ?
916 (PIMAGE_NT_HEADERS)analyzer.pNtHeaders64 :
917 (PIMAGE_NT_HEADERS)analyzer.pNtHeaders32),
918 analyzer.is64Bit ?
919 analyzer.pNtHeaders64->FileHeader.NumberOfSections :
920 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
921 analyzer.lpFileContent,
922 analyzer.fileSize);
923
924 if (!IsSafeToRead(analyzer, pImportDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
925 throw std::runtime_error("Invalid import descriptor");
926 }
927
928 while (pImportDesc->Name != 0) {
929 const char* dllName = (const char*)PEHelpers::GetRvaPtr(
930 pImportDesc->Name,
931 IMAGE_FIRST_SECTION(analyzer.is64Bit ?
932 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders64) :
933 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders32)),
934 analyzer.is64Bit ?
935 analyzer.pNtHeaders64->FileHeader.NumberOfSections :
936 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
937 analyzer.lpFileContent,
938 analyzer.fileSize);
939
940 if (!IsSafeToRead(analyzer, dllName, 1)) {
941 break;
942 }
943
944 if (dllName && !IsBadReadPtr(dllName, 1)) {
945 OUTPUT("\n\tDLL NAME: %ls\n", AnsiToWide(dllName).c_str());
946 OUTPUT("\tCharacteristics: 0x%X\n", pImportDesc->Characteristics);
947 OUTPUT("\tTimeDateStamp: 0x%X\n", pImportDesc->TimeDateStamp);
948 OUTPUT("\tForwarderChain: 0x%X\n", pImportDesc->ForwarderChain);
949 OUTPUT("\tFirstThunk: 0x%X\n\n", pImportDesc->FirstThunk);
950 OUTPUT("\tImported Functions:\n");
951 }
952
953 // Parse functions based on architecture
954 if (analyzer.is64Bit) {
955 ParseImportFunctions64(analyzer, pImportDesc);
956 }
957 else {
958 ParseImportFunctions32(analyzer, pImportDesc);
959 }
960
961 pImportDesc++;
962 if (!IsSafeToRead(analyzer, pImportDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
963 break;
964 }
965 }
966}
967
968void ParseImportFunctions32(const PEAnalyzer& analyzer, PIMAGE_IMPORT_DESCRIPTOR pImportDesc) {
969 auto pThunk = (PIMAGE_THUNK_DATA32)PEHelpers::GetRvaPtr(
970 pImportDesc->OriginalFirstThunk ? pImportDesc->OriginalFirstThunk : pImportDesc->FirstThunk,
971 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
972 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
973 analyzer.lpFileContent,
974 analyzer.fileSize);
975
976 while (pThunk && pThunk->u1.AddressOfData) {
977 if (!(pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32)) {
978 auto pImportByName = (PIMAGE_IMPORT_BY_NAME)PEHelpers::GetRvaPtr(
979 pThunk->u1.AddressOfData,
980 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
981 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
982 analyzer.lpFileContent,
983 analyzer.fileSize);
984
985 if (pImportByName && !IsBadReadPtr(pImportByName, sizeof(IMAGE_IMPORT_BY_NAME))) {
986 wchar_t wFuncName[MAX_PATH];
987 MultiByteToWideChar(CP_ACP, 0, pImportByName->Name, -1, wFuncName, MAX_PATH);
988 OUTPUT("\t\t%ls\n", wFuncName);
989 }
990 }
991 else {
992 OUTPUT("\t\tOrdinal: %d\n", pThunk->u1.Ordinal & 0xFFFF);
993 }
994 pThunk++;
995 }
996}
997
998void ParseImportFunctions64(const PEAnalyzer& analyzer, PIMAGE_IMPORT_DESCRIPTOR pImportDesc) {
999 auto pThunk = (PIMAGE_THUNK_DATA64)PEHelpers::GetRvaPtr(
1000 pImportDesc->OriginalFirstThunk ? pImportDesc->OriginalFirstThunk : pImportDesc->FirstThunk,
1001 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1002 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1003 analyzer.lpFileContent,
1004 analyzer.fileSize);
1005
1006 while (pThunk && pThunk->u1.AddressOfData) {
1007 if (!(pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64)) {
1008 auto pImportByName = (PIMAGE_IMPORT_BY_NAME)PEHelpers::GetRvaPtr(
1009 (DWORD)pThunk->u1.AddressOfData,
1010 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1011 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1012 analyzer.lpFileContent,
1013 analyzer.fileSize);
1014
1015 if (pImportByName && !IsBadReadPtr(pImportByName, sizeof(IMAGE_IMPORT_BY_NAME))) {
1016 wchar_t wFuncName[MAX_PATH];
1017 MultiByteToWideChar(CP_ACP, 0, pImportByName->Name, -1, wFuncName, MAX_PATH);
1018 OUTPUT("\t\t%ls\n", wFuncName);
1019 }
1020 }
1021 else {
1022 OUTPUT("\t\tOrdinal: %lld\n", pThunk->u1.Ordinal & 0xFFFF);
1023 }
1024 pThunk++;
1025 }
1026}
1027
1028// Export Directory parsing with safety checks
1029void ParseExportDirectory(const PEAnalyzer& analyzer) {
1030 const auto& exportDir = analyzer.is64Bit ?
1031 analyzer.pNtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] :
1032 analyzer.pNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
1033
1034 if (!exportDir.VirtualAddress || !exportDir.Size) {
1035 OUTPUT("\n[-] No export directory found.\n");
1036 return;
1037 }
1038
1039 OUTPUT("\n[+] EXPORT DIRECTORY (%ls)\n", analyzer.is64Bit ? L"64-bit" : L"32-bit");
1040
1041 auto pExportDir = (PIMAGE_EXPORT_DIRECTORY)PEHelpers::GetRvaPtr(
1042 exportDir.VirtualAddress,
1043 IMAGE_FIRST_SECTION(analyzer.is64Bit ?
1044 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders64) :
1045 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders32)),
1046 analyzer.is64Bit ?
1047 analyzer.pNtHeaders64->FileHeader.NumberOfSections :
1048 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1049 analyzer.lpFileContent,
1050 analyzer.fileSize);
1051
1052 if (!IsSafeToRead(analyzer, pExportDir, sizeof(IMAGE_EXPORT_DIRECTORY))) {
1053 throw std::runtime_error("Invalid export directory");
1054 }
1055
1056 // Output export directory information
1057 OUTPUT("\tCharacteristics: 0x%X\n", pExportDir->Characteristics);
1058 OUTPUT("\tTimeDateStamp: 0x%X\n", pExportDir->TimeDateStamp);
1059 OUTPUT("\tMajorVersion: %d\n", pExportDir->MajorVersion);
1060 OUTPUT("\tMinorVersion: %d\n", pExportDir->MinorVersion);
1061 OUTPUT("\tName: 0x%X\n", pExportDir->Name);
1062 OUTPUT("\tBase: %d\n", pExportDir->Base);
1063 OUTPUT("\tNumberOfFunctions: %d\n", pExportDir->NumberOfFunctions);
1064 OUTPUT("\tNumberOfNames: %d\n", pExportDir->NumberOfNames);
1065 OUTPUT("\tAddressOfFunctions: 0x%X\n", pExportDir->AddressOfFunctions);
1066 OUTPUT("\tAddressOfNames: 0x%X\n", pExportDir->AddressOfNames);
1067 OUTPUT("\tAddressOfNameOrdinals: 0x%X\n\n", pExportDir->AddressOfNameOrdinals);
1068
1069 // Get export tables with safety checks
1070
1071 // Add IMAGE_FIRST_SECTION and section count parameters
1072 auto pFunctions = (PDWORD)PEHelpers::GetRvaPtr(pExportDir->AddressOfFunctions,
1073 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1074 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1075 analyzer.lpFileContent,
1076 analyzer.fileSize);
1077
1078 auto pNames = (PDWORD)PEHelpers::GetRvaPtr(pExportDir->AddressOfNames,
1079 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1080 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1081 analyzer.lpFileContent,
1082 analyzer.fileSize);
1083
1084 auto pOrdinals = (PWORD)PEHelpers::GetRvaPtr(pExportDir->AddressOfNameOrdinals,
1085 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1086 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1087 analyzer.lpFileContent,
1088 analyzer.fileSize);
1089
1090 //auto pFunctions = (PDWORD)PEHelpers::GetRvaPtr(pExportDir->AddressOfFunctions, /*...*/);
1091 //auto pNames = (PDWORD)PEHelpers::GetRvaPtr(pExportDir->AddressOfNames, /*...*/);
1092 //auto pOrdinals = (PWORD)PEHelpers::GetRvaPtr(pExportDir->AddressOfNameOrdinals, /*...*/);
1093
1094 if (!IsSafeToRead(analyzer, pFunctions, sizeof(DWORD) * pExportDir->NumberOfFunctions) ||
1095 !IsSafeToRead(analyzer, pNames, sizeof(DWORD) * pExportDir->NumberOfNames) ||
1096 !IsSafeToRead(analyzer, pOrdinals, sizeof(WORD) * pExportDir->NumberOfNames)) {
1097 throw std::runtime_error("Invalid export tables");
1098 }
1099
1100 // Parse and output exported functions
1101 ParseExportedFunctions(analyzer, pExportDir, pFunctions, pNames, pOrdinals);
1102}
1103
1104void ParseExportedFunctions(const PEAnalyzer& analyzer, PIMAGE_EXPORT_DIRECTORY pExportDir,
1105 PDWORD pFunctions, PDWORD pNames, PWORD pOrdinals) {
1106
1107 OUTPUT("\tExported Functions:\n\n");
1108 for (DWORD i = 0; i < pExportDir->NumberOfNames; i++) {
1109 if (IsBadReadPtr(pNames + i, sizeof(DWORD)) ||
1110 IsBadReadPtr(pOrdinals + i, sizeof(WORD))) {
1111 break;
1112 }
1113
1114 const char* functionName = (const char*)PEHelpers::GetRvaPtr(
1115 pNames[i],
1116 analyzer.is64Bit ? IMAGE_FIRST_SECTION((PIMAGE_NT_HEADERS64)analyzer.pNtHeaders64) : IMAGE_FIRST_SECTION((PIMAGE_NT_HEADERS32)analyzer.pNtHeaders32),
1117 analyzer.is64Bit ? analyzer.pNtHeaders64->FileHeader.NumberOfSections : analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1118 analyzer.lpFileContent,
1119 analyzer.fileSize);
1120
1121 /*const char* functionName = (const char*)PEHelpers::GetRvaPtr(
1122 pNames[i],
1123 IMAGE_FIRST_SECTION(analyzer.is64Bit ? analyzer.pNtHeaders64 : analyzer.pNtHeaders32),
1124 analyzer.is64Bit ? analyzer.pNtHeaders64->FileHeader.NumberOfSections :
1125 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1126 analyzer.lpFileContent);*/
1127
1128 if (functionName && !IsBadReadPtr(functionName, 1)) {
1129 WORD ordinal = pOrdinals[i];
1130 if (ordinal < pExportDir->NumberOfFunctions) {
1131 DWORD functionRva = pFunctions[ordinal];
1132 wchar_t wFunctionName[MAX_PATH];
1133 MultiByteToWideChar(CP_ACP, 0, functionName, -1, wFunctionName, MAX_PATH);
1134 OUTPUT("\t\t%ls (Ordinal: %d, RVA: 0x%08X)\n", wFunctionName, ordinal + pExportDir->Base, functionRva);
1135 }
1136 }
1137 }
1138}
1139
1140void ParseResourceDirectory(const PEAnalyzer& analyzer) {
1141 const auto& resourceDir = analyzer.is64Bit ?
1142 analyzer.pNtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] :
1143 analyzer.pNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
1144
1145 if (!resourceDir.VirtualAddress || !resourceDir.Size) {
1146 OUTPUT("\n[-] No resource directory found.\n");
1147 return;
1148 }
1149
1150 OUTPUT("\n[+] RESOURCE DIRECTORY (%ls)\n", analyzer.is64Bit ? L"64-bit" : L"32-bit");
1151
1152 auto pResourceDir = (PIMAGE_RESOURCE_DIRECTORY)PEHelpers::GetRvaPtr(
1153 resourceDir.VirtualAddress,
1154 IMAGE_FIRST_SECTION(analyzer.is64Bit ?
1155 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders64) :
1156 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders32)),
1157 analyzer.is64Bit ?
1158 analyzer.pNtHeaders64->FileHeader.NumberOfSections :
1159 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1160 analyzer.lpFileContent,
1161 analyzer.fileSize);
1162
1163 if (!IsSafeToRead(analyzer, pResourceDir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
1164 throw std::runtime_error("Invalid resource directory");
1165 }
1166
1167 ProcessResourceDirectory(pResourceDir, 0, nullptr, pResourceDir, analyzer);
1168}
1169
1170void ProcessResourceDirectory(
1171 PIMAGE_RESOURCE_DIRECTORY resDir,
1172 int level,
1173 const wchar_t* type,
1174 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
1175 const PEAnalyzer& analyzer)
1176{
1177 if (!IsSafeToRead(analyzer, resDir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
1178 return;
1179 }
1180
1181 auto entry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resDir + 1);
1182 WORD totalEntries = resDir->NumberOfNamedEntries + resDir->NumberOfIdEntries;
1183
1184 for (WORD i = 0; i < totalEntries; i++) {
1185 if (!IsSafeToRead(analyzer, entry + i, sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY))) {
1186 break;
1187 }
1188
1189 // Indent based on level
1190 for (int indent = 0; indent < level; indent++) {
1191 OUTPUT("\t");
1192 }
1193
1194 // Process named entries
1195 if (entry[i].NameIsString) {
1196 ProcessNamedResourceEntry(entry[i], level, baseResourceDir, analyzer);
1197 }
1198 // Process ID entries
1199 else {
1200 ProcessIdResourceEntry(entry[i], level, type, baseResourceDir, analyzer);
1201 }
1202
1203 // Process subdirectories or data
1204 if (entry[i].DataIsDirectory) {
1205 ProcessResourceSubdirectory(entry[i], level, type, baseResourceDir, analyzer);
1206 }
1207 else {
1208 ProcessResourceData(entry[i], level, type, baseResourceDir, analyzer);
1209 }
1210 }
1211}
1212
1213//newlyfrom You,com Claude
1214void ProcessNamedResourceEntry(const IMAGE_RESOURCE_DIRECTORY_ENTRY& entry,
1215 int level, PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
1216 const PEAnalyzer& analyzer) {
1217
1218 auto nameEntry = (PIMAGE_RESOURCE_DIR_STRING_U)((BYTE*)baseResourceDir + (entry.NameOffset & 0x7FFFFFFF));
1219 if (!IsBadReadPtr(nameEntry, sizeof(IMAGE_RESOURCE_DIR_STRING_U))) {
1220 std::vector<wchar_t> resourceName(nameEntry->Length + 1);
1221 wcsncpy_s(resourceName.data(), nameEntry->Length + 1,
1222 nameEntry->NameString, nameEntry->Length);
1223 resourceName[nameEntry->Length] = L'\0';
1224
1225 if (level == 0) {
1226 OUTPUT("Resource Type: Custom (%ls)\n", resourceName.data());
1227 }
1228 else {
1229 OUTPUT("Name: %ls\n", resourceName.data());
1230 }
1231 }
1232}
1233
1234void ProcessIdResourceEntry(const IMAGE_RESOURCE_DIRECTORY_ENTRY& entry,
1235 int level, const wchar_t* type,
1236 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
1237 const PEAnalyzer& analyzer) {
1238
1239 if (level == 0) {
1240 DWORD resourceType = entry.Id;
1241 if (resourceType < 16) {
1242 OUTPUT("Resource Type: %ls (ID: %d)\n", RESOURCE_TYPES[resourceType], resourceType);
1243 }
1244 else {
1245 OUTPUT("Resource Type: Custom (ID: %d)\n", resourceType);
1246 }
1247 }
1248 else {
1249 OUTPUT("ID: %d\n", entry.Id);
1250 }
1251}
1252
1253void ProcessResourceSubdirectory(const IMAGE_RESOURCE_DIRECTORY_ENTRY& entry,
1254 int level, const wchar_t* type,
1255 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
1256 const PEAnalyzer& analyzer) {
1257
1258 auto nextDir = (PIMAGE_RESOURCE_DIRECTORY)((BYTE*)baseResourceDir + (entry.OffsetToDirectory & 0x7FFFFFFF));
1259 if (!IsBadReadPtr(nextDir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
1260 ProcessResourceDirectory(nextDir, level + 1,
1261 level == 0 ? RESOURCE_TYPES[min(entry.Id, 15)] : type,
1262 baseResourceDir, analyzer);
1263 }
1264}
1265
1266void ProcessResourceData(const IMAGE_RESOURCE_DIRECTORY_ENTRY& entry,
1267 int level, const wchar_t* type,
1268 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
1269 const PEAnalyzer& analyzer) {
1270
1271 auto dataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)((BYTE*)baseResourceDir + (entry.OffsetToData & 0x7FFFFFFF));
1272 if (!IsBadReadPtr(dataEntry, sizeof(IMAGE_RESOURCE_DATA_ENTRY))) {
1273 for (int indent = 0; indent < level + 1; indent++) {
1274 OUTPUT("\t");
1275 }
1276 OUTPUT("Size: %d bytes, RVA: 0x%X\n", dataEntry->Size, dataEntry->OffsetToData);
1277 }
1278}
1279
1280void ParseDebugDirectory(const PEAnalyzer& analyzer) {
1281 const auto& debugDir = analyzer.is64Bit ?
1282 analyzer.pNtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] :
1283 analyzer.pNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
1284
1285 if (!debugDir.VirtualAddress || !debugDir.Size) {
1286 OUTPUT("\n[-] No debug directory found.\n");
1287 return;
1288 }
1289
1290 OUTPUT("\n[+] DEBUG DIRECTORY (%ls)\n", analyzer.is64Bit ? L"64-bit" : L"32-bit");
1291
1292 auto pDebugDir = (PIMAGE_DEBUG_DIRECTORY)PEHelpers::GetRvaPtr(
1293 debugDir.VirtualAddress,
1294 IMAGE_FIRST_SECTION(analyzer.is64Bit ?
1295 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders64) :
1296 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders32)),
1297 analyzer.is64Bit ?
1298 analyzer.pNtHeaders64->FileHeader.NumberOfSections :
1299 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1300 analyzer.lpFileContent,
1301 analyzer.fileSize);
1302
1303 if (!IsSafeToRead(analyzer, pDebugDir, sizeof(IMAGE_DEBUG_DIRECTORY))) {
1304 throw std::runtime_error("Invalid debug directory");
1305 }
1306
1307 DWORD numEntries = min(debugDir.Size / sizeof(IMAGE_DEBUG_DIRECTORY), 16);
1308 for (DWORD i = 0; i < numEntries; i++) {
1309 ProcessDebugEntry(pDebugDir[i], analyzer);
1310 }
1311}
1312
1313void ProcessDebugEntry(const IMAGE_DEBUG_DIRECTORY& debugEntry, const PEAnalyzer& analyzer) {
1314 OUTPUT("\tDebug Entry:\n");
1315 OUTPUT("\tCharacteristics: 0x%X\n", debugEntry.Characteristics);
1316 OUTPUT("\tTimeDateStamp: 0x%X\n", debugEntry.TimeDateStamp);
1317 OUTPUT("\tVersion: %d.%d\n", debugEntry.MajorVersion, debugEntry.MinorVersion);
1318 OUTPUT("\tType: 0x%X", debugEntry.Type);
1319
1320 // Output debug type
1321 switch (debugEntry.Type) {
1322 case IMAGE_DEBUG_TYPE_COFF:
1323 OUTPUT(" (COFF)\n"); break;
1324 case IMAGE_DEBUG_TYPE_CODEVIEW:
1325 OUTPUT(" (CodeView)\n");
1326 ProcessCodeViewDebugInfo(debugEntry, analyzer);
1327 break;
1328 // ... other debug types ...
1329 default:
1330 OUTPUT(" (Unknown)\n"); break;
1331 }
1332
1333 OUTPUT("\tSizeOfData: 0x%X\n", debugEntry.SizeOfData);
1334 OUTPUT("\tAddressOfRawData: 0x%X\n", debugEntry.AddressOfRawData);
1335 OUTPUT("\tPointerToRawData: 0x%X\n\n", debugEntry.PointerToRawData);
1336}
1337
1338// Helper functions for processing specific debug info types
1339void ProcessCodeViewDebugInfo(const IMAGE_DEBUG_DIRECTORY& debugEntry, const PEAnalyzer& analyzer) {
1340 if (debugEntry.Type != IMAGE_DEBUG_TYPE_CODEVIEW ||
1341 !debugEntry.PointerToRawData ||
1342 debugEntry.SizeOfData < sizeof(DWORD)) {
1343 return;
1344 }
1345
1346 auto pCVHeader = (DWORD*)((BYTE*)analyzer.lpFileContent + debugEntry.PointerToRawData);
1347 if (!IsSafeToRead(analyzer, pCVHeader, sizeof(DWORD))) {
1348 return;
1349 }
1350
1351 // Process different CodeView formats
1352 switch (*pCVHeader) {
1353 case 0x53445352: // 'RSDS'
1354 ProcessRSDSDebugInfo(debugEntry, pCVHeader, analyzer);
1355 break;
1356 case 0x3031424E: // 'NB10'
1357 ProcessNB10DebugInfo(debugEntry, pCVHeader, analyzer);
1358 break;
1359 }
1360}
1361
1362void ProcessRSDSDebugInfo(const IMAGE_DEBUG_DIRECTORY& debugEntry, DWORD* pCVHeader,
1363 const PEAnalyzer& analyzer) {
1364
1365 if (debugEntry.SizeOfData >= (sizeof(DWORD) + sizeof(GUID) + sizeof(DWORD) + 1)) {
1366 auto pCVData = (char*)(pCVHeader + 1);
1367 if (!IsBadReadPtr(pCVData + 16, 1)) {
1368 auto guid = (GUID*)pCVData;
1369 DWORD age = *(DWORD*)(pCVData + 16);
1370 const char* pdbPath = pCVData + 20;
1371
1372 OUTPUT("\tPDB Information:\n");
1373 OUTPUT("\tGUID: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
1374 guid->Data1, guid->Data2, guid->Data3,
1375 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
1376 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
1377 OUTPUT("\tAge: %d\n", age);
1378 OUTPUT("\tPDB Path: %ls\n\n", AnsiToWide(pdbPath).c_str());
1379 }
1380 }
1381}
1382
1383void ProcessNB10DebugInfo(const IMAGE_DEBUG_DIRECTORY& debugEntry, DWORD* pCVHeader,
1384 const PEAnalyzer& analyzer) {
1385
1386 if (debugEntry.SizeOfData >= 16) {
1387 auto pNB10Data = (char*)(pCVHeader + 1);
1388 DWORD offset = *(DWORD*)pNB10Data;
1389 DWORD timestamp = *(DWORD*)(pNB10Data + 4);
1390 DWORD age = *(DWORD*)(pNB10Data + 8);
1391 const char* pdbPath = pNB10Data + 12;
1392
1393 OUTPUT("\tPDB Information (NB10):\n");
1394 OUTPUT("\tOffset: 0x%X\n", offset);
1395 OUTPUT("\tTimestamp: 0x%X\n", timestamp);
1396 OUTPUT("\tAge: %d\n", age);
1397 OUTPUT("\tPDB Path: %ls\n\n", pdbPath);
1398 }
1399}
1400
1401//colonelburton
1402
1403void ParseImportDirectory32(const PEAnalyzer& analyzer) {
1404 const auto& importDir = analyzer.pNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
1405 if (!importDir.VirtualAddress || !importDir.Size) return;
1406
1407 if (!PEHelpers::IsRvaValid(importDir.VirtualAddress, analyzer.fileSize,
1408 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders32))) {
1409 OUTPUT("[-] Invalid import directory RVA!\n");
1410 throw std::runtime_error("RVA out of bounds");
1411 return;
1412 }
1413
1414 OUTPUT("\n[+] IMPORT DIRECTORY (32-bit)\n");
1415 auto pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)PEHelpers::GetRvaPtr(
1416 importDir.VirtualAddress,
1417 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1418 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1419 analyzer.lpFileContent,
1420 analyzer.fileSize);
1421
1422 if (!pImportDesc) return;
1423
1424 while (pImportDesc->Name != 0) {
1425 if (IsBadReadPtr(pImportDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
1426 OUTPUT("[-] Invalid import descriptor detected!\n");
1427 break;
1428 }
1429
1430 const char* dllName = (const char*)PEHelpers::GetRvaPtr(
1431 pImportDesc->Name,
1432 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1433 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1434 analyzer.lpFileContent,
1435 analyzer.fileSize);
1436
1437 if (dllName && !IsBadReadPtr(dllName, 1)) {
1438 std::vector<wchar_t> wideDllName(MAX_PATH);
1439 MultiByteToWideChar(CP_UTF8, 0, dllName, -1, wideDllName.data(), MAX_PATH);
1440
1441 OUTPUT("\n\tDLL NAME: %ls\n", wideDllName.data());
1442 OUTPUT("\tCharacteristics: 0x%X\n", pImportDesc->Characteristics);
1443 OUTPUT("\tTimeDateStamp: 0x%X\n", pImportDesc->TimeDateStamp);
1444 OUTPUT("\tForwarderChain: 0x%X\n", pImportDesc->ForwarderChain);
1445 OUTPUT("\tFirstThunk: 0x%X\n", pImportDesc->FirstThunk);
1446 OUTPUT("\n\tImported Functions:\n");
1447
1448 auto pThunk = (PIMAGE_THUNK_DATA32)PEHelpers::GetRvaPtr(
1449 pImportDesc->OriginalFirstThunk ? pImportDesc->OriginalFirstThunk : pImportDesc->FirstThunk,
1450 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1451 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1452 analyzer.lpFileContent,
1453 analyzer.fileSize);
1454
1455 while (pThunk && pThunk->u1.AddressOfData) {
1456 if (!(pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32)) {
1457 auto pImportByName = (PIMAGE_IMPORT_BY_NAME)PEHelpers::GetRvaPtr(
1458 pThunk->u1.AddressOfData,
1459 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1460 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1461 analyzer.lpFileContent,
1462 analyzer.fileSize);
1463
1464 if (pImportByName && !IsBadReadPtr(pImportByName, sizeof(IMAGE_IMPORT_BY_NAME))) {
1465 std::vector<wchar_t> wideFuncName(MAX_PATH);
1466 MultiByteToWideChar(CP_ACP, 0, (char*)pImportByName->Name, -1,
1467 wideFuncName.data(), MAX_PATH);
1468 OUTPUT("\t\t%ls\n", wideFuncName.data());
1469 }
1470 }
1471 else {
1472 OUTPUT("\t\tOrdinal: %d\n", pThunk->u1.Ordinal & 0xFFFF);
1473 }
1474 pThunk++;
1475 }
1476 }
1477 pImportDesc++;
1478 }
1479}
1480
1481void ParseImportDirectory64(const PEAnalyzer& analyzer) {
1482 const auto& importDir = analyzer.pNtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
1483 if (!importDir.VirtualAddress || !importDir.Size) return;
1484
1485 if (!PEHelpers::IsRvaValid(importDir.VirtualAddress, analyzer.fileSize,
1486 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders64))) {
1487 OUTPUT("[-] Invalid import directory RVA!\n");
1488 throw std::runtime_error("RVA out of bounds");
1489 return;
1490 }
1491
1492 OUTPUT("\n[+] IMPORT DIRECTORY (64-bit)\n");
1493 auto pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)PEHelpers::GetRvaPtr(
1494 importDir.VirtualAddress,
1495 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1496 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1497 analyzer.lpFileContent,
1498 analyzer.fileSize);
1499
1500 if (!pImportDesc) return;
1501
1502 while (pImportDesc->Name != 0) {
1503 if (IsBadReadPtr(pImportDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
1504 OUTPUT("[-] Invalid import descriptor detected!\n");
1505 break;
1506 }
1507
1508 const char* dllName = (const char*)PEHelpers::GetRvaPtr(
1509 pImportDesc->Name,
1510 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1511 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1512 analyzer.lpFileContent,
1513 analyzer.fileSize);
1514
1515 if (dllName && !IsBadReadPtr(dllName, 1)) {
1516 std::vector<wchar_t> wideDllName(MAX_PATH);
1517 MultiByteToWideChar(CP_UTF8, 0, dllName, -1, wideDllName.data(), MAX_PATH);
1518
1519 OUTPUT("\n\tDLL NAME: %ls\n", wideDllName.data());
1520 OUTPUT("\tCharacteristics: 0x%X\n", pImportDesc->Characteristics);
1521 OUTPUT("\tTimeDateStamp: 0x%X\n", pImportDesc->TimeDateStamp);
1522 OUTPUT("\tForwarderChain: 0x%X\n", pImportDesc->ForwarderChain);
1523 OUTPUT("\tFirstThunk: 0x%X\n", pImportDesc->FirstThunk);
1524 OUTPUT("\n\tImported Functions:\n");
1525
1526 auto pThunk = (PIMAGE_THUNK_DATA64)PEHelpers::GetRvaPtr(
1527 pImportDesc->OriginalFirstThunk ? pImportDesc->OriginalFirstThunk : pImportDesc->FirstThunk,
1528 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1529 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1530 analyzer.lpFileContent,
1531 analyzer.fileSize);
1532
1533 while (pThunk && pThunk->u1.AddressOfData) {
1534 if (!(pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64)) {
1535 auto pImportByName = (PIMAGE_IMPORT_BY_NAME)PEHelpers::GetRvaPtr(
1536 (DWORD)pThunk->u1.AddressOfData,
1537 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1538 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1539 analyzer.lpFileContent,
1540 analyzer.fileSize);
1541
1542 if (pImportByName && !IsBadReadPtr(pImportByName, sizeof(IMAGE_IMPORT_BY_NAME))) {
1543 std::vector<wchar_t> wideFuncName(MAX_PATH);
1544 MultiByteToWideChar(CP_ACP, 0, (char*)pImportByName->Name, -1,
1545 wideFuncName.data(), MAX_PATH);
1546 OUTPUT("\t\t%ls\n", wideFuncName.data());
1547 }
1548 }
1549 else {
1550 OUTPUT("\t\tOrdinal: %lld\n", pThunk->u1.Ordinal & 0xFFFF);
1551 }
1552 pThunk++;
1553 }
1554 }
1555 pImportDesc++;
1556 }
1557}
1558
1559/*void ParseImportDirectory(const PEAnalyzer& analyzer) {
1560 if (analyzer.is64Bit) {
1561 ParseImportDirectory64(analyzer);
1562 }
1563 else {
1564 ParseImportDirectory32(analyzer);
1565 }
1566}*/ //removing the empty content duplicates
1567//}
1568
1569void ParseExportDirectory32(const PEAnalyzer& analyzer) {
1570 const auto& exportDir = analyzer.pNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
1571 if (!exportDir.VirtualAddress || !exportDir.Size) return;
1572
1573 if (!PEHelpers::IsRvaValid(exportDir.VirtualAddress, analyzer.fileSize,
1574 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders32))) {
1575 OUTPUT("[-] Invalid export directory RVA!\n");
1576 throw std::runtime_error("RVA out of bounds");
1577 return;
1578 }
1579
1580 OUTPUT("\n[+] EXPORT DIRECTORY (32-bit)\n");
1581 auto pExportDir = (PIMAGE_EXPORT_DIRECTORY)PEHelpers::GetRvaPtr(
1582 exportDir.VirtualAddress,
1583 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1584 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1585 analyzer.lpFileContent,
1586 analyzer.fileSize);
1587
1588 if (!pExportDir || IsBadReadPtr(pExportDir, sizeof(IMAGE_EXPORT_DIRECTORY))) {
1589 OUTPUT("[-] Invalid export directory structure!\n");
1590 return;
1591 }
1592
1593 OUTPUT("\tCharacteristics: 0x%X\n", pExportDir->Characteristics);
1594 OUTPUT("\tTimeDateStamp: 0x%X\n", pExportDir->TimeDateStamp);
1595 OUTPUT("\tMajorVersion: %d\n", pExportDir->MajorVersion);
1596 OUTPUT("\tMinorVersion: %d\n", pExportDir->MinorVersion);
1597 OUTPUT("\tName: 0x%X\n", pExportDir->Name);
1598 OUTPUT("\tBase: %d\n", pExportDir->Base);
1599 OUTPUT("\tNumberOfFunctions: %d\n", pExportDir->NumberOfFunctions);
1600 OUTPUT("\tNumberOfNames: %d\n", pExportDir->NumberOfNames);
1601 OUTPUT("\tAddressOfFunctions: 0x%X\n", pExportDir->AddressOfFunctions);
1602 OUTPUT("\tAddressOfNames: 0x%X\n", pExportDir->AddressOfNames);
1603 OUTPUT("\tAddressOfNameOrdinals: 0x%X\n\n", pExportDir->AddressOfNameOrdinals);
1604
1605 auto pFunctions = (PDWORD)PEHelpers::GetRvaPtr(
1606 pExportDir->AddressOfFunctions,
1607 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1608 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1609 analyzer.lpFileContent,
1610 analyzer.fileSize);
1611
1612 auto pNames = (PDWORD)PEHelpers::GetRvaPtr(
1613 pExportDir->AddressOfNames,
1614 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1615 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1616 analyzer.lpFileContent,
1617 analyzer.fileSize);
1618
1619 auto pNameOrdinals = (PWORD)PEHelpers::GetRvaPtr(
1620 pExportDir->AddressOfNameOrdinals,
1621 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1622 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1623 analyzer.lpFileContent,
1624 analyzer.fileSize);
1625
1626 if (!pNames || !pNameOrdinals || !pFunctions) {
1627 OUTPUT("[-] Invalid export address tables!\n");
1628 return;
1629 }
1630
1631 OUTPUT("\tExported Functions:\n\n");
1632 for (DWORD i = 0; i < pExportDir->NumberOfNames; i++) {
1633 if (IsBadReadPtr(pNames + i, sizeof(DWORD)) ||
1634 IsBadReadPtr(pNameOrdinals + i, sizeof(WORD))) {
1635 break;
1636 }
1637
1638 const char* functionName = (const char*)PEHelpers::GetRvaPtr(
1639 pNames[i],
1640 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1641 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1642 analyzer.lpFileContent,
1643 analyzer.fileSize);
1644
1645 if (functionName && !IsBadReadPtr(functionName, 1)) {
1646 WORD ordinal = pNameOrdinals[i];
1647 if (ordinal < pExportDir->NumberOfFunctions) {
1648 DWORD functionRva = pFunctions[ordinal];
1649
1650 // Check for forwarded export
1651 if (functionRva >= exportDir.VirtualAddress &&
1652 functionRva < (exportDir.VirtualAddress + exportDir.Size)) {
1653
1654 const char* forwardName = (const char*)PEHelpers::GetRvaPtr(
1655 functionRva,
1656 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1657 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1658 analyzer.lpFileContent,
1659 analyzer.fileSize);
1660
1661 if (forwardName && !IsBadReadPtr(forwardName, 1)) {
1662 std::vector<wchar_t> wideForwardName(MAX_PATH);
1663 MultiByteToWideChar(CP_ACP, 0, forwardName, -1,
1664 wideForwardName.data(), MAX_PATH);
1665 OUTPUT("\t\t%ls (Ordinal: %d) -> Forward to: %ls\n",
1666 functionName,
1667 ordinal + pExportDir->Base,
1668 wideForwardName.data());
1669 }
1670 }
1671 else {
1672 OUTPUT("\t\t%ls (Ordinal: %d, RVA: 0x%08X)\n",
1673 functionName,
1674 ordinal + pExportDir->Base,
1675 functionRva);
1676 }
1677 }
1678 }
1679 }
1680}
1681
1682void ParseExportDirectory64(const PEAnalyzer& analyzer) {
1683 const auto& exportDir = analyzer.pNtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
1684 if (!exportDir.VirtualAddress || !exportDir.Size) return;
1685
1686 if (!PEHelpers::IsRvaValid(exportDir.VirtualAddress, analyzer.fileSize,
1687 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders64))) {
1688 OUTPUT("[-] Invalid export directory RVA!\n");
1689 throw std::runtime_error("RVA out of bounds");
1690 return;
1691 }
1692
1693 OUTPUT("\n[+] EXPORT DIRECTORY (64-bit)\n");
1694 // Rest of the implementation is identical to 32-bit version
1695 // Just using pNtHeaders64 instead of pNtHeaders64
1696 auto pExportDir = (PIMAGE_EXPORT_DIRECTORY)PEHelpers::GetRvaPtr(
1697 exportDir.VirtualAddress,
1698 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1699 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1700 analyzer.lpFileContent,
1701 analyzer.fileSize);
1702
1703 if (!pExportDir || IsBadReadPtr(pExportDir, sizeof(IMAGE_EXPORT_DIRECTORY))) {
1704 OUTPUT("[-] Invalid export directory structure!\n");
1705 return;
1706 }
1707
1708 OUTPUT("\tCharacteristics: 0x%X\n", pExportDir->Characteristics);
1709 OUTPUT("\tTimeDateStamp: 0x%X\n", pExportDir->TimeDateStamp);
1710 OUTPUT("\tMajorVersion: %d\n", pExportDir->MajorVersion);
1711 OUTPUT("\tMinorVersion: %d\n", pExportDir->MinorVersion);
1712 OUTPUT("\tName: 0x%X\n", pExportDir->Name);
1713 OUTPUT("\tBase: %d\n", pExportDir->Base);
1714 OUTPUT("\tNumberOfFunctions: %d\n", pExportDir->NumberOfFunctions);
1715 OUTPUT("\tNumberOfNames: %d\n", pExportDir->NumberOfNames);
1716 OUTPUT("\tAddressOfFunctions: 0x%X\n", pExportDir->AddressOfFunctions);
1717 OUTPUT("\tAddressOfNames: 0x%X\n", pExportDir->AddressOfNames);
1718 OUTPUT("\tAddressOfNameOrdinals: 0x%X\n\n", pExportDir->AddressOfNameOrdinals);
1719
1720 auto pFunctions = (PDWORD)PEHelpers::GetRvaPtr(
1721 pExportDir->AddressOfFunctions,
1722 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1723 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1724 analyzer.lpFileContent,
1725 analyzer.fileSize);
1726
1727 auto pNames = (PDWORD)PEHelpers::GetRvaPtr(
1728 pExportDir->AddressOfNames,
1729 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1730 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1731 analyzer.lpFileContent,
1732 analyzer.fileSize);
1733
1734 auto pNameOrdinals = (PWORD)PEHelpers::GetRvaPtr(
1735 pExportDir->AddressOfNameOrdinals,
1736 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1737 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1738 analyzer.lpFileContent,
1739 analyzer.fileSize);
1740
1741 if (!pNames || !pNameOrdinals || !pFunctions) {
1742 OUTPUT("[-] Invalid export address tables!\n");
1743 return;
1744 }
1745
1746 OUTPUT("\tExported Functions:\n\n");
1747 for (DWORD i = 0; i < pExportDir->NumberOfNames; i++) {
1748 if (IsBadReadPtr(pNames + i, sizeof(DWORD)) ||
1749 IsBadReadPtr(pNameOrdinals + i, sizeof(WORD))) {
1750 break;
1751 }
1752
1753 const char* functionName = (const char*)PEHelpers::GetRvaPtr(
1754 pNames[i],
1755 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1756 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1757 analyzer.lpFileContent,
1758 analyzer.fileSize);
1759
1760 if (functionName && !IsBadReadPtr(functionName, 1)) {
1761 WORD ordinal = pNameOrdinals[i];
1762 if (ordinal < pExportDir->NumberOfFunctions) {
1763 DWORD functionRva = pFunctions[ordinal];
1764
1765 // Check for forwarded export
1766 if (functionRva >= exportDir.VirtualAddress &&
1767 functionRva < (exportDir.VirtualAddress + exportDir.Size)) {
1768
1769 const char* forwardName = (const char*)PEHelpers::GetRvaPtr(
1770 functionRva,
1771 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1772 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1773 analyzer.lpFileContent,
1774 analyzer.fileSize);
1775
1776 if (forwardName && !IsBadReadPtr(forwardName, 1)) {
1777 std::vector<wchar_t> wideForwardName(MAX_PATH);
1778 MultiByteToWideChar(CP_ACP, 0, forwardName, -1,
1779 wideForwardName.data(), MAX_PATH);
1780 OUTPUT("\t\t%ls (Ordinal: %d) -> Forward to: %ls\n",
1781 functionName,
1782 ordinal + pExportDir->Base,
1783 wideForwardName.data());
1784 }
1785 }
1786 else {
1787 OUTPUT("\t\t%ls (Ordinal: %d, RVA: 0x%08X)\n",
1788 functionName,
1789 ordinal + pExportDir->Base,
1790 functionRva);
1791 }
1792 }
1793 }
1794 }
1795}
1796// Copying the same logic as ParseExportDirectory32 but with 64-bit headers
1797// ... [Same implementation as above, just using pNtHeaders64]
1798
1799/*void ParseExportDirectory(const PEAnalyzer& analyzer) {
1800 if (analyzer.is64Bit) {
1801 ParseExportDirectory64(analyzer);
1802 }
1803 else {
1804 ParseExportDirectory32(analyzer);
1805 }
1806}*/ //removing this duplicate
1807
1808void ProcessResourceDirectory32(
1809 PIMAGE_RESOURCE_DIRECTORY resDir,
1810 int level,
1811 const wchar_t* type,
1812 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
1813 const wchar_t* resourceTypes[],
1814 const PEAnalyzer& analyzer)
1815{
1816 if (IsBadReadPtr(resDir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
1817 return;
1818 }
1819
1820 auto entry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resDir + 1);
1821 WORD totalEntries = resDir->NumberOfNamedEntries + resDir->NumberOfIdEntries;
1822
1823 for (WORD i = 0; i < totalEntries; i++) {
1824 if (IsBadReadPtr(entry + i, sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY))) {
1825 break;
1826 }
1827
1828 for (int indent = 0; indent < level; indent++) {
1829 OUTPUT("\t");
1830 }
1831
1832 if (entry[i].NameIsString) {
1833 auto nameEntry = (PIMAGE_RESOURCE_DIR_STRING_U)((BYTE*)baseResourceDir + entry[i].NameOffset);
1834 if (!IsBadReadPtr(nameEntry, sizeof(IMAGE_RESOURCE_DIR_STRING_U))) {
1835 std::vector<wchar_t> resourceName(nameEntry->Length + 1);
1836 wcsncpy_s(resourceName.data(), nameEntry->Length + 1,
1837 nameEntry->NameString, nameEntry->Length);
1838 resourceName[nameEntry->Length] = L'\0';
1839
1840 if (level == 0) {
1841 OUTPUT("Resource Type: Custom (%ls)\n", resourceName.data());
1842 }
1843 else {
1844 OUTPUT("Name: %ls\n", resourceName.data());
1845 }
1846 }
1847 }
1848 else {
1849 if (level == 0) {
1850 DWORD resourceType = entry[i].Id;
1851 if (resourceType < 16) {
1852 OUTPUT("Resource Type: %ls (ID: %d)\n", resourceTypes[resourceType], resourceType);
1853 }
1854 else {
1855 OUTPUT("Resource Type: Custom (ID: %d)\n", resourceType);
1856 }
1857 }
1858 else {
1859 OUTPUT("ID: %d\n", entry[i].Id);
1860 }
1861 }
1862
1863 if (entry[i].DataIsDirectory) {
1864 auto nextDir = (PIMAGE_RESOURCE_DIRECTORY)((BYTE*)baseResourceDir + entry[i].OffsetToDirectory);
1865 if (!IsBadReadPtr(nextDir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
1866 ProcessResourceDirectory32(nextDir, level + 1,
1867 level == 0 ? resourceTypes[min(entry[i].Id, 15)] : type,
1868 baseResourceDir, resourceTypes, analyzer);
1869 }
1870 }
1871 else {
1872 auto dataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)((BYTE*)baseResourceDir + entry[i].OffsetToData);
1873 if (!IsBadReadPtr(dataEntry, sizeof(IMAGE_RESOURCE_DATA_ENTRY))) {
1874 for (int indent = 0; indent < level + 1; indent++) {
1875 OUTPUT("\t");
1876 }
1877 OUTPUT("Size: %d bytes, RVA: 0x%X\n", dataEntry->Size, dataEntry->OffsetToData);
1878
1879 // Special handling for Version resources
1880 if (type && wcscmp(type, L"Version") == 0) {
1881 auto versionData = (BYTE*)PEHelpers::GetRvaPtr(
1882 dataEntry->OffsetToData,
1883 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1884 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1885 analyzer.lpFileContent,
1886 analyzer.fileSize);
1887
1888 if (versionData && !IsBadReadPtr(versionData, sizeof(VS_FIXEDFILEINFO))) {
1889 auto versionInfo = (VS_FIXEDFILEINFO*)(versionData + 40);
1890 if (versionInfo->dwSignature == 0xFEEF04BD) {
1891 for (int indent = 0; indent < level + 2; indent++) {
1892 OUTPUT("\t");
1893 }
1894 OUTPUT("File Version: %d.%d.%d.%d\n",
1895 HIWORD(versionInfo->dwFileVersionMS),
1896 LOWORD(versionInfo->dwFileVersionMS),
1897 HIWORD(versionInfo->dwFileVersionLS),
1898 LOWORD(versionInfo->dwFileVersionLS));
1899 }
1900 }
1901 }
1902 }
1903 }
1904 }
1905}
1906
1907void ProcessResourceDirectory64(
1908 PIMAGE_RESOURCE_DIRECTORY resDir,
1909 int level,
1910 const wchar_t* type,
1911 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
1912 const wchar_t* resourceTypes[],
1913 const PEAnalyzer& analyzer)
1914{
1915 // Similar to ProcessResourceDirectory32 but using 64-bit structures
1916 // Main difference is using analyzer.pNtHeaders64 instead of analyzer.pNtHeaders32
1917 if (IsBadReadPtr(resDir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
1918 return;
1919 // Rest of the implementation follows the same pattern
1920 }
1921
1922 auto entry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resDir + 1);
1923 WORD totalEntries = resDir->NumberOfNamedEntries + resDir->NumberOfIdEntries;
1924
1925 for (WORD i = 0; i < totalEntries; i++) {
1926 if (IsBadReadPtr(entry + i, sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY))) {
1927 break;
1928 }
1929
1930 for (int indent = 0; indent < level; indent++) {
1931 OUTPUT("\t");
1932 }
1933
1934 if (entry[i].NameIsString) {
1935 auto nameEntry = (PIMAGE_RESOURCE_DIR_STRING_U)((BYTE*)baseResourceDir + entry[i].NameOffset);
1936 if (!IsBadReadPtr(nameEntry, sizeof(IMAGE_RESOURCE_DIR_STRING_U))) {
1937 std::vector<wchar_t> resourceName(nameEntry->Length + 1);
1938 wcsncpy_s(resourceName.data(), nameEntry->Length + 1,
1939 nameEntry->NameString, nameEntry->Length);
1940 resourceName[nameEntry->Length] = L'\0';
1941
1942 if (level == 0) {
1943 OUTPUT("Resource Type: Custom (%ls)\n", resourceName.data());
1944 }
1945 else {
1946 OUTPUT("Name: %ls\n", resourceName.data());
1947 }
1948 }
1949 }
1950 else {
1951 if (level == 0) {
1952 DWORD resourceType = entry[i].Id;
1953 if (resourceType < 16) {
1954 OUTPUT("Resource Type: %ls (ID: %d)\n", resourceTypes[resourceType], resourceType);
1955 }
1956 else {
1957 OUTPUT("Resource Type: Custom (ID: %d)\n", resourceType);
1958 }
1959 }
1960 else {
1961 OUTPUT("ID: %d\n", entry[i].Id);
1962 }
1963 }
1964
1965 if (entry[i].DataIsDirectory) {
1966 auto nextDir = (PIMAGE_RESOURCE_DIRECTORY)((BYTE*)baseResourceDir + entry[i].OffsetToDirectory);
1967 if (!IsBadReadPtr(nextDir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
1968 ProcessResourceDirectory32(nextDir, level + 1,
1969 level == 0 ? resourceTypes[min(entry[i].Id, 15)] : type,
1970 baseResourceDir, resourceTypes, analyzer);
1971 }
1972 }
1973 else {
1974 auto dataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)((BYTE*)baseResourceDir + entry[i].OffsetToData);
1975 if (!IsBadReadPtr(dataEntry, sizeof(IMAGE_RESOURCE_DATA_ENTRY))) {
1976 for (int indent = 0; indent < level + 1; indent++) {
1977 OUTPUT("\t");
1978 }
1979 OUTPUT("Size: %d bytes, RVA: 0x%X\n", dataEntry->Size, dataEntry->OffsetToData);
1980
1981 // Special handling for Version resources
1982 if (type && wcscmp(type, L"Version") == 0) {
1983 auto versionData = (BYTE*)PEHelpers::GetRvaPtr(
1984 dataEntry->OffsetToData,
1985 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1986 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1987 analyzer.lpFileContent,
1988 analyzer.fileSize);
1989
1990 if (versionData && !IsBadReadPtr(versionData, sizeof(VS_FIXEDFILEINFO))) {
1991 auto versionInfo = (VS_FIXEDFILEINFO*)(versionData + 40);
1992 if (versionInfo->dwSignature == 0xFEEF04BD) {
1993 for (int indent = 0; indent < level + 2; indent++) {
1994 OUTPUT("\t");
1995 }
1996 OUTPUT("File Version: %d.%d.%d.%d\n",
1997 HIWORD(versionInfo->dwFileVersionMS),
1998 LOWORD(versionInfo->dwFileVersionMS),
1999 HIWORD(versionInfo->dwFileVersionLS),
2000 LOWORD(versionInfo->dwFileVersionLS));
2001 }
2002 }
2003 }
2004 }
2005 }
2006 }
2007}
2008
2009void ParseResourceDirectory32(const PEAnalyzer& analyzer) {
2010 const auto& resourceDir = analyzer.pNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
2011 if (!resourceDir.VirtualAddress || !resourceDir.Size) return;
2012
2013 if (!PEHelpers::IsRvaValid(resourceDir.VirtualAddress, analyzer.fileSize,
2014 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders32))) {
2015 OUTPUT("[-] Invalid resource directory RVA!\n");
2016 throw std::runtime_error("RVA out of bounds");
2017 return;
2018 }
2019
2020 OUTPUT("\n[+] RESOURCE DIRECTORY (32-bit)\n");
2021 auto pResourceDir = (PIMAGE_RESOURCE_DIRECTORY)PEHelpers::GetRvaPtr(
2022 resourceDir.VirtualAddress,
2023 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
2024 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
2025 analyzer.lpFileContent,
2026 analyzer.fileSize);
2027
2028 if (!pResourceDir || IsBadReadPtr(pResourceDir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
2029 OUTPUT("[-] Invalid or corrupted resource directory\n");
2030 return;
2031 }
2032
2033 const wchar_t* resourceTypes[] = {
2034 L"Unknown", L"Cursor", L"Bitmap", L"Icon",
2035 L"Menu", L"Dialog", L"String", L"FontDir",
2036 L"Font", L"Accelerator", L"RCData", L"MessageTable",
2037 L"GroupCursor", L"GroupIcon", L"Version", L"DlgInclude"
2038 };
2039
2040 ProcessResourceDirectory32(pResourceDir, 0, nullptr, pResourceDir, resourceTypes, analyzer);
2041}
2042
2043void ParseDebugDirectory32(const PEAnalyzer& analyzer) {
2044 const auto& debugDir = analyzer.pNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
2045 if (!debugDir.VirtualAddress || !debugDir.Size) return;
2046
2047 if (!PEHelpers::IsRvaValid(debugDir.VirtualAddress, analyzer.fileSize,
2048 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders32))) {
2049 OUTPUT("[-] Invalid debug directory RVA!\n");
2050 throw std::runtime_error("RVA out of bounds");
2051 return;
2052 }
2053
2054 OUTPUT("\n[+] DEBUG DIRECTORY (32-bit)\n");
2055 auto pDebugDir = (PIMAGE_DEBUG_DIRECTORY)PEHelpers::GetRvaPtr(
2056 debugDir.VirtualAddress,
2057 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
2058 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
2059 analyzer.lpFileContent,
2060 analyzer.fileSize);
2061
2062 if (!pDebugDir || IsBadReadPtr(pDebugDir, sizeof(IMAGE_DEBUG_DIRECTORY))) {
2063 OUTPUT("[-] Invalid debug directory structure!\n");
2064 return;
2065 }
2066
2067 DWORD numEntries = min(debugDir.Size / sizeof(IMAGE_DEBUG_DIRECTORY), 16);
2068 for (DWORD i = 0; i < numEntries; i++) {
2069 OUTPUT("\tDebug Entry %d:\n", i + 1);
2070 OUTPUT("\tCharacteristics: 0x%X\n", pDebugDir[i].Characteristics);
2071 OUTPUT("\tTimeDateStamp: 0x%X\n", pDebugDir[i].TimeDateStamp);
2072 OUTPUT("\tMajorVersion: %d\n", pDebugDir[i].MajorVersion);
2073 OUTPUT("\tMinorVersion: %d\n", pDebugDir[i].MinorVersion);
2074 OUTPUT("\tType: 0x%X", pDebugDir[i].Type);
2075
2076 switch (pDebugDir[i].Type) {
2077 case IMAGE_DEBUG_TYPE_COFF:
2078 OUTPUT(" (COFF)\n"); break;
2079 case IMAGE_DEBUG_TYPE_CODEVIEW:
2080 OUTPUT(" (CodeView)\n"); break;
2081 case IMAGE_DEBUG_TYPE_FPO:
2082 OUTPUT(" (FPO)\n"); break;
2083 case IMAGE_DEBUG_TYPE_MISC:
2084 OUTPUT(" (Misc)\n"); break;
2085 case IMAGE_DEBUG_TYPE_EXCEPTION:
2086 OUTPUT(" (Exception)\n"); break;
2087 case IMAGE_DEBUG_TYPE_FIXUP:
2088 OUTPUT(" (Fixup)\n"); break;
2089 case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
2090 OUTPUT(" (OMAP to Src)\n"); break;
2091 case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
2092 OUTPUT(" (OMAP from Src)\n"); break;
2093 case IMAGE_DEBUG_TYPE_BORLAND:
2094 OUTPUT(" (Borland)\n"); break;
2095 default:
2096 OUTPUT(" (Unknown)\n"); break;
2097 }
2098
2099 OUTPUT("\tSizeOfData: 0x%X\n", pDebugDir[i].SizeOfData);
2100 OUTPUT("\tAddressOfRawData: 0x%X\n", pDebugDir[i].AddressOfRawData);
2101 OUTPUT("\tPointerToRawData: 0x%X\n\n", pDebugDir[i].PointerToRawData);
2102
2103 // Special handling for CodeView debug information
2104 if (pDebugDir[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW &&
2105 pDebugDir[i].PointerToRawData != 0 &&
2106 pDebugDir[i].SizeOfData >= sizeof(DWORD)) {
2107
2108 auto pCVHeader = (DWORD*)((BYTE*)analyzer.lpFileContent + pDebugDir[i].PointerToRawData);
2109 if (!IsBadReadPtr(pCVHeader, sizeof(DWORD))) {
2110 switch (*pCVHeader) {
2111 case 0x53445352: // 'RSDS'
2112 if (pDebugDir[i].SizeOfData >= (sizeof(DWORD) + sizeof(GUID) + sizeof(DWORD) + 1)) {
2113 auto pCVData = (char*)(pCVHeader + 1);
2114 if (!IsBadReadPtr(pCVData + 16, 1)) {
2115 auto guid = (GUID*)pCVData;
2116 DWORD age = *(DWORD*)(pCVData + 16);
2117 const char* pdbPath = pCVData + 20;
2118
2119 OUTPUT("\tPDB Information:\n");
2120 OUTPUT("\tGUID: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
2121 guid->Data1, guid->Data2, guid->Data3,
2122 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
2123 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
2124 OUTPUT("\tAge: %d\n", age);
2125 OUTPUT("\tPDB Path: %ls\n\n", pdbPath);
2126 }
2127 }
2128 break;
2129
2130 case 0x3031424E: // 'NB10'
2131 if (pDebugDir[i].SizeOfData >= 16) {
2132 auto pNB10Data = (char*)(pCVHeader + 1);
2133 DWORD offset = *(DWORD*)pNB10Data;
2134 DWORD timestamp = *(DWORD*)(pNB10Data + 4);
2135 DWORD age = *(DWORD*)(pNB10Data + 8);
2136 const char* pdbPath = pNB10Data + 12;
2137
2138 OUTPUT("\tPDB Information (NB10):\n");
2139 OUTPUT("\tOffset: 0x%X\n", offset);
2140 OUTPUT("\tTimestamp: 0x%X\n", timestamp);
2141 OUTPUT("\tAge: %d\n", age);
2142 OUTPUT("\tPDB Path: %ls\n\n", pdbPath);
2143 }
2144 break;
2145 }
2146 }
2147 }
2148 }
2149}
2150
2151void ParseDebugDirectory64(const PEAnalyzer& analyzer) {
2152 const auto& debugDir = analyzer.pNtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
2153 if (!debugDir.VirtualAddress || !debugDir.Size) return;
2154
2155 if (!PEHelpers::IsRvaValid(debugDir.VirtualAddress, analyzer.fileSize,
2156 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders64))) {
2157 OUTPUT("[-] Invalid debug directory RVA!\n");
2158 throw std::runtime_error("RVA out of bounds");
2159 return;
2160 }
2161
2162 OUTPUT("\n[+] DEBUG DIRECTORY (64-bit)\n");
2163 // Rest of implementation follows same pattern as 32-bit version
2164 // Just using pNtHeaders64 instead of pNtHeaders32
2165 auto pDebugDir = (PIMAGE_DEBUG_DIRECTORY)PEHelpers::GetRvaPtr(
2166 debugDir.VirtualAddress,
2167 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
2168 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
2169 analyzer.lpFileContent,
2170 analyzer.fileSize);
2171
2172 if (!pDebugDir || IsBadReadPtr(pDebugDir, sizeof(IMAGE_DEBUG_DIRECTORY))) {
2173 OUTPUT("[-] Invalid debug directory structure!\n");
2174 return;
2175 }
2176
2177 DWORD numEntries = min(debugDir.Size / sizeof(IMAGE_DEBUG_DIRECTORY), 16);
2178 for (DWORD i = 0; i < numEntries; i++) {
2179 OUTPUT("\tDebug Entry %d:\n", i + 1);
2180 OUTPUT("\tCharacteristics: 0x%X\n", pDebugDir[i].Characteristics);
2181 OUTPUT("\tTimeDateStamp: 0x%X\n", pDebugDir[i].TimeDateStamp);
2182 OUTPUT("\tMajorVersion: %d\n", pDebugDir[i].MajorVersion);
2183 OUTPUT("\tMinorVersion: %d\n", pDebugDir[i].MinorVersion);
2184 OUTPUT("\tType: 0x%X", pDebugDir[i].Type);
2185
2186 switch (pDebugDir[i].Type) {
2187 case IMAGE_DEBUG_TYPE_COFF:
2188 OUTPUT(" (COFF)\n"); break;
2189 case IMAGE_DEBUG_TYPE_CODEVIEW:
2190 OUTPUT(" (CodeView)\n"); break;
2191 case IMAGE_DEBUG_TYPE_FPO:
2192 OUTPUT(" (FPO)\n"); break;
2193 case IMAGE_DEBUG_TYPE_MISC:
2194 OUTPUT(" (Misc)\n"); break;
2195 case IMAGE_DEBUG_TYPE_EXCEPTION:
2196 OUTPUT(" (Exception)\n"); break;
2197 case IMAGE_DEBUG_TYPE_FIXUP:
2198 OUTPUT(" (Fixup)\n"); break;
2199 case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
2200 OUTPUT(" (OMAP to Src)\n"); break;
2201 case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
2202 OUTPUT(" (OMAP from Src)\n"); break;
2203 case IMAGE_DEBUG_TYPE_BORLAND:
2204 OUTPUT(" (Borland)\n"); break;
2205 default:
2206 OUTPUT(" (Unknown)\n"); break;
2207 }
2208
2209 OUTPUT("\tSizeOfData: 0x%X\n", pDebugDir[i].SizeOfData);
2210 OUTPUT("\tAddressOfRawData: 0x%X\n", pDebugDir[i].AddressOfRawData);
2211 OUTPUT("\tPointerToRawData: 0x%X\n\n", pDebugDir[i].PointerToRawData);
2212
2213 // Special handling for CodeView debug information
2214 if (pDebugDir[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW &&
2215 pDebugDir[i].PointerToRawData != 0 &&
2216 pDebugDir[i].SizeOfData >= sizeof(DWORD)) {
2217
2218 auto pCVHeader = (DWORD*)((BYTE*)analyzer.lpFileContent + pDebugDir[i].PointerToRawData);
2219 if (!IsBadReadPtr(pCVHeader, sizeof(DWORD))) {
2220 switch (*pCVHeader) {
2221 case 0x53445352: // 'RSDS'
2222 if (pDebugDir[i].SizeOfData >= (sizeof(DWORD) + sizeof(GUID) + sizeof(DWORD) + 1)) {
2223 auto pCVData = (char*)(pCVHeader + 1);
2224 if (!IsBadReadPtr(pCVData + 16, 1)) {
2225 auto guid = (GUID*)pCVData;
2226 DWORD age = *(DWORD*)(pCVData + 16);
2227 const char* pdbPath = pCVData + 20;
2228
2229 OUTPUT("\tPDB Information:\n");
2230 OUTPUT("\tGUID: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
2231 guid->Data1, guid->Data2, guid->Data3,
2232 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
2233 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
2234 OUTPUT("\tAge: %d\n", age);
2235 OUTPUT("\tPDB Path: %ls\n\n", pdbPath);
2236 }
2237 }
2238 break;
2239
2240 case 0x3031424E: // 'NB10'
2241 if (pDebugDir[i].SizeOfData >= 16) {
2242 auto pNB10Data = (char*)(pCVHeader + 1);
2243 DWORD offset = *(DWORD*)pNB10Data;
2244 DWORD timestamp = *(DWORD*)(pNB10Data + 4);
2245 DWORD age = *(DWORD*)(pNB10Data + 8);
2246 const char* pdbPath = pNB10Data + 12;
2247
2248 OUTPUT("\tPDB Information (NB10):\n");
2249 OUTPUT("\tOffset: 0x%X\n", offset);
2250 OUTPUT("\tTimestamp: 0x%X\n", timestamp);
2251 OUTPUT("\tAge: %d\n", age);
2252 OUTPUT("\tPDB Path: %ls\n\n", pdbPath);
2253 }
2254 break;
2255 }
2256 }
2257 }
2258 }
2259}
2260// ... [Same implementation as ParseDebugDirectory32]
2261
2262//newfunctionshere (lateest fixes)
2263
2264
2265void ProcessResourceDirectory32(
2266 PIMAGE_RESOURCE_DIRECTORY resDir,
2267 int level,
2268 const wchar_t* type,
2269 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
2270 const wchar_t* resourceTypes[],
2271 const PEAnalyzer& analyzer);
2272
2273void ProcessResourceDirectory64(
2274 PIMAGE_RESOURCE_DIRECTORY resDir,
2275 int level,
2276 const wchar_t* type,
2277 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
2278 const wchar_t* resourceTypes[],
2279 const PEAnalyzer& analyzer);
2280
2281// Main window class name
2282//const char* const WINDOW_CLASS_NAME = "PEAnalyzerWindow";
2283
2284//new inserted here >>
2285
2286// Page Break
2287
2288//here
2289
2290// Page Break
2291
2292void AddMenus(HWND hwnd) {
2293 HMENU hMenuBar = CreateMenu();
2294 HMENU hFileMenu = CreateMenu();
2295 AppendMenu(hMenuBar, MF_POPUP, (UINT_PTR)hFileMenu, L"&File");
2296 AppendMenu(hFileMenu, MF_STRING, 1, L"&Open\tCtrl+O"); // Updated to show shortcut
2297 AppendMenu(hFileMenu, MF_STRING, 2, L"&Select All\tCtrl+A");
2298 AppendMenu(hFileMenu, MF_STRING, 3, L"E&xit\tAlt+F4");
2299 EnableMenuItem(hFileMenu, 2, MF_BYCOMMAND | MF_GRAYED);
2300 //EnableMenuItem(hFileMenu, ID_FILE_SELECTALL, MF_BYCOMMAND | MF_GRAYED);
2301 SetMenu(hwnd, hMenuBar);
2302}
2303
2304/*void AddMenus(HWND hwnd) {
2305 HMENU hMenuBar = CreateMenu();
2306 HMENU hFileMenu = CreateMenu();
2307
2308 // Create the File menu using the defined IDs.
2309 AppendMenu(hMenuBar, MF_POPUP, (UINT_PTR)hFileMenu, L"&File");
2310 AppendMenu(hFileMenu, MF_STRING, ID_FILE_OPEN, L"&Open\tCtrl+O");
2311 AppendMenu(hFileMenu, MF_STRING, ID_FILE_SELECTALL, L"&Select All");
2312 AppendMenu(hFileMenu, MF_STRING, ID_FILE_EXIT, L"E&xit");
2313
2314 // Initially disable the "Select All" menu item.
2315 EnableMenuItem(hFileMenu, ID_FILE_SELECTALL, MF_BYCOMMAND | MF_GRAYED);
2316 SetMenu(hwnd, hMenuBar);
2317}*/
2318
2319// First, add this helper function to determine if the PE file is 64-bit
2320bool Is64BitPE(PIMAGE_NT_HEADERS pNtHeaders) {
2321 return pNtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
2322} //removing this duplicate
2323
2324// Helper function to safely get file size
2325/*DWORD GetFileSizeCustom(const wchar_t* filePath) {
2326 HANDLE hFile = CreateFileW(filePath, GENERIC_READ, FILE_SHARE_READ,
2327 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
2328
2329 if (hFile == INVALID_HANDLE_VALUE) {
2330 return 0;
2331 }
2332
2333 DWORD fileSize = ::GetFileSize(hFile, nullptr);
2334 CloseHandle(hFile);
2335 return fileSize;
2336}*/ //removing this duplicate instead
2337
2338// Add this helper function
2339void SafeOutput(const std::wstring& text) {
2340 try {
2341 g_OutputText << text;
2342 UpdateEditControl();
2343 }
2344 catch (...) {
2345 SetStatusText(L"Error writing output");
2346 }
2347}
2348
2349void UpdateStatusBar(const wchar_t* text, int progress = -1) {
2350 if (text) {
2351 SetStatusText(text);
2352 }
2353 if (progress >= 0) {
2354 ShowProgress(progress);
2355 }
2356}
2357
2358void ClearProgress() {
2359 ShowWindow(g_hProgressBar, SW_HIDE);
2360 SetStatusText(L"Ready");
2361}
2362
2363
2364
2365void SetStatusText(const wchar_t* text) {
2366 SendMessage(g_hStatusBar, SB_SETTEXT, 0, (LPARAM)text);
2367}
2368
2369void ShowProgress(int percentage) {
2370 if (percentage < 0 || percentage > 100) {
2371 OUTPUT("[-] Invalid progress percentage: %d\n", percentage);
2372 return;
2373 }
2374
2375 SendMessage(g_hProgressBar, PBM_SETPOS, (WPARAM)percentage, 0);
2376 wchar_t status[256];
2377 swprintf_s(status, L"Analyzing... %d%%", percentage);
2378 SetStatusText(status);
2379 SendMessage(g_hStatusBar, SB_SETTEXT, 0, (LPARAM)status);
2380}
2381
2382void OpenFileDialog(HWND hwnd) {
2383 WCHAR fileName[MAX_PATH] = L"";
2384 OPENFILENAMEW ofn = { sizeof(OPENFILENAMEW), hwnd, NULL, L"Executable Files (*.exe;*.dll)\0*.exe;*.dll\0All Files (*.*)\0*.*\0", NULL, 0, 1, fileName, MAX_PATH, NULL, 0, NULL, NULL, OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, 0, 0, L"exe", NULL, NULL, NULL };
2385 if (GetOpenFileNameW(&ofn)) {
2386 SetWindowTextW(g_hEditControl, L"");
2387 g_OutputText.str(L"");
2388 g_OutputText.clear();
2389 AnalyzePEFile(ofn.lpstrFile);
2390 UpdateEditControl();
2391 }
2392}
2393
2394
2395// Modified AppendToOutput to handle newlines properly:
2396void AppendToOutput(const wchar_t* format, ...) {
2397 std::vector<wchar_t> buffer(4096); //recent 19/2/25 (1024)*
2398 va_list args;
2399 va_start(args, format);
2400
2401 while (true) {
2402 va_list argsCopy;
2403 va_copy(argsCopy, args);
2404 int result = _vsnwprintf(buffer.data(), buffer.size(), format, argsCopy);
2405 va_end(argsCopy);
2406 if (result >= 0) break;
2407 buffer.resize(buffer.size() * 2);
2408 }
2409 va_end(args);
2410
2411 // Convert \n to \r\n
2412 std::wstring output = buffer.data();
2413 size_t pos = 0;
2414 while ((pos = output.find(L'\n', pos)) != std::wstring::npos) {
2415 if (pos == 0 || output[pos - 1] != L'\r') {
2416 output.insert(pos, L"\r");
2417 pos += 2;
2418 }
2419 else {
2420 pos++;
2421 }
2422 }
2423
2424 g_OutputText << output;
2425 UpdateEditControl();
2426}
2427
2428
2429//use vectors for unlimited size growth of buffer, use an alternative to editbox, check for fast loops overloading, in its primitive form it works properly! try w/o getimports3264 datadirectories getsections
2430
2431//adding here
2432// Line Break
2433// new code below starting here vv
2434
2435
2436
2437DWORD GetFileSize(const wchar_t* filePath) {
2438 HANDLE hFile = CreateFileW(filePath, GENERIC_READ, FILE_SHARE_READ,
2439 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
2440 if (hFile == INVALID_HANDLE_VALUE) return 0;
2441
2442 DWORD fileSize = ::GetFileSize(hFile, nullptr);
2443 CloseHandle(hFile);
2444 return fileSize;
2445}
2446//}
2447// Page Break
2448
2449//}
2450
2451//UpdateEditControl();
2452//}
2453
2454// new code upto here ending here ^^
2455// Line Break
2456// //end adding here
2457
2458
2459
2460//filePathW
2461//lpFilePath
2462/*
2463HANDLE GetFileContent(const wchar_t* lpFilePath) {
2464 HANDLE hFile = CreateFileW(lpFilePath, GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);
2465 if (hFile == INVALID_HANDLE_VALUE) return nullptr;
2466 DWORD fileSize = ::GetFileSize(hFile, nullptr);
2467 auto lpFileContent = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, fileSize);
2468 DWORD bytesRead;
2469 ReadFile(hFile, lpFileContent, fileSize, &bytesRead, nullptr);
2470 CloseHandle(hFile);
2471 return lpFileContent;
2472}
2473*/
2474
2475void UpdateEditControl() {
2476 SetWindowTextW(g_hEditControl, g_OutputText.str().c_str());
2477 SendMessage(g_hEditControl, EM_SETSEL, -1, -1);
2478 SendMessage(g_hEditControl, EM_SCROLLCARET, 0, 0);
2479}
2480//}
2481
2482int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
2483 INITCOMMONCONTROLSEX icc = { sizeof(INITCOMMONCONTROLSEX), ICC_WIN95_CLASSES };
2484 InitCommonControlsEx(&icc);
2485
2486 // Get command line parameters in Unicode
2487 int argc;
2488 LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
2489
2490 CreateMainWindow(hInstance);
2491 if (!g_hMainWindow) {
2492 LocalFree(argv);
2493 return -1;
2494 }
2495
2496 ShowWindow(g_hMainWindow, nCmdShow);
2497 UpdateWindow(g_hMainWindow);
2498 SetWindowPos(g_hMainWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2499
2500 // If there's a command line parameter, process it
2501 if (argc > 1) {
2502 // Process the first parameter as file path
2503 SetWindowTextW(g_hEditControl, L"");
2504 g_OutputText.str(L"");
2505 g_OutputText.clear();
2506 AnalyzePEFile(argv[1]);
2507 UpdateEditControl();
2508 }
2509
2510 LocalFree(argv);
2511
2512 MSG msg = {};
2513 while (GetMessage(&msg, NULL, 0, 0)) {
2514 TranslateMessage(&msg);
2515 DispatchMessage(&msg);
2516 }
2517
2518 if (g_hFont) DeleteObject(g_hFont);
2519 return (int)msg.wParam;
2520}
2521
2522void CreateMainWindow(HINSTANCE hInstance) {
2523 WNDCLASSEXW wc = { sizeof(WNDCLASSEXW), 0, WindowProc, 0, 0, hInstance,
2524 LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)),
2525 LoadCursor(NULL, IDC_ARROW),
2526 (HBRUSH)(COLOR_WINDOW + 1),
2527 NULL, WINDOW_CLASS_NAME,
2528 LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)) };
2529 RegisterClassExW(&wc);
2530
2531 // Get screen dimensions
2532 int screenWidth = GetSystemMetrics(SM_CXSCREEN);
2533 int screenHeight = GetSystemMetrics(SM_CYSCREEN);
2534
2535 // Calculate center position
2536 int windowX = (screenWidth - WINDOW_WIDTH) / 2;
2537 int windowY = (screenHeight - WINDOW_HEIGHT) / 2;
2538
2539 // Remove WS_MAXIMIZEBOX and WS_THICKFRAME from the window style
2540 DWORD style = (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX) & ~WS_THICKFRAME;
2541 //WS_OVERLAPPEDWINDOW ~~> style
2542 g_hMainWindow = CreateWindowExW(0, WINDOW_CLASS_NAME, L"PE File Analyzer v6.7 (F1=About)",
2543 style, windowX, windowY, WINDOW_WIDTH, WINDOW_HEIGHT,
2544 nullptr, nullptr, hInstance, nullptr);
2545}
2546
2547void InitializeControls(HWND hwnd) {
2548 // Create status bar
2549 g_hStatusBar = CreateWindowEx(0, STATUSCLASSNAME, NULL,
2550 WS_CHILD | WS_VISIBLE,
2551 0, 0, 0, 0, hwnd, NULL,
2552 (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), NULL);
2553
2554 // Set up status bar parts
2555 RECT rcClient;
2556 GetClientRect(hwnd, &rcClient);
2557 int statusParts[2] = { 150, rcClient.right };
2558 SendMessage(g_hStatusBar, SB_SETPARTS, 2, (LPARAM)statusParts);
2559
2560 // Create progress bar in the second part of status bar
2561 RECT rcPart;
2562 SendMessage(g_hStatusBar, SB_GETRECT, 1, (LPARAM)&rcPart);
2563
2564 g_hProgressBar = CreateWindowEx(0, PROGRESS_CLASS, NULL,
2565 WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
2566 rcPart.left + 5, rcPart.top + 2,
2567 rcPart.right - rcPart.left - 10, rcPart.bottom - rcPart.top - 4,
2568 g_hStatusBar, NULL,
2569 (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), NULL);
2570
2571 // Set blue color and range
2572 SendMessage(g_hProgressBar, PBM_SETBARCOLOR, 0, (LPARAM)RGB(0, 120, 215)); // Windows 10 blue
2573 SendMessage(g_hProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
2574 SendMessage(g_hProgressBar, PBM_SETSTEP, 1, 0);
2575
2576 // Get status bar height for edit control positioning
2577 RECT rcStatus;
2578 GetWindowRect(g_hStatusBar, &rcStatus);
2579 int statusHeight = rcStatus.bottom - rcStatus.top;
2580
2581 // Create edit control
2582 g_hEditControl = CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT", L"",
2583 WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL |
2584 ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL,
2585 EDIT_MARGIN, EDIT_MARGIN,
2586 rcClient.right - (2 * EDIT_MARGIN),
2587 rcClient.bottom - statusHeight - (2 * EDIT_MARGIN),
2588 hwnd, nullptr,
2589 (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);
2590
2591 // Allow the edit control to accept dropped files.
2592 DragAcceptFiles(g_hEditControl, TRUE);
2593
2594 // Create and set font
2595 g_hFont = CreateFont(-14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0,
2596 ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
2597 DEFAULT_QUALITY, DEFAULT_PITCH | FF_MODERN, L"Consolas");
2598
2599 if (g_hFont)
2600 SendMessage(g_hEditControl, WM_SETFONT, (WPARAM)g_hFont, TRUE);
2601
2602 SetWindowSubclass(g_hEditControl, EditSubclassProc, 0, 0);
2603}
2604
2605LRESULT CALLBACK EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {
2606 if (uMsg == WM_KEYDOWN) {
2607 if ((GetKeyState(VK_CONTROL) & 0x8000) && wParam == 'O') {
2608 SendMessage(GetParent(hwnd), WM_COMMAND, 1, 0);
2609 return 0;
2610 }
2611 switch (wParam) {
2612 case VK_F1:
2613 SendMessage(GetParent(hwnd), WM_KEYDOWN, VK_F1, 0);
2614 return 0;
2615 case VK_ESCAPE:
2616 SendMessage(GetParent(hwnd), WM_KEYDOWN, VK_ESCAPE, 0);
2617 return 0;
2618 case VK_PRIOR:
2619 // Scroll up
2620 SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_PAGEUP, 0), 0);
2621 return 0;
2622 case VK_NEXT:
2623 // Scroll down
2624 SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_PAGEDOWN, 0), 0);
2625 return 0;
2626 case VK_UP:
2627 // Scroll one line up
2628 SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0);
2629 return 0;
2630 case VK_DOWN:
2631 // Scroll one line down
2632 SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0);
2633 return 0;
2634 }
2635 }
2636 if (uMsg == WM_MOUSEWHEEL) {
2637 int delta = GET_WHEEL_DELTA_WPARAM(wParam);
2638 if (delta > 0) {
2639 // Scroll up
2640 SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_PAGEUP, 0), 0);
2641 }
2642 else {
2643 // Scroll down
2644 SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_PAGEDOWN, 0), 0);
2645 }
2646 return 0;
2647 }
2648 // Check for Ctrl+A: the 'A' key (wParam == 'A') along with the CTRL key held down.
2649 if (wParam == 'A' && (GetKeyState(VK_CONTROL) & 0x8000))
2650 {
2651 // Select all text in the edit control.
2652 SendMessage(hwnd, EM_SETSEL, 0, -1);
2653 return 0; // indicate that the message has been handled.
2654 }
2655 // Handle file drops
2656 if (uMsg == WM_DROPFILES) {
2657 HDROP hDrop = (HDROP)wParam;
2658 UINT fileCount = DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0);
2659 if (fileCount > 0) {
2660 wchar_t filePath[MAX_PATH];
2661 if (DragQueryFileW(hDrop, 0, filePath, MAX_PATH)) {
2662 // Call your file analysis function with the dropped file path.
2663 AnalyzePEFile(filePath);
2664 }
2665 }
2666 DragFinish(hDrop);
2667 return 0; // Indicate that the message was handled.
2668 }
2669 return DefSubclassProc(hwnd, uMsg, wParam, lParam);
2670}
2671
2672LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
2673 switch (uMsg) {
2674 case WM_CREATE: InitializeControls(hwnd); AddMenus(hwnd); return 0;
2675 case WM_SIZE:
2676 {
2677 RECT rcClient;
2678 GetClientRect(hwnd, &rcClient);
2679
2680 // Resize status bar
2681 SendMessage(g_hStatusBar, WM_SIZE, 0, 0);
2682
2683 // Recalculate status bar parts
2684 int statusParts[2] = { 150, rcClient.right };
2685 SendMessage(g_hStatusBar, SB_SETPARTS, 2, (LPARAM)statusParts);
2686
2687 // Reposition progress bar
2688 RECT rcPart;
2689 SendMessage(g_hStatusBar, SB_GETRECT, 1, (LPARAM)&rcPart);
2690 SetWindowPos(g_hProgressBar, NULL,
2691 rcPart.left + 5, rcPart.top + 2,
2692 rcPart.right - rcPart.left - 10, rcPart.bottom - rcPart.top - 4,
2693 SWP_NOZORDER);
2694
2695 // Get status bar height
2696 RECT rcStatus;
2697 GetWindowRect(g_hStatusBar, &rcStatus);
2698 int statusHeight = rcStatus.bottom - rcStatus.top;
2699
2700 // Resize edit control
2701 SetWindowPos(g_hEditControl, NULL,
2702 EDIT_MARGIN,
2703 EDIT_MARGIN,
2704 rcClient.right - (2 * EDIT_MARGIN),
2705 rcClient.bottom - statusHeight - (2 * EDIT_MARGIN),
2706 SWP_NOZORDER);
2707
2708 if (wParam == SIZE_MINIMIZED)
2709 {
2710 SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2711 }
2712 else
2713 {
2714 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2715 }
2716
2717 return 0;
2718 }
2719
2720 case WM_KEYDOWN:
2721 {
2722 if (GetKeyState(VK_CONTROL) & 0x8000) {
2723 switch (wParam) {
2724 case 'O':
2725 OpenFileDialog(hwnd);
2726 return 0;
2727 }
2728 }
2729 switch (wParam) {
2730 case VK_F1:
2731 MessageBoxW(hwnd,
2732 L"PE Header Parser 6.7 GUI-based Programmed in C++ Win32 API (2834+ lines of code) by Entisoft Software (c) Evans Thorpemorton.\nFiles can be #1 Drag & Dropped #2 File Menu > Open Dialog #3 Command-Line Argument FilePath #4 Ctrl+O Hotkey",
2733 L"About",
2734 MB_OK | MB_ICONINFORMATION);
2735 return 0;
2736 case VK_ESCAPE:
2737 PostQuitMessage(0);
2738 return 0;
2739 case VK_PRIOR:
2740 // Scroll up
2741 SendMessage(g_hEditControl, WM_VSCROLL, MAKELONG(SB_PAGEUP, 0), 0);
2742 return 0;
2743 case VK_NEXT:
2744 // Scroll down
2745 SendMessage(g_hEditControl, WM_VSCROLL, MAKELONG(SB_PAGEDOWN, 0), 0);
2746 return 0;
2747 case VK_UP:
2748 // Scroll one line up
2749 SendMessage(g_hEditControl, WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0);
2750 return 0;
2751 case VK_DOWN:
2752 // Scroll one line down
2753 SendMessage(g_hEditControl, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0);
2754 return 0;
2755 }
2756 break;
2757 }
2758 case WM_MOUSEWHEEL:
2759 {
2760 int delta = GET_WHEEL_DELTA_WPARAM(wParam);
2761 if (delta > 0) {
2762 // Scroll up
2763 SendMessage(g_hEditControl, WM_VSCROLL, MAKELONG(SB_PAGEUP, 0), 0);
2764 }
2765 else {
2766 // Scroll down
2767 SendMessage(g_hEditControl, WM_VSCROLL, MAKELONG(SB_PAGEDOWN, 0), 0);
2768 }
2769 return 0;
2770 }
2771 case WM_COMMAND:
2772 if (LOWORD(wParam) == 1) OpenFileDialog(hwnd); if (LOWORD(wParam) == 2) { if (g_hEditControl) { SetFocus(g_hEditControl); SendMessage(g_hEditControl, EM_SETSEL, 0, -1); } } if (LOWORD(wParam) == 3) PostQuitMessage(0); return 0;
2773
2774/* switch (LOWORD(wParam)) {
2775 case ID_FILE_OPEN:
2776 OpenFileDialog(hwnd);
2777 break;
2778 case ID_FILE_SELECTALL:
2779 if (g_hEditControl) {
2780 // Set focus to the edit control if needed.
2781 SetFocus(g_hEditControl);
2782 // Select all text.
2783 SendMessage(g_hEditControl, EM_SETSEL, 0, -1);
2784 UpdateEditControl();
2785 }
2786 break;
2787 case ID_FILE_EXIT:
2788 PostQuitMessage(0);
2789 break;
2790 }
2791 return 0; */
2792
2793 /* {
2794 int cmd = LOWORD(wParam);
2795 if (cmd == 1) {
2796 OpenFileDialog(hwnd);
2797 }
2798 else if (cmd == 2) { // This is your Select All command.
2799 if (g_hEditControl) {
2800 SetFocus(g_hEditControl);
2801 SendMessage(g_hEditControl, EM_SETSEL, 0, -1);
2802 UpdateEditControl(); // if necessary to refresh display
2803 }
2804 }
2805 else if (cmd == 3) { // This is your Exit command.
2806 PostQuitMessage(0);
2807 }
2808 return 0;
2809 } */
2810
2811/* switch (LOWORD(wParam)) {
2812 case ID_FILE_OPEN:
2813 OpenFileDialog(hwnd);
2814 break;
2815 case ID_FILE_SELECTALL:
2816 if (g_hEditControl) {
2817 // Set focus to the edit control
2818 SetFocus(g_hEditControl);
2819 // Select all text
2820 SendMessage(g_hEditControl, EM_SETSEL, 0, -1);
2821 UpdateEditControl();
2822 }
2823 break;
2824 case ID_FILE_EXIT:
2825 PostQuitMessage(0);
2826 break;
2827 }
2828 return 0;
2829*/
2830 case WM_DESTROY:
2831 if (g_hStatusBar) DestroyWindow(g_hStatusBar);
2832 PostQuitMessage(0);
2833 return 0;
2834 }
2835 return DefWindowProc(hwnd, uMsg, wParam, lParam);
2836}
2837```
2838
2839==++ Here's the full source for (file 2/3) "PEHeaders.h"::: ++==
2840```PEHeaders.h
2841#pragma once
2842#ifndef PE_ANALYZER_STRUCT_H
2843#define PE_ANALYZER_STRUCT_H
2844#include <Windows.h>
2845#include <winternl.h>
2846#include <memory>
2847class FileMapper;
2848
2849// Core PE analysis structure
2850struct PEAnalyzer {
2851 LPVOID lpFileContent;
2852 DWORD fileSize;
2853 bool is64Bit;
2854 PIMAGE_NT_HEADERS32 pNtHeaders32;
2855 PIMAGE_NT_HEADERS64 pNtHeaders64;
2856 PIMAGE_DOS_HEADER pDosHeader;
2857 FileMapper* pMapper; // <<-- inserted
2858
2859 PEAnalyzer() : lpFileContent(nullptr), fileSize(0), is64Bit(false),
2860 pNtHeaders32(nullptr), pNtHeaders64(nullptr), pDosHeader(nullptr), pMapper(nullptr) {}
2861
2862 // Remove destructor as FileMapper will handle cleanup
2863};
2864//struct PEAnalyzer; // Add this before the namespace
2865// Declare functions that use PEAnalyzer
2866 template<typename T>
2867 bool IsSafeToRead(const PEAnalyzer& analyzer, const T* ptr, size_t size);
2868#endif // PE_ANALYZER_STRUCT_H
2869namespace PEHelpers {
2870//ifndef OUTPUT was here
2871
2872 // Inline function to prevent multiple definition
2873 inline bool Is64BitPE(PIMAGE_NT_HEADERS pNtHeaders) {
2874 return pNtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
2875 }
2876 //bool ValidateFileSize(const PEAnalyzer& analyzer, DWORD expectedSize, DWORD fileSize);
2877 bool ValidateFileSize(DWORD expectedSize, DWORD fileSize);
2878 // Add the template function declaration here
2879 //template<typename T>
2880 //bool IsSafeToRead(const PEAnalyzer& analyzer, const T* ptr, size_t size);
2881 bool IsRvaValid(DWORD rva, DWORD fileSize, PIMAGE_NT_HEADERS pNtHeaders);
2882 DWORD_PTR GetImageBase(PIMAGE_NT_HEADERS pNtHeaders);
2883 DWORD GetSizeOfImage(PIMAGE_NT_HEADERS pNtHeaders);
2884 DWORD_PTR GetRvaPtr(DWORD rva, PIMAGE_SECTION_HEADER pSectionHeader,
2885 WORD numberOfSections, LPVOID baseAddress);
2886 DWORD RvaToOffset(DWORD rva, PIMAGE_SECTION_HEADER pSectionHeader,
2887 WORD numberOfSections);
2888 std::wstring GetImageCharacteristics(DWORD characteristics);
2889 std::wstring GetSubsystem(WORD subsystem);
2890 std::wstring GetDataDirectoryName(int DirectoryNumber);
2891 std::wstring GetSectionProtection(DWORD characteristics);
2892
2893 // using namespace std;
2894 // using namespace PEAnalyzer;
2895 // Core PE validation functions
2896 // Ensure this function is defined exactly once
2897 /*inline bool Is64BitPE(PIMAGE_NT_HEADERS pNtHeaders) {
2898 return pNtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
2899 }*/
2900
2901/*bool Is64BitPE(PIMAGE_NT_HEADERS pNtHeaders) {
2902 return pNtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
2903}*/
2904
2905bool ValidateFileSize(DWORD expectedSize, DWORD fileSize) {
2906 return expectedSize > 0 && expectedSize <= fileSize;
2907}
2908
2909template<typename T>
2910bool IsSafeToRead(const PEAnalyzer& analyzer, const T* ptr, size_t size = sizeof(T)) {
2911 // Check if pointer is null
2912 if (!ptr) {
2913 OUTPUT("[-] Null pointer detected\n");
2914 return false;
2915 }
2916
2917 // Calculate pointer ranges
2918 DWORD_PTR startAddress = reinterpret_cast<DWORD_PTR>(analyzer.lpFileContent);
2919 DWORD_PTR endAddress = startAddress + analyzer.fileSize;
2920 DWORD_PTR ptrAddress = reinterpret_cast<DWORD_PTR>(ptr);
2921 DWORD_PTR ptrEndAddress = ptrAddress + size;
2922
2923 // Comprehensive pointer validation
2924 bool isValidPointer = (
2925 ptr != nullptr && // Not null
2926 ptrAddress >= startAddress && // Above file start
2927 ptrEndAddress <= endAddress && // Below file end
2928 ptrAddress < ptrEndAddress // Prevent integer overflow
2929 );
2930
2931 if (!isValidPointer) {
2932 OUTPUT("[-] Pointer validation failed\n");
2933 OUTPUT(" Pointer: 0x%p\n", ptr);
2934 OUTPUT(" File Start: 0x%p\n", reinterpret_cast<void*>(startAddress));
2935 OUTPUT(" File End: 0x%p\n", reinterpret_cast<void*>(endAddress));
2936 OUTPUT(" Pointer Start: 0x%p\n", reinterpret_cast<void*>(ptrAddress));
2937 OUTPUT(" Pointer End: 0x%p\n", reinterpret_cast<void*>(ptrEndAddress));
2938 return false;
2939 }
2940
2941 return true;
2942}
2943
2944bool IsRvaValid(DWORD rva, DWORD fileSize, PIMAGE_NT_HEADERS pNtHeaders) {
2945 if (!pNtHeaders) {
2946 OUTPUT("[-] Invalid NT Headers for RVA validation\n");
2947 return false;
2948 }
2949
2950 DWORD sizeOfImage = PEHelpers::Is64BitPE(pNtHeaders) ?
2951 reinterpret_cast<PIMAGE_NT_HEADERS64>(pNtHeaders)->OptionalHeader.SizeOfImage :
2952 reinterpret_cast<PIMAGE_NT_HEADERS32>(pNtHeaders)->OptionalHeader.SizeOfImage;
2953
2954 bool isValid = (
2955 rva > 0 && // RVA is non-zero
2956 rva < sizeOfImage&& // RVA is within image size
2957 rva < fileSize // RVA is within file size
2958 );
2959
2960 if (!isValid) {
2961 OUTPUT("[-] Invalid RVA: 0x%X\n", rva);
2962 OUTPUT(" Size of Image: 0x%X\n", sizeOfImage);
2963 OUTPUT(" File Size: 0x%X\n", fileSize);
2964 }
2965
2966 return isValid;
2967}
2968
2969/*bool IsRvaValid(DWORD rva, DWORD fileSize, PIMAGE_NT_HEADERS pNtHeaders) {
2970 return rva < pNtHeaders->OptionalHeader.SizeOfImage&& rva < fileSize;
2971}*/
2972
2973DWORD_PTR GetImageBase(PIMAGE_NT_HEADERS pNtHeaders) {
2974 if (PEHelpers::Is64BitPE(pNtHeaders)) { // Add PEHelpers:: namespace qualifier
2975 auto pNtHeaders64 = reinterpret_cast<PIMAGE_NT_HEADERS64>(pNtHeaders);
2976 return static_cast<DWORD_PTR>(pNtHeaders64->OptionalHeader.ImageBase);
2977 }
2978 auto pNtHeaders32 = reinterpret_cast<PIMAGE_NT_HEADERS32>(pNtHeaders);
2979 return static_cast<DWORD_PTR>(pNtHeaders32->OptionalHeader.ImageBase);
2980}
2981
2982DWORD GetSizeOfImage(PIMAGE_NT_HEADERS pNtHeaders) {
2983 if (PEHelpers::Is64BitPE(pNtHeaders)) { // Add PEHelpers:: namespace qualifier
2984 auto pNtHeaders64 = reinterpret_cast<PIMAGE_NT_HEADERS64>(pNtHeaders);
2985 return pNtHeaders64->OptionalHeader.SizeOfImage;
2986 }
2987 auto pNtHeaders32 = reinterpret_cast<PIMAGE_NT_HEADERS32>(pNtHeaders);
2988 return pNtHeaders32->OptionalHeader.SizeOfImage;
2989}
2990
2991/* // RVA and address conversion helpers
2992DWORD_PTR GetImageBase(PIMAGE_NT_HEADERS pNtHeaders) {
2993 if (Is64BitPE(pNtHeaders)) {
2994 auto pNtHeaders64 = reinterpret_cast<PIMAGE_NT_HEADERS64>(pNtHeaders);
2995 return static_cast<DWORD_PTR>(pNtHeaders64->OptionalHeader.ImageBase);
2996 }
2997 auto pNtHeaders32 = reinterpret_cast<PIMAGE_NT_HEADERS32>(pNtHeaders);
2998 return static_cast<DWORD_PTR>(pNtHeaders32->OptionalHeader.ImageBase);
2999}
3000
3001DWORD GetSizeOfImage(PIMAGE_NT_HEADERS pNtHeaders) {
3002 if (Is64BitPE(pNtHeaders)) {
3003 auto pNtHeaders64 = reinterpret_cast<PIMAGE_NT_HEADERS64>(pNtHeaders);
3004 return pNtHeaders64->OptionalHeader.SizeOfImage;
3005 }
3006 auto pNtHeaders32 = reinterpret_cast<PIMAGE_NT_HEADERS32>(pNtHeaders);
3007 return pNtHeaders32->OptionalHeader.SizeOfImage;
3008}*/
3009
3010DWORD_PTR GetRvaPtr(
3011 DWORD rva,
3012 PIMAGE_SECTION_HEADER pSectionHeader,
3013 WORD numberOfSections,
3014 LPVOID baseAddress,
3015 DWORD fileSize // Add file size as a parameter
3016) {
3017 if (!rva || !pSectionHeader || !baseAddress) {
3018 OUTPUT("[-] Invalid parameters in GetRvaPtr\n");
3019 return 0;
3020 }
3021
3022 for (WORD i = 0; i < numberOfSections; i++) {
3023 // Check if RVA falls within this section
3024 if (rva >= pSectionHeader[i].VirtualAddress &&
3025 rva < (pSectionHeader[i].VirtualAddress + pSectionHeader[i].SizeOfRawData)) {
3026
3027 // Calculate pointer
3028 DWORD_PTR delta = reinterpret_cast<DWORD_PTR>(baseAddress) +
3029 pSectionHeader[i].PointerToRawData;
3030
3031 DWORD_PTR result = delta + (rva - pSectionHeader[i].VirtualAddress);
3032
3033 // Additional validation
3034 if (result < reinterpret_cast<DWORD_PTR>(baseAddress) ||
3035 result >= (reinterpret_cast<DWORD_PTR>(baseAddress) + fileSize)) {
3036 OUTPUT("[-] RVA pointer out of bounds\n");
3037 return 0;
3038 }
3039
3040 return result;
3041 }
3042 }
3043
3044 OUTPUT("[-] RVA not found in any section: 0x%X\n", rva);
3045 return 0;
3046}
3047//}
3048//}
3049
3050/* DWORD_PTR GetRvaPtr(DWORD rva, PIMAGE_SECTION_HEADER pSectionHeader,
3051 WORD numberOfSections, LPVOID baseAddress) {
3052 if (!rva || !pSectionHeader || !baseAddress) return 0;
3053
3054 for (WORD i = 0; i < numberOfSections; i++) {
3055 if (rva >= pSectionHeader[i].VirtualAddress &&
3056 rva < (pSectionHeader[i].VirtualAddress + pSectionHeader[i].SizeOfRawData)) {
3057 DWORD_PTR delta = (DWORD_PTR)baseAddress + pSectionHeader[i].PointerToRawData;
3058 return delta + (rva - pSectionHeader[i].VirtualAddress);
3059 }
3060 }
3061 OUTPUT("[-] Failed to map RVA: 0x%X\n", rva);
3062 return 0;
3063} */
3064
3065DWORD RvaToOffset(DWORD rva, PIMAGE_SECTION_HEADER pSectionHeader, WORD numberOfSections) {
3066 if (!rva || !pSectionHeader) return 0;
3067
3068 for (WORD i = 0; i < numberOfSections; i++) {
3069 if (rva >= pSectionHeader[i].VirtualAddress &&
3070 rva < (pSectionHeader[i].VirtualAddress + pSectionHeader[i].SizeOfRawData)) {
3071 return (rva - pSectionHeader[i].VirtualAddress) + pSectionHeader[i].PointerToRawData;
3072 }
3073 }
3074 OUTPUT("[-] Failed to map RVA: 0x%X\n", rva);
3075 return 0;
3076}
3077
3078// PE information helper functions
3079std::wstring GetImageCharacteristics(DWORD characteristics) {
3080 if (characteristics & IMAGE_FILE_DLL) return L"(DLL)";
3081 if (characteristics & IMAGE_FILE_SYSTEM) return L"(DRIVER)";
3082 if (characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) return L"(EXE)";
3083 return L"(UNKNOWN)";
3084}
3085
3086std::wstring GetSubsystem(WORD subsystem) {
3087 switch (subsystem) {
3088 case IMAGE_SUBSYSTEM_NATIVE: return L"(NATIVE/DRIVER)";
3089 case IMAGE_SUBSYSTEM_WINDOWS_GUI: return L"(GUI)";
3090 case IMAGE_SUBSYSTEM_WINDOWS_CUI: return L"(CONSOLE)";
3091 default: return L"(UNKNOWN)";
3092 }
3093}
3094
3095std::wstring GetDataDirectoryName(int DirectoryNumber) {
3096 static const wchar_t* names[] = {
3097 L"Export Table", L"Import Table", L"Resource Table",
3098 L"Exception Entry", L"Security Entry", L"Relocation Table",
3099 L"Debug Entry", L"Copyright Entry", L"Global PTR Entry",
3100 L"TLS Entry", L"Configuration Entry", L"Bound Import Entry",
3101 L"IAT", L"Delay Import Descriptor", L"COM Descriptor"
3102 };
3103 return (DirectoryNumber < 15) ? names[DirectoryNumber] : L"Unknown";
3104}
3105
3106std::wstring GetSectionProtection(DWORD characteristics) {
3107 std::wstring protection = L"(";
3108 bool needsSeparator = false;
3109
3110 if (characteristics & IMAGE_SCN_MEM_EXECUTE) {
3111 protection += L"EXECUTE";
3112 needsSeparator = true;
3113 }
3114 if (characteristics & IMAGE_SCN_MEM_READ) {
3115 if (needsSeparator) protection += L" | ";
3116 protection += L"READ";
3117 needsSeparator = true;
3118 }
3119 if (characteristics & IMAGE_SCN_MEM_WRITE) {
3120 if (needsSeparator) protection += L" | ";
3121 protection += L"WRITE";
3122 }
3123 protection += L")";
3124 return protection;
3125}
3126}
3127```
3128
3129==++ Here's the full source for (file 1/3) "resource.h"::: ++==
3130```resource.h
3131//{{NO_DEPENDENCIES}}
3132// Microsoft Visual C++ generated include file.
3133// Used by PE-Explorer.rc
3134//
3135#pragma once
3136#define IDI_ICON1 101
3137// resource.h
3138#define ID_FILE_OPEN 1001
3139#define ID_FILE_SELECTALL 1002 // New "Select All" command
3140#define ID_FILE_EXIT 1003
3141
3142// Next default values for new objects
3143//
3144#ifdef APSTUDIO_INVOKED
3145#ifndef APSTUDIO_READONLY_SYMBOLS
3146#define _APS_NEXT_RESOURCE_VALUE 102
3147#define _APS_NEXT_COMMAND_VALUE 40001
3148#define _APS_NEXT_CONTROL_VALUE 1001
3149#define _APS_NEXT_SYMED_VALUE 101
3150#endif
3151#endif
3152
3153```