Assuming you have a binary dump created by say WinDbg .writemem
0:000> lm m cdb start end module name 00007ff6`af510000 00007ff6`af53e000 cdb (deferred) 0:000> .writemem c:\dumped.bin 00007ff6`af510000 l?(00007ff6`af53e000-00007ff6`af510000) Writing 2e000 bytes............................................................................................ 0:000>
C++ does not have the glue to parse PE files. You may need to use the Windows API or roll your own parsing routines.
For example the first few bytes of the dump should be IMAGE_DOS_HEADER for it to be a valid PE file.
I will dump the section of the aforementioned dump using pefile by Ero a versatile PE parsing Python module.
Dumping the first section using the above module from command line
C:\>python -c "import pefile;print(pefile.PE(r\"c:\\dumped.bin\").sections[0]") [IMAGE_SECTION_HEADER] 0x200 0x0 Name: .text 0x208 0x8 Misc: 0xC1FF 0x208 0x8 Misc_PhysicalAddress: 0xC1FF 0x208 0x8 Misc_VirtualSize: 0xC1FF 0x20C 0xC VirtualAddress: 0x1000 0x210 0x10 SizeOfRawData: 0xC200 0x214 0x14 PointerToRawData: 0x400 0x218 0x18 PointerToRelocations: 0x0 0x21C 0x1C PointerToLinenumbers: 0x0 0x220 0x20 NumberOfRelocations: 0x0 0x222 0x22 NumberOfLinenumbers: 0x0 0x224 0x24 Characteristics: 0x60000020
If you are going to use C basic routines
You may need to fopen(....) and fread();, then cast the bytes as DOS header, read e_lfanew as offset to the PE header, then continue to cast, read and parse until you finish.
A sample DOS header to PE header offset routine may look like:
#include <stdio.h> #include <stdlib.h> #include <windows.h> #define BUSIZ 0x50 #define MAXREAD 0x40 int main(void) { FILE *infile = NULL; errno_t err = fopen_s(&infile, "c:\\dumped.bin", "rb"); if (err == 0 && infile != NULL) { unsigned char buf[BUSIZ] = {0}; size_t siz = 0; siz = fread_s(buf, BUSIZ, 1, MAXREAD, infile); if (siz != 0) { for (int i = 0; i < 16; i++) { printf("%02x ", buf[i]); } for (int i = 0; i < 16; i++) { printf("%c ", buf[i]); } printf("\n"); } PIMAGE_DOS_HEADER dhead = (PIMAGE_DOS_HEADER)&buf; printf("%x\n", dhead->e_magic); printf("offset to PE Header from start = %x\n", dhead->e_lfanew); } else { printf("file not opened failure \n"); } }
compiled and executed
:\>cl /Zi /W4 /analyze /Od /EHsc /nologo parse.cpp /link /release parse.cpp :\>parse.exe 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 M Z É 5a4d offset to PE Header from start = f8
edit
a different demo for IMAGE_FIRST_SECTION
edit src that uses IMAGE_FIRST_SECTION to retrieve all section with 16 initial bytes at each section
#include <stdio.h> #include <stdlib.h> #include <windows.h> #define BUSIZ 0x500 #define MAXREAD 0x400 FILE *infile = NULL; unsigned char buf[BUSIZ] = {0}; unsigned char tmpbuf[BUFSIZ] = {0}; void hexdump(int bpos, unsigned char *inbuf){ memset(inbuf, 0, BUSIZ); fseek(infile, bpos, SEEK_SET); size_t siz = fread_s(inbuf, BUSIZ, 1, MAXREAD, infile); if (siz != 0) { for (int i = 0; i < 16; i++) { printf("%02x ", inbuf[i]); } printf("\n"); } } int main(void){ errno_t err = fopen_s(&infile, "c:\\dumped.bin", "rb"); if (err == 0 && infile != NULL){ hexdump(0, buf); PIMAGE_DOS_HEADER dhead = (PIMAGE_DOS_HEADER)&buf; hexdump(dhead->e_lfanew, buf); PIMAGE_NT_HEADERS64 nthead = (PIMAGE_NT_HEADERS64)&buf; PIMAGE_SECTION_HEADER Section = IMAGE_FIRST_SECTION(nthead); for (WORD i = 0; i < nthead->FileHeader.NumberOfSections; i++){ printf("%-8s\t%x\t%x\t%x\n", Section->Name, Section->VirtualAddress, Section->PointerToRawData, Section->SizeOfRawData); hexdump(Section->VirtualAddress, tmpbuf); Section++; } } }
compiled and executed
>cl /Zi /W4 /analyze /Od /EHsc /nologo parse.cpp /link /release parse.cpp >parse.exe 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 50 45 00 00 64 86 08 00 00 1d 9c 8d 00 00 00 00 .text 1000 400 c200 cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc .rdata e000 c600 f800 b0 ff 52 af f6 7f 00 00 50 00 53 af f6 7f 00 00 .data 1e000 1be00 2000 60 e0 51 af f6 7f 00 00 90 e0 51 af f6 7f 00 00 .pdata 27000 1de00 800 10 10 00 00 88 10 00 00 4c ba 01 00 90 10 00 00 .didat 28000 1e600 200 92 ce 51 af f6 7f 00 00 00 00 00 00 00 00 00 00 .mrdata 29000 1e800 2e00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .rsrc 2c000 21600 1000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 .reloc 2d000 22600 a00 00 e0 00 00 28 02 00 00 00 a0 08 a0 10 a0 18 a0
confirmed independently with a hex editor
C:\>for %i in (0x0000,0x1000,0xe000,0x1e000,0x27000,0x28000,0x29000,0x2c000,0x2d000) do xxd -s %i -g 1 -l 16 dumped.bin C:\>xxd -s 0x0000 -g 1 -l 16 dumped.bin 00000000: 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 MZ.............. C:\>xxd -s 0x1000 -g 1 -l 16 dumped.bin 00001000: cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc ................ C:\>xxd -s 0xe000 -g 1 -l 16 dumped.bin 0000e000: b0 ff 52 af f6 7f 00 00 50 00 53 af f6 7f 00 00 ..R.....P.S..... C:\>xxd -s 0x1e000 -g 1 -l 16 dumped.bin 0001e000: 60 e0 51 af f6 7f 00 00 90 e0 51 af f6 7f 00 00 `.Q.......Q..... C:\>xxd -s 0x27000 -g 1 -l 16 dumped.bin 00027000: 10 10 00 00 88 10 00 00 4c ba 01 00 90 10 00 00 ........L....... C:\>xxd -s 0x28000 -g 1 -l 16 dumped.bin 00028000: 92 ce 51 af f6 7f 00 00 00 00 00 00 00 00 00 00 ..Q............. C:\>xxd -s 0x29000 -g 1 -l 16 dumped.bin 00029000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ C:\>xxd -s 0x2c000 -g 1 -l 16 dumped.bin 0002c000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 ................ C:\>xxd -s 0x2d000 -g 1 -l 16 dumped.bin 0002d000: 00 e0 00 00 28 02 00 00 00 a0 08 a0 10 a0 18 a0 ....(...........
SEC_IMAGEand possibly relocated etc) or are you talking about a PE file, which you loaded into a buffer and now you want to make sense of the RVAs?