2

PE ファイル内の特定のデータ ディレクトリのイメージ アドレス (ファイル内のバイト オフセット) を特定するにはどうすればよいですか?

たとえば、データ ディレクトリが次のように指定されているとします。

directory  1  RVA: 0x0  Size: 0
directory  2  RVA: 0xaf974  Size: 300
directory  3  RVA: 0xb8000  Size: 22328
directory  4  RVA: 0x0  Size: 0
directory  5  RVA: 0xc0800  Size: 6440
directory  6  RVA: 0xbe000  Size: 27776
directory  7  RVA: 0x91760  Size: 28
directory  8  RVA: 0x0  Size: 0
directory  9  RVA: 0x0  Size: 0
directory 10  RVA: 0x0  Size: 0
directory 11  RVA: 0xa46b8  Size: 64
directory 12  RVA: 0x0  Size: 0
directory 13  RVA: 0x91000  Size: 1736
directory 14  RVA: 0x0  Size: 0
directory 15  RVA: 0x0  Size: 0
directory 16  RVA: 0x0  Size: 0

インポート ディレクトリ (上記の #2) は、0xAF974 の RVA にあるものとして示されています。ただし、インポート ディレクトリは、EXE ファイルのバイト 0xAF974 にはありません。ファイルがディスクに書き込まれるときに、ファイル内のインポート ディレクトリのバイト オフセットを計算するにはどうすればよいですか?

4

1 に答える 1

3

これは楽しいです!仮想アドレスに基づいて正しい場所を見つけるには、セクションをループする必要があります。ここに私が書いたいくつかのコードがあります

これを説明しようとすることはできますが、自分で理解するのにかなりの時間がかかり、数週間見ていないので、技術的なことの多くをすでに忘れていました。私もこれをたくさん処理するためにC++クラスを書いていました

私のコード バッファーには MapViewOfFile へのポインターがありますが、任意の char ポインターにすることができます。

/* Example usage...I know not perfect but should help a bit. */
    unsigned char * lpFile = (unsigned char *)(void *)MapViewOfFile(fileMap, FILE_MAP_ALL_ACCESS, 0,0, 0);

    if(lpFile==NULL) {
        printf("Failed to MapViewOfFile\r\n");
        exit(0);
    }

    header_dos = (PIMAGE_DOS_HEADER)lpFile;
    header_nt = (PIMAGE_NT_HEADERS32)&lpFile [header_dos->e_lfanew];

    IMAGE_DATA_DIRECTORY import = header_nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    PIMAGE_IMPORT_DESCRIPTOR im = (PIMAGE_IMPORT_DESCRIPTOR)&lpFile[RVA2Offset(lpFile, import.VirtualAddress)];


        /* RVA is relative to the section it resides in. */
    int RVA2Offset(unsigned char * buffer, DWORD rva)
    {
        PIMAGE_NT_HEADERS header = (PIMAGE_NT_HEADERS) &buffer[ ((PIMAGE_DOS_HEADER)buffer)->e_lfanew ];
        PIMAGE_SECTION_HEADER section = (PIMAGE_SECTION_HEADER) &buffer[ ((PIMAGE_DOS_HEADER)buffer)->e_lfanew + sizeof(IMAGE_NT_HEADERS) ];

        for(int sectionIndex = 0; sectionIndex < header->FileHeader.NumberOfSections; sectionIndex++) {
            /*
                Check if the RVA is within the virtual addressing space of the section
                Make sure the RVA is less than  the VirtualAddress plus its raw data size
                IMAGE_HEADER_SECTION.VirtualAddress = The address of the first byte of the section when loaded into memory, relative to the image base. For object files, this is the address of the first byte before relocation is applied.
                Our ImageBase is 0, since we aren't loaded into actual memory
            */
            section = (PIMAGE_SECTION_HEADER) &buffer[ ((PIMAGE_DOS_HEADER)buffer)->e_lfanew + sizeof(IMAGE_NT_HEADERS) + (sectionIndex*sizeof(IMAGE_SECTION_HEADER))];

            if (rva >= section->VirtualAddress && (rva <= section->VirtualAddress + section->SizeOfRawData)) {
                /**
                    PointerToRawData gives us the section's location within the file.
                    RVA - VirtualAddress = Offset WITHIN the address space
                **/
                return section->PointerToRawData + (rva - section->VirtualAddress);
            }
        }

        return 0;
    }
于 2015-06-11T17:07:00.947 に答える