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