8

I'm trying to build a PE viewer in C++ and it seems to crash if i try to output the names of the libraries in the Import Directory Table. It seems that I am not getting the correct pointers for the DLLs that are used by the program.

HANDLE handle = CreateFile("messagebox.exe",GENERIC_READ,0,0,OPEN_EXISTING,
                              FILE_ATTRIBUTE_NORMAL,0);
DWORD size = GetFileSize(handle,NULL);
PVOID virtualpointer = VirtualAlloc(NULL,size,MEM_COMMIT,PAGE_READWRITE);
state = ReadFile(handle,virtualpointer,size,&byteread,NULL);
CloseHandle(handle);
PIMAGE_NT_HEADERS ntheaders = PIMAGE_NT_HEADERS(PCHAR(vpointer) + 
                                     PIMAGE_DOS_HEADER(vpointer)->e_lfanew);
handle = GetCurrentProcess();
DWORD EntryAddr = ntheaders->OptionalHeader.ImageBase + 
                       ntheaders->OptionalHeader.AddressOfEntryPoint;

DWORD importdir = 
       (DWORD) &(ntheaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]);

DWORD va = (DWORD)(ntheaders->OptionalHeader.ImageBase) + 
                     ((PIMAGE_DATA_DIRECTORY)dwValueB)->VirtualAddress;
LPSTR libname[128];
int i =0;
while(((PIMAGE_IMPORT_DESCRIPTOR)dwValueC)->Name)
{
       // get DLL name
       libname[i] = (LPSTR)(nt->OptionalHeader.ImageBase + 
                         ((PIMAGE_IMPORT_DESCRIPTOR)dwValueC)->Name);
       i++;
}
3
  • Irrespective of the rest, where do you intialize nt? Commented Apr 12, 2013 at 0:54
  • sorry about that, fixed it now Commented Apr 12, 2013 at 7:19
  • Do you mind providing complete code? The above is missing a number of variable declarations at the minimum. Commented Apr 12, 2013 at 8:22

1 Answer 1

19

To read the names of the libraries in the Import Directory Table, you can do the following:

  1. Get the file's memory-mapped base address.
  2. Get pointer to IMAGE_NT_HEADERS structure.
  3. Get pointer to IMAGE_SECTION_HEADER structure.

  4. DataDirectory is the final 128 bytes of OptionalHeader, which in turn is the final member of the PE header IMAGE_NT_HEADERS. The structure has 2 members which contain the location and size of the data structure.
    If you want to look up information about the dll names, you first find the RVA (Relative Virtual Address) of the Import Directory from the Data Directory, find that address in the raw section data and now you have an array of IMAGE_IMPORT_DESCRIPTOR. Get the member of this array that relates to mapped image by inspecting the strings pointed to by the Name fields.

I will not describe structure of Portable Executable File Format, but you can look at the following links:
Peering Inside the PE
Microsoft Systems Journal

Some variables in your code are not declared and this is confusing, but sticking to your skeleton code I wrote it so that it meets to your question.

DWORD Rva2Offset(DWORD rva,PIMAGE_SECTION_HEADER psh,PIMAGE_NT_HEADERS pnt);
int _tmain(int argc, _TCHAR* argv[])
{
LPCWSTR fNmae=L"C:\\Windows\\system32\\notepad.exe";
HANDLE handle=CreateFile(fNmae/*"messagebox.exe"*/, GENERIC_READ, 0, 0, OPEN_EXISTING,  FILE_ATTRIBUTE_NORMAL, 0);
DWORD byteread,size=GetFileSize(handle, NULL);
PVOID virtualpointer=VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
ReadFile(handle, virtualpointer, size, &byteread, NULL);
CloseHandle(handle);
// Get pointer to NT header
PIMAGE_NT_HEADERS           ntheaders=(PIMAGE_NT_HEADERS)(PCHAR(virtualpointer) + PIMAGE_DOS_HEADER(virtualpointer)-> e_lfanew);   
PIMAGE_SECTION_HEADER       pSech=IMAGE_FIRST_SECTION(ntheaders);//Pointer to first section header
PIMAGE_IMPORT_DESCRIPTOR    pImportDescriptor; //Pointer to import descriptor 
__try
{
    if(ntheaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size != 0)/*if size of the table is 0 - Import Table does not exist */
    {
        pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD_PTR)virtualpointer +\
                            Rva2Offset(ntheaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,pSech,ntheaders));
        LPSTR libname[256];
        size_t i=0;
        // Walk until you reached an empty IMAGE_IMPORT_DESCRIPTOR
        while(pImportDescriptor->Name != NULL)
        {
            printf("Library Name   :");
            //Get the name of each DLL
            libname[i]=(PCHAR)((DWORD_PTR)virtualpointer + Rva2Offset(pImportDescriptor->Name,pSech,ntheaders));
            printf("%s\n", libname[i]);
            pImportDescriptor++; //advance to next IMAGE_IMPORT_DESCRIPTOR
            i++;

        }

    }
    else
    {
        printf("No Import Table!\n");
        return 1;
    }
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
    if(EXCEPTION_ACCESS_VIOLATION == GetExceptionCode())
    {
        printf("Exception: EXCEPTION_ACCESS_VIOLATION\n");
        return 1;
    }

}
if(virtualpointer)
    VirtualFree(virtualpointer, size, MEM_DECOMMIT);

return 0;
}
 /*Convert Virtual Address to File Offset */
DWORD Rva2Offset(DWORD rva,PIMAGE_SECTION_HEADER psh,PIMAGE_NT_HEADERS pnt)
{
    size_t i = 0;
    PIMAGE_SECTION_HEADER pSeh;
    if(rva == 0)
    {
            return (rva);
    }
    pSeh = psh;
    for(i = 0; i < pnt->FileHeader.NumberOfSections; i++)
    {
            if(rva >= pSeh->VirtualAddress && rva < pSeh->VirtualAddress +
               pSeh->Misc.VirtualSize)
            {
                    break;
            }
            pSeh++;
    }
    return (rva - pSeh->VirtualAddress + pSeh->PointerToRawData);
} 
Sign up to request clarification or add additional context in comments.

3 Comments

Btw, you can get the archived Microsoft Systems Journal from March 1994 for the PE Article at this direct link ( download.microsoft.com/download/0/6/7/… ), and this for browsing the rest ( microsoft.com/msj/backissues86.aspx ) ; you don't need to, but in case you ever want to hop into a time machine...
I know this is old.But wanted to know why we need rva - pSeh->VirtualAddress + pSeh->PointerToRawData.Can't we just add rva to the base image address?
@GauravSehgal, the file offset is different than the in memory offset because of section alignment. pSeh->PointerToRawData is the relative file offset for the data, which completes the conversion to a file based offset.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.