0
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-07-01 12:40:25 +03:00
Files
ParkanPlayground/X86Disassembler/PE/Parsers/ExportDirectoryParser.cs

161 lines
5.7 KiB
C#
Raw Normal View History

using System.Text;
2025-04-20 19:54:52 +03:00
using X86Disassembler.PE.Types;
namespace X86Disassembler.PE.Parsers;
/// <summary>
/// Parser for the Export Directory of a PE file
/// </summary>
public class ExportDirectoryParser
{
private readonly PEUtility _utility;
2025-04-20 19:54:52 +03:00
public ExportDirectoryParser(PEUtility utility)
{
_utility = utility;
}
2025-04-20 19:54:52 +03:00
/// <summary>
/// Parse the Export Directory from the binary reader
/// </summary>
/// <param name="reader">The binary reader</param>
/// <param name="rva">The RVA of the Export Directory</param>
/// <returns>The parsed Export Directory</returns>
public ExportDirectory Parse(BinaryReader reader, uint rva)
{
ExportDirectory directory = new ExportDirectory();
2025-04-20 19:54:52 +03:00
reader.BaseStream.Seek(_utility.RvaToOffset(rva), SeekOrigin.Begin);
2025-04-20 19:54:52 +03:00
directory.Characteristics = reader.ReadUInt32();
directory.TimeDateStamp = reader.ReadUInt32();
directory.MajorVersion = reader.ReadUInt16();
directory.MinorVersion = reader.ReadUInt16();
2025-04-12 18:49:23 +03:00
directory.DllNameRva = reader.ReadUInt32();
directory.Base = reader.ReadUInt32();
directory.NumberOfFunctions = reader.ReadUInt32();
directory.NumberOfNames = reader.ReadUInt32();
directory.AddressOfFunctions = reader.ReadUInt32();
directory.AddressOfNames = reader.ReadUInt32();
directory.AddressOfNameOrdinals = reader.ReadUInt32();
2025-04-20 19:54:52 +03:00
uint dllNameOffset = _utility.RvaToOffset(directory.DllNameRva);
reader.BaseStream.Seek(dllNameOffset, SeekOrigin.Begin);
// Read the null-terminated ASCII string
var nameBuilder = new StringBuilder();
byte b;
while ((b = reader.ReadByte()) != 0)
{
2025-04-20 19:54:52 +03:00
nameBuilder.Append((char) b);
}
2025-04-20 19:54:52 +03:00
directory.DllName = nameBuilder.ToString();
return directory;
}
2025-04-20 19:54:52 +03:00
/// <summary>
/// Parse the exported functions using the export directory information
/// </summary>
/// <param name="reader">The binary reader</param>
/// <param name="directory">The Export Directory</param>
/// <param name="exportDirRva">The RVA of the Export Directory</param>
/// <param name="exportDirSize">The size of the Export Directory</param>
/// <returns>List of exported functions</returns>
public List<ExportedFunction> ParseExportedFunctions(BinaryReader reader, ExportDirectory directory, uint exportDirRva, uint exportDirSize)
{
List<ExportedFunction> exportedFunctions = new List<ExportedFunction>();
2025-04-20 19:54:52 +03:00
// Read the array of function addresses (RVAs)
uint[] functionRVAs = new uint[directory.NumberOfFunctions];
reader.BaseStream.Seek(_utility.RvaToOffset(directory.AddressOfFunctions), SeekOrigin.Begin);
for (int i = 0; i < directory.NumberOfFunctions; i++)
{
functionRVAs[i] = reader.ReadUInt32();
}
2025-04-20 19:54:52 +03:00
// Read the array of name RVAs
uint[] nameRVAs = new uint[directory.NumberOfNames];
reader.BaseStream.Seek(_utility.RvaToOffset(directory.AddressOfNames), SeekOrigin.Begin);
for (int i = 0; i < directory.NumberOfNames; i++)
{
nameRVAs[i] = reader.ReadUInt32();
}
2025-04-20 19:54:52 +03:00
// Read the array of name ordinals
ushort[] nameOrdinals = new ushort[directory.NumberOfNames];
reader.BaseStream.Seek(_utility.RvaToOffset(directory.AddressOfNameOrdinals), SeekOrigin.Begin);
for (int i = 0; i < directory.NumberOfNames; i++)
{
nameOrdinals[i] = reader.ReadUInt16();
}
2025-04-20 19:54:52 +03:00
// Create a dictionary to map ordinals to names
Dictionary<ushort, string> ordinalToName = new Dictionary<ushort, string>();
for (int i = 0; i < directory.NumberOfNames; i++)
{
// Read the function name
reader.BaseStream.Seek(_utility.RvaToOffset(nameRVAs[i]), SeekOrigin.Begin);
2025-04-20 19:54:52 +03:00
var nameBuilder = new StringBuilder();
byte b;
while ((b = reader.ReadByte()) != 0)
{
2025-04-20 19:54:52 +03:00
nameBuilder.Append((char) b);
}
2025-04-20 19:54:52 +03:00
string name = nameBuilder.ToString();
// Map the ordinal to the name
ordinalToName[nameOrdinals[i]] = name;
}
2025-04-20 19:54:52 +03:00
// Create the exported functions
for (ushort i = 0; i < directory.NumberOfFunctions; i++)
{
uint functionRVA = functionRVAs[i];
if (functionRVA == 0)
{
continue; // Skip empty entries
}
2025-04-20 19:54:52 +03:00
ExportedFunction function = new ExportedFunction();
2025-04-20 19:54:52 +03:00
function.Ordinal = (ushort) (i + directory.Base);
2025-04-12 18:49:23 +03:00
function.AddressRva = functionRVA;
2025-04-20 19:54:52 +03:00
// Check if this function has a name
if (ordinalToName.TryGetValue(i, out string? name))
{
2025-04-20 19:54:52 +03:00
function.Name = name;
}
else
{
function.Name = $"Ordinal_{function.Ordinal}";
}
2025-04-20 19:54:52 +03:00
// Check if this is a forwarder
uint exportDirEnd = exportDirRva + exportDirSize;
2025-04-20 19:54:52 +03:00
if (functionRVA >= exportDirRva && functionRVA < exportDirEnd)
{
function.IsForwarder = true;
2025-04-20 19:54:52 +03:00
// Read the forwarder string
reader.BaseStream.Seek(_utility.RvaToOffset(functionRVA), SeekOrigin.Begin);
2025-04-20 19:54:52 +03:00
var forwarderBuilder = new StringBuilder();
byte b;
while ((b = reader.ReadByte()) != 0)
{
2025-04-20 19:54:52 +03:00
forwarderBuilder.Append((char) b);
}
2025-04-20 19:54:52 +03:00
function.ForwarderName = forwarderBuilder.ToString();
}
2025-04-20 19:54:52 +03:00
exportedFunctions.Add(function);
}
2025-04-20 19:54:52 +03:00
return exportedFunctions;
}
2025-04-20 19:54:52 +03:00
}