Retrieving PE file's import module names.

Hi
I am trying to get list of import module names from PE file. But i can not find the solution.
This is my code:

CString CPE::GetImportModuleNames(CString str_SectionHdrName)
{
CString c;

IMAGE_DOS_HEADER * dosheader=(IMAGE_DOS_HEADER *)g_pMappedFileBase;
IMAGE_OPTIONAL_HEADER * opthdr =(IMAGE_OPTIONAL_HEADER *)
((BYTE*)dosheader+dosheader->e_lfanew+24);

IMAGE_IMPORT_DESCRIPTOR * descriptor=(IMAGE_IMPORT_DESCRIPTOR *)
((BYTE*)dosheader+
opthdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

// (?)

return c;
}

In Documentation, it says:

" The IMAGE_IMPORT_DESCRIPTOR struct consists of five fields :

Union {
DWORD Characteristics;
PIMAGE_THUNK_DATA OriginalFirstThunk;
};
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name;
PIMAGE_THUNK_DATA FirstThunk;"

“Name contains the a pointer (RVA) to the ASCII name of the DLL.”
How can i retrieve the name of modules from that pointer(RVA).
Now i think i must write a loop and get the names but i couldn’t do the the last step.

while(?)
{
descriptor->Name (?)
}

Could you please help me.
Thank you.

You’ve got a lot of problems here. What works here and what doesn’t? The use of hard coded values (i. e. - 24) makes me apprehensive about looking at this code. I believe 24 is correct, and it will never change without breaking applications, but why not just use IMAGE_NT_HEADERS and make everything cleaner. However, what you’re doing with IMAGE_OPTIONAL_HEADER will definitely be incorrect with either 32-bit PE’s or 64-bit PE’s, depending on for which platform you compile this code. You’re also not validating any signatures, nor are you dumping traces along the way to figure out where you’ve gone wrong. In order to handle both types of PE’s, you need to look at the Magic field of the IMAGE_OPTIONAL_HEADER (at this point, it may be either an IMAGE_OPTIONAL_HEADER32 or IMAGE_OPTIONAL_HEADER64), and if matches the 32-bit signature, cast it to a IMAGE_OPTIONAL_HEADER32, or the other way around. If you don’t do this, the DataDirectory field will be in the wrong place if you hit the type of PE that you weren’t expecting.

I think that you’re basic question is how to go from an RVA to VA. This is the most important concept of the PE. Basically, you have to find out in which section the RVA falls, and then the VA = (Base + (Rva - Section->VirtualAddress) + Section->PointerToRawData). To find the section, use the IMAGE_FIRST_SECTION passing it the IMAGE_NT_HEADERS * you should be using, and then loop through the sections until you find the one that encompasses the RVA:

IMAGE_NT_SECTION * section = IMAGE_FIRST_SECTION(ntHeaders);

for (int index = 0; index < ntHeaders->FileHeader.NumberOfSections; index++)
{
if ((rva >= section->VirtualAddress) &&
(Rva < section->VirtualAddress + section->SizeOfRawData)
break;
section++;
}

That should do it, leaving out error checking, et. c. If it does not, which is certainly possible, I can go no further until you add some trace statements to show where it is failing, and please get rid of the hard coded values, and make the corrections for both types of PE’s.

I hope this is legibile. Typing code in to this little box via the web interface leaves much to be desired, although I really like it otherwise.

Good luck,

mm

Thank you very much MM
I understood what you mean.
I used ImageRvaToVa() and ImageRvaToSection and changed my code as you said:

CString CPE::GetImportModuleNames(CString str_SectionHdrName)
{
CString c;

IMAGE_DOS_HEADER * dosheader=(IMAGE_DOS_HEADER *)g_pMappedFileBase;
IMAGE_OPTIONAL_HEADER * opthdr =(IMAGE_OPTIONAL_HEADER *)
((BYTE*)dosheader+dosheader->e_lfanew+24);

IMAGE_IMPORT_DESCRIPTOR * descriptor=(IMAGE_IMPORT_DESCRIPTOR *)
((BYTE*)dosheader+
opthdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

void* virtualAddress = ImageRvaToVa(loi.FileHeader, g_pMappedFileBase, descriptor->Name, &(loi.LastRvaSection));
PIMAGE_SECTION_HEADER pish = ImageRvaToSection(loi.FileHeader,g_pMappedFileBase,descriptor->Name);

while(descriptor->Name)
{
//(?)
}
return c;
}

Now i have both va and section. In that article http://www.jps.at/pefile.html
while (pid->dwRVAModuleName)
{
/* Allocate buffer for absolute string offsets. */
pModule[nCnt] = (char *)(pData +
(pid->dwRVAModuleName-idsh.VirtualAddress));

}
It calculates with this:

(pData +(pid->dwRVAModuleName-idsh.VirtualAddress));
I have both name and Virtualadress but not pData
for pData:
It used something different in ImageDirectoryOffset function which is defined top of the page.

Could you help me the calculate “pdata”.
If i am not wrong anywhere, i think this is the last thing i have to do.

Thank you again for your long answer.

I took a look. I think all that’s going on is that he is calculating the
location of the directory entry; pData is that address, cast as a (byte *).

This guy’s stuff is unusual. In particular, he is making up his
structures, like IMAGE_IMPORT_MODULE_DIRECTORY. Also, as I mentioned
before, all of this will break with 64-bit PE modules, which are
probably as close to as common as their 32-bit counterparts these days.
Finally, if you’re trying to figure out what is going on, the use of
classes makes things more difficult, in my opinion.

I would recommend that you use the standard types and sources. Here are
a few places to start:

WINNT.H - Search for “IMAGE”

http://msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx

This is the first of two articles by Matt Pietrek that are about as old
as me, but still very good and come with code. I would start here.

If you haven’t already, get a hold of copy of the most recent COFF PE
spec, which Microsoft seems to have buried as deep as possible:

http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx

Good luck,

mm

xxxxx@gmail.com wrote:

Thank you very much MM
I understood what you mean.
I used ImageRvaToVa() and ImageRvaToSection and changed my code as you said:

CString CPE::GetImportModuleNames(CString str_SectionHdrName)
{
CString c;

IMAGE_DOS_HEADER * dosheader=(IMAGE_DOS_HEADER *)g_pMappedFileBase;
IMAGE_OPTIONAL_HEADER * opthdr =(IMAGE_OPTIONAL_HEADER *)
((BYTE*)dosheader+dosheader->e_lfanew+24);

IMAGE_IMPORT_DESCRIPTOR * descriptor=(IMAGE_IMPORT_DESCRIPTOR *)
((BYTE*)dosheader+
opthdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

void* virtualAddress = ImageRvaToVa(loi.FileHeader, g_pMappedFileBase, descriptor->Name, &(loi.LastRvaSection));
PIMAGE_SECTION_HEADER pish = ImageRvaToSection(loi.FileHeader,g_pMappedFileBase,descriptor->Name);

while(descriptor->Name)
{
//(?)
}
return c;
}

Now i have both va and section. In that article http://www.jps.at/pefile.html
while (pid->dwRVAModuleName)
{
/* Allocate buffer for absolute string offsets. */
pModule[nCnt] = (char *)(pData +
(pid->dwRVAModuleName-idsh.VirtualAddress));

}
It calculates with this:

(pData +(pid->dwRVAModuleName-idsh.VirtualAddress));
I have both name and Virtualadress but not pData
for pData:
It used something different in ImageDirectoryOffset function which is defined top of the page.

Could you help me the calculate “pdata”.
If i am not wrong anywhere, i think this is the last thing i have to do.

Thank you again for your long answer.

Thank you
I am only trying to understand how i can calculate string offsets. That article realy confused me lot. Also i used onşy standart types that define in MSDN. As i wrote. I have
-Modulename
-Virtualaddress (virtualAddress)
-PIMAGE_SECTION_HEADER (pish) etc…

But i do not know how to calculate import dll names “string offset”. This calculation must be standart. I only want to understand what the summation expression of string offsets is (with standart types).

Thank you.

In the case of the module name, it’s an RVA. You calculate it the same
way I showed in the first e-mail: find the section in to which the rva
falls, …

Or I am not understanding you correctly? If you haven’t read the the
Microsoft document I sent you a lik, you need to do so before
proceeding; it will make things much clearer, and it’s not that long.

Good luck,

mm

xxxxx@gmail.com wrote:

Thank you
I am only trying to understand how i can calculate string offsets. That article realy confused me lot. Also i used onÅŸy standart types that define in MSDN. As i wrote. I have
-Modulename
-Virtualaddress (virtualAddress)
-PIMAGE_SECTION_HEADER (pish) etc…

But i do not know how to calculate import dll names “string offset”. This calculation must be standart. I only want to understand what the summation expression of string offsets is (with standart types).

Thank you.