We help IT Professionals succeed at work.

We've partnered with Certified Experts, Carl Webster and Richard Faulkner, to bring you two Citrix podcasts. Learn about 2020 trends and get answers to your biggest Citrix questions!Listen Now

x

How to read PE header with "CArchive" or "fstream"

anhtuaninfo
anhtuaninfo asked
on
Medium Priority
800 Views
Last Modified: 2013-11-20

i want to read the PE header , here is my code, i see it ok, but i alway give the result is "0xeba1f0e" in my edit box for the   "ntHeader.Signature" while it must be "0x00004550"(PE00), though  i get the right result in "dosHeader.e_magic"=0x5a4d(MZ)


void CNewDlg::OnOpen()
{
         IMAGE_DOS_HEADER  dosHeader;
        IMAGE_NT_HEADERS  ntHeader;
        CString Display;
        UpdateData();

      char strFilter[] = { "EXE File(*.exe)|*exe|All Files (*.*)|*.*||" };
      CFileDialog dlgFile(TRUE, ".exe", NULL, 0, strFilter);

      if( dlgFile.DoModal() == IDOK )
      {
            ifstream stmHeader(dlgFile.GetFileName(), ios::binary);
          stmHeader.read((char *)&dosHeader, sizeof(dosHeader));
          stmHeader.read((char *)&ntHeader, sizeof(ntHeader));
       
            Display.Format("%x",ntHeader.Signature);
          m_headerInfo=Display;                  // m_headerInfo is a variable of an edit box that i use to display the result

      }
    UpdateData(FALSE);
      
}


        
      
Comment
Watch Question

CERTIFIED EXPERT
Top Expert 2012
Commented:
There seems to be a misconception about the header layout - see the code at http://support.microsoft.com/default.aspx?scid=kb;en-us;90493 ("HOWTO: How To Determine Whether an Application is Console or GUI"):

    /*
     *  Read the MS-DOS image header.
     */
    ReadBytes(hImage,
              &image_dos_header,
              sizeof(IMAGE_DOS_HEADER));

    if (IMAGE_DOS_SIGNATURE != image_dos_header.e_magic)
    {
        printf("Sorry, I do not understand this file.\n");
        exit(1);
    }

    /*
     *  Read more MS-DOS header.       */
    ReadBytes(hImage,
              MoreDosHeader,
              sizeof(MoreDosHeader));

    /*
     *  Get actual COFF header.
     */
    CoffHeaderOffset = AbsoluteSeek(hImage, image_dos_header.e_lfanew) +
                       sizeof(ULONG);

    ReadBytes (hImage, &ntSignature, sizeof(ULONG));

    if (IMAGE_NT_SIGNATURE != ntSignature)
    {
     printf("Missing NT signature. Unknown file type.\n");
     exit(1);
    }

    SectionOffset = CoffHeaderOffset + IMAGE_SIZEOF_FILE_HEADER +
                    IMAGE_SIZEOF_NT_OPTIONAL_HEADER;

    ReadBytes(hImage,
              &image_file_header,
              IMAGE_SIZEOF_FILE_HEADER);

    /*
     *  Read optional header.
     */
    ReadBytes(hImage,
              &image_optional_header,
              IMAGE_SIZEOF_NT_OPTIONAL_HEADER);

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts

Author

Commented:

thank you very much,it's very useful for my shoolwork.

now ,i 've understanded why my code failed. it is simply because i don't know the exactly PE header which has some differrences from msdn:
        http://search.msdn.microsoft.com/search/results.aspx?qu=An+In-Depth+Look+into+the+Win32+Portable+Executable+File+Format&View=msdn&st=b&c=0&s=1&swc=0

The difference is "MoreDosHeader[16]".
But when i Insert the line :
     stmHeader.read((char*)MoreDosHeader,sizeof(MoreDosHeader));
after read dosHeader anh before read ntHeader, my code still dispaly the wrong result.
Do you know why???

jkr
CERTIFIED EXPERT
Top Expert 2012

Commented:
I'd start with opening the file in a hex editor to check where the difference comes from.
Commented:
One of the members of the DOS header is a field called "e_lfanew", which contains the byte offset from the beginning of the file to where the PE header starts.

So after you read the dos header, you need to look in the structure for where the PE header really is, and seek that many bytes. Something like this:

    ifstream stmHeader(dlgFile.GetFileName(), ios::binary);
    stmHeader.read((char *)&dosHeader, sizeof(dosHeader));

    stmHeader.seekoff(dosHeader.e_lfanew, ios_base::beg);

    stmHeader.read((char *)&ntHeader, sizeof(ntHeader));

Author

Commented:
i think we read the file on disk, so the parts of file follows the sequence order and needn't to seekoff, isn't it ???

Commented:
There's a variable-sized chunk in there that holds the DOS stub program - this is the part that prints a message like "This program cannot be run in DOS mode" or "This program must be run under Win32" if you try and run it in DOS. Different linkers put different stubs in there, and leave different amounts of space before the NT header. The way you get around this variable-sized chunk is to look at the e_lfanew field in the dos header. This tells you the offset *from the beginning of the file* of where the NT header starts.

So you can figure out how many bytes to read by figuring out how many bytes you've already read and subtract that from e_lfanew and then read that many more to get to the NT header, or you can just jump there using seekoff(). There's nothing interesting in the DOS stub, so there's no reason to read it if you don't have to.
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.