· 6 months ago · Mar 17, 2025, 09:55 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
1362//new with sanity checks
1363void ProcessRSDSDebugInfo(const IMAGE_DEBUG_DIRECTORY& debugEntry, DWORD* pCVHeader,
1364 const PEAnalyzer& analyzer) {
1365
1366 if (debugEntry.SizeOfData >= (sizeof(DWORD) + sizeof(GUID) + sizeof(DWORD) + 1)) {
1367 auto pCVData = (char*)(pCVHeader + 1);
1368 if (!IsBadReadPtr(pCVData + 16, 1)) {
1369 auto guid = (GUID*)pCVData;
1370 DWORD age = *(DWORD*)(pCVData + 16);
1371 const char* pdbPath = pCVData + 20;
1372
1373 // Ensure we do not read beyond allocated memory
1374 int pdbPathLength = debugEntry.SizeOfData - (sizeof(DWORD) + sizeof(GUID) + sizeof(DWORD));
1375 if (pdbPathLength <= 0 || IsBadReadPtr(pdbPath, 1)) {
1376 OUTPUT("\tPDB Information:\n");
1377 OUTPUT("\tGUID: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
1378 guid->Data1, guid->Data2, guid->Data3,
1379 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
1380 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
1381 OUTPUT("\tAge: %d\n", age);
1382 OUTPUT("\tPDB Path: N/A (Not Found)\n\n");
1383 return;
1384 }
1385
1386 // Convert the extracted PDB path safely
1387 std::string pdbPathStr(pdbPath, pdbPathLength);
1388 size_t nullTerminator = pdbPathStr.find('\0');
1389 if (nullTerminator != std::string::npos) {
1390 pdbPathStr = pdbPathStr.substr(0, nullTerminator); // Trim at null terminator
1391 }
1392
1393 std::wstring pdbPathW = AnsiToWide(pdbPathStr.c_str());
1394
1395 OUTPUT("\tPDB Information:\n");
1396 OUTPUT("\tGUID: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
1397 guid->Data1, guid->Data2, guid->Data3,
1398 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
1399 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
1400 OUTPUT("\tAge: %d\n", age);
1401 OUTPUT("\tPDB Path: %ls\n\n", pdbPathW.empty() ? L"N/A (Not Found)" : pdbPathW.c_str());
1402 }
1403 }
1404}
1405
1406//new with fixed n/a + other sanity checks
1407void ProcessNB10DebugInfo(const IMAGE_DEBUG_DIRECTORY& debugEntry, DWORD* pCVHeader,
1408 const PEAnalyzer& analyzer) {
1409 // Ensure there's enough data: three DWORDs (offset, timestamp, age) plus at least one byte for the PDB path.
1410 if (debugEntry.SizeOfData < (sizeof(DWORD) * 3 + 1)) {
1411 OUTPUT("\tPDB Information (NB10): Insufficient data\n\n");
1412 return;
1413 }
1414
1415 // pCVHeader points to the start of the NB10 record.
1416 const char* pNB10Data = reinterpret_cast<const char*>(pCVHeader + 1);
1417 DWORD offset = *reinterpret_cast<const DWORD*>(pNB10Data);
1418 DWORD timestamp = *reinterpret_cast<const DWORD*>(pNB10Data + 4);
1419 DWORD age = *reinterpret_cast<const DWORD*>(pNB10Data + 8);
1420
1421 // The PDB path starts at offset 12 in the NB10 record.
1422 const char* pdbPath = pNB10Data + 12;
1423 int pdbPathBytes = debugEntry.SizeOfData - 12;
1424 if (pdbPathBytes <= 0 || IsBadReadPtr(pdbPath, 1)) {
1425 OUTPUT("\tPDB Information (NB10):\n");
1426 OUTPUT("\tOffset: 0x%X\n", offset);
1427 OUTPUT("\tTimestamp: 0x%X\n", timestamp);
1428 OUTPUT("\tAge: %d\n", age);
1429 OUTPUT("\tPDB Path: N/A (Not Found)\n\n");
1430 return;
1431 }
1432
1433 // Construct an ANSI string from the exact number of bytes.
1434 std::string pdbPathStr(pdbPath, pdbPathBytes);
1435 // Trim at the first null terminator (if any).
1436 size_t nullPos = pdbPathStr.find('\0');
1437 if (nullPos != std::string::npos) {
1438 pdbPathStr = pdbPathStr.substr(0, nullPos);
1439 }
1440
1441 // Convert the ANSI string to a wide string.
1442 std::wstring pdbPathW = AnsiToWide(pdbPathStr.c_str());
1443 // If the conversion yields an empty string, treat it as missing.
1444 if (pdbPathW.empty()) {
1445 pdbPathW = L"N/A (Not Found)";
1446 }
1447 else {
1448 // Check if the file exists on disk.
1449 DWORD attr = GetFileAttributesW(pdbPathW.c_str());
1450 if (attr == INVALID_FILE_ATTRIBUTES) {
1451 pdbPathW = L"N/A (Not Found)";
1452 }
1453 }
1454
1455 OUTPUT("\tPDB Information (NB10):\n");
1456 OUTPUT("\tOffset: 0x%X\n", offset);
1457 OUTPUT("\tTimestamp: 0x%X\n", timestamp);
1458 OUTPUT("\tAge: %d\n", age);
1459 OUTPUT("\tPDB Path: %ls\n\n", pdbPathW.c_str());
1460}
1461
1462
1463//this fix does not take into account n/a not found
1464/* void ProcessNB10DebugInfo(const IMAGE_DEBUG_DIRECTORY& debugEntry, DWORD* pCVHeader,
1465 const PEAnalyzer& analyzer) {
1466 // Ensure we have enough data: 3 DWORDs (offset, timestamp, age) plus at least 1 byte for the PDB path.
1467 if (debugEntry.SizeOfData < (sizeof(DWORD) * 3 + 1)) {
1468 OUTPUT("\tPDB Information (NB10): Insufficient data\n\n");
1469 return;
1470 }
1471
1472 // pCVHeader points to the start of the NB10 data record.
1473 const char* pNB10Data = reinterpret_cast<const char*>(pCVHeader + 1);
1474 DWORD offset = *reinterpret_cast<const DWORD*>(pNB10Data);
1475 DWORD timestamp = *reinterpret_cast<const DWORD*>(pNB10Data + 4);
1476 DWORD age = *reinterpret_cast<const DWORD*>(pNB10Data + 8);
1477
1478 // The PDB path starts at offset 12 in the NB10 record.
1479 const char* pdbPath = pNB10Data + 12;
1480 int pdbPathBytes = debugEntry.SizeOfData - 12; // Remaining bytes available for the PDB path
1481
1482 // Validate that we have a readable PDB path.
1483 if (pdbPathBytes <= 0 || IsBadReadPtr(pdbPath, 1)) {
1484 OUTPUT("\tPDB Information (NB10):\n");
1485 OUTPUT("\tOffset: 0x%X\n", offset);
1486 OUTPUT("\tTimestamp: 0x%X\n", timestamp);
1487 OUTPUT("\tAge: %d\n", age);
1488 OUTPUT("\tPDB Path: N/A (Not Found)\n\n");
1489 return;
1490 }
1491
1492 // Construct an ANSI string from the exact number of bytes.
1493 std::string pdbPathStr(pdbPath, pdbPathBytes);
1494 // Trim at the first null terminator if one exists.
1495 size_t nullPos = pdbPathStr.find('\0');
1496 if (nullPos != std::string::npos) {
1497 pdbPathStr = pdbPathStr.substr(0, nullPos);
1498 }
1499
1500 // Convert the ANSI string to a wide string.
1501 std::wstring pdbPathW = AnsiToWide(pdbPathStr.c_str());
1502 if (pdbPathW.empty()) {
1503 pdbPathW = L"N/A (Not Found)";
1504 }
1505
1506 OUTPUT("\tPDB Information (NB10):\n");
1507 OUTPUT("\tOffset: 0x%X\n", offset);
1508 OUTPUT("\tTimestamp: 0x%X\n", timestamp);
1509 OUTPUT("\tAge: %d\n", age);
1510 OUTPUT("\tPDB Path: %ls\n\n", pdbPathW.c_str());
1511} */
1512
1513//original functions
1514/* void ProcessRSDSDebugInfo(const IMAGE_DEBUG_DIRECTORY& debugEntry, DWORD* pCVHeader,
1515 const PEAnalyzer& analyzer) {
1516
1517 if (debugEntry.SizeOfData >= (sizeof(DWORD) + sizeof(GUID) + sizeof(DWORD) + 1)) {
1518 auto pCVData = (char*)(pCVHeader + 1);
1519 if (!IsBadReadPtr(pCVData + 16, 1)) {
1520 auto guid = (GUID*)pCVData;
1521 DWORD age = *(DWORD*)(pCVData + 16);
1522 const char* pdbPath = pCVData + 20;
1523
1524 OUTPUT("\tPDB Information:\n");
1525 OUTPUT("\tGUID: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
1526 guid->Data1, guid->Data2, guid->Data3,
1527 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
1528 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
1529 OUTPUT("\tAge: %d\n", age);
1530 OUTPUT("\tPDB Path: %ls\n\n", AnsiToWide(pdbPath).c_str());
1531 }
1532 }
1533}
1534
1535//original functions
1536void ProcessNB10DebugInfo(const IMAGE_DEBUG_DIRECTORY& debugEntry, DWORD* pCVHeader,
1537 const PEAnalyzer& analyzer) {
1538
1539 if (debugEntry.SizeOfData >= 16) {
1540 auto pNB10Data = (char*)(pCVHeader + 1);
1541 DWORD offset = *(DWORD*)pNB10Data;
1542 DWORD timestamp = *(DWORD*)(pNB10Data + 4);
1543 DWORD age = *(DWORD*)(pNB10Data + 8);
1544 const char* pdbPath = pNB10Data + 12;
1545
1546 OUTPUT("\tPDB Information (NB10):\n");
1547 OUTPUT("\tOffset: 0x%X\n", offset);
1548 OUTPUT("\tTimestamp: 0x%X\n", timestamp);
1549 OUTPUT("\tAge: %d\n", age);
1550 OUTPUT("\tPDB Path: %ls\n\n", pdbPath);
1551 }
1552} */
1553
1554//colonelburton
1555
1556void ParseImportDirectory32(const PEAnalyzer& analyzer) {
1557 const auto& importDir = analyzer.pNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
1558 if (!importDir.VirtualAddress || !importDir.Size) return;
1559
1560 if (!PEHelpers::IsRvaValid(importDir.VirtualAddress, analyzer.fileSize,
1561 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders32))) {
1562 OUTPUT("[-] Invalid import directory RVA!\n");
1563 throw std::runtime_error("RVA out of bounds");
1564 return;
1565 }
1566
1567 OUTPUT("\n[+] IMPORT DIRECTORY (32-bit)\n");
1568 auto pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)PEHelpers::GetRvaPtr(
1569 importDir.VirtualAddress,
1570 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1571 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1572 analyzer.lpFileContent,
1573 analyzer.fileSize);
1574
1575 if (!pImportDesc) return;
1576
1577 while (pImportDesc->Name != 0) {
1578 if (IsBadReadPtr(pImportDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
1579 OUTPUT("[-] Invalid import descriptor detected!\n");
1580 break;
1581 }
1582
1583 const char* dllName = (const char*)PEHelpers::GetRvaPtr(
1584 pImportDesc->Name,
1585 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1586 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1587 analyzer.lpFileContent,
1588 analyzer.fileSize);
1589
1590 if (dllName && !IsBadReadPtr(dllName, 1)) {
1591 std::vector<wchar_t> wideDllName(MAX_PATH);
1592 MultiByteToWideChar(CP_UTF8, 0, dllName, -1, wideDllName.data(), MAX_PATH);
1593
1594 OUTPUT("\n\tDLL NAME: %ls\n", wideDllName.data());
1595 OUTPUT("\tCharacteristics: 0x%X\n", pImportDesc->Characteristics);
1596 OUTPUT("\tTimeDateStamp: 0x%X\n", pImportDesc->TimeDateStamp);
1597 OUTPUT("\tForwarderChain: 0x%X\n", pImportDesc->ForwarderChain);
1598 OUTPUT("\tFirstThunk: 0x%X\n", pImportDesc->FirstThunk);
1599 OUTPUT("\n\tImported Functions:\n");
1600
1601 auto pThunk = (PIMAGE_THUNK_DATA32)PEHelpers::GetRvaPtr(
1602 pImportDesc->OriginalFirstThunk ? pImportDesc->OriginalFirstThunk : pImportDesc->FirstThunk,
1603 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1604 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1605 analyzer.lpFileContent,
1606 analyzer.fileSize);
1607
1608 while (pThunk && pThunk->u1.AddressOfData) {
1609 if (!(pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32)) {
1610 auto pImportByName = (PIMAGE_IMPORT_BY_NAME)PEHelpers::GetRvaPtr(
1611 pThunk->u1.AddressOfData,
1612 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1613 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1614 analyzer.lpFileContent,
1615 analyzer.fileSize);
1616
1617 if (pImportByName && !IsBadReadPtr(pImportByName, sizeof(IMAGE_IMPORT_BY_NAME))) {
1618 std::vector<wchar_t> wideFuncName(MAX_PATH);
1619 MultiByteToWideChar(CP_ACP, 0, (char*)pImportByName->Name, -1,
1620 wideFuncName.data(), MAX_PATH);
1621 OUTPUT("\t\t%ls\n", wideFuncName.data());
1622 }
1623 }
1624 else {
1625 OUTPUT("\t\tOrdinal: %d\n", pThunk->u1.Ordinal & 0xFFFF);
1626 }
1627 pThunk++;
1628 }
1629 }
1630 pImportDesc++;
1631 }
1632}
1633
1634void ParseImportDirectory64(const PEAnalyzer& analyzer) {
1635 const auto& importDir = analyzer.pNtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
1636 if (!importDir.VirtualAddress || !importDir.Size) return;
1637
1638 if (!PEHelpers::IsRvaValid(importDir.VirtualAddress, analyzer.fileSize,
1639 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders64))) {
1640 OUTPUT("[-] Invalid import directory RVA!\n");
1641 throw std::runtime_error("RVA out of bounds");
1642 return;
1643 }
1644
1645 OUTPUT("\n[+] IMPORT DIRECTORY (64-bit)\n");
1646 auto pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)PEHelpers::GetRvaPtr(
1647 importDir.VirtualAddress,
1648 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1649 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1650 analyzer.lpFileContent,
1651 analyzer.fileSize);
1652
1653 if (!pImportDesc) return;
1654
1655 while (pImportDesc->Name != 0) {
1656 if (IsBadReadPtr(pImportDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
1657 OUTPUT("[-] Invalid import descriptor detected!\n");
1658 break;
1659 }
1660
1661 const char* dllName = (const char*)PEHelpers::GetRvaPtr(
1662 pImportDesc->Name,
1663 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1664 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1665 analyzer.lpFileContent,
1666 analyzer.fileSize);
1667
1668 if (dllName && !IsBadReadPtr(dllName, 1)) {
1669 std::vector<wchar_t> wideDllName(MAX_PATH);
1670 MultiByteToWideChar(CP_UTF8, 0, dllName, -1, wideDllName.data(), MAX_PATH);
1671
1672 OUTPUT("\n\tDLL NAME: %ls\n", wideDllName.data());
1673 OUTPUT("\tCharacteristics: 0x%X\n", pImportDesc->Characteristics);
1674 OUTPUT("\tTimeDateStamp: 0x%X\n", pImportDesc->TimeDateStamp);
1675 OUTPUT("\tForwarderChain: 0x%X\n", pImportDesc->ForwarderChain);
1676 OUTPUT("\tFirstThunk: 0x%X\n", pImportDesc->FirstThunk);
1677 OUTPUT("\n\tImported Functions:\n");
1678
1679 auto pThunk = (PIMAGE_THUNK_DATA64)PEHelpers::GetRvaPtr(
1680 pImportDesc->OriginalFirstThunk ? pImportDesc->OriginalFirstThunk : pImportDesc->FirstThunk,
1681 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1682 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1683 analyzer.lpFileContent,
1684 analyzer.fileSize);
1685
1686 while (pThunk && pThunk->u1.AddressOfData) {
1687 if (!(pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64)) {
1688 auto pImportByName = (PIMAGE_IMPORT_BY_NAME)PEHelpers::GetRvaPtr(
1689 (DWORD)pThunk->u1.AddressOfData,
1690 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1691 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1692 analyzer.lpFileContent,
1693 analyzer.fileSize);
1694
1695 if (pImportByName && !IsBadReadPtr(pImportByName, sizeof(IMAGE_IMPORT_BY_NAME))) {
1696 std::vector<wchar_t> wideFuncName(MAX_PATH);
1697 MultiByteToWideChar(CP_ACP, 0, (char*)pImportByName->Name, -1,
1698 wideFuncName.data(), MAX_PATH);
1699 OUTPUT("\t\t%ls\n", wideFuncName.data());
1700 }
1701 }
1702 else {
1703 OUTPUT("\t\tOrdinal: %lld\n", pThunk->u1.Ordinal & 0xFFFF);
1704 }
1705 pThunk++;
1706 }
1707 }
1708 pImportDesc++;
1709 }
1710}
1711
1712/*void ParseImportDirectory(const PEAnalyzer& analyzer) {
1713 if (analyzer.is64Bit) {
1714 ParseImportDirectory64(analyzer);
1715 }
1716 else {
1717 ParseImportDirectory32(analyzer);
1718 }
1719}*/ //removing the empty content duplicates
1720//}
1721
1722void ParseExportDirectory32(const PEAnalyzer& analyzer) {
1723 const auto& exportDir = analyzer.pNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
1724 if (!exportDir.VirtualAddress || !exportDir.Size) return;
1725
1726 if (!PEHelpers::IsRvaValid(exportDir.VirtualAddress, analyzer.fileSize,
1727 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders32))) {
1728 OUTPUT("[-] Invalid export directory RVA!\n");
1729 throw std::runtime_error("RVA out of bounds");
1730 return;
1731 }
1732
1733 OUTPUT("\n[+] EXPORT DIRECTORY (32-bit)\n");
1734 auto pExportDir = (PIMAGE_EXPORT_DIRECTORY)PEHelpers::GetRvaPtr(
1735 exportDir.VirtualAddress,
1736 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1737 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1738 analyzer.lpFileContent,
1739 analyzer.fileSize);
1740
1741 if (!pExportDir || IsBadReadPtr(pExportDir, sizeof(IMAGE_EXPORT_DIRECTORY))) {
1742 OUTPUT("[-] Invalid export directory structure!\n");
1743 return;
1744 }
1745
1746 OUTPUT("\tCharacteristics: 0x%X\n", pExportDir->Characteristics);
1747 OUTPUT("\tTimeDateStamp: 0x%X\n", pExportDir->TimeDateStamp);
1748 OUTPUT("\tMajorVersion: %d\n", pExportDir->MajorVersion);
1749 OUTPUT("\tMinorVersion: %d\n", pExportDir->MinorVersion);
1750 OUTPUT("\tName: 0x%X\n", pExportDir->Name);
1751 OUTPUT("\tBase: %d\n", pExportDir->Base);
1752 OUTPUT("\tNumberOfFunctions: %d\n", pExportDir->NumberOfFunctions);
1753 OUTPUT("\tNumberOfNames: %d\n", pExportDir->NumberOfNames);
1754 OUTPUT("\tAddressOfFunctions: 0x%X\n", pExportDir->AddressOfFunctions);
1755 OUTPUT("\tAddressOfNames: 0x%X\n", pExportDir->AddressOfNames);
1756 OUTPUT("\tAddressOfNameOrdinals: 0x%X\n\n", pExportDir->AddressOfNameOrdinals);
1757
1758 auto pFunctions = (PDWORD)PEHelpers::GetRvaPtr(
1759 pExportDir->AddressOfFunctions,
1760 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1761 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1762 analyzer.lpFileContent,
1763 analyzer.fileSize);
1764
1765 auto pNames = (PDWORD)PEHelpers::GetRvaPtr(
1766 pExportDir->AddressOfNames,
1767 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1768 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1769 analyzer.lpFileContent,
1770 analyzer.fileSize);
1771
1772 auto pNameOrdinals = (PWORD)PEHelpers::GetRvaPtr(
1773 pExportDir->AddressOfNameOrdinals,
1774 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1775 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1776 analyzer.lpFileContent,
1777 analyzer.fileSize);
1778
1779 if (!pNames || !pNameOrdinals || !pFunctions) {
1780 OUTPUT("[-] Invalid export address tables!\n");
1781 return;
1782 }
1783
1784 OUTPUT("\tExported Functions:\n\n");
1785 for (DWORD i = 0; i < pExportDir->NumberOfNames; i++) {
1786 if (IsBadReadPtr(pNames + i, sizeof(DWORD)) ||
1787 IsBadReadPtr(pNameOrdinals + i, sizeof(WORD))) {
1788 break;
1789 }
1790
1791 const char* functionName = (const char*)PEHelpers::GetRvaPtr(
1792 pNames[i],
1793 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1794 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1795 analyzer.lpFileContent,
1796 analyzer.fileSize);
1797
1798 if (functionName && !IsBadReadPtr(functionName, 1)) {
1799 WORD ordinal = pNameOrdinals[i];
1800 if (ordinal < pExportDir->NumberOfFunctions) {
1801 DWORD functionRva = pFunctions[ordinal];
1802
1803 // Check for forwarded export
1804 if (functionRva >= exportDir.VirtualAddress &&
1805 functionRva < (exportDir.VirtualAddress + exportDir.Size)) {
1806
1807 const char* forwardName = (const char*)PEHelpers::GetRvaPtr(
1808 functionRva,
1809 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
1810 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
1811 analyzer.lpFileContent,
1812 analyzer.fileSize);
1813
1814 if (forwardName && !IsBadReadPtr(forwardName, 1)) {
1815 std::vector<wchar_t> wideForwardName(MAX_PATH);
1816 MultiByteToWideChar(CP_ACP, 0, forwardName, -1,
1817 wideForwardName.data(), MAX_PATH);
1818 OUTPUT("\t\t%ls (Ordinal: %d) -> Forward to: %ls\n",
1819 functionName,
1820 ordinal + pExportDir->Base,
1821 wideForwardName.data());
1822 }
1823 }
1824 else {
1825 OUTPUT("\t\t%ls (Ordinal: %d, RVA: 0x%08X)\n",
1826 functionName,
1827 ordinal + pExportDir->Base,
1828 functionRva);
1829 }
1830 }
1831 }
1832 }
1833}
1834
1835void ParseExportDirectory64(const PEAnalyzer& analyzer) {
1836 const auto& exportDir = analyzer.pNtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
1837 if (!exportDir.VirtualAddress || !exportDir.Size) return;
1838
1839 if (!PEHelpers::IsRvaValid(exportDir.VirtualAddress, analyzer.fileSize,
1840 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders64))) {
1841 OUTPUT("[-] Invalid export directory RVA!\n");
1842 throw std::runtime_error("RVA out of bounds");
1843 return;
1844 }
1845
1846 OUTPUT("\n[+] EXPORT DIRECTORY (64-bit)\n");
1847 // Rest of the implementation is identical to 32-bit version
1848 // Just using pNtHeaders64 instead of pNtHeaders64
1849 auto pExportDir = (PIMAGE_EXPORT_DIRECTORY)PEHelpers::GetRvaPtr(
1850 exportDir.VirtualAddress,
1851 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1852 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1853 analyzer.lpFileContent,
1854 analyzer.fileSize);
1855
1856 if (!pExportDir || IsBadReadPtr(pExportDir, sizeof(IMAGE_EXPORT_DIRECTORY))) {
1857 OUTPUT("[-] Invalid export directory structure!\n");
1858 return;
1859 }
1860
1861 OUTPUT("\tCharacteristics: 0x%X\n", pExportDir->Characteristics);
1862 OUTPUT("\tTimeDateStamp: 0x%X\n", pExportDir->TimeDateStamp);
1863 OUTPUT("\tMajorVersion: %d\n", pExportDir->MajorVersion);
1864 OUTPUT("\tMinorVersion: %d\n", pExportDir->MinorVersion);
1865 OUTPUT("\tName: 0x%X\n", pExportDir->Name);
1866 OUTPUT("\tBase: %d\n", pExportDir->Base);
1867 OUTPUT("\tNumberOfFunctions: %d\n", pExportDir->NumberOfFunctions);
1868 OUTPUT("\tNumberOfNames: %d\n", pExportDir->NumberOfNames);
1869 OUTPUT("\tAddressOfFunctions: 0x%X\n", pExportDir->AddressOfFunctions);
1870 OUTPUT("\tAddressOfNames: 0x%X\n", pExportDir->AddressOfNames);
1871 OUTPUT("\tAddressOfNameOrdinals: 0x%X\n\n", pExportDir->AddressOfNameOrdinals);
1872
1873 auto pFunctions = (PDWORD)PEHelpers::GetRvaPtr(
1874 pExportDir->AddressOfFunctions,
1875 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1876 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1877 analyzer.lpFileContent,
1878 analyzer.fileSize);
1879
1880 auto pNames = (PDWORD)PEHelpers::GetRvaPtr(
1881 pExportDir->AddressOfNames,
1882 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1883 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1884 analyzer.lpFileContent,
1885 analyzer.fileSize);
1886
1887 auto pNameOrdinals = (PWORD)PEHelpers::GetRvaPtr(
1888 pExportDir->AddressOfNameOrdinals,
1889 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1890 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1891 analyzer.lpFileContent,
1892 analyzer.fileSize);
1893
1894 if (!pNames || !pNameOrdinals || !pFunctions) {
1895 OUTPUT("[-] Invalid export address tables!\n");
1896 return;
1897 }
1898
1899 OUTPUT("\tExported Functions:\n\n");
1900 for (DWORD i = 0; i < pExportDir->NumberOfNames; i++) {
1901 if (IsBadReadPtr(pNames + i, sizeof(DWORD)) ||
1902 IsBadReadPtr(pNameOrdinals + i, sizeof(WORD))) {
1903 break;
1904 }
1905
1906 const char* functionName = (const char*)PEHelpers::GetRvaPtr(
1907 pNames[i],
1908 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1909 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1910 analyzer.lpFileContent,
1911 analyzer.fileSize);
1912
1913 if (functionName && !IsBadReadPtr(functionName, 1)) {
1914 WORD ordinal = pNameOrdinals[i];
1915 if (ordinal < pExportDir->NumberOfFunctions) {
1916 DWORD functionRva = pFunctions[ordinal];
1917
1918 // Check for forwarded export
1919 if (functionRva >= exportDir.VirtualAddress &&
1920 functionRva < (exportDir.VirtualAddress + exportDir.Size)) {
1921
1922 const char* forwardName = (const char*)PEHelpers::GetRvaPtr(
1923 functionRva,
1924 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
1925 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
1926 analyzer.lpFileContent,
1927 analyzer.fileSize);
1928
1929 if (forwardName && !IsBadReadPtr(forwardName, 1)) {
1930 std::vector<wchar_t> wideForwardName(MAX_PATH);
1931 MultiByteToWideChar(CP_ACP, 0, forwardName, -1,
1932 wideForwardName.data(), MAX_PATH);
1933 OUTPUT("\t\t%ls (Ordinal: %d) -> Forward to: %ls\n",
1934 functionName,
1935 ordinal + pExportDir->Base,
1936 wideForwardName.data());
1937 }
1938 }
1939 else {
1940 OUTPUT("\t\t%ls (Ordinal: %d, RVA: 0x%08X)\n",
1941 functionName,
1942 ordinal + pExportDir->Base,
1943 functionRva);
1944 }
1945 }
1946 }
1947 }
1948}
1949// Copying the same logic as ParseExportDirectory32 but with 64-bit headers
1950// ... [Same implementation as above, just using pNtHeaders64]
1951
1952/*void ParseExportDirectory(const PEAnalyzer& analyzer) {
1953 if (analyzer.is64Bit) {
1954 ParseExportDirectory64(analyzer);
1955 }
1956 else {
1957 ParseExportDirectory32(analyzer);
1958 }
1959}*/ //removing this duplicate
1960
1961void ProcessResourceDirectory32(
1962 PIMAGE_RESOURCE_DIRECTORY resDir,
1963 int level,
1964 const wchar_t* type,
1965 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
1966 const wchar_t* resourceTypes[],
1967 const PEAnalyzer& analyzer)
1968{
1969 if (IsBadReadPtr(resDir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
1970 return;
1971 }
1972
1973 auto entry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resDir + 1);
1974 WORD totalEntries = resDir->NumberOfNamedEntries + resDir->NumberOfIdEntries;
1975
1976 for (WORD i = 0; i < totalEntries; i++) {
1977 if (IsBadReadPtr(entry + i, sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY))) {
1978 break;
1979 }
1980
1981 for (int indent = 0; indent < level; indent++) {
1982 OUTPUT("\t");
1983 }
1984
1985 if (entry[i].NameIsString) {
1986 auto nameEntry = (PIMAGE_RESOURCE_DIR_STRING_U)((BYTE*)baseResourceDir + entry[i].NameOffset);
1987 if (!IsBadReadPtr(nameEntry, sizeof(IMAGE_RESOURCE_DIR_STRING_U))) {
1988 std::vector<wchar_t> resourceName(nameEntry->Length + 1);
1989 wcsncpy_s(resourceName.data(), nameEntry->Length + 1,
1990 nameEntry->NameString, nameEntry->Length);
1991 resourceName[nameEntry->Length] = L'\0';
1992
1993 if (level == 0) {
1994 OUTPUT("Resource Type: Custom (%ls)\n", resourceName.data());
1995 }
1996 else {
1997 OUTPUT("Name: %ls\n", resourceName.data());
1998 }
1999 }
2000 }
2001 else {
2002 if (level == 0) {
2003 DWORD resourceType = entry[i].Id;
2004 if (resourceType < 16) {
2005 OUTPUT("Resource Type: %ls (ID: %d)\n", resourceTypes[resourceType], resourceType);
2006 }
2007 else {
2008 OUTPUT("Resource Type: Custom (ID: %d)\n", resourceType);
2009 }
2010 }
2011 else {
2012 OUTPUT("ID: %d\n", entry[i].Id);
2013 }
2014 }
2015
2016 if (entry[i].DataIsDirectory) {
2017 auto nextDir = (PIMAGE_RESOURCE_DIRECTORY)((BYTE*)baseResourceDir + entry[i].OffsetToDirectory);
2018 if (!IsBadReadPtr(nextDir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
2019 ProcessResourceDirectory32(nextDir, level + 1,
2020 level == 0 ? resourceTypes[min(entry[i].Id, 15)] : type,
2021 baseResourceDir, resourceTypes, analyzer);
2022 }
2023 }
2024 else {
2025 auto dataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)((BYTE*)baseResourceDir + entry[i].OffsetToData);
2026 if (!IsBadReadPtr(dataEntry, sizeof(IMAGE_RESOURCE_DATA_ENTRY))) {
2027 for (int indent = 0; indent < level + 1; indent++) {
2028 OUTPUT("\t");
2029 }
2030 OUTPUT("Size: %d bytes, RVA: 0x%X\n", dataEntry->Size, dataEntry->OffsetToData);
2031
2032 // Special handling for Version resources
2033 if (type && wcscmp(type, L"Version") == 0) {
2034 auto versionData = (BYTE*)PEHelpers::GetRvaPtr(
2035 dataEntry->OffsetToData,
2036 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
2037 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
2038 analyzer.lpFileContent,
2039 analyzer.fileSize);
2040
2041 if (versionData && !IsBadReadPtr(versionData, sizeof(VS_FIXEDFILEINFO))) {
2042 auto versionInfo = (VS_FIXEDFILEINFO*)(versionData + 40);
2043 if (versionInfo->dwSignature == 0xFEEF04BD) {
2044 for (int indent = 0; indent < level + 2; indent++) {
2045 OUTPUT("\t");
2046 }
2047 OUTPUT("File Version: %d.%d.%d.%d\n",
2048 HIWORD(versionInfo->dwFileVersionMS),
2049 LOWORD(versionInfo->dwFileVersionMS),
2050 HIWORD(versionInfo->dwFileVersionLS),
2051 LOWORD(versionInfo->dwFileVersionLS));
2052 }
2053 }
2054 }
2055 }
2056 }
2057 }
2058}
2059
2060void ProcessResourceDirectory64(
2061 PIMAGE_RESOURCE_DIRECTORY resDir,
2062 int level,
2063 const wchar_t* type,
2064 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
2065 const wchar_t* resourceTypes[],
2066 const PEAnalyzer& analyzer)
2067{
2068 // Similar to ProcessResourceDirectory32 but using 64-bit structures
2069 // Main difference is using analyzer.pNtHeaders64 instead of analyzer.pNtHeaders32
2070 if (IsBadReadPtr(resDir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
2071 return;
2072 // Rest of the implementation follows the same pattern
2073 }
2074
2075 auto entry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resDir + 1);
2076 WORD totalEntries = resDir->NumberOfNamedEntries + resDir->NumberOfIdEntries;
2077
2078 for (WORD i = 0; i < totalEntries; i++) {
2079 if (IsBadReadPtr(entry + i, sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY))) {
2080 break;
2081 }
2082
2083 for (int indent = 0; indent < level; indent++) {
2084 OUTPUT("\t");
2085 }
2086
2087 if (entry[i].NameIsString) {
2088 auto nameEntry = (PIMAGE_RESOURCE_DIR_STRING_U)((BYTE*)baseResourceDir + entry[i].NameOffset);
2089 if (!IsBadReadPtr(nameEntry, sizeof(IMAGE_RESOURCE_DIR_STRING_U))) {
2090 std::vector<wchar_t> resourceName(nameEntry->Length + 1);
2091 wcsncpy_s(resourceName.data(), nameEntry->Length + 1,
2092 nameEntry->NameString, nameEntry->Length);
2093 resourceName[nameEntry->Length] = L'\0';
2094
2095 if (level == 0) {
2096 OUTPUT("Resource Type: Custom (%ls)\n", resourceName.data());
2097 }
2098 else {
2099 OUTPUT("Name: %ls\n", resourceName.data());
2100 }
2101 }
2102 }
2103 else {
2104 if (level == 0) {
2105 DWORD resourceType = entry[i].Id;
2106 if (resourceType < 16) {
2107 OUTPUT("Resource Type: %ls (ID: %d)\n", resourceTypes[resourceType], resourceType);
2108 }
2109 else {
2110 OUTPUT("Resource Type: Custom (ID: %d)\n", resourceType);
2111 }
2112 }
2113 else {
2114 OUTPUT("ID: %d\n", entry[i].Id);
2115 }
2116 }
2117
2118 if (entry[i].DataIsDirectory) {
2119 auto nextDir = (PIMAGE_RESOURCE_DIRECTORY)((BYTE*)baseResourceDir + entry[i].OffsetToDirectory);
2120 if (!IsBadReadPtr(nextDir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
2121 ProcessResourceDirectory32(nextDir, level + 1,
2122 level == 0 ? resourceTypes[min(entry[i].Id, 15)] : type,
2123 baseResourceDir, resourceTypes, analyzer);
2124 }
2125 }
2126 else {
2127 auto dataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)((BYTE*)baseResourceDir + entry[i].OffsetToData);
2128 if (!IsBadReadPtr(dataEntry, sizeof(IMAGE_RESOURCE_DATA_ENTRY))) {
2129 for (int indent = 0; indent < level + 1; indent++) {
2130 OUTPUT("\t");
2131 }
2132 OUTPUT("Size: %d bytes, RVA: 0x%X\n", dataEntry->Size, dataEntry->OffsetToData);
2133
2134 // Special handling for Version resources
2135 if (type && wcscmp(type, L"Version") == 0) {
2136 auto versionData = (BYTE*)PEHelpers::GetRvaPtr(
2137 dataEntry->OffsetToData,
2138 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
2139 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
2140 analyzer.lpFileContent,
2141 analyzer.fileSize);
2142
2143 if (versionData && !IsBadReadPtr(versionData, sizeof(VS_FIXEDFILEINFO))) {
2144 auto versionInfo = (VS_FIXEDFILEINFO*)(versionData + 40);
2145 if (versionInfo->dwSignature == 0xFEEF04BD) {
2146 for (int indent = 0; indent < level + 2; indent++) {
2147 OUTPUT("\t");
2148 }
2149 OUTPUT("File Version: %d.%d.%d.%d\n",
2150 HIWORD(versionInfo->dwFileVersionMS),
2151 LOWORD(versionInfo->dwFileVersionMS),
2152 HIWORD(versionInfo->dwFileVersionLS),
2153 LOWORD(versionInfo->dwFileVersionLS));
2154 }
2155 }
2156 }
2157 }
2158 }
2159 }
2160}
2161
2162void ParseResourceDirectory32(const PEAnalyzer& analyzer) {
2163 const auto& resourceDir = analyzer.pNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
2164 if (!resourceDir.VirtualAddress || !resourceDir.Size) return;
2165
2166 if (!PEHelpers::IsRvaValid(resourceDir.VirtualAddress, analyzer.fileSize,
2167 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders32))) {
2168 OUTPUT("[-] Invalid resource directory RVA!\n");
2169 throw std::runtime_error("RVA out of bounds");
2170 return;
2171 }
2172
2173 OUTPUT("\n[+] RESOURCE DIRECTORY (32-bit)\n");
2174 auto pResourceDir = (PIMAGE_RESOURCE_DIRECTORY)PEHelpers::GetRvaPtr(
2175 resourceDir.VirtualAddress,
2176 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
2177 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
2178 analyzer.lpFileContent,
2179 analyzer.fileSize);
2180
2181 if (!pResourceDir || IsBadReadPtr(pResourceDir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
2182 OUTPUT("[-] Invalid or corrupted resource directory\n");
2183 return;
2184 }
2185
2186 const wchar_t* resourceTypes[] = {
2187 L"Unknown", L"Cursor", L"Bitmap", L"Icon",
2188 L"Menu", L"Dialog", L"String", L"FontDir",
2189 L"Font", L"Accelerator", L"RCData", L"MessageTable",
2190 L"GroupCursor", L"GroupIcon", L"Version", L"DlgInclude"
2191 };
2192
2193 ProcessResourceDirectory32(pResourceDir, 0, nullptr, pResourceDir, resourceTypes, analyzer);
2194}
2195
2196void ParseDebugDirectory32(const PEAnalyzer& analyzer) {
2197 const auto& debugDir = analyzer.pNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
2198 if (!debugDir.VirtualAddress || !debugDir.Size) return;
2199
2200 if (!PEHelpers::IsRvaValid(debugDir.VirtualAddress, analyzer.fileSize,
2201 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders32))) {
2202 OUTPUT("[-] Invalid debug directory RVA!\n");
2203 throw std::runtime_error("RVA out of bounds");
2204 return;
2205 }
2206
2207 OUTPUT("\n[+] DEBUG DIRECTORY (32-bit)\n");
2208 auto pDebugDir = (PIMAGE_DEBUG_DIRECTORY)PEHelpers::GetRvaPtr(
2209 debugDir.VirtualAddress,
2210 IMAGE_FIRST_SECTION(analyzer.pNtHeaders32),
2211 analyzer.pNtHeaders32->FileHeader.NumberOfSections,
2212 analyzer.lpFileContent,
2213 analyzer.fileSize);
2214
2215 if (!pDebugDir || IsBadReadPtr(pDebugDir, sizeof(IMAGE_DEBUG_DIRECTORY))) {
2216 OUTPUT("[-] Invalid debug directory structure!\n");
2217 return;
2218 }
2219
2220 DWORD numEntries = min(debugDir.Size / sizeof(IMAGE_DEBUG_DIRECTORY), 16);
2221 for (DWORD i = 0; i < numEntries; i++) {
2222 OUTPUT("\tDebug Entry %d:\n", i + 1);
2223 OUTPUT("\tCharacteristics: 0x%X\n", pDebugDir[i].Characteristics);
2224 OUTPUT("\tTimeDateStamp: 0x%X\n", pDebugDir[i].TimeDateStamp);
2225 OUTPUT("\tMajorVersion: %d\n", pDebugDir[i].MajorVersion);
2226 OUTPUT("\tMinorVersion: %d\n", pDebugDir[i].MinorVersion);
2227 OUTPUT("\tType: 0x%X", pDebugDir[i].Type);
2228
2229 switch (pDebugDir[i].Type) {
2230 case IMAGE_DEBUG_TYPE_COFF:
2231 OUTPUT(" (COFF)\n"); break;
2232 case IMAGE_DEBUG_TYPE_CODEVIEW:
2233 OUTPUT(" (CodeView)\n"); break;
2234 case IMAGE_DEBUG_TYPE_FPO:
2235 OUTPUT(" (FPO)\n"); break;
2236 case IMAGE_DEBUG_TYPE_MISC:
2237 OUTPUT(" (Misc)\n"); break;
2238 case IMAGE_DEBUG_TYPE_EXCEPTION:
2239 OUTPUT(" (Exception)\n"); break;
2240 case IMAGE_DEBUG_TYPE_FIXUP:
2241 OUTPUT(" (Fixup)\n"); break;
2242 case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
2243 OUTPUT(" (OMAP to Src)\n"); break;
2244 case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
2245 OUTPUT(" (OMAP from Src)\n"); break;
2246 case IMAGE_DEBUG_TYPE_BORLAND:
2247 OUTPUT(" (Borland)\n"); break;
2248 default:
2249 OUTPUT(" (Unknown)\n"); break;
2250 }
2251
2252 OUTPUT("\tSizeOfData: 0x%X\n", pDebugDir[i].SizeOfData);
2253 OUTPUT("\tAddressOfRawData: 0x%X\n", pDebugDir[i].AddressOfRawData);
2254 OUTPUT("\tPointerToRawData: 0x%X\n\n", pDebugDir[i].PointerToRawData);
2255
2256 // Special handling for CodeView debug information
2257 if (pDebugDir[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW &&
2258 pDebugDir[i].PointerToRawData != 0 &&
2259 pDebugDir[i].SizeOfData >= sizeof(DWORD)) {
2260
2261 auto pCVHeader = (DWORD*)((BYTE*)analyzer.lpFileContent + pDebugDir[i].PointerToRawData);
2262 if (!IsBadReadPtr(pCVHeader, sizeof(DWORD))) {
2263 switch (*pCVHeader) {
2264 case 0x53445352: // 'RSDS'
2265 if (pDebugDir[i].SizeOfData >= (sizeof(DWORD) + sizeof(GUID) + sizeof(DWORD) + 1)) {
2266 auto pCVData = (char*)(pCVHeader + 1);
2267 if (!IsBadReadPtr(pCVData + 16, 1)) {
2268 auto guid = (GUID*)pCVData;
2269 DWORD age = *(DWORD*)(pCVData + 16);
2270 const char* pdbPath = pCVData + 20;
2271
2272 OUTPUT("\tPDB Information:\n");
2273 OUTPUT("\tGUID: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
2274 guid->Data1, guid->Data2, guid->Data3,
2275 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
2276 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
2277 OUTPUT("\tAge: %d\n", age);
2278 OUTPUT("\tPDB Path: %ls\n\n", pdbPath);
2279 }
2280 }
2281 break;
2282
2283 case 0x3031424E: // 'NB10'
2284 if (pDebugDir[i].SizeOfData >= 16) {
2285 auto pNB10Data = (char*)(pCVHeader + 1);
2286 DWORD offset = *(DWORD*)pNB10Data;
2287 DWORD timestamp = *(DWORD*)(pNB10Data + 4);
2288 DWORD age = *(DWORD*)(pNB10Data + 8);
2289 const char* pdbPath = pNB10Data + 12;
2290
2291 OUTPUT("\tPDB Information (NB10):\n");
2292 OUTPUT("\tOffset: 0x%X\n", offset);
2293 OUTPUT("\tTimestamp: 0x%X\n", timestamp);
2294 OUTPUT("\tAge: %d\n", age);
2295 OUTPUT("\tPDB Path: %ls\n\n", pdbPath);
2296 }
2297 break;
2298 }
2299 }
2300 }
2301 }
2302}
2303
2304void ParseDebugDirectory64(const PEAnalyzer& analyzer) {
2305 const auto& debugDir = analyzer.pNtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
2306 if (!debugDir.VirtualAddress || !debugDir.Size) return;
2307
2308 if (!PEHelpers::IsRvaValid(debugDir.VirtualAddress, analyzer.fileSize,
2309 reinterpret_cast<PIMAGE_NT_HEADERS>(analyzer.pNtHeaders64))) {
2310 OUTPUT("[-] Invalid debug directory RVA!\n");
2311 throw std::runtime_error("RVA out of bounds");
2312 return;
2313 }
2314
2315 OUTPUT("\n[+] DEBUG DIRECTORY (64-bit)\n");
2316 // Rest of implementation follows same pattern as 32-bit version
2317 // Just using pNtHeaders64 instead of pNtHeaders32
2318 auto pDebugDir = (PIMAGE_DEBUG_DIRECTORY)PEHelpers::GetRvaPtr(
2319 debugDir.VirtualAddress,
2320 IMAGE_FIRST_SECTION(analyzer.pNtHeaders64),
2321 analyzer.pNtHeaders64->FileHeader.NumberOfSections,
2322 analyzer.lpFileContent,
2323 analyzer.fileSize);
2324
2325 if (!pDebugDir || IsBadReadPtr(pDebugDir, sizeof(IMAGE_DEBUG_DIRECTORY))) {
2326 OUTPUT("[-] Invalid debug directory structure!\n");
2327 return;
2328 }
2329
2330 DWORD numEntries = min(debugDir.Size / sizeof(IMAGE_DEBUG_DIRECTORY), 16);
2331 for (DWORD i = 0; i < numEntries; i++) {
2332 OUTPUT("\tDebug Entry %d:\n", i + 1);
2333 OUTPUT("\tCharacteristics: 0x%X\n", pDebugDir[i].Characteristics);
2334 OUTPUT("\tTimeDateStamp: 0x%X\n", pDebugDir[i].TimeDateStamp);
2335 OUTPUT("\tMajorVersion: %d\n", pDebugDir[i].MajorVersion);
2336 OUTPUT("\tMinorVersion: %d\n", pDebugDir[i].MinorVersion);
2337 OUTPUT("\tType: 0x%X", pDebugDir[i].Type);
2338
2339 switch (pDebugDir[i].Type) {
2340 case IMAGE_DEBUG_TYPE_COFF:
2341 OUTPUT(" (COFF)\n"); break;
2342 case IMAGE_DEBUG_TYPE_CODEVIEW:
2343 OUTPUT(" (CodeView)\n"); break;
2344 case IMAGE_DEBUG_TYPE_FPO:
2345 OUTPUT(" (FPO)\n"); break;
2346 case IMAGE_DEBUG_TYPE_MISC:
2347 OUTPUT(" (Misc)\n"); break;
2348 case IMAGE_DEBUG_TYPE_EXCEPTION:
2349 OUTPUT(" (Exception)\n"); break;
2350 case IMAGE_DEBUG_TYPE_FIXUP:
2351 OUTPUT(" (Fixup)\n"); break;
2352 case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
2353 OUTPUT(" (OMAP to Src)\n"); break;
2354 case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
2355 OUTPUT(" (OMAP from Src)\n"); break;
2356 case IMAGE_DEBUG_TYPE_BORLAND:
2357 OUTPUT(" (Borland)\n"); break;
2358 default:
2359 OUTPUT(" (Unknown)\n"); break;
2360 }
2361
2362 OUTPUT("\tSizeOfData: 0x%X\n", pDebugDir[i].SizeOfData);
2363 OUTPUT("\tAddressOfRawData: 0x%X\n", pDebugDir[i].AddressOfRawData);
2364 OUTPUT("\tPointerToRawData: 0x%X\n\n", pDebugDir[i].PointerToRawData);
2365
2366 // Special handling for CodeView debug information
2367 if (pDebugDir[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW &&
2368 pDebugDir[i].PointerToRawData != 0 &&
2369 pDebugDir[i].SizeOfData >= sizeof(DWORD)) {
2370
2371 auto pCVHeader = (DWORD*)((BYTE*)analyzer.lpFileContent + pDebugDir[i].PointerToRawData);
2372 if (!IsBadReadPtr(pCVHeader, sizeof(DWORD))) {
2373 switch (*pCVHeader) {
2374 case 0x53445352: // 'RSDS'
2375 if (pDebugDir[i].SizeOfData >= (sizeof(DWORD) + sizeof(GUID) + sizeof(DWORD) + 1)) {
2376 auto pCVData = (char*)(pCVHeader + 1);
2377 if (!IsBadReadPtr(pCVData + 16, 1)) {
2378 auto guid = (GUID*)pCVData;
2379 DWORD age = *(DWORD*)(pCVData + 16);
2380 const char* pdbPath = pCVData + 20;
2381
2382 OUTPUT("\tPDB Information:\n");
2383 OUTPUT("\tGUID: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
2384 guid->Data1, guid->Data2, guid->Data3,
2385 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
2386 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
2387 OUTPUT("\tAge: %d\n", age);
2388 OUTPUT("\tPDB Path: %ls\n\n", pdbPath);
2389 }
2390 }
2391 break;
2392
2393 case 0x3031424E: // 'NB10'
2394 if (pDebugDir[i].SizeOfData >= 16) {
2395 auto pNB10Data = (char*)(pCVHeader + 1);
2396 DWORD offset = *(DWORD*)pNB10Data;
2397 DWORD timestamp = *(DWORD*)(pNB10Data + 4);
2398 DWORD age = *(DWORD*)(pNB10Data + 8);
2399 const char* pdbPath = pNB10Data + 12;
2400
2401 OUTPUT("\tPDB Information (NB10):\n");
2402 OUTPUT("\tOffset: 0x%X\n", offset);
2403 OUTPUT("\tTimestamp: 0x%X\n", timestamp);
2404 OUTPUT("\tAge: %d\n", age);
2405 OUTPUT("\tPDB Path: %ls\n\n", pdbPath);
2406 }
2407 break;
2408 }
2409 }
2410 }
2411 }
2412}
2413// ... [Same implementation as ParseDebugDirectory32]
2414
2415//newfunctionshere (lateest fixes)
2416
2417
2418void ProcessResourceDirectory32(
2419 PIMAGE_RESOURCE_DIRECTORY resDir,
2420 int level,
2421 const wchar_t* type,
2422 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
2423 const wchar_t* resourceTypes[],
2424 const PEAnalyzer& analyzer);
2425
2426void ProcessResourceDirectory64(
2427 PIMAGE_RESOURCE_DIRECTORY resDir,
2428 int level,
2429 const wchar_t* type,
2430 PIMAGE_RESOURCE_DIRECTORY baseResourceDir,
2431 const wchar_t* resourceTypes[],
2432 const PEAnalyzer& analyzer);
2433
2434// Main window class name
2435//const char* const WINDOW_CLASS_NAME = "PEAnalyzerWindow";
2436
2437//new inserted here >>
2438
2439// Page Break
2440
2441//here
2442
2443// Page Break
2444
2445void AddMenus(HWND hwnd) {
2446 HMENU hMenuBar = CreateMenu();
2447 HMENU hFileMenu = CreateMenu();
2448 AppendMenu(hMenuBar, MF_POPUP, (UINT_PTR)hFileMenu, L"&File");
2449 AppendMenu(hFileMenu, MF_STRING, 1, L"&Open\tCtrl+O"); // Updated to show shortcut
2450 AppendMenu(hFileMenu, MF_STRING, 2, L"&Select All\tCtrl+A");
2451 AppendMenu(hFileMenu, MF_STRING, 3, L"E&xit\tAlt+F4");
2452 EnableMenuItem(hFileMenu, 2, MF_BYCOMMAND | MF_GRAYED);
2453 //EnableMenuItem(hFileMenu, ID_FILE_SELECTALL, MF_BYCOMMAND | MF_GRAYED);
2454 SetMenu(hwnd, hMenuBar);
2455}
2456
2457/*void AddMenus(HWND hwnd) {
2458 HMENU hMenuBar = CreateMenu();
2459 HMENU hFileMenu = CreateMenu();
2460
2461 // Create the File menu using the defined IDs.
2462 AppendMenu(hMenuBar, MF_POPUP, (UINT_PTR)hFileMenu, L"&File");
2463 AppendMenu(hFileMenu, MF_STRING, ID_FILE_OPEN, L"&Open\tCtrl+O");
2464 AppendMenu(hFileMenu, MF_STRING, ID_FILE_SELECTALL, L"&Select All");
2465 AppendMenu(hFileMenu, MF_STRING, ID_FILE_EXIT, L"E&xit");
2466
2467 // Initially disable the "Select All" menu item.
2468 EnableMenuItem(hFileMenu, ID_FILE_SELECTALL, MF_BYCOMMAND | MF_GRAYED);
2469 SetMenu(hwnd, hMenuBar);
2470}*/
2471
2472// First, add this helper function to determine if the PE file is 64-bit
2473bool Is64BitPE(PIMAGE_NT_HEADERS pNtHeaders) {
2474 return pNtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
2475} //removing this duplicate
2476
2477// Helper function to safely get file size
2478/*DWORD GetFileSizeCustom(const wchar_t* filePath) {
2479 HANDLE hFile = CreateFileW(filePath, GENERIC_READ, FILE_SHARE_READ,
2480 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
2481
2482 if (hFile == INVALID_HANDLE_VALUE) {
2483 return 0;
2484 }
2485
2486 DWORD fileSize = ::GetFileSize(hFile, nullptr);
2487 CloseHandle(hFile);
2488 return fileSize;
2489}*/ //removing this duplicate instead
2490
2491// Add this helper function
2492void SafeOutput(const std::wstring& text) {
2493 try {
2494 g_OutputText << text;
2495 UpdateEditControl();
2496 }
2497 catch (...) {
2498 SetStatusText(L"Error writing output");
2499 }
2500}
2501
2502void UpdateStatusBar(const wchar_t* text, int progress = -1) {
2503 if (text) {
2504 SetStatusText(text);
2505 }
2506 if (progress >= 0) {
2507 ShowProgress(progress);
2508 }
2509}
2510
2511void ClearProgress() {
2512 ShowWindow(g_hProgressBar, SW_HIDE);
2513 SetStatusText(L"Ready");
2514}
2515
2516
2517
2518void SetStatusText(const wchar_t* text) {
2519 SendMessage(g_hStatusBar, SB_SETTEXT, 0, (LPARAM)text);
2520}
2521
2522void ShowProgress(int percentage) {
2523 if (percentage < 0 || percentage > 100) {
2524 OUTPUT("[-] Invalid progress percentage: %d\n", percentage);
2525 return;
2526 }
2527
2528 SendMessage(g_hProgressBar, PBM_SETPOS, (WPARAM)percentage, 0);
2529 wchar_t status[256];
2530 swprintf_s(status, L"Analyzing... %d%%", percentage);
2531 SetStatusText(status);
2532 SendMessage(g_hStatusBar, SB_SETTEXT, 0, (LPARAM)status);
2533}
2534
2535void OpenFileDialog(HWND hwnd) {
2536 WCHAR fileName[MAX_PATH] = L"";
2537 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 };
2538 if (GetOpenFileNameW(&ofn)) {
2539 SetWindowTextW(g_hEditControl, L"");
2540 g_OutputText.str(L"");
2541 g_OutputText.clear();
2542 AnalyzePEFile(ofn.lpstrFile);
2543 UpdateEditControl();
2544 }
2545}
2546
2547
2548// Modified AppendToOutput to handle newlines properly:
2549void AppendToOutput(const wchar_t* format, ...) {
2550 std::vector<wchar_t> buffer(4096); //recent 19/2/25 (1024)*
2551 va_list args;
2552 va_start(args, format);
2553
2554 while (true) {
2555 va_list argsCopy;
2556 va_copy(argsCopy, args);
2557 int result = _vsnwprintf(buffer.data(), buffer.size(), format, argsCopy);
2558 va_end(argsCopy);
2559 if (result >= 0) break;
2560 buffer.resize(buffer.size() * 2);
2561 }
2562 va_end(args);
2563
2564 // Convert \n to \r\n
2565 std::wstring output = buffer.data();
2566 size_t pos = 0;
2567 while ((pos = output.find(L'\n', pos)) != std::wstring::npos) {
2568 if (pos == 0 || output[pos - 1] != L'\r') {
2569 output.insert(pos, L"\r");
2570 pos += 2;
2571 }
2572 else {
2573 pos++;
2574 }
2575 }
2576
2577 g_OutputText << output;
2578 UpdateEditControl();
2579}
2580
2581
2582//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
2583
2584//adding here
2585// Line Break
2586// new code below starting here vv
2587
2588
2589
2590DWORD GetFileSize(const wchar_t* filePath) {
2591 HANDLE hFile = CreateFileW(filePath, GENERIC_READ, FILE_SHARE_READ,
2592 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
2593 if (hFile == INVALID_HANDLE_VALUE) return 0;
2594
2595 DWORD fileSize = ::GetFileSize(hFile, nullptr);
2596 CloseHandle(hFile);
2597 return fileSize;
2598}
2599//}
2600// Page Break
2601
2602//}
2603
2604//UpdateEditControl();
2605//}
2606
2607// new code upto here ending here ^^
2608// Line Break
2609// //end adding here
2610
2611
2612
2613//filePathW
2614//lpFilePath
2615/*
2616HANDLE GetFileContent(const wchar_t* lpFilePath) {
2617 HANDLE hFile = CreateFileW(lpFilePath, GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);
2618 if (hFile == INVALID_HANDLE_VALUE) return nullptr;
2619 DWORD fileSize = ::GetFileSize(hFile, nullptr);
2620 auto lpFileContent = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, fileSize);
2621 DWORD bytesRead;
2622 ReadFile(hFile, lpFileContent, fileSize, &bytesRead, nullptr);
2623 CloseHandle(hFile);
2624 return lpFileContent;
2625}
2626*/
2627
2628void UpdateEditControl() {
2629 SetWindowTextW(g_hEditControl, g_OutputText.str().c_str());
2630 SendMessage(g_hEditControl, EM_SETSEL, -1, -1);
2631 SendMessage(g_hEditControl, EM_SCROLLCARET, 0, 0);
2632}
2633//}
2634
2635int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
2636 INITCOMMONCONTROLSEX icc = { sizeof(INITCOMMONCONTROLSEX), ICC_WIN95_CLASSES };
2637 InitCommonControlsEx(&icc);
2638
2639 // Get command line parameters in Unicode
2640 int argc;
2641 LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
2642
2643 CreateMainWindow(hInstance);
2644 if (!g_hMainWindow) {
2645 LocalFree(argv);
2646 return -1;
2647 }
2648
2649 ShowWindow(g_hMainWindow, nCmdShow);
2650 UpdateWindow(g_hMainWindow);
2651 SetWindowPos(g_hMainWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2652
2653 // If there's a command line parameter, process it
2654 if (argc > 1) {
2655 // Process the first parameter as file path
2656 SetWindowTextW(g_hEditControl, L"");
2657 g_OutputText.str(L"");
2658 g_OutputText.clear();
2659 AnalyzePEFile(argv[1]);
2660 UpdateEditControl();
2661 }
2662
2663 LocalFree(argv);
2664
2665 MSG msg = {};
2666 while (GetMessage(&msg, NULL, 0, 0)) {
2667 TranslateMessage(&msg);
2668 DispatchMessage(&msg);
2669 }
2670
2671 if (g_hFont) DeleteObject(g_hFont);
2672 return (int)msg.wParam;
2673}
2674
2675void CreateMainWindow(HINSTANCE hInstance) {
2676 WNDCLASSEXW wc = { sizeof(WNDCLASSEXW), 0, WindowProc, 0, 0, hInstance,
2677 LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)),
2678 LoadCursor(NULL, IDC_ARROW),
2679 (HBRUSH)(COLOR_WINDOW + 1),
2680 NULL, WINDOW_CLASS_NAME,
2681 LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)) };
2682 RegisterClassExW(&wc);
2683
2684 // Get screen dimensions
2685 int screenWidth = GetSystemMetrics(SM_CXSCREEN);
2686 int screenHeight = GetSystemMetrics(SM_CYSCREEN);
2687
2688 // Calculate center position
2689 int windowX = (screenWidth - WINDOW_WIDTH) / 2;
2690 int windowY = (screenHeight - WINDOW_HEIGHT) / 2;
2691
2692 // Remove WS_MAXIMIZEBOX and WS_THICKFRAME from the window style
2693 DWORD style = (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX) & ~WS_THICKFRAME;
2694 //WS_OVERLAPPEDWINDOW ~~> style
2695 g_hMainWindow = CreateWindowExW(0, WINDOW_CLASS_NAME, L"PE File Analyzer v6.7 (F1=About)",
2696 style, windowX, windowY, WINDOW_WIDTH, WINDOW_HEIGHT,
2697 nullptr, nullptr, hInstance, nullptr);
2698}
2699
2700void InitializeControls(HWND hwnd) {
2701 // Create status bar
2702 g_hStatusBar = CreateWindowEx(0, STATUSCLASSNAME, NULL,
2703 WS_CHILD | WS_VISIBLE,
2704 0, 0, 0, 0, hwnd, NULL,
2705 (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), NULL);
2706
2707 // Set up status bar parts
2708 RECT rcClient;
2709 GetClientRect(hwnd, &rcClient);
2710 int statusParts[2] = { 150, rcClient.right };
2711 SendMessage(g_hStatusBar, SB_SETPARTS, 2, (LPARAM)statusParts);
2712
2713 // Create progress bar in the second part of status bar
2714 RECT rcPart;
2715 SendMessage(g_hStatusBar, SB_GETRECT, 1, (LPARAM)&rcPart);
2716
2717 g_hProgressBar = CreateWindowEx(0, PROGRESS_CLASS, NULL,
2718 WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
2719 rcPart.left + 5, rcPart.top + 2,
2720 rcPart.right - rcPart.left - 10, rcPart.bottom - rcPart.top - 4,
2721 g_hStatusBar, NULL,
2722 (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), NULL);
2723
2724 // Set blue color and range
2725 SendMessage(g_hProgressBar, PBM_SETBARCOLOR, 0, (LPARAM)RGB(0, 120, 215)); // Windows 10 blue
2726 SendMessage(g_hProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
2727 SendMessage(g_hProgressBar, PBM_SETSTEP, 1, 0);
2728
2729 // Get status bar height for edit control positioning
2730 RECT rcStatus;
2731 GetWindowRect(g_hStatusBar, &rcStatus);
2732 int statusHeight = rcStatus.bottom - rcStatus.top;
2733
2734 // Create edit control
2735 g_hEditControl = CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT", L"",
2736 WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL |
2737 ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL,
2738 EDIT_MARGIN, EDIT_MARGIN,
2739 rcClient.right - (2 * EDIT_MARGIN),
2740 rcClient.bottom - statusHeight - (2 * EDIT_MARGIN),
2741 hwnd, nullptr,
2742 (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), nullptr);
2743
2744 // Allow the edit control to accept dropped files.
2745 DragAcceptFiles(g_hEditControl, TRUE);
2746
2747 // Create and set font
2748 g_hFont = CreateFont(-14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0,
2749 ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
2750 DEFAULT_QUALITY, DEFAULT_PITCH | FF_MODERN, L"Consolas");
2751
2752 if (g_hFont)
2753 SendMessage(g_hEditControl, WM_SETFONT, (WPARAM)g_hFont, TRUE);
2754
2755 SetWindowSubclass(g_hEditControl, EditSubclassProc, 0, 0);
2756}
2757
2758LRESULT CALLBACK EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {
2759 if (uMsg == WM_KEYDOWN) {
2760 if ((GetKeyState(VK_CONTROL) & 0x8000) && wParam == 'O') {
2761 SendMessage(GetParent(hwnd), WM_COMMAND, 1, 0);
2762 return 0;
2763 }
2764 switch (wParam) {
2765 case VK_F1:
2766 SendMessage(GetParent(hwnd), WM_KEYDOWN, VK_F1, 0);
2767 return 0;
2768 case VK_ESCAPE:
2769 SendMessage(GetParent(hwnd), WM_KEYDOWN, VK_ESCAPE, 0);
2770 return 0;
2771 case VK_PRIOR:
2772 // Scroll up
2773 SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_PAGEUP, 0), 0);
2774 return 0;
2775 case VK_NEXT:
2776 // Scroll down
2777 SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_PAGEDOWN, 0), 0);
2778 return 0;
2779 case VK_UP:
2780 // Scroll one line up
2781 SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0);
2782 return 0;
2783 case VK_DOWN:
2784 // Scroll one line down
2785 SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0);
2786 return 0;
2787 }
2788 }
2789 if (uMsg == WM_MOUSEWHEEL) {
2790 int delta = GET_WHEEL_DELTA_WPARAM(wParam);
2791 if (delta > 0) {
2792 // Scroll up
2793 SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_PAGEUP, 0), 0);
2794 }
2795 else {
2796 // Scroll down
2797 SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_PAGEDOWN, 0), 0);
2798 }
2799 return 0;
2800 }
2801 // Check for Ctrl+A: the 'A' key (wParam == 'A') along with the CTRL key held down.
2802 if (wParam == 'A' && (GetKeyState(VK_CONTROL) & 0x8000))
2803 {
2804 // Select all text in the edit control.
2805 SendMessage(hwnd, EM_SETSEL, 0, -1);
2806 return 0; // indicate that the message has been handled.
2807 }
2808 // Handle file drops
2809 if (uMsg == WM_DROPFILES) {
2810 HDROP hDrop = (HDROP)wParam;
2811 UINT fileCount = DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0);
2812 if (fileCount > 0) {
2813 wchar_t filePath[MAX_PATH];
2814 if (DragQueryFileW(hDrop, 0, filePath, MAX_PATH)) {
2815 // Call your file analysis function with the dropped file path.
2816 AnalyzePEFile(filePath);
2817 }
2818 }
2819 DragFinish(hDrop);
2820 return 0; // Indicate that the message was handled.
2821 }
2822 return DefSubclassProc(hwnd, uMsg, wParam, lParam);
2823}
2824
2825LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
2826 switch (uMsg) {
2827 case WM_CREATE: InitializeControls(hwnd); AddMenus(hwnd); return 0;
2828 case WM_SIZE:
2829 {
2830 RECT rcClient;
2831 GetClientRect(hwnd, &rcClient);
2832
2833 // Resize status bar
2834 SendMessage(g_hStatusBar, WM_SIZE, 0, 0);
2835
2836 // Recalculate status bar parts
2837 int statusParts[2] = { 150, rcClient.right };
2838 SendMessage(g_hStatusBar, SB_SETPARTS, 2, (LPARAM)statusParts);
2839
2840 // Reposition progress bar
2841 RECT rcPart;
2842 SendMessage(g_hStatusBar, SB_GETRECT, 1, (LPARAM)&rcPart);
2843 SetWindowPos(g_hProgressBar, NULL,
2844 rcPart.left + 5, rcPart.top + 2,
2845 rcPart.right - rcPart.left - 10, rcPart.bottom - rcPart.top - 4,
2846 SWP_NOZORDER);
2847
2848 // Get status bar height
2849 RECT rcStatus;
2850 GetWindowRect(g_hStatusBar, &rcStatus);
2851 int statusHeight = rcStatus.bottom - rcStatus.top;
2852
2853 // Resize edit control
2854 SetWindowPos(g_hEditControl, NULL,
2855 EDIT_MARGIN,
2856 EDIT_MARGIN,
2857 rcClient.right - (2 * EDIT_MARGIN),
2858 rcClient.bottom - statusHeight - (2 * EDIT_MARGIN),
2859 SWP_NOZORDER);
2860
2861 if (wParam == SIZE_MINIMIZED)
2862 {
2863 SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2864 }
2865 else
2866 {
2867 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2868 }
2869
2870 return 0;
2871 }
2872
2873 case WM_KEYDOWN:
2874 {
2875 if (GetKeyState(VK_CONTROL) & 0x8000) {
2876 switch (wParam) {
2877 case 'O':
2878 OpenFileDialog(hwnd);
2879 return 0;
2880 }
2881 }
2882 switch (wParam) {
2883 case VK_F1:
2884 MessageBoxW(hwnd,
2885 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",
2886 L"About",
2887 MB_OK | MB_ICONINFORMATION);
2888 return 0;
2889 case VK_ESCAPE:
2890 PostQuitMessage(0);
2891 return 0;
2892 case VK_PRIOR:
2893 // Scroll up
2894 SendMessage(g_hEditControl, WM_VSCROLL, MAKELONG(SB_PAGEUP, 0), 0);
2895 return 0;
2896 case VK_NEXT:
2897 // Scroll down
2898 SendMessage(g_hEditControl, WM_VSCROLL, MAKELONG(SB_PAGEDOWN, 0), 0);
2899 return 0;
2900 case VK_UP:
2901 // Scroll one line up
2902 SendMessage(g_hEditControl, WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0);
2903 return 0;
2904 case VK_DOWN:
2905 // Scroll one line down
2906 SendMessage(g_hEditControl, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0);
2907 return 0;
2908 }
2909 break;
2910 }
2911 case WM_MOUSEWHEEL:
2912 {
2913 int delta = GET_WHEEL_DELTA_WPARAM(wParam);
2914 if (delta > 0) {
2915 // Scroll up
2916 SendMessage(g_hEditControl, WM_VSCROLL, MAKELONG(SB_PAGEUP, 0), 0);
2917 }
2918 else {
2919 // Scroll down
2920 SendMessage(g_hEditControl, WM_VSCROLL, MAKELONG(SB_PAGEDOWN, 0), 0);
2921 }
2922 return 0;
2923 }
2924 case WM_COMMAND:
2925 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;
2926
2927/* switch (LOWORD(wParam)) {
2928 case ID_FILE_OPEN:
2929 OpenFileDialog(hwnd);
2930 break;
2931 case ID_FILE_SELECTALL:
2932 if (g_hEditControl) {
2933 // Set focus to the edit control if needed.
2934 SetFocus(g_hEditControl);
2935 // Select all text.
2936 SendMessage(g_hEditControl, EM_SETSEL, 0, -1);
2937 UpdateEditControl();
2938 }
2939 break;
2940 case ID_FILE_EXIT:
2941 PostQuitMessage(0);
2942 break;
2943 }
2944 return 0; */
2945
2946 /* {
2947 int cmd = LOWORD(wParam);
2948 if (cmd == 1) {
2949 OpenFileDialog(hwnd);
2950 }
2951 else if (cmd == 2) { // This is your Select All command.
2952 if (g_hEditControl) {
2953 SetFocus(g_hEditControl);
2954 SendMessage(g_hEditControl, EM_SETSEL, 0, -1);
2955 UpdateEditControl(); // if necessary to refresh display
2956 }
2957 }
2958 else if (cmd == 3) { // This is your Exit command.
2959 PostQuitMessage(0);
2960 }
2961 return 0;
2962 } */
2963
2964/* switch (LOWORD(wParam)) {
2965 case ID_FILE_OPEN:
2966 OpenFileDialog(hwnd);
2967 break;
2968 case ID_FILE_SELECTALL:
2969 if (g_hEditControl) {
2970 // Set focus to the edit control
2971 SetFocus(g_hEditControl);
2972 // Select all text
2973 SendMessage(g_hEditControl, EM_SETSEL, 0, -1);
2974 UpdateEditControl();
2975 }
2976 break;
2977 case ID_FILE_EXIT:
2978 PostQuitMessage(0);
2979 break;
2980 }
2981 return 0;
2982*/
2983 case WM_DESTROY:
2984 if (g_hStatusBar) DestroyWindow(g_hStatusBar);
2985 PostQuitMessage(0);
2986 return 0;
2987 }
2988 return DefWindowProc(hwnd, uMsg, wParam, lParam);
2989}
2990```
2991
2992==++ Here's the full source for (file 2/3) "PEHeaders.h"::: ++==
2993```PEHeaders.h
2994#pragma once
2995#ifndef PE_ANALYZER_STRUCT_H
2996#define PE_ANALYZER_STRUCT_H
2997#include <Windows.h>
2998#include <winternl.h>
2999#include <memory>
3000class FileMapper;
3001
3002// Core PE analysis structure
3003struct PEAnalyzer {
3004 LPVOID lpFileContent;
3005 DWORD fileSize;
3006 bool is64Bit;
3007 PIMAGE_NT_HEADERS32 pNtHeaders32;
3008 PIMAGE_NT_HEADERS64 pNtHeaders64;
3009 PIMAGE_DOS_HEADER pDosHeader;
3010 FileMapper* pMapper; // <<-- inserted
3011
3012 PEAnalyzer() : lpFileContent(nullptr), fileSize(0), is64Bit(false),
3013 pNtHeaders32(nullptr), pNtHeaders64(nullptr), pDosHeader(nullptr), pMapper(nullptr) {}
3014
3015 // Remove destructor as FileMapper will handle cleanup
3016};
3017//struct PEAnalyzer; // Add this before the namespace
3018// Declare functions that use PEAnalyzer
3019 template<typename T>
3020 bool IsSafeToRead(const PEAnalyzer& analyzer, const T* ptr, size_t size);
3021#endif // PE_ANALYZER_STRUCT_H
3022namespace PEHelpers {
3023//ifndef OUTPUT was here
3024
3025 // Inline function to prevent multiple definition
3026 inline bool Is64BitPE(PIMAGE_NT_HEADERS pNtHeaders) {
3027 return pNtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
3028 }
3029 //bool ValidateFileSize(const PEAnalyzer& analyzer, DWORD expectedSize, DWORD fileSize);
3030 bool ValidateFileSize(DWORD expectedSize, DWORD fileSize);
3031 // Add the template function declaration here
3032 //template<typename T>
3033 //bool IsSafeToRead(const PEAnalyzer& analyzer, const T* ptr, size_t size);
3034 bool IsRvaValid(DWORD rva, DWORD fileSize, PIMAGE_NT_HEADERS pNtHeaders);
3035 DWORD_PTR GetImageBase(PIMAGE_NT_HEADERS pNtHeaders);
3036 DWORD GetSizeOfImage(PIMAGE_NT_HEADERS pNtHeaders);
3037 DWORD_PTR GetRvaPtr(DWORD rva, PIMAGE_SECTION_HEADER pSectionHeader,
3038 WORD numberOfSections, LPVOID baseAddress);
3039 DWORD RvaToOffset(DWORD rva, PIMAGE_SECTION_HEADER pSectionHeader,
3040 WORD numberOfSections);
3041 std::wstring GetImageCharacteristics(DWORD characteristics);
3042 std::wstring GetSubsystem(WORD subsystem);
3043 std::wstring GetDataDirectoryName(int DirectoryNumber);
3044 std::wstring GetSectionProtection(DWORD characteristics);
3045
3046 // using namespace std;
3047 // using namespace PEAnalyzer;
3048 // Core PE validation functions
3049 // Ensure this function is defined exactly once
3050 /*inline bool Is64BitPE(PIMAGE_NT_HEADERS pNtHeaders) {
3051 return pNtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
3052 }*/
3053
3054/*bool Is64BitPE(PIMAGE_NT_HEADERS pNtHeaders) {
3055 return pNtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
3056}*/
3057
3058bool ValidateFileSize(DWORD expectedSize, DWORD fileSize) {
3059 return expectedSize > 0 && expectedSize <= fileSize;
3060}
3061
3062template<typename T>
3063bool IsSafeToRead(const PEAnalyzer& analyzer, const T* ptr, size_t size = sizeof(T)) {
3064 // Check if pointer is null
3065 if (!ptr) {
3066 OUTPUT("[-] Null pointer detected\n");
3067 return false;
3068 }
3069
3070 // Calculate pointer ranges
3071 DWORD_PTR startAddress = reinterpret_cast<DWORD_PTR>(analyzer.lpFileContent);
3072 DWORD_PTR endAddress = startAddress + analyzer.fileSize;
3073 DWORD_PTR ptrAddress = reinterpret_cast<DWORD_PTR>(ptr);
3074 DWORD_PTR ptrEndAddress = ptrAddress + size;
3075
3076 // Comprehensive pointer validation
3077 bool isValidPointer = (
3078 ptr != nullptr && // Not null
3079 ptrAddress >= startAddress && // Above file start
3080 ptrEndAddress <= endAddress && // Below file end
3081 ptrAddress < ptrEndAddress // Prevent integer overflow
3082 );
3083
3084 if (!isValidPointer) {
3085 OUTPUT("[-] Pointer validation failed\n");
3086 OUTPUT(" Pointer: 0x%p\n", ptr);
3087 OUTPUT(" File Start: 0x%p\n", reinterpret_cast<void*>(startAddress));
3088 OUTPUT(" File End: 0x%p\n", reinterpret_cast<void*>(endAddress));
3089 OUTPUT(" Pointer Start: 0x%p\n", reinterpret_cast<void*>(ptrAddress));
3090 OUTPUT(" Pointer End: 0x%p\n", reinterpret_cast<void*>(ptrEndAddress));
3091 return false;
3092 }
3093
3094 return true;
3095}
3096
3097bool IsRvaValid(DWORD rva, DWORD fileSize, PIMAGE_NT_HEADERS pNtHeaders) {
3098 if (!pNtHeaders) {
3099 OUTPUT("[-] Invalid NT Headers for RVA validation\n");
3100 return false;
3101 }
3102
3103 DWORD sizeOfImage = PEHelpers::Is64BitPE(pNtHeaders) ?
3104 reinterpret_cast<PIMAGE_NT_HEADERS64>(pNtHeaders)->OptionalHeader.SizeOfImage :
3105 reinterpret_cast<PIMAGE_NT_HEADERS32>(pNtHeaders)->OptionalHeader.SizeOfImage;
3106
3107 bool isValid = (
3108 rva > 0 && // RVA is non-zero
3109 rva < sizeOfImage&& // RVA is within image size
3110 rva < fileSize // RVA is within file size
3111 );
3112
3113 if (!isValid) {
3114 OUTPUT("[-] Invalid RVA: 0x%X\n", rva);
3115 OUTPUT(" Size of Image: 0x%X\n", sizeOfImage);
3116 OUTPUT(" File Size: 0x%X\n", fileSize);
3117 }
3118
3119 return isValid;
3120}
3121
3122/*bool IsRvaValid(DWORD rva, DWORD fileSize, PIMAGE_NT_HEADERS pNtHeaders) {
3123 return rva < pNtHeaders->OptionalHeader.SizeOfImage&& rva < fileSize;
3124}*/
3125
3126DWORD_PTR GetImageBase(PIMAGE_NT_HEADERS pNtHeaders) {
3127 if (PEHelpers::Is64BitPE(pNtHeaders)) { // Add PEHelpers:: namespace qualifier
3128 auto pNtHeaders64 = reinterpret_cast<PIMAGE_NT_HEADERS64>(pNtHeaders);
3129 return static_cast<DWORD_PTR>(pNtHeaders64->OptionalHeader.ImageBase);
3130 }
3131 auto pNtHeaders32 = reinterpret_cast<PIMAGE_NT_HEADERS32>(pNtHeaders);
3132 return static_cast<DWORD_PTR>(pNtHeaders32->OptionalHeader.ImageBase);
3133}
3134
3135DWORD GetSizeOfImage(PIMAGE_NT_HEADERS pNtHeaders) {
3136 if (PEHelpers::Is64BitPE(pNtHeaders)) { // Add PEHelpers:: namespace qualifier
3137 auto pNtHeaders64 = reinterpret_cast<PIMAGE_NT_HEADERS64>(pNtHeaders);
3138 return pNtHeaders64->OptionalHeader.SizeOfImage;
3139 }
3140 auto pNtHeaders32 = reinterpret_cast<PIMAGE_NT_HEADERS32>(pNtHeaders);
3141 return pNtHeaders32->OptionalHeader.SizeOfImage;
3142}
3143
3144/* // RVA and address conversion helpers
3145DWORD_PTR GetImageBase(PIMAGE_NT_HEADERS pNtHeaders) {
3146 if (Is64BitPE(pNtHeaders)) {
3147 auto pNtHeaders64 = reinterpret_cast<PIMAGE_NT_HEADERS64>(pNtHeaders);
3148 return static_cast<DWORD_PTR>(pNtHeaders64->OptionalHeader.ImageBase);
3149 }
3150 auto pNtHeaders32 = reinterpret_cast<PIMAGE_NT_HEADERS32>(pNtHeaders);
3151 return static_cast<DWORD_PTR>(pNtHeaders32->OptionalHeader.ImageBase);
3152}
3153
3154DWORD GetSizeOfImage(PIMAGE_NT_HEADERS pNtHeaders) {
3155 if (Is64BitPE(pNtHeaders)) {
3156 auto pNtHeaders64 = reinterpret_cast<PIMAGE_NT_HEADERS64>(pNtHeaders);
3157 return pNtHeaders64->OptionalHeader.SizeOfImage;
3158 }
3159 auto pNtHeaders32 = reinterpret_cast<PIMAGE_NT_HEADERS32>(pNtHeaders);
3160 return pNtHeaders32->OptionalHeader.SizeOfImage;
3161}*/
3162
3163DWORD_PTR GetRvaPtr(
3164 DWORD rva,
3165 PIMAGE_SECTION_HEADER pSectionHeader,
3166 WORD numberOfSections,
3167 LPVOID baseAddress,
3168 DWORD fileSize // Add file size as a parameter
3169) {
3170 if (!rva || !pSectionHeader || !baseAddress) {
3171 OUTPUT("[-] Invalid parameters in GetRvaPtr\n");
3172 return 0;
3173 }
3174
3175 for (WORD i = 0; i < numberOfSections; i++) {
3176 // Check if RVA falls within this section
3177 if (rva >= pSectionHeader[i].VirtualAddress &&
3178 rva < (pSectionHeader[i].VirtualAddress + pSectionHeader[i].SizeOfRawData)) {
3179
3180 // Calculate pointer
3181 DWORD_PTR delta = reinterpret_cast<DWORD_PTR>(baseAddress) +
3182 pSectionHeader[i].PointerToRawData;
3183
3184 DWORD_PTR result = delta + (rva - pSectionHeader[i].VirtualAddress);
3185
3186 // Additional validation
3187 if (result < reinterpret_cast<DWORD_PTR>(baseAddress) ||
3188 result >= (reinterpret_cast<DWORD_PTR>(baseAddress) + fileSize)) {
3189 OUTPUT("[-] RVA pointer out of bounds\n");
3190 return 0;
3191 }
3192
3193 return result;
3194 }
3195 }
3196
3197 OUTPUT("[-] RVA not found in any section: 0x%X\n", rva);
3198 return 0;
3199}
3200//}
3201//}
3202
3203/* DWORD_PTR GetRvaPtr(DWORD rva, PIMAGE_SECTION_HEADER pSectionHeader,
3204 WORD numberOfSections, LPVOID baseAddress) {
3205 if (!rva || !pSectionHeader || !baseAddress) return 0;
3206
3207 for (WORD i = 0; i < numberOfSections; i++) {
3208 if (rva >= pSectionHeader[i].VirtualAddress &&
3209 rva < (pSectionHeader[i].VirtualAddress + pSectionHeader[i].SizeOfRawData)) {
3210 DWORD_PTR delta = (DWORD_PTR)baseAddress + pSectionHeader[i].PointerToRawData;
3211 return delta + (rva - pSectionHeader[i].VirtualAddress);
3212 }
3213 }
3214 OUTPUT("[-] Failed to map RVA: 0x%X\n", rva);
3215 return 0;
3216} */
3217
3218DWORD RvaToOffset(DWORD rva, PIMAGE_SECTION_HEADER pSectionHeader, WORD numberOfSections) {
3219 if (!rva || !pSectionHeader) return 0;
3220
3221 for (WORD i = 0; i < numberOfSections; i++) {
3222 if (rva >= pSectionHeader[i].VirtualAddress &&
3223 rva < (pSectionHeader[i].VirtualAddress + pSectionHeader[i].SizeOfRawData)) {
3224 return (rva - pSectionHeader[i].VirtualAddress) + pSectionHeader[i].PointerToRawData;
3225 }
3226 }
3227 OUTPUT("[-] Failed to map RVA: 0x%X\n", rva);
3228 return 0;
3229}
3230
3231// PE information helper functions
3232std::wstring GetImageCharacteristics(DWORD characteristics) {
3233 if (characteristics & IMAGE_FILE_DLL) return L"(DLL)";
3234 if (characteristics & IMAGE_FILE_SYSTEM) return L"(DRIVER)";
3235 if (characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) return L"(EXE)";
3236 return L"(UNKNOWN)";
3237}
3238
3239std::wstring GetSubsystem(WORD subsystem) {
3240 switch (subsystem) {
3241 case IMAGE_SUBSYSTEM_NATIVE: return L"(NATIVE/DRIVER)";
3242 case IMAGE_SUBSYSTEM_WINDOWS_GUI: return L"(GUI)";
3243 case IMAGE_SUBSYSTEM_WINDOWS_CUI: return L"(CONSOLE)";
3244 default: return L"(UNKNOWN)";
3245 }
3246}
3247
3248std::wstring GetDataDirectoryName(int DirectoryNumber) {
3249 static const wchar_t* names[] = {
3250 L"Export Table", L"Import Table", L"Resource Table",
3251 L"Exception Entry", L"Security Entry", L"Relocation Table",
3252 L"Debug Entry", L"Copyright Entry", L"Global PTR Entry",
3253 L"TLS Entry", L"Configuration Entry", L"Bound Import Entry",
3254 L"IAT", L"Delay Import Descriptor", L"COM Descriptor"
3255 };
3256 return (DirectoryNumber < 15) ? names[DirectoryNumber] : L"Unknown";
3257}
3258
3259std::wstring GetSectionProtection(DWORD characteristics) {
3260 std::wstring protection = L"(";
3261 bool needsSeparator = false;
3262
3263 if (characteristics & IMAGE_SCN_MEM_EXECUTE) {
3264 protection += L"EXECUTE";
3265 needsSeparator = true;
3266 }
3267 if (characteristics & IMAGE_SCN_MEM_READ) {
3268 if (needsSeparator) protection += L" | ";
3269 protection += L"READ";
3270 needsSeparator = true;
3271 }
3272 if (characteristics & IMAGE_SCN_MEM_WRITE) {
3273 if (needsSeparator) protection += L" | ";
3274 protection += L"WRITE";
3275 }
3276 protection += L")";
3277 return protection;
3278}
3279}
3280```
3281
3282==++ Here's the full source for (file 1/3) "resource.h"::: ++==
3283```resource.h
3284//{{NO_DEPENDENCIES}}
3285// Microsoft Visual C++ generated include file.
3286// Used by PE-Explorer.rc
3287//
3288#pragma once
3289#define IDI_ICON1 101
3290// resource.h
3291#define ID_FILE_OPEN 1001
3292#define ID_FILE_SELECTALL 1002 // New "Select All" command
3293#define ID_FILE_EXIT 1003
3294
3295// Next default values for new objects
3296//
3297#ifdef APSTUDIO_INVOKED
3298#ifndef APSTUDIO_READONLY_SYMBOLS
3299#define _APS_NEXT_RESOURCE_VALUE 102
3300#define _APS_NEXT_COMMAND_VALUE 40001
3301#define _APS_NEXT_CONTROL_VALUE 1001
3302#define _APS_NEXT_SYMED_VALUE 101
3303#endif
3304#endif
3305
3306```