public static string HashExecutable(string path)
        {
            WindowsBinaryData r = ExecutableParser(path);

            byte[] selfHash;
            int    checkSumIndex = r.checkSumPos;
            int    tableIndex    = r.CertificateTableSizePos - 4;
            int    endIndex      = 0;

            if (r.CertificateTableAddress != 0)
            {
                endIndex = r.CertificateTableAddress;
            }

            if (endIndex == 0)
            {
                // Hash the entire file except the .msh at the end if .msh is present
                int mshLen = GetMshLengthFromExecutable(path);
                if (mshLen > 0)
                {
                    mshLen += 20;
                }
                using (SHA384 sha384 = SHA384Managed.Create())
                {
                    sha384.Initialize();
                    using (FileStream stream = File.OpenRead(path))
                    {
                        hashPortionOfStream(sha384, stream, 0, (int)stream.Length - mshLen); // Start --> end - (mshLen + 20)
                        sha384.TransformFinalBlock(new byte[0], 0, 0);
                        selfHash = sha384.Hash;
                    }
                }
                return(BitConverter.ToString(selfHash).Replace("-", string.Empty).ToLower());
            }

            using (SHA384 sha384 = SHA384Managed.Create())
            {
                sha384.Initialize();
                using (FileStream stream = File.OpenRead(path))
                {
                    hashPortionOfStream(sha384, stream, 0, checkSumIndex);              // Start --> checkSumIndex
                    sha384.TransformBlock(new byte[4], 0, 4, null, 0);                  // 4 zero bytes
                    hashPortionOfStream(sha384, stream, checkSumIndex + 4, tableIndex); // checkSumIndex + 4 --> tableIndex
                    sha384.TransformBlock(new byte[8], 0, 8, null, 0);                  // 8 zero bytes
                    hashPortionOfStream(sha384, stream, tableIndex + 8, endIndex);      // tableIndex + 8 --> endIndex
                    sha384.TransformFinalBlock(new byte[0], 0, 0);
                    selfHash = sha384.Hash;
                }
            }
            return(BitConverter.ToString(selfHash).Replace("-", string.Empty).ToLower());
        }
        public static WindowsBinaryData ExecutableParser(string path)
        {
            WindowsBinaryData r = new WindowsBinaryData();

            FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);

            if (fs.Length < 64)
            {
                fs.Close(); return(null);
            }                                                // File too short
            fs.Seek(0, SeekOrigin.Begin);

            // Read DOS header
            byte[] dosHeader = new byte[64];
            fs.Read(dosHeader, 0, 64);
            if ((dosHeader[0] != 0x4d) || (dosHeader[1] != 0x5a))
            {
                return(null);
            }                                                                      // Unrecognized binary format
            int ntHeaderPosition = BitConverter.ToInt32(dosHeader, 60);

            // Read NT header
            fs.Seek(ntHeaderPosition, SeekOrigin.Begin);
            byte[] ntHeader = new byte[24];
            fs.Read(ntHeader, 0, ntHeader.Length);
            if ((ntHeader[0] != 0x50) || (ntHeader[1] != 0x45) || (ntHeader[2] != 0x00) || (ntHeader[3] != 0x00))
            {
                return(null);
            }                                                                                                                      // Not a PE file
            int binaryType = BitConverter.ToInt16(ntHeader, 4);

            if (binaryType == 0x014C)
            {
                r.BinaryType = WindowsBinaryData.BinaryTypeEnum.x32bit;
            }                                                                                     // 32 bit
            else if (binaryType == 0x8664)
            {
                r.BinaryType = WindowsBinaryData.BinaryTypeEnum.x64bit;
            }                                                                                          // 64 bit

            // Read the optional header
            r.optionalHeaderSize        = BitConverter.ToInt16(ntHeader, 20);
            r.optionalHeaderSizeAddress = BitConverter.ToInt16(dosHeader, 60) + 24;
            byte[] optHeader = new byte[r.optionalHeaderSize];
            fs.Seek(r.optionalHeaderSizeAddress, SeekOrigin.Begin);
            fs.Read(optHeader, 0, optHeader.Length);

            // Set values
            r.checkSumPos             = ntHeaderPosition + 24 + 64;
            r.sizeOfCode              = BitConverter.ToInt32(optHeader, 4);
            r.sizeOfInitializedData   = BitConverter.ToInt32(optHeader, 8);
            r.sizeOfUnInitializedData = BitConverter.ToInt32(optHeader, 12);

            int optionalMagic = BitConverter.ToInt16(optHeader, 0);

            switch (optionalMagic)
            {
            case 0x010B:     // 32bit
            {
                r.rvaCount = BitConverter.ToInt32(optHeader, 92);
                r.CertificateTableAddress = BitConverter.ToInt32(optHeader, 128);
                r.CertificateTableSize    = BitConverter.ToInt32(optHeader, 132);
                r.CertificateTableSizePos = r.optionalHeaderSizeAddress + 132;
                r.rvaStartAddress         = r.optionalHeaderSizeAddress + 96;

                /*
                 *                      if (ILibMemory_AllocateA_Size(optHeader) >= 132)
                 *                      {
                 *                              if (((unsigned int*)(optHeader + 128))[0] != 0)
                 *                              {
                 *                                      endIndex = ((unsigned int*)(optHeader + 128))[0];
                 *                              }
                 *                              tableIndex = NTHeaderIndex + 24 + 128;
                 *                              retVal = 0;
                 *                      }
                 */
                break;
            }

            case 0x020B:     // 64bit
            {
                r.rvaCount = BitConverter.ToInt32(optHeader, 108);
                r.CertificateTableAddress = BitConverter.ToInt32(optHeader, 144);
                r.CertificateTableSize    = BitConverter.ToInt32(optHeader, 148);
                r.CertificateTableSizePos = r.optionalHeaderSizeAddress + 148;
                r.rvaStartAddress         = r.optionalHeaderSizeAddress + 112;
                break;
            }

            default:     // Unknown Value found for Optional Magic
            {
                return(null);
            }
            }

            if (r.CertificateTableAddress > 0)
            {
                // Read the authenticode certificate, only one cert (only the first entry)
                byte[] hdr = new byte[8];
                fs.Seek(r.CertificateTableAddress, SeekOrigin.Begin);
                fs.Read(hdr, 0, hdr.Length);
                int certLen = BitConverter.ToInt32(hdr, 0);
                r.certificate = new byte[certLen];
                fs.Seek(r.CertificateTableAddress + hdr.Length, SeekOrigin.Begin);
                fs.Read(r.certificate, 0, r.certificate.Length);
            }

            return(r);
        }