nuget reorganization
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.IO;
|
||||
|
||||
#pragma warning disable CA2022 // Stream.Read validation handled via ReadExactly/ReadAtLeast
|
||||
using System.Text;
|
||||
|
||||
namespace StellaOps.Scanner.Analyzers.Native;
|
||||
@@ -13,17 +11,18 @@ public static class NativeFormatDetector
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(stream);
|
||||
|
||||
Span<byte> header = stackalloc byte[512];
|
||||
var read = stream.ReadAtLeast(header, 4, throwOnEndOfStream: false);
|
||||
if (read < 4)
|
||||
using var buffer = new MemoryStream();
|
||||
stream.CopyTo(buffer);
|
||||
var data = buffer.ToArray();
|
||||
var span = data.AsSpan();
|
||||
|
||||
if (span.Length < 4)
|
||||
{
|
||||
identity = new NativeBinaryIdentity(NativeFormat.Unknown, null, null, null, null, null, null);
|
||||
return false;
|
||||
}
|
||||
|
||||
var span = header[..read];
|
||||
|
||||
if (IsElf(span, stream, out identity))
|
||||
if (IsElf(span, out identity))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -33,7 +32,7 @@ public static class NativeFormatDetector
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsMachO(span, stream, out identity))
|
||||
if (IsMachO(span, out identity))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -42,7 +41,7 @@ public static class NativeFormatDetector
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsElf(ReadOnlySpan<byte> span, Stream stream, out NativeBinaryIdentity identity)
|
||||
private static bool IsElf(ReadOnlySpan<byte> span, out NativeBinaryIdentity identity)
|
||||
{
|
||||
identity = default!;
|
||||
if (span.Length < 20)
|
||||
@@ -92,15 +91,12 @@ public static class NativeFormatDetector
|
||||
for (var i = 0; i < phnum; i++)
|
||||
{
|
||||
var entryOffset = (long)(phoff + (ulong)(i * phentsize));
|
||||
if (entryOffset + phentsize > stream.Length)
|
||||
if (entryOffset + phentsize > span.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var ph = new byte[phentsize];
|
||||
stream.Seek(entryOffset, SeekOrigin.Begin);
|
||||
stream.ReadExactly(ph, 0, ph.Length);
|
||||
var phSpan = ph.AsSpan();
|
||||
var phSpan = span.Slice((int)entryOffset, phentsize);
|
||||
|
||||
var pType = dataEncoding == 2
|
||||
? BinaryPrimitives.ReadUInt32BigEndian(phSpan)
|
||||
@@ -115,12 +111,12 @@ public static class NativeFormatDetector
|
||||
? BinaryPrimitives.ReadUInt32BigEndian(phSpan.Slice(32, 4))
|
||||
: BinaryPrimitives.ReadUInt32LittleEndian(phSpan.Slice(32, 4));
|
||||
|
||||
if (fileSize > 0 && offset + fileSize <= (ulong)stream.Length)
|
||||
if (fileSize > 0 && offset + fileSize <= (ulong)span.Length)
|
||||
{
|
||||
var buffer = new byte[fileSize];
|
||||
stream.Seek((long)offset, SeekOrigin.Begin);
|
||||
stream.ReadExactly(buffer, 0, buffer.Length);
|
||||
var str = System.Text.Encoding.ASCII.GetString(buffer).TrimEnd('\0');
|
||||
var interpSpan = span.Slice((int)offset, (int)fileSize);
|
||||
var terminator = interpSpan.IndexOf((byte)0);
|
||||
var count = terminator >= 0 ? terminator : interpSpan.Length;
|
||||
var str = Encoding.ASCII.GetString(interpSpan[..count]);
|
||||
if (!string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
interp = str;
|
||||
@@ -136,12 +132,10 @@ public static class NativeFormatDetector
|
||||
? BinaryPrimitives.ReadUInt32BigEndian(phSpan.Slice(32, 4))
|
||||
: BinaryPrimitives.ReadUInt32LittleEndian(phSpan.Slice(32, 4));
|
||||
|
||||
if (fileSize > 0 && offset + fileSize <= (ulong)stream.Length)
|
||||
if (fileSize > 0 && offset + fileSize <= (ulong)span.Length)
|
||||
{
|
||||
var buffer = new byte[fileSize];
|
||||
stream.Seek((long)offset, SeekOrigin.Begin);
|
||||
stream.ReadExactly(buffer, 0, buffer.Length);
|
||||
ParseElfNote(buffer, dataEncoding == 2, ref buildId);
|
||||
var noteSpan = span.Slice((int)offset, (int)fileSize);
|
||||
buildId ??= ParseElfNote(noteSpan, dataEncoding == 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +187,7 @@ public static class NativeFormatDetector
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsMachO(ReadOnlySpan<byte> span, Stream stream, out NativeBinaryIdentity identity)
|
||||
private static bool IsMachO(ReadOnlySpan<byte> span, out NativeBinaryIdentity identity)
|
||||
{
|
||||
identity = default!;
|
||||
if (span.Length < 12)
|
||||
@@ -237,55 +231,46 @@ public static class NativeFormatDetector
|
||||
var arch = MapMachCpuType(cputype);
|
||||
var endianness = bigEndian ? "be" : "le";
|
||||
|
||||
var uuid = ExtractMachUuid(stream, bigEndian);
|
||||
string? uuid = null;
|
||||
if (!isFat)
|
||||
{
|
||||
var headerSize = is64 ? 32 : 28;
|
||||
if (span.Length >= headerSize + 8)
|
||||
{
|
||||
var ncmds = bigEndian
|
||||
? BinaryPrimitives.ReadUInt32BigEndian(span.Slice(16, 4))
|
||||
: BinaryPrimitives.ReadUInt32LittleEndian(span.Slice(16, 4));
|
||||
var offset = headerSize;
|
||||
for (uint i = 0; i < ncmds && offset + 8 <= span.Length; i++)
|
||||
{
|
||||
var cmd = bigEndian
|
||||
? BinaryPrimitives.ReadUInt32BigEndian(span.Slice(offset, 4))
|
||||
: BinaryPrimitives.ReadUInt32LittleEndian(span.Slice(offset, 4));
|
||||
var cmdsize = bigEndian
|
||||
? BinaryPrimitives.ReadUInt32BigEndian(span.Slice(offset + 4, 4))
|
||||
: BinaryPrimitives.ReadUInt32LittleEndian(span.Slice(offset + 4, 4));
|
||||
|
||||
if (cmd == 0x1B && cmdsize >= 24 && offset + cmdsize <= span.Length) // LC_UUID
|
||||
{
|
||||
var uuidSpan = span.Slice(offset + 8, 16);
|
||||
uuid = Convert.ToHexString(uuidSpan).ToLowerInvariant();
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmdsize == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
offset += (int)cmdsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
identity = new NativeBinaryIdentity(NativeFormat.MachO, arch, "darwin", Endianness: endianness, BuildId: null, Uuid: uuid, InterpreterPath: null);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string? ExtractMachUuid(Stream stream, bool bigEndian)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
using var reader = new BinaryReader(stream, System.Text.Encoding.ASCII, leaveOpen: true);
|
||||
|
||||
var magic = reader.ReadUInt32();
|
||||
var is64 = magic is 0xFEEDFACF or 0xCFFAEDFE;
|
||||
var headerSize = is64 ? 32 : 28;
|
||||
stream.Seek(16, SeekOrigin.Begin);
|
||||
var ncmds = ReadUInt32(reader, bigEndian);
|
||||
_ = ReadUInt32(reader, bigEndian); // sizeofcmds
|
||||
|
||||
stream.Seek(headerSize, SeekOrigin.Begin);
|
||||
for (var i = 0; i < ncmds; i++)
|
||||
{
|
||||
var cmdStart = stream.Position;
|
||||
var cmd = ReadUInt32(reader, bigEndian);
|
||||
var cmdsize = ReadUInt32(reader, bigEndian);
|
||||
if (cmd == 0x1B) // LC_UUID
|
||||
{
|
||||
var uuidBytes = reader.ReadBytes(16);
|
||||
return new Guid(uuidBytes).ToString();
|
||||
}
|
||||
|
||||
stream.Seek(cmdStart + cmdsize, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static uint ReadUInt32(BinaryReader reader, bool bigEndian)
|
||||
{
|
||||
var data = reader.ReadBytes(4);
|
||||
return bigEndian ? BinaryPrimitives.ReadUInt32BigEndian(data) : BinaryPrimitives.ReadUInt32LittleEndian(data);
|
||||
}
|
||||
|
||||
private static string? MapElfMachine(ushort machine) => machine switch
|
||||
{
|
||||
0x03 => "x86",
|
||||
@@ -330,45 +315,48 @@ public static class NativeFormatDetector
|
||||
_ => null,
|
||||
};
|
||||
|
||||
private static void ParseElfNote(ReadOnlySpan<byte> note, bool bigEndian, ref string? buildId)
|
||||
private static string? ParseElfNote(ReadOnlySpan<byte> note, bool bigEndian)
|
||||
{
|
||||
if (note.Length < 12)
|
||||
var offset = 0;
|
||||
while (offset + 12 <= note.Length)
|
||||
{
|
||||
return;
|
||||
var namesz = bigEndian
|
||||
? BinaryPrimitives.ReadUInt32BigEndian(note.Slice(offset))
|
||||
: BinaryPrimitives.ReadUInt32LittleEndian(note.Slice(offset));
|
||||
var descsz = bigEndian
|
||||
? BinaryPrimitives.ReadUInt32BigEndian(note.Slice(offset + 4))
|
||||
: BinaryPrimitives.ReadUInt32LittleEndian(note.Slice(offset + 4));
|
||||
var type = bigEndian
|
||||
? BinaryPrimitives.ReadUInt32BigEndian(note.Slice(offset + 8))
|
||||
: BinaryPrimitives.ReadUInt32LittleEndian(note.Slice(offset + 8));
|
||||
|
||||
var nameStart = offset + 12;
|
||||
var namePadded = AlignTo4(namesz);
|
||||
var descStart = nameStart + namePadded;
|
||||
var descPadded = AlignTo4(descsz);
|
||||
var next = descStart + descPadded;
|
||||
|
||||
if (next > note.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (type == 3 && namesz >= 3)
|
||||
{
|
||||
var name = note.Slice(nameStart, (int)Math.Min(namesz, (uint)(note.Length - nameStart)));
|
||||
if (name[0] == (byte)'G' && name[1] == (byte)'N' && name[2] == (byte)'U')
|
||||
{
|
||||
var desc = note.Slice(descStart, (int)Math.Min(descsz, (uint)(note.Length - descStart)));
|
||||
return Convert.ToHexString(desc).ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
|
||||
offset = next;
|
||||
}
|
||||
|
||||
var namesz = bigEndian
|
||||
? BinaryPrimitives.ReadUInt32BigEndian(note)
|
||||
: BinaryPrimitives.ReadUInt32LittleEndian(note);
|
||||
var descsz = bigEndian
|
||||
? BinaryPrimitives.ReadUInt32BigEndian(note.Slice(4))
|
||||
: BinaryPrimitives.ReadUInt32LittleEndian(note.Slice(4));
|
||||
var type = bigEndian
|
||||
? BinaryPrimitives.ReadUInt32BigEndian(note.Slice(8))
|
||||
: BinaryPrimitives.ReadUInt32LittleEndian(note.Slice(8));
|
||||
|
||||
var offset = 12;
|
||||
var nameEnd = offset + (int)namesz;
|
||||
if (nameEnd > note.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var name = System.Text.Encoding.ASCII.GetString(note.Slice(offset, (int)namesz)).TrimEnd('\0');
|
||||
offset = Align(nameEnd, 4);
|
||||
var descEnd = offset + (int)descsz;
|
||||
if (descEnd > note.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (name == "GNU" && type == 3 && descsz > 0)
|
||||
{
|
||||
var desc = note.Slice(offset, (int)descsz);
|
||||
buildId = Convert.ToHexString(desc).ToLowerInvariant();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int Align(int value, int alignment) => (value + (alignment - 1)) & ~(alignment - 1);
|
||||
private static int AlignTo4(uint value) => (int)((value + 3) & ~3u);
|
||||
}
|
||||
#pragma warning restore CA2022
|
||||
|
||||
Reference in New Issue
Block a user