Skip to content

Commit

Permalink
fix: Add compatibility with larger assemblies with varying heap index…
Browse files Browse the repository at this point in the history
… widths.

Fixes: #3
  • Loading branch information
NoSharp committed May 12, 2021
1 parent c531788 commit d8c4bed
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 56 deletions.
1 change: 1 addition & 0 deletions CsharpFunctionDumper/CLRProcessing/MetaDataHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public MetaDataHeader(AssemblyBuffer buffer, CLRHeader clrHeader, SectionsHeader

this.Streams[(uint)MetaDataStreamType.DEFS_AND_REFS] = new DefsAndRefsStream(buffer, clrHeader,this);
this.Streams[(uint)MetaDataStreamType.STRINGS] = new StringStream(buffer, clrHeader);
// These are boiler plate.
this.Streams[(uint)MetaDataStreamType.US] = new StringStream(buffer, clrHeader);
this.Streams[(uint)MetaDataStreamType.GUID] = new StringStream(buffer, clrHeader);
this.Streams[(uint)MetaDataStreamType.BLOB] = new BlobStream(buffer, clrHeader);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,22 @@ namespace CsharpFunctionDumper.CLRProcessing.MetaDataStreams
/// </summary>
public class BlobStream : StreamHeader
{
public BlobStream(AssemblyBuffer buffer, CLRHeader clrHeader) : base(buffer, clrHeader)
public BlobStream(AssemblyBuffer buffer, CLRHeader clrHeader) :
base(buffer, clrHeader)
{
}

public uint GetSignatureAtOffset(uint offset)
{
return _cachedBuffer[offset];
return CachedBuffer[offset];
}

public MethodDefSignature GetMethodDefValue(uint signatureOffset)
{
_cachedAssemblyBuffer.SetIndexPointer(signatureOffset);
CachedAssemblyBuffer.SetIndexPointer(signatureOffset);

MethodDefSignature signature = new MethodDefSignature();
signature.PopulateFields(_cachedAssemblyBuffer);
signature.PopulateFields(CachedAssemblyBuffer);

return signature;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ public class DefsAndRefsStream : StreamHeader

public Dictionary<MetaDataTableType, List<TableRow>> TableRows { get; private set; }

public DefsAndRefsStream(AssemblyBuffer buffer, CLRHeader clrHeader, MetaDataHeader metaDataHeader) : base(
buffer, clrHeader)
public DefsAndRefsStream(AssemblyBuffer buffer, CLRHeader clrHeader, MetaDataHeader metaDataHeader) :
base(buffer, clrHeader)
{
this._metaDataHeader = metaDataHeader;
this.TableLengths = new uint[64];
Expand All @@ -47,14 +47,43 @@ public static DefsAndRefsStream GetInstance()
return Instance;
}

public uint ReadBlobOffset(AssemblyBuffer buffer)
{
if ((this.HeapOffsetSizes & (byte)HeapOffsetSize.BlobTableIndexOversize) != 0)
{
return buffer.ReadDWord();
}

return buffer.ReadWord();
}

public uint ReadStringOffset(AssemblyBuffer buffer)
{
if ((this.HeapOffsetSizes & (byte)HeapOffsetSize.StringTableIndexOversize) != 0)
{
return buffer.ReadDWord();
}

return buffer.ReadWord();
}

public uint ReadGuidOffset(AssemblyBuffer buffer)
{
if ((this.HeapOffsetSizes & (byte)HeapOffsetSize.GuidTableIndexOversize) != 0)
{
return buffer.ReadDWord();
}

return buffer.ReadWord();
}

public override void ProcessTables(AssemblyBuffer buffer)
{
buffer.SetIndexPointer(this.AbsoluteAddress);
uint val = buffer.ReadDWord(); // Reserved.
byte major = buffer.ReadByte(); // Major and minor version
byte minor = buffer.ReadByte(); // Major and minor version
this.HeapOffsetSizes =
buffer.ReadByte(); // Bit flags for the heap index width. Ref: https://www.codeproject.com/Articles/12585/The-NET-File-Format
this.HeapOffsetSizes = buffer.ReadByte(); // Bit flags for the heap index width. Ref: https://www.codeproject.com/Articles/12585/The-NET-File-Format

buffer.ReadByte(); // Padding byte.

Expand Down Expand Up @@ -82,7 +111,8 @@ public override void ProcessTables(AssemblyBuffer buffer)

private MetaDataTableType GetMetaTableTypeFromType(Type type)
{
return (MetaDataTableType) type.GetField("OwnerTable", BindingFlags.Static | BindingFlags.Public)
return (MetaDataTableType) type
.GetField("OwnerTable", BindingFlags.Static | BindingFlags.Public)
.GetValue(null);
}

Expand Down Expand Up @@ -114,6 +144,7 @@ private void PopulateTableRows(AssemblyBuffer buffer)
MetaDataTableType tableType = (MetaDataTableType) idx;
// These weren't valid in the present DWORD.
if (this.TableLengths[idx] == 0) continue;

if (!this.TableRowTypes.ContainsKey(tableType))
{
Console.WriteLine($"WARNING: NO TYPE HANDLER FOR: {tableType.ToString()}");
Expand Down Expand Up @@ -141,19 +172,29 @@ private void PopulateTableRows(AssemblyBuffer buffer)
}
}

public List<MethodTableRow> GetMethodTableRowsFromOffset(int offset)
private uint ResolveEndOfMethodList(int idxInTableRows)
{
List<MethodTableRow> methodTableRows = new List<MethodTableRow>();
List<TableRow> tableRows = this.TableRows[MetaDataTableType.MethodDef];
int currentOffset = offset;
methodTableRows.Add((MethodTableRow) tableRows[currentOffset]);
currentOffset++;
var typeDefRows = this.TableRows[MetaDataTableType.TypeDef];
var methodDefRows = this.TableRows[MetaDataTableType.MethodDef];
TypeDefTableRow row = (TypeDefTableRow)typeDefRows[idxInTableRows];
//Console.WriteLine($"{idxInTableRows + 1 >= typeDefRows.Count}: {(uint)methodDefRows.Count - 1} {((TypeDefTableRow) typeDefRows[idxInTableRows + 1])?.MethodList}");
return idxInTableRows + 1 >= typeDefRows.Count
? (uint)methodDefRows.Count - 1
: ((TypeDefTableRow) typeDefRows[idxInTableRows + 1]).MethodList;
}

while (true)
{
if (currentOffset >= tableRows.Count) break;
MethodTableRow methodTableRow = (MethodTableRow) tableRows[currentOffset];
if (methodTableRow.Name == ".ctor") break;
public List<MethodTableRow> GetMethodTableRowsFromTypeDef(TypeDefTableRow typeDef)
{
int posInTableRows = this.TableRows[MetaDataTableType.TypeDef].FindIndex((x)=> x == typeDef);

List<MethodTableRow> methodTableRows = new List<MethodTableRow>();
List<TableRow> methodRows = this.TableRows[MetaDataTableType.MethodDef];

int currentOffset = typeDef.MethodList - 1;
int endOfList = (int)ResolveEndOfMethodList(posInTableRows) - 1;
int deltaMethodList = endOfList - currentOffset;
for(int i =0; i < deltaMethodList ; i++){
MethodTableRow methodTableRow = (MethodTableRow) methodRows[currentOffset];
methodTableRows.Add(methodTableRow);
currentOffset++;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace CsharpFunctionDumper.CLRProcessing.MetaDataStreams
{
/// <summary>
/// This is the size displayed in the Stream headers,
/// It's representative of "HeapOffsetSize".
/// </summary>
public enum HeapIndexSize
{
WORD,
DWORD
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ public abstract class StreamHeader

public uint AbsoluteAddress { get; private set; }

protected byte[] _cachedBuffer { get; private set; }

protected AssemblyBuffer _cachedAssemblyBuffer { get; private set; }
protected byte[] CachedBuffer { get; private set; }

protected AssemblyBuffer CachedAssemblyBuffer { get; private set; }


public StreamHeader(AssemblyBuffer buffer, CLRHeader clrHeader)
{
Expand All @@ -30,9 +30,9 @@ public StreamHeader(AssemblyBuffer buffer, CLRHeader clrHeader)
public void CacheBuffer(AssemblyBuffer buffer)
{
buffer.SetIndexPointer(this.AbsoluteAddress);
this._cachedBuffer = new byte[this.Size];
this._cachedBuffer = buffer.ReadBytes(this.Size);
this._cachedAssemblyBuffer = new AssemblyBuffer("", this._cachedBuffer);
this.CachedBuffer = new byte[this.Size];
this.CachedBuffer = buffer.ReadBytes(this.Size);
this.CachedAssemblyBuffer = new AssemblyBuffer("", this.CachedBuffer);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ namespace CsharpFunctionDumper.CLRProcessing.MetaDataStreams
public class StringStream : StreamHeader
{

public StringStream(AssemblyBuffer buffer, CLRHeader clrHeader) : base(buffer,clrHeader)
public StringStream(AssemblyBuffer buffer, CLRHeader clrHeader) :
base(buffer, clrHeader)
{
}

Expand All @@ -17,7 +18,7 @@ public string ReadUntilNull(uint startOffset)
byte val;
while(true)
{
val = this._cachedBuffer[startOffset];
val = this.CachedBuffer[startOffset];

if (val == 0x0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ public class FieldTableRow : TableRow
{
public static MetaDataTableType OwnerTable = MetaDataTableType.Field;

public ushort NameAddress { get; private set; }
public uint NameAddress { get; private set; }

public string Name { get; private set; }

public ushort Flags { get; private set; }

public ushort Signature { get; private set; }
public uint Signature { get; private set; }


public FieldTableRow(AssemblyBuffer buffer) : base(buffer)
Expand All @@ -22,8 +22,8 @@ public FieldTableRow(AssemblyBuffer buffer) : base(buffer)
public override void Read(AssemblyBuffer buffer)
{
this.Flags = buffer.ReadWord();
this.NameAddress = buffer.ReadWord();
this.Signature = buffer.ReadWord();
this.NameAddress = this.ReadStringTableOffset(buffer);
this.Signature = this.ReadBlobTableOffset(buffer);

this.Name = this.ReadStringAtOffset(this.NameAddress);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ public class MethodTableRow : TableRow
public uint RVA { get; private set; }
public ushort ImplementationFlags { get; private set; }
public ushort DefinitionFlags { get; private set; }
public ushort NameAddress { get; private set; }
public ushort Signature { get; private set; }
public uint NameAddress { get; private set; }
public uint Signature { get; private set; }
public ushort ParamsListIndex { get; private set; }
public string Name { get; private set; }

Expand All @@ -28,8 +28,8 @@ public override void Read(AssemblyBuffer buffer)
this.RVA = buffer.ReadDWord();
this.ImplementationFlags = buffer.ReadWord();
this.DefinitionFlags = buffer.ReadWord();
this.NameAddress = buffer.ReadWord();
this.Signature = buffer.ReadWord();
this.NameAddress = this.ReadStringTableOffset(buffer);
this.Signature = this.ReadBlobTableOffset(buffer);
this.ParamsListIndex = buffer.ReadWord();

this.Name = this.ReadStringAtOffset(this.NameAddress);
Expand Down Expand Up @@ -61,13 +61,15 @@ public override string Display()
{
StringBuilder funcDef = new StringBuilder();
funcDef.Append($"func {this.Name}(");

DefsAndRefsStream defsAndRefsStream = DefsAndRefsStream.GetInstance();
List<ParamTableRow> paramTableRows = defsAndRefsStream.GetParameterTableRowsFromOffset(this.ParamsListIndex);

MethodDefSignature method = this.GetBlobStream().GetMethodDefValue(this.Signature);

for (var i = 0; i < paramTableRows.Count; i++)
{
ParamTableRow paramTableRow = paramTableRows[i];


if (i < method.ParameterTypes.Count)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ namespace CsharpFunctionDumper.CLRProcessing.MetaDataStreams.TableRows
public class ModuleTableRow : TableRow
{
public ushort Generation { get; private set; }
public ushort NameAddress { get; private set; }
public ushort MvId { get; private set; }
public ushort EncId { get; private set; }
public ushort EncBaseId { get; private set; }
public uint NameAddress { get; private set; }
public uint MvId { get; private set; }
public uint EncId { get; private set; }
public uint EncBaseId { get; private set; }

public string Name { get; private set; }

Expand All @@ -21,10 +21,10 @@ public ModuleTableRow(AssemblyBuffer buffer) : base(buffer)
public override void Read(AssemblyBuffer buffer)
{
this.Generation = buffer.ReadWord();
this.NameAddress = buffer.ReadWord();
this.MvId = buffer.ReadWord();
this.EncId = buffer.ReadWord();
this.EncBaseId = buffer.ReadWord();
this.NameAddress = this.ReadStringTableOffset(buffer);
this.MvId = this.ReadGuidOffset(buffer);
this.EncId = this.ReadGuidOffset(buffer);
this.EncBaseId = this.ReadGuidOffset(buffer);
this.Name = this.ReadStringAtOffset(this.NameAddress);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class ParamTableRow : TableRow

public ushort Flags { get; private set; }
public ushort Sequence { get; private set; }
public ushort NameAddresss { get; private set; }
public uint NameAddresss { get; private set; }
public string Name { get; private set; }


Expand All @@ -22,7 +22,7 @@ public override void Read(AssemblyBuffer buffer)
{
this.Flags = buffer.ReadWord();
this.Sequence = buffer.ReadWord();
this.NameAddresss = buffer.ReadWord();
this.NameAddresss = this.ReadStringTableOffset(buffer);
this.Name = this.ReadStringAtOffset(this.NameAddresss);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,27 @@ public TableRow(AssemblyBuffer buffer)
{
}

protected DefsAndRefsStream GetDefsAndRefsStream()
{
return (DefsAndRefsStream)this._streamHeaders[(uint) MetaDataStreamType.DEFS_AND_REFS];
}

protected uint ReadStringTableOffset(AssemblyBuffer buffer)
{
return this.GetDefsAndRefsStream().ReadStringOffset(buffer);
}

protected uint ReadBlobTableOffset(AssemblyBuffer buffer)
{
return this.GetDefsAndRefsStream().ReadBlobOffset(buffer);
}

protected uint ReadGuidOffset(AssemblyBuffer buffer)
{
return this.GetDefsAndRefsStream().ReadGuidOffset(buffer);
}


public string ReadStringAtOffset(uint offset)
{
return ((StringStream)this._streamHeaders[(uint)MetaDataStreamType.STRINGS]).ReadUntilNull(offset);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ public class TypeDefTableRow : TableRow

public uint Flags { get; private set; }

public ushort NameAddress { get; private set; }
public ushort NamespaceAddress { get; private set; }
public uint NameAddress { get; private set; }
public uint NamespaceAddress { get; private set; }
public ushort Extends { get; private set; }
public ushort FieldList { get; private set; }
public ushort MethodList { get; private set; }
Expand Down Expand Up @@ -41,8 +41,8 @@ public TypeDefTableRow(AssemblyBuffer buffer) : base(buffer)
public override void Read(AssemblyBuffer buffer)
{
this.Flags = buffer.ReadDWord();
this.NameAddress = buffer.ReadWord();
this.NamespaceAddress = buffer.ReadWord();
this.NameAddress = this.ReadStringTableOffset(buffer);
this.NamespaceAddress = this.ReadStringTableOffset(buffer);
this.Extends = buffer.ReadWord();
this.FieldList = buffer.ReadWord();
this.MethodList = buffer.ReadWord();
Expand Down Expand Up @@ -70,7 +70,7 @@ public override string Display()
DefsAndRefsStream defsAndRefsStream = DefsAndRefsStream.GetInstance();
StringBuilder classFormat = new StringBuilder();
classFormat.Append($"{this.Namespace}.{this.Name}\n");
foreach (var methodTableRow in defsAndRefsStream.GetMethodTableRowsFromOffset(this.MethodList))
foreach (var methodTableRow in defsAndRefsStream.GetMethodTableRowsFromTypeDef(this))
{
classFormat.Append($"\t {methodTableRow.Display()}\n");
}
Expand Down

0 comments on commit d8c4bed

Please sign in to comment.