Example #1
0
        /// <summary>
        /// Looks up the debug signature information in the EXE.   Returns true and sets the parameters if it is found.
        /// If 'first' is true then the first entry is returned, otherwise (by default) the last entry is used
        /// (this is what debuggers do today).   Thus NGEN images put the IL PDB last (which means debuggers
        /// pick up that one), but we can set it to 'first' if we want the NGEN PDB.
        /// </summary>
        public bool GetPdbSignature(out string pdbName, out Guid pdbGuid, out int pdbAge, bool first = false)
        {
            pdbName = null;
            pdbGuid = Guid.Empty;
            pdbAge  = 0;
            bool ret = false;

            if (Header == null)
            {
                return(false);
            }

            if (Header.DebugDirectory.VirtualAddress != 0)
            {
                PEBuffer buff = AllocBuff();
                IMAGE_DEBUG_DIRECTORY *debugEntries = (IMAGE_DEBUG_DIRECTORY *)FetchRVA((int)Header.DebugDirectory.VirtualAddress, (int)Header.DebugDirectory.Size, buff);
                if (Header.DebugDirectory.Size % sizeof(IMAGE_DEBUG_DIRECTORY) != 0)
                {
                    return(false);
                }

                int debugCount = (int)Header.DebugDirectory.Size / sizeof(IMAGE_DEBUG_DIRECTORY);
                for (int i = 0; i < debugCount; i++)
                {
                    if (debugEntries[i].Type == IMAGE_DEBUG_TYPE.CODEVIEW)
                    {
                        PEBuffer       stringBuff = AllocBuff();
                        int            ptr        = _virt ? debugEntries[i].AddressOfRawData : debugEntries[i].PointerToRawData;
                        CV_INFO_PDB70 *info       = (CV_INFO_PDB70 *)stringBuff.Fetch(ptr, debugEntries[i].SizeOfData);
                        if (info->CvSignature == CV_INFO_PDB70.PDB70CvSignature)
                        {
                            // If there are several this picks the last one.
                            pdbGuid = info->Signature;
                            pdbAge  = info->Age;
                            pdbName = info->PdbFileName;
                            ret     = true;
                            if (first)
                            {
                                break;
                            }
                        }

                        FreeBuff(stringBuff);
                    }
                }

                FreeBuff(buff);
            }

            return(ret);
        }
Example #2
0
        /// <summary>
        /// Simple PE Parser, That Extracts The PDB Location From a PE File, which also checks for PE File Validity.
        /// </summary>
        /// <param name="path"></param>
        public PEFile(string path)
        {
            if (String.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException("path");
            }

            FileInfo peContainer = new FileInfo(path);

            if (!peContainer.Exists)
            {
                throw new FileNotFoundException(path);
            }

            m_fileInfo = peContainer;
            try {
                m_fileVersionInfo = FileVersionInfo.GetVersionInfo(path);
            }
            catch (Exception exc) {
                Debug.WriteLine(exc.ToString());
                m_fileVersionInfo = null;
            }

            using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
            {
                using (BinaryReader br = new BinaryReader(fs))
                {
                    // Find the address of the PE Header
                    try
                    {
                        br.BaseStream.Seek(PESignatureOffsetLoc, SeekOrigin.Begin);
                        // BugFix For Bug Number 677
                        // After the MS DOS stub, at the file offset specified at offset 0x3c,
                        // We must read 4 bytes to located the position of the PE Header In The Executable File
                        // is a 4-byte signature that identifies the file as a PE format image file.
                        // This signature is “PE\0\0” (the letters “P” and “E” followed by two null bytes).
                        // m_PESignatureOffset = br.ReadByte();
                        // Thx to Microsofts mdb source code in pdb2xml this was wrongly implemented.
                        // Should i trust their code :)
                        // Better Writing The Code Like In Pdb Extractor myself seems to be the right way :)
                        m_PESignatureOffset = br.ReadUInt32();
                        br.BaseStream.Seek(m_PESignatureOffset, SeekOrigin.Begin);
                        // The PE Signature like defined
                        // in Microsoft Portable Executable and Common Object File Format Specification v8.0
                        if (br.ReadByte() != 'P')
                        {
                            throw new FileLoadException("PE Signature corrupt");
                        }
                        if (br.ReadByte() != 'E')
                        {
                            throw new FileLoadException("PE Signature corrupt");
                        }
                        if (br.ReadByte() != '\0')
                        {
                            throw new FileLoadException("PE Signature corrupt");
                        }
                        if (br.ReadByte() != '\0')
                        {
                            throw new FileLoadException("PE Signature corrupt");
                        }
                    }
                    catch (EndOfStreamException)
                    {
                        throw new FileLoadException("Read past end of file");
                    }
                }
            }


            m_ExePath = path;

            byte[] Data = System.IO.File.ReadAllBytes(path);

            //This section is unsafe so faster access is achieved :)
            unsafe
            {
                //First Check The Length If it is lesser then dos header + image headers
                if (peContainer.Length < (sizeof(IMAGE_DOS_HEADER)) + sizeof(IMAGE_NT_HEADERS32))
                    throw new FileLoadException("Invalid PE File");

                fixed(byte *p_Data = Data)
                {
                    // Get the first 64 bytes and turn it into a IMAGE_DOS_HEADER
                    IMAGE_DOS_HEADER *idh =
                        (IMAGE_DOS_HEADER *)p_Data;
                    //Read Image Nt Headers
                    IMAGE_NT_HEADERS64 *inhs64 =
                        (IMAGE_NT_HEADERS64 *)(idh->lfanew + p_Data);

                    //Check The PE00 signature
                    if (inhs64->Signature != PEMAGIC)
                    {
                        throw new FileLoadException("PE Signature corrupt");
                    }

                    // The calculated values that are different depending on
                    // 32 vs. 64-bit.
                    int    SizeOfOptionalHeader = 0;
                    uint   rva              = 0;
                    uint   DebugDirSize     = 0;
                    ushort NumberOfSections = 0;

                    if (inhs64->OptionalHeader.Magic == PE32)
                    {
                        // Get all the 32-bit offsets.
                        IMAGE_NT_HEADERS32 *inhs32 =
                            (IMAGE_NT_HEADERS32 *)(idh->lfanew + p_Data);

                        SizeOfOptionalHeader = (int)
                                               inhs32->FileHeader.SizeOfOptionalHeader;
                        //Debug Section Is Always In 7th Member Of The Optional Headers Data Directory
                        rva          = inhs32->OptionalHeader.DataDirectory7.VirtualAddress;
                        DebugDirSize =
                            inhs32->OptionalHeader.DataDirectory7.Size;
                        NumberOfSections = inhs32->FileHeader.NumberOfSections;
                    }
                    else if (inhs64->OptionalHeader.Magic == PE32PLUS)
                    {
                        SizeOfOptionalHeader = (int)
                                               inhs64->FileHeader.SizeOfOptionalHeader;
                        //Debug Section Is Always In 7th Member Of The Optional Headers Data Directory
                        rva =
                            inhs64->OptionalHeader.DataDirectory7.VirtualAddress;
                        DebugDirSize =
                            inhs64->OptionalHeader.DataDirectory7.Size;
                        NumberOfSections = inhs64->FileHeader.NumberOfSections;
                    }

                    //No Debug Section Found So Exit.
                    if ((rva == 0) || (DebugDirSize == 0))
                    {
                        throw new NoDebugSectionException( );
                    }

                    //Find out the data section
                    Int32 dataSectionsOffset = (idh->lfanew) +
                                               4 +
                                               sizeof(IMAGE_FILE_HEADER)
                                               +
                                               (int)SizeOfOptionalHeader;
                    bool found = false;

                    //Loop through the debug sections, enumerate whole sections try to locate the type 2(CODEVIEW) section
                    //with magical header 0x53445352 For PDB 7.0 Entries , my code won't support PDB V2.0 Entries , because none
                    //of the .Net Assemblies Use It.
                    for (int i = 0; i < NumberOfSections; i++)
                    {
                        PESectionHeader *myHeader =
                            (PESectionHeader *)(dataSectionsOffset + p_Data);

                        uint sectionSize =
                            myHeader->VirtualSize;

                        if (sectionSize == 0)
                        {
                            sectionSize = myHeader->RawDataSize;
                        }

                        if ((rva >= myHeader->VirtualAddress) &&
                            (rva < myHeader->VirtualAddress + sectionSize))
                        {
                            found = true;
                        }

                        if (found)
                        {
                            found = false;

                            int diff =
                                (int)(myHeader->VirtualAddress - myHeader->RawDataAddress);

                            UInt32 fileOffset = rva - (uint)diff;

                            _IMAGE_DEBUG_DIRECTORY *debugDirectory =
                                (_IMAGE_DEBUG_DIRECTORY *)(fileOffset + p_Data);

                            int NumEntries = (int)(DebugDirSize / sizeof(_IMAGE_DEBUG_DIRECTORY));


                            for (int ix = 1; ix <= NumEntries; ix++, debugDirectory++)
                            {
                                if (debugDirectory->Type == 2)
                                {
                                    UInt32 cvSignature = *(UInt32 *)(p_Data + debugDirectory->PointerToRawData);
                                    if (cvSignature == 0x53445352)
                                    {
                                        CV_INFO_PDB70 *pCvInfo =
                                            (CV_INFO_PDB70 *)(p_Data + debugDirectory->PointerToRawData);

                                        string hexAge = pCvInfo->Age.ToString("x2");

                                        if (hexAge != "0")
                                        {
                                            hexAge = (hexAge.StartsWith("0") ? hexAge.Substring(1) : hexAge);
                                        }
                                        else
                                        {
                                            hexAge = "0";
                                        }

                                        m_pdbAge = pCvInfo->Age.ToString();

                                        string finalHex = String.Empty;

                                        byte[] firstHeader =
                                            BitConverter.GetBytes(pCvInfo->firstPart);

                                        byte[] secondHeader =
                                            BitConverter.GetBytes(pCvInfo->secondPart);

                                        byte[] thirdHeader =
                                            BitConverter.GetBytes(pCvInfo->thirdPart);

                                        byte[] fourthHeader =
                                            BitConverter.GetBytes(pCvInfo->fourthPart);


                                        byte[] finalGuid = new byte[16];

                                        //Make The Byte Order Correct So We Can Construct The Right Guid Out Of It

                                        //Guid Buildup Begin
                                        finalGuid[0] = firstHeader[3];
                                        finalGuid[1] = firstHeader[2];
                                        finalGuid[2] = firstHeader[1];
                                        finalGuid[3] = firstHeader[0];
                                        //c section
                                        finalGuid[4] = secondHeader[5 - 4];
                                        finalGuid[5] = secondHeader[4 - 4];
                                        //d relocation
                                        finalGuid[6] = secondHeader[7 - 4];
                                        finalGuid[7] = secondHeader[6 - 4];

                                        for (int xx = 8; xx < 12; xx++)
                                        {
                                            finalGuid[xx] = thirdHeader[xx - 8];
                                        }

                                        for (int x = 12; x < 16; x++)
                                        {
                                            finalGuid[x] = fourthHeader[x - 12];
                                        }
                                        //Guid Buildup End
                                        //Get The Original Guid
                                        m_pdbGuid = new Guid(finalGuid);

                                        finalHex = Utility.ByteArrayToHex(finalGuid);

                                        m_pdbVersion =
                                            finalHex.ToUpperInvariant() + hexAge.ToUpperInvariant();

                                        //Locate The Pdb Name Entry, it is a null terminated string.
                                        uint stringBeginLocation =
                                            debugDirectory->PointerToRawData + 24;

                                        byte stringLocator =
                                            *(p_Data + stringBeginLocation);

                                        System.Text.StringBuilder resultBuilder =
                                            new System.Text.StringBuilder();

                                        MemoryStream stringHolder = new MemoryStream();

                                        while (stringLocator != 0)
                                        {
                                            stringHolder.WriteByte(stringLocator);
                                            //resultBuilder.Append(Encoding.ASCII.GetString(new byte[]{stringLocator}));

                                            stringBeginLocation++;

                                            stringLocator = *(p_Data + stringBeginLocation);
                                        }
                                        ;

                                        // Buildup The String And Return It.
                                        // We assume always that it is ascii encoded.
                                        m_pdbFullName = Encoding.ASCII.GetString(stringHolder.ToArray());    //resultBuilder.ToString();


                                        return;
                                    }
                                }
                            }
                        }

                        dataSectionsOffset +=
                            sizeof(PESectionHeader);
                    }
                    throw new NoPdbSectionException();
                }
            }
        }