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_IMAGE
and 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?