Пример #1
0
        public void Ctor(
            string name,
            int virtualSize,
            int virtualAddress,
            int sizeOfRawData,
            int ptrToRawData,
            int ptrToRelocations,
            int ptrToLineNumbers,
            ushort numRelocations,
            ushort numLineNumbers,
            SectionCharacteristics characteristics)
        {
            var stream = new MemoryStream();
            var writer = new BinaryWriter(stream, Encoding.UTF8, leaveOpen: true);
            writer.Write(PadSectionName(name));
            writer.Write(virtualSize);
            writer.Write(virtualAddress);
            writer.Write(sizeOfRawData);
            writer.Write(ptrToRawData);
            writer.Write(ptrToRelocations);
            writer.Write(ptrToLineNumbers);
            writer.Write(numRelocations);
            writer.Write(numLineNumbers);
            writer.Write((uint) characteristics);
            writer.Dispose();

            stream.Position = 0;
            var reader = new PEBinaryReader(stream, (int) stream.Length);

            var header = new SectionHeader(ref reader);

            Assert.Equal(name, header.Name);
            Assert.Equal(virtualSize, header.VirtualSize);
            Assert.Equal(virtualAddress, header.VirtualAddress);
            Assert.Equal(sizeOfRawData, header.SizeOfRawData);
            Assert.Equal(ptrToRawData, header.PointerToRawData);
            Assert.Equal(ptrToLineNumbers, header.PointerToLineNumbers);
            Assert.Equal(numRelocations, header.NumberOfRelocations);
            Assert.Equal(numLineNumbers, header.NumberOfLineNumbers);
            Assert.Equal(characteristics, header.SectionCharacteristics);
        }
        private bool Validate32BitImage(BinaryAnalyzerContext context)
        {
            PEHeader peHeader = context.PE.PEHeaders.PEHeader;
            SafePointer sp = new SafePointer(context.PE.ImageBytes, peHeader.LoadConfigTableDirectory.RelativeVirtualAddress);
            SafePointer loadConfigVA = context.PE.RVA2VA(sp);
            ImageLoadConfigDirectory32 loadConfig = new ImageLoadConfigDirectory32(peHeader, loadConfigVA);

            UInt32 cookieVA = (UInt32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.SecurityCookie);
            UInt32 baseAddress = (UInt32)peHeader.ImageBase;

            // we need to find the offset in the file based on the cookie's VA
            UInt32 sectionSize, sectionVA = 0;
            SectionHeader ish = new SectionHeader();
            bool foundCookieSection = false;
            foreach (SectionHeader t in context.PE.PEHeaders.SectionHeaders)
            {
                sectionVA = (UInt32)t.VirtualAddress + baseAddress;
                sectionSize = (UInt32)t.VirtualSize;
                if ((cookieVA >= sectionVA) &&
                    (cookieVA < sectionVA + sectionSize))
                {
                    ish = t;
                    foundCookieSection = true;
                    break;
                }
            }

            if (!foundCookieSection)
            {
                LogCouldNotLocateCookie(context);
                return false;
            }

            UInt64 fileCookieOffset = (cookieVA - baseAddress) - (sectionVA - baseAddress) + (UInt32)ish.PointerToRawData;
            SafePointer fileCookiePtr = loadConfigVA;
            fileCookiePtr.Address = (int)fileCookieOffset;
            UInt32 cookie = BitConverter.ToUInt32(fileCookiePtr.GetBytes(8), 0);

            if (!StackProtectionUtilities.DefaultCookiesX86.Contains(cookie) && context.PE.Machine == Machine.I386)
            {
                LogFailure(context, cookie.ToString("x"));
                return false;
            }

            return true;
        }
Пример #3
0
        public SafePointer RVA2VA(SafePointer rva)
        {
            // find which section is our rva in
            SectionHeader ish = new SectionHeader();
            foreach (SectionHeader sectionHeader in PEHeaders.SectionHeaders)
            {
                if ((rva.Address >= sectionHeader.VirtualAddress) &&
                    (rva.Address < sectionHeader.VirtualAddress + sectionHeader.SizeOfRawData))
                {
                    ish = sectionHeader;
                    break;
                }
            }

            if (ish.VirtualAddress == 0) throw new InvalidOperationException("RVA does not belong to any section");

            // calculate the VA
            rva.Address = (int)(rva.Address - ish.VirtualAddress + ish.PointerToRawData);

            return rva;
        }
Пример #4
0
        static internal Microsoft.Cci.ResourceSection ReadWin32ResourcesFromCOFF(Stream stream)
        {
            var peHeaders = new PEHeaders(stream);
            var rsrc1 = new SectionHeader();
            var rsrc2 = new SectionHeader();

            int foundCount = 0;
            foreach (var sectionHeader in peHeaders.SectionHeaders)
            {
                if (sectionHeader.Name == ".rsrc$01")
                {
                    rsrc1 = sectionHeader;
                    foundCount++;
                }
                else if (sectionHeader.Name == ".rsrc$02")
                {
                    rsrc2 = sectionHeader;
                    foundCount++;
                }
            }

            if (foundCount != 2)
                throw new ResourceException(CodeAnalysisResources.CoffResourceMissingSection);

            ConfirmSectionValues(rsrc1, stream.Length);
            ConfirmSectionValues(rsrc2, stream.Length);

            //This will be the final resource section bytes without a header. It contains the concatenation
            //of .rsrc$02 on to the end of .rsrc$01.
            var imageResourceSectionBytes = new byte[checked(rsrc1.SizeOfRawData + rsrc2.SizeOfRawData)];

            stream.Seek(rsrc1.PointerToRawData, SeekOrigin.Begin);
            stream.Read(imageResourceSectionBytes, 0, rsrc1.SizeOfRawData);
            stream.Seek(rsrc2.PointerToRawData, SeekOrigin.Begin);
            stream.Read(imageResourceSectionBytes, rsrc1.SizeOfRawData, rsrc2.SizeOfRawData);

            const int SizeOfRelocationEntry = 10;

            try
            {
                var relocLastAddress = checked(rsrc1.PointerToRelocations + (rsrc1.NumberOfRelocations * SizeOfRelocationEntry));

                if (relocLastAddress > stream.Length)
                    throw new ResourceException(CodeAnalysisResources.CoffResourceInvalidRelocation);
            }
            catch (OverflowException)
            {
                throw new ResourceException(CodeAnalysisResources.CoffResourceInvalidRelocation);
            }

            //.rsrc$01 contains the directory tree. .rsrc$02 contains the raw resource data.
            //.rsrc$01 has references to spots in .rsrc$02. Those spots are expressed as relocations.
            //These will need to be fixed up when the RVA of the .rsrc section in the final image is known.
            var relocationOffsets = new uint[rsrc1.NumberOfRelocations];    //offsets into .rsrc$01

            var relocationSymbolIndices = new uint[rsrc1.NumberOfRelocations];

            var reader = new BinaryReader(stream, Encoding.Unicode);
            stream.Position = rsrc1.PointerToRelocations;

            for (int i = 0; i < rsrc1.NumberOfRelocations; i++)
            {
                relocationOffsets[i] = reader.ReadUInt32();
                //What is being read and stored is the reloc's "Value"
                //This is the symbol's index.
                relocationSymbolIndices[i] = reader.ReadUInt32();
                reader.ReadUInt16(); //we do nothing with the "Type"
            }

            //now that symbol indices are gathered, begin indexing the symbols
            stream.Position = peHeaders.CoffHeader.PointerToSymbolTable;
            const uint ImageSizeOfSymbol = 18;

            try
            {
                var lastSymAddress = checked(peHeaders.CoffHeader.PointerToSymbolTable + peHeaders.CoffHeader.NumberOfSymbols * ImageSizeOfSymbol);

                if (lastSymAddress > stream.Length)
                    throw new ResourceException(CodeAnalysisResources.CoffResourceInvalidSymbol);
            }
            catch (OverflowException)
            {
                throw new ResourceException(CodeAnalysisResources.CoffResourceInvalidSymbol);
            }

            var outputStream = new MemoryStream(imageResourceSectionBytes);
            var writer = new BinaryWriter(outputStream);  //encoding shouldn't matter. There are no strings being written.

            for (int i = 0; i < relocationSymbolIndices.Length; i++)
            {
                if (relocationSymbolIndices[i] > peHeaders.CoffHeader.NumberOfSymbols)
                    throw new ResourceException(CodeAnalysisResources.CoffResourceInvalidRelocation);

                var offsetOfSymbol = peHeaders.CoffHeader.PointerToSymbolTable + relocationSymbolIndices[i] * ImageSizeOfSymbol;

                stream.Position = offsetOfSymbol;
                stream.Position += 8; //skip over symbol name
                var symValue = reader.ReadUInt32();
                var symSection = reader.ReadInt16();
                var symType = reader.ReadUInt16();
                //ignore the rest of the fields.

                const ushort IMAGE_SYM_TYPE_NULL = 0x0000;

                if (symType != IMAGE_SYM_TYPE_NULL ||
                    symSection != 3)  //3rd section is .rsrc$02
                    throw new ResourceException(CodeAnalysisResources.CoffResourceInvalidSymbol);

                //perform relocation. We are concatenating the contents of .rsrc$02 (the raw resource data)
                //on to the end of .rsrc$01 (the directory tree) to yield the final resource section for the image.
                //The directory tree has references into the raw resource data. These references are expressed
                //in the final image as file positions, not positions relative to the beginning of the section.
                //First make the resources be relative to the beginning of the section by adding the size
                //of .rsrc$01 to them. They will ultimately need the RVA of the final image resource section added 
                //to them. We don't know that yet. That is why the array of offsets is preserved. 

                outputStream.Position = relocationOffsets[i];
                writer.Write((uint)(symValue + rsrc1.SizeOfRawData));
            }

            return new Cci.ResourceSection(imageResourceSectionBytes, relocationOffsets);
        }
Пример #5
0
 private static void ConfirmSectionValues(SectionHeader hdr, long fileSize)
 {
     if ((long)hdr.PointerToRawData + hdr.SizeOfRawData > fileSize)
         throw new ResourceException(CodeAnalysisResources.CoffResourceInvalidSectionSize);
 }
        private bool Validate32BitImage(BinaryAnalyzerContext context)
        {
            PEHeader peHeader = context.PE.PEHeaders.PEHeader;
            SafePointer sp = new SafePointer(context.PE.ImageBytes, peHeader.LoadConfigTableDirectory.RelativeVirtualAddress);
            SafePointer loadConfigVA = context.PE.RVA2VA(sp);
            ImageLoadConfigDirectory32 loadConfig = new ImageLoadConfigDirectory32(peHeader, loadConfigVA);

            UInt32 cookieVA = (UInt32)loadConfig.GetField(ImageLoadConfigDirectory32.Fields.SecurityCookie);
            UInt32 baseAddress = (UInt32)peHeader.ImageBase;

            // we need to find the offset in the file based on the cookie's VA
            UInt32 sectionSize, sectionVA = 0;
            SectionHeader ish = new SectionHeader();
            bool foundCookieSection = false;
            foreach (SectionHeader t in context.PE.PEHeaders.SectionHeaders)
            {
                sectionVA = (UInt32)t.VirtualAddress + baseAddress;
                sectionSize = (UInt32)t.VirtualSize;
                if ((cookieVA >= sectionVA) &&
                    (cookieVA < sectionVA + sectionSize))
                {
                    ish = t;
                    foundCookieSection = true;
                    break;
                }
            }

            if (!foundCookieSection)
            {
                // '{0}' is a C or C++binary that enables the stack protection feature but the security cookie could not be located. The binary may be corrupted.
                context.Logger.Log(MessageKind.Fail, context,
                        RuleUtilities.BuildMessage(context,
                            RulesResources.DoNotModifyStackProtectionCookie_CouldNotLocateCookie_Fail));
                return false;
            }

            UInt64 fileCookieOffset = (cookieVA - baseAddress) - (sectionVA - baseAddress) + (UInt32)ish.PointerToRawData;
            SafePointer fileCookiePtr = loadConfigVA;
            fileCookiePtr.Address = (int)fileCookieOffset;
            UInt32 cookie = BitConverter.ToUInt32(fileCookiePtr.GetBytes(8), 0);

            if (!StackProtectionUtilities.DefaultCookiesX86.Contains(cookie) && context.PE.Machine == Machine.I386)
            {
                // '{0}' is a C or C++ binary that interferes with the stack protector. The
                // stack protector (/GS) is a security feature of the compiler which makes
                // it more difficult to exploit stack buffer overflow memory corruption
                // vulnerabilities. The stack protector relies on a random number, called
                // the "security cookie", to detect these buffer overflows. This 'cookie'
                // is statically linked with your binary from a Visual C++ library in the
                // form of the symbol __security_cookie. On recent Windows versions, the
                // loader looks for the magic statically linked value of this cookie, and
                // initializes the cookie with a far better source of entropy -- the system's
                // secure random number generator -- rather than the limited random number
                // generator available early in the C runtime startup code. When this symbol
                // is not the default value, the additional entropy is not injected by the
                // operating system, reducing the effectiveness of the stack protector. To
                // resolve this issue, ensure that your code does not reference or create a
                // symbol named __security_cookie or __security_cookie_complement. NOTE:
                // the modified cookie value detected was: {1}
                context.Logger.Log(MessageKind.Fail, context,
                    RuleUtilities.BuildMessage(context,
                    RulesResources.DoNotModifyStackProtectionCookie_Fail, cookie.ToString("x")));
                return false;
            }

            return true;
        }
        private bool Validate64BitImage(BinaryAnalyzerContext context)
        {
            PEHeader peHeader = context.PE.PEHeaders.PEHeader;
            SafePointer sp = new SafePointer(context.PE.ImageBytes, peHeader.LoadConfigTableDirectory.RelativeVirtualAddress);
            SafePointer loadConfigVA = context.PE.RVA2VA(sp);
            ImageLoadConfigDirectory64 loadConfig = new ImageLoadConfigDirectory64(peHeader, loadConfigVA);

            UInt64 cookieVA = (UInt64)loadConfig.GetField(ImageLoadConfigDirectory64.Fields.SecurityCookie);
            UInt64 baseAddress = peHeader.ImageBase;

            // we need to find the offset in the file based on the cookie's VA
            UInt64 sectionSize, sectionVA = 0;
            SectionHeader ish = new SectionHeader();
            bool foundCookieSection = false;
            foreach (SectionHeader t in context.PE.PEHeaders.SectionHeaders)
            {
                sectionVA = (UInt64)(UInt32)t.VirtualAddress + baseAddress;
                sectionSize = (UInt32)t.VirtualSize;
                if ((cookieVA >= sectionVA) &&
                    (cookieVA < sectionVA + sectionSize))
                {
                    ish = t;
                    foundCookieSection = true;
                    break;
                }
            }

            if (!foundCookieSection)
            {
                LogCouldNotLocateCookie(context);
                return false;
            }

            UInt64 fileCookieOffset = (cookieVA - baseAddress) - (sectionVA - baseAddress) + (UInt32)ish.PointerToRawData;
            SafePointer fileCookiePtr = loadConfigVA;
            fileCookiePtr.Address = (int)fileCookieOffset;

            SafePointer boundsCheck = fileCookiePtr + 8;
            if (!CookieOffsetValid(context, boundsCheck))
            {
                return false;
            }

            if (!boundsCheck.IsValid && context.PE.IsPacked)
            {
                LogInvalidCookieOffsetForKnownPackedFile(context);
                return false;
            }

            UInt64 cookie = BitConverter.ToUInt64(fileCookiePtr.GetBytes(8), 0);

            if (cookie != StackProtectionUtilities.DefaultCookieX64)
            {
                LogFailure(context, cookie.ToString("x"));
                return false;
            }
            return true;
        }