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