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; }
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; }
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); }
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; }