diff --git a/ParkanPlayground.sln b/ParkanPlayground.sln
index c09d3a1..932cc48 100644
--- a/ParkanPlayground.sln
+++ b/ParkanPlayground.sln
@@ -1,4 +1,3 @@
-
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParkanPlayground", "ParkanPlayground\ParkanPlayground.csproj", "{7DB19000-6F41-4BAE-A904-D34EFCA065E9}"
EndProject
@@ -27,6 +26,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScrLib", "ScrLib\ScrLib.csp
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VarsetLib", "VarsetLib\VarsetLib.csproj", "{0EC800E2-1444-40D5-9EDD-93276F4D1FF5}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Visualisator", "Visualisator\Visualisator.csproj", "{667A7E03-5CAA-4591-9980-F6C722911A35}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "X86Disassembler", "X86Disassembler\X86Disassembler.csproj", "{B5C2E94A-0F63-4E09-BC04-F2518E2CC1F0}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -77,5 +80,13 @@ Global
{0EC800E2-1444-40D5-9EDD-93276F4D1FF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0EC800E2-1444-40D5-9EDD-93276F4D1FF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0EC800E2-1444-40D5-9EDD-93276F4D1FF5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {667A7E03-5CAA-4591-9980-F6C722911A35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {667A7E03-5CAA-4591-9980-F6C722911A35}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {667A7E03-5CAA-4591-9980-F6C722911A35}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {667A7E03-5CAA-4591-9980-F6C722911A35}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B5C2E94A-0F63-4E09-BC04-F2518E2CC1F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B5C2E94A-0F63-4E09-BC04-F2518E2CC1F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B5C2E94A-0F63-4E09-BC04-F2518E2CC1F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B5C2E94A-0F63-4E09-BC04-F2518E2CC1F0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/ParkanPlayground.sln.DotSettings.user b/ParkanPlayground.sln.DotSettings.user
new file mode 100644
index 0000000..780c784
--- /dev/null
+++ b/ParkanPlayground.sln.DotSettings.user
@@ -0,0 +1,11 @@
+
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
\ No newline at end of file
diff --git a/ParkanPlayground/ParkanPlayground.csproj b/ParkanPlayground/ParkanPlayground.csproj
index a0a96e4..527979a 100644
--- a/ParkanPlayground/ParkanPlayground.csproj
+++ b/ParkanPlayground/ParkanPlayground.csproj
@@ -13,4 +13,8 @@
+
+
+
+
diff --git a/ParkanPlayground/Program.cs b/ParkanPlayground/Program.cs
index 289364b..367ee58 100644
--- a/ParkanPlayground/Program.cs
+++ b/ParkanPlayground/Program.cs
@@ -1,4 +1,9 @@
-using VarsetLib;
+using System.Buffers.Binary;
+using System.Numerics;
+using System.Text.Json;
+using ScrLib;
+using SharpDisasm;
+using VarsetLib;
// var path = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\SCRIPTS\\default.scr";
@@ -6,7 +11,7 @@
// var path = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\SCRIPTS\\scream.scr";
// var path = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\SCRIPTS\\scream1.scr";
// var path = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\SCRIPTS";
-var path = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\SCRIPTS\\varset.var";
+// var path = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\SCRIPTS\\varset.var";
// var path = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\preload.lda";
//
// var fs = new FileStream(path, FileMode.Open);
@@ -24,6 +29,88 @@ var path = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MISSIONS\\SCRIPTS\\v
// fs.Position == fs.Length
// );
-var items = VarsetParser.Parse(path);
+// var items = VarsetParser.Parse(path);
-Console.WriteLine(items.Count);
\ No newline at end of file
+// Console.WriteLine(items.Count);
+
+// Span flt = stackalloc byte[4];
+// flt[0] = 0x7f;
+// flt[1] = 0x7f;
+// flt[2] = 0xff;
+// flt[3] = 0xff;
+// var f = BinaryPrimitives.ReadSingleBigEndian(flt);
+//
+// Console.WriteLine(f);
+
+// return;
+
+// var path = "C:\\Program Files (x86)\\Nikita\\Iron Strategy\\MisLoad.dll";
+var path = "C:\\ParkanUnpacked\\Land.msh\\2_03 00 00 00_Land.bin";
+
+var fs = new FileStream(path, FileMode.Open);
+var outputFs = new FileStream("Land.obj", FileMode.Create);
+var sw = new StreamWriter(outputFs);
+
+List points = [];
+var count = 0;
+while (fs.Position < fs.Length)
+{
+ var x = fs.ReadFloatLittleEndian();
+ var y = fs.ReadFloatLittleEndian();
+ var z = fs.ReadFloatLittleEndian();
+
+ var vertex = new Vector3D(x, y, z);
+ sw.WriteLine($"v {x} {y} {z}");
+
+ var seenIndex = points.FindIndex(vec => vec == vertex);
+ if (seenIndex != -1)
+ {
+ vertex.Duplicates = seenIndex;
+ }
+
+ points.Add(vertex);
+ count++;
+}
+
+File.WriteAllText("human-readable.json", JsonSerializer.Serialize(points, new JsonSerializerOptions()
+{
+ WriteIndented = true
+}));
+
+Console.WriteLine($"Total vertices: {count}");
+
+
+// for (int i = 0; i < count / 4; i++)
+
+public record Vector3D(float X, float Y, float Z)
+{
+ public int Duplicates { get; set; }
+}
+// var indices = string.Join(" ", Enumerable.Range(1, count));
+//
+// sw.WriteLine($"l {indices}");
+
+//
+// fs.Seek(0x1000, SeekOrigin.Begin);
+//
+// byte[] buf = new byte[34];
+// fs.ReadExactly(buf);
+//
+// var disassembler = new SharpDisasm.Disassembler(buf, ArchitectureMode.x86_32);
+// foreach (var instruction in disassembler.Disassemble())
+// {
+// Console.WriteLine($"{instruction.PC - instruction.Offset}: {instruction}");
+//
+// new Instruction()
+// {
+// Action = instruction.Mnemonic.ToString(),
+// Arguments = {instruction.Operands[0].ToString()}
+// };
+// }
+
+public class Instruction
+{
+ public string Action { get; set; } = "";
+
+ public List Arguments { get; set; } = [];
+}
diff --git a/Visualisator/Program.cs b/Visualisator/Program.cs
new file mode 100644
index 0000000..7933aff
--- /dev/null
+++ b/Visualisator/Program.cs
@@ -0,0 +1,180 @@
+// Configure window options
+
+using System.Buffers.Binary;
+using System.Numerics;
+using Silk.NET.OpenGL;
+using Silk.NET.Windowing;
+
+public static class Program
+{
+ private static string vertexShaderSource = @"
+ #version 330 core
+ layout (location = 0) in vec3 aPos;
+ uniform mat4 uMVP;
+
+ void main()
+ {
+ gl_Position = uMVP * vec4(aPos, 1.0);
+ gl_PointSize = 8.0;
+ }
+ ";
+
+ private static string fragmentShaderSource = @"
+ #version 330 core
+ out vec4 FragColor;
+
+ void main()
+ {
+ FragColor = vec4(1.0, 1.0, 1.0, 1.0); // White points
+ }
+ ";
+
+
+ private static IWindow? window;
+ private static GL? gl = null;
+
+
+ private static uint shaderProgram = uint.MaxValue;
+ private static uint vao = uint.MaxValue;
+ private static uint vbo = uint.MaxValue;
+ private static Matrix4x4 mvp = new Matrix4x4();
+ private static float[] points = [];
+
+ public static void Main(string[] args)
+ {
+ var path = "C:\\ParkanUnpacked\\Land.msh\\2_03 00 00 00_Land.bin";
+ var bytes = File.ReadAllBytes(path);
+
+ points = new float[bytes.Length / 4];
+ for (int i = 0; i < bytes.Length / 4; i++)
+ {
+ points[i] = BinaryPrimitives.ReadSingleBigEndian(bytes.AsSpan()[(i * 4)..]);
+ }
+
+ var options = WindowOptions.Default;
+ options.API = new GraphicsAPI(ContextAPI.OpenGL, new APIVersion(3, 3));
+ options.Title = "3D Points with Silk.NET";
+ window = Window.Create(options);
+
+ window.Load += OnLoad;
+ window.Render += OnRender;
+ window.Run();
+ }
+
+
+ unsafe static void OnLoad()
+ {
+ gl = window.CreateOpenGL();
+ // Compile shaders
+ uint vertexShader = gl.CreateShader(ShaderType.VertexShader);
+ gl.ShaderSource(vertexShader, vertexShaderSource);
+ gl.CompileShader(vertexShader);
+ CheckShaderCompile(vertexShader);
+
+ uint fragmentShader = gl.CreateShader(ShaderType.FragmentShader);
+ gl.ShaderSource(fragmentShader, fragmentShaderSource);
+ gl.CompileShader(fragmentShader);
+ CheckShaderCompile(fragmentShader);
+
+ // Create shader program
+ shaderProgram = gl.CreateProgram();
+ gl.AttachShader(shaderProgram, vertexShader);
+ gl.AttachShader(shaderProgram, fragmentShader);
+ gl.LinkProgram(shaderProgram);
+ CheckProgramLink(shaderProgram);
+
+ gl.DeleteShader(vertexShader);
+ gl.DeleteShader(fragmentShader);
+
+ // Create VAO and VBO
+ vao = gl.GenVertexArray();
+ gl.BindVertexArray(vao);
+
+ vbo = gl.GenBuffer();
+ gl.BindBuffer(BufferTargetARB.ArrayBuffer, vbo);
+ unsafe
+ {
+ fixed (float* ptr = points)
+ {
+ gl.BufferData(
+ BufferTargetARB.ArrayBuffer,
+ (nuint) (points.Length * sizeof(float)),
+ ptr,
+ BufferUsageARB.StaticDraw
+ );
+ }
+ }
+
+ gl.VertexAttribPointer(
+ 0,
+ 3,
+ VertexAttribPointerType.Float,
+ false,
+ 3 * sizeof(float),
+ (void*) 0
+ );
+ gl.EnableVertexAttribArray(0);
+
+ gl.BindVertexArray(0); // Unbind VAO
+
+ gl.Enable(EnableCap.DepthTest);
+ }
+
+ unsafe static void OnRender(double dt)
+ {
+ gl.ClearColor(
+ 0.1f,
+ 0.1f,
+ 0.1f,
+ 1.0f
+ );
+ gl.Clear((uint) (ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit));
+
+ // Set up MVP matrix
+ Matrix4x4 view = Matrix4x4.CreateLookAt(
+ new Vector3(100, 100, 40), // Camera position
+ Vector3.Zero, // Look at origin
+ Vector3.UnitY
+ ); // Up direction
+ Matrix4x4 projection = Matrix4x4.CreatePerspectiveFieldOfView(
+ (float) Math.PI / 4f, // 45 degrees
+ (float) window.Size.X / window.Size.Y,
+ 0.1f,
+ 100f
+ );
+ mvp = view * projection;
+
+ gl.UseProgram(shaderProgram);
+
+ // Set MVP matrix (transpose=true for column-major format)
+ int mvpLocation = gl.GetUniformLocation(shaderProgram, "uMVP");
+
+ fixed (Matrix4x4* ptr = &mvp)
+ {
+ gl.UniformMatrix4(
+ mvpLocation,
+ 1,
+ true,
+ (float*) ptr
+ );
+ }
+
+ gl.BindVertexArray(vao);
+ gl.DrawArrays(PrimitiveType.Points, 0, (uint) (points.Length / 3));
+ }
+
+ // Error checking methods
+ static void CheckShaderCompile(uint shader)
+ {
+ gl.GetShader(shader, ShaderParameterName.CompileStatus, out int success);
+ if (success == 0)
+ Console.WriteLine(gl.GetShaderInfoLog(shader));
+ }
+
+ static void CheckProgramLink(uint program)
+ {
+ gl.GetProgram(program, ProgramPropertyARB.LinkStatus, out int success);
+ if (success == 0)
+ Console.WriteLine(gl.GetProgramInfoLog(program));
+ }
+}
\ No newline at end of file
diff --git a/Visualisator/Visualisator.csproj b/Visualisator/Visualisator.csproj
new file mode 100644
index 0000000..b9b125f
--- /dev/null
+++ b/Visualisator/Visualisator.csproj
@@ -0,0 +1,18 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
diff --git a/X86Disassembler/PEFormat.cs b/X86Disassembler/PEFormat.cs
new file mode 100644
index 0000000..a66ddc2
--- /dev/null
+++ b/X86Disassembler/PEFormat.cs
@@ -0,0 +1,834 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace X86Disassembler
+{
+ ///
+ /// Represents a Portable Executable (PE) file format parser
+ ///
+ public class PEFormat
+ {
+ // DOS Header constants
+ private const ushort DOS_SIGNATURE = 0x5A4D; // 'MZ'
+ private const uint PE_SIGNATURE = 0x00004550; // 'PE\0\0'
+
+ // Optional Header Magic values
+ private const ushort PE32_MAGIC = 0x10B; // 32-bit executable
+ private const ushort PE32PLUS_MAGIC = 0x20B; // 64-bit executable
+
+ // Section characteristics flags
+ private const uint IMAGE_SCN_CNT_CODE = 0x00000020; // Section contains code
+ private const uint IMAGE_SCN_MEM_EXECUTE = 0x20000000; // Section is executable
+ private const uint IMAGE_SCN_MEM_READ = 0x40000000; // Section is readable
+ private const uint IMAGE_SCN_MEM_WRITE = 0x80000000; // Section is writable
+
+ // Data directories
+ private const int IMAGE_DIRECTORY_ENTRY_EXPORT = 0; // Export Directory
+ private const int IMAGE_DIRECTORY_ENTRY_IMPORT = 1; // Import Directory
+ private const int IMAGE_DIRECTORY_ENTRY_RESOURCE = 2; // Resource Directory
+ private const int IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3; // Exception Directory
+ private const int IMAGE_DIRECTORY_ENTRY_SECURITY = 4; // Security Directory
+ private const int IMAGE_DIRECTORY_ENTRY_BASERELOC = 5; // Base Relocation Table
+ private const int IMAGE_DIRECTORY_ENTRY_DEBUG = 6; // Debug Directory
+ private const int IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7; // Architecture Specific Data
+ private const int IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8; // RVA of GP
+ private const int IMAGE_DIRECTORY_ENTRY_TLS = 9; // TLS Directory
+ private const int IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10; // Load Configuration Directory
+ private const int IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11; // Bound Import Directory
+ private const int IMAGE_DIRECTORY_ENTRY_IAT = 12; // Import Address Table
+ private const int IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13; // Delay Load Import Descriptors
+ private const int IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14; // COM Runtime descriptor
+
+ // PE file data
+ private byte[] _fileData;
+
+ // Parsed headers
+ public DOSHeader DosHeader { get; private set; }
+ public FileHeader FileHeader { get; private set; }
+ public OptionalHeader OptionalHeader { get; private set; }
+ public List SectionHeaders { get; private set; }
+ public bool Is64Bit { get; private set; }
+
+ // Export and Import information
+ public ExportDirectory ExportDirectory { get; private set; }
+ public List ExportedFunctions { get; private set; }
+ public List ImportDescriptors { get; private set; }
+
+ ///
+ /// Parses a PE file from the given byte array
+ ///
+ /// The raw file data
+ public PEFormat(byte[] fileData)
+ {
+ _fileData = fileData;
+ SectionHeaders = new List();
+ ExportedFunctions = new List();
+ ImportDescriptors = new List();
+ Parse();
+ }
+
+ ///
+ /// Parses the PE file structure
+ ///
+ private void Parse()
+ {
+ using (MemoryStream stream = new MemoryStream(_fileData))
+ using (BinaryReader reader = new BinaryReader(stream))
+ {
+ // Parse DOS header
+ DosHeader = ParseDOSHeader(reader);
+
+ // Move to PE header
+ reader.BaseStream.Seek(DosHeader.e_lfanew, SeekOrigin.Begin);
+
+ // Verify PE signature
+ uint peSignature = reader.ReadUInt32();
+ if (peSignature != PE_SIGNATURE)
+ {
+ throw new InvalidDataException("Invalid PE signature");
+ }
+
+ // Parse File Header
+ FileHeader = ParseFileHeader(reader);
+
+ // Parse Optional Header
+ OptionalHeader = ParseOptionalHeader(reader);
+
+ // Parse Section Headers
+ for (int i = 0; i < FileHeader.NumberOfSections; i++)
+ {
+ SectionHeaders.Add(ParseSectionHeader(reader));
+ }
+
+ // Parse Export Directory
+ if (OptionalHeader.DataDirectories.Length > IMAGE_DIRECTORY_ENTRY_EXPORT &&
+ OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != 0)
+ {
+ ExportDirectory = ParseExportDirectory(reader, OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
+ ParseExportedFunctions(reader);
+ }
+
+ // Parse Import Descriptors
+ if (OptionalHeader.DataDirectories.Length > IMAGE_DIRECTORY_ENTRY_IMPORT &&
+ OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != 0)
+ {
+ ImportDescriptors = ParseImportDescriptors(reader, OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
+ }
+ }
+ }
+
+ ///
+ /// Parses the DOS header
+ ///
+ private DOSHeader ParseDOSHeader(BinaryReader reader)
+ {
+ DOSHeader header = new DOSHeader();
+
+ header.e_magic = reader.ReadUInt16();
+ if (header.e_magic != DOS_SIGNATURE)
+ {
+ throw new InvalidDataException("Invalid DOS signature (MZ)");
+ }
+
+ header.e_cblp = reader.ReadUInt16();
+ header.e_cp = reader.ReadUInt16();
+ header.e_crlc = reader.ReadUInt16();
+ header.e_cparhdr = reader.ReadUInt16();
+ header.e_minalloc = reader.ReadUInt16();
+ header.e_maxalloc = reader.ReadUInt16();
+ header.e_ss = reader.ReadUInt16();
+ header.e_sp = reader.ReadUInt16();
+ header.e_csum = reader.ReadUInt16();
+ header.e_ip = reader.ReadUInt16();
+ header.e_cs = reader.ReadUInt16();
+ header.e_lfarlc = reader.ReadUInt16();
+ header.e_ovno = reader.ReadUInt16();
+
+ header.e_res = new ushort[4];
+ for (int i = 0; i < 4; i++)
+ {
+ header.e_res[i] = reader.ReadUInt16();
+ }
+
+ header.e_oemid = reader.ReadUInt16();
+ header.e_oeminfo = reader.ReadUInt16();
+
+ header.e_res2 = new ushort[10];
+ for (int i = 0; i < 10; i++)
+ {
+ header.e_res2[i] = reader.ReadUInt16();
+ }
+
+ header.e_lfanew = reader.ReadUInt32();
+
+ return header;
+ }
+
+ ///
+ /// Parses the File header
+ ///
+ private FileHeader ParseFileHeader(BinaryReader reader)
+ {
+ FileHeader header = new FileHeader();
+
+ header.Machine = reader.ReadUInt16();
+ header.NumberOfSections = reader.ReadUInt16();
+ header.TimeDateStamp = reader.ReadUInt32();
+ header.PointerToSymbolTable = reader.ReadUInt32();
+ header.NumberOfSymbols = reader.ReadUInt32();
+ header.SizeOfOptionalHeader = reader.ReadUInt16();
+ header.Characteristics = reader.ReadUInt16();
+
+ return header;
+ }
+
+ ///
+ /// Parses the Optional header
+ ///
+ private OptionalHeader ParseOptionalHeader(BinaryReader reader)
+ {
+ OptionalHeader header = new OptionalHeader();
+
+ // Standard fields
+ header.Magic = reader.ReadUInt16();
+
+ // Determine if this is a PE32 or PE32+ file
+ Is64Bit = header.Magic == PE32PLUS_MAGIC;
+
+ header.MajorLinkerVersion = reader.ReadByte();
+ header.MinorLinkerVersion = reader.ReadByte();
+ header.SizeOfCode = reader.ReadUInt32();
+ header.SizeOfInitializedData = reader.ReadUInt32();
+ header.SizeOfUninitializedData = reader.ReadUInt32();
+ header.AddressOfEntryPoint = reader.ReadUInt32();
+ header.BaseOfCode = reader.ReadUInt32();
+
+ // PE32 has BaseOfData, PE32+ doesn't
+ if (!Is64Bit)
+ {
+ header.BaseOfData = reader.ReadUInt32();
+ }
+
+ // Windows-specific fields
+ if (Is64Bit)
+ {
+ header.ImageBase = reader.ReadUInt64();
+ }
+ else
+ {
+ header.ImageBase = reader.ReadUInt32();
+ }
+
+ header.SectionAlignment = reader.ReadUInt32();
+ header.FileAlignment = reader.ReadUInt32();
+ header.MajorOperatingSystemVersion = reader.ReadUInt16();
+ header.MinorOperatingSystemVersion = reader.ReadUInt16();
+ header.MajorImageVersion = reader.ReadUInt16();
+ header.MinorImageVersion = reader.ReadUInt16();
+ header.MajorSubsystemVersion = reader.ReadUInt16();
+ header.MinorSubsystemVersion = reader.ReadUInt16();
+ header.Win32VersionValue = reader.ReadUInt32();
+ header.SizeOfImage = reader.ReadUInt32();
+ header.SizeOfHeaders = reader.ReadUInt32();
+ header.CheckSum = reader.ReadUInt32();
+ header.Subsystem = reader.ReadUInt16();
+ header.DllCharacteristics = reader.ReadUInt16();
+
+ // Size fields differ between PE32 and PE32+
+ if (Is64Bit)
+ {
+ header.SizeOfStackReserve = reader.ReadUInt64();
+ header.SizeOfStackCommit = reader.ReadUInt64();
+ header.SizeOfHeapReserve = reader.ReadUInt64();
+ header.SizeOfHeapCommit = reader.ReadUInt64();
+ }
+ else
+ {
+ header.SizeOfStackReserve = reader.ReadUInt32();
+ header.SizeOfStackCommit = reader.ReadUInt32();
+ header.SizeOfHeapReserve = reader.ReadUInt32();
+ header.SizeOfHeapCommit = reader.ReadUInt32();
+ }
+
+ header.LoaderFlags = reader.ReadUInt32();
+ header.NumberOfRvaAndSizes = reader.ReadUInt32();
+
+ // Data directories
+ int numDirectories = (int)Math.Min(header.NumberOfRvaAndSizes, 16); // Maximum of 16 directories
+ header.DataDirectories = new DataDirectory[numDirectories];
+
+ for (int i = 0; i < numDirectories; i++)
+ {
+ DataDirectory dir = new DataDirectory();
+ dir.VirtualAddress = reader.ReadUInt32();
+ dir.Size = reader.ReadUInt32();
+ header.DataDirectories[i] = dir;
+ }
+
+ return header;
+ }
+
+ ///
+ /// Parses a section header
+ ///
+ private SectionHeader ParseSectionHeader(BinaryReader reader)
+ {
+ SectionHeader header = new SectionHeader();
+
+ // Read section name (8 bytes)
+ byte[] nameBytes = reader.ReadBytes(8);
+ // Convert to string, removing any null characters
+ header.Name = Encoding.ASCII.GetString(nameBytes).TrimEnd('\0');
+
+ header.VirtualSize = reader.ReadUInt32();
+ header.VirtualAddress = reader.ReadUInt32();
+ header.SizeOfRawData = reader.ReadUInt32();
+ header.PointerToRawData = reader.ReadUInt32();
+ header.PointerToRelocations = reader.ReadUInt32();
+ header.PointerToLinenumbers = reader.ReadUInt32();
+ header.NumberOfRelocations = reader.ReadUInt16();
+ header.NumberOfLinenumbers = reader.ReadUInt16();
+ header.Characteristics = reader.ReadUInt32();
+
+ return header;
+ }
+
+ ///
+ /// Parses the Export Directory
+ ///
+ private ExportDirectory ParseExportDirectory(BinaryReader reader, uint rva)
+ {
+ ExportDirectory directory = new ExportDirectory();
+
+ reader.BaseStream.Seek(RvaToOffset(rva), SeekOrigin.Begin);
+
+ directory.Characteristics = reader.ReadUInt32();
+ directory.TimeDateStamp = reader.ReadUInt32();
+ directory.MajorVersion = reader.ReadUInt16();
+ directory.MinorVersion = reader.ReadUInt16();
+ directory.Name = 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();
+
+ // Read the DLL name
+ uint dllNameRVA = directory.Name;
+ reader.BaseStream.Seek(RvaToOffset(dllNameRVA), SeekOrigin.Begin);
+ byte[] dllNameBytes = reader.ReadBytes(256);
+ directory.DllName = Encoding.ASCII.GetString(dllNameBytes).TrimEnd('\0');
+
+ return directory;
+ }
+
+ ///
+ /// Parses the Import Descriptors
+ ///
+ private List ParseImportDescriptors(BinaryReader reader, uint rva)
+ {
+ List descriptors = new List();
+
+ try
+ {
+ reader.BaseStream.Seek(RvaToOffset(rva), SeekOrigin.Begin);
+
+ while (true)
+ {
+ ImportDescriptor descriptor = new ImportDescriptor();
+
+ descriptor.OriginalFirstThunk = reader.ReadUInt32();
+ descriptor.TimeDateStamp = reader.ReadUInt32();
+ descriptor.ForwarderChain = reader.ReadUInt32();
+ descriptor.Name = reader.ReadUInt32();
+ descriptor.FirstThunk = reader.ReadUInt32();
+
+ // Check if we've reached the end of the import descriptors
+ if (descriptor.OriginalFirstThunk == 0 && descriptor.Name == 0 && descriptor.FirstThunk == 0)
+ {
+ break;
+ }
+
+ try
+ {
+ // Read the DLL name
+ uint dllNameOffset = RvaToOffset(descriptor.Name);
+ reader.BaseStream.Seek(dllNameOffset, SeekOrigin.Begin);
+
+ List nameBytes = new List();
+ byte b;
+ while ((b = reader.ReadByte()) != 0)
+ {
+ nameBytes.Add(b);
+ }
+ descriptor.DllName = Encoding.ASCII.GetString(nameBytes.ToArray());
+
+ // Read the imported functions (use FirstThunk if OriginalFirstThunk is 0)
+ uint thunkRVA = descriptor.OriginalFirstThunk != 0 ? descriptor.OriginalFirstThunk : descriptor.FirstThunk;
+
+ if (thunkRVA != 0)
+ {
+ try
+ {
+ uint thunkOffset = RvaToOffset(thunkRVA);
+ uint currentThunkOffset = thunkOffset;
+
+ while (true)
+ {
+ reader.BaseStream.Seek(currentThunkOffset, SeekOrigin.Begin);
+ uint thunk = reader.ReadUInt32();
+
+ if (thunk == 0)
+ {
+ break;
+ }
+
+ ImportedFunction function = new ImportedFunction();
+ function.ThunkRVA = thunkRVA + (currentThunkOffset - thunkOffset);
+
+ // Check if the function is imported by ordinal
+ if ((thunk & 0x80000000) != 0)
+ {
+ function.IsOrdinal = true;
+ function.Ordinal = (ushort)(thunk & 0xFFFF);
+ function.Name = $"Ordinal_{function.Ordinal}";
+ }
+ else
+ {
+ // Read the function name and hint
+ try
+ {
+ uint nameOffset = RvaToOffset(thunk);
+ reader.BaseStream.Seek(nameOffset, SeekOrigin.Begin);
+
+ function.Hint = reader.ReadUInt16();
+
+ List funcNameBytes = new List();
+ byte c;
+ while ((c = reader.ReadByte()) != 0)
+ {
+ funcNameBytes.Add(c);
+ }
+ function.Name = Encoding.ASCII.GetString(funcNameBytes.ToArray());
+ }
+ catch (Exception)
+ {
+ function.Name = $"Function_at_{thunk:X8}";
+ }
+ }
+
+ descriptor.Functions.Add(function);
+
+ currentThunkOffset += 4; // Move to the next thunk
+ }
+ }
+ catch (Exception)
+ {
+ // Skip this thunk table if there's an error
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // If we can't read the DLL name, use a placeholder
+ descriptor.DllName = $"DLL_at_{descriptor.Name:X8}";
+ }
+
+ descriptors.Add(descriptor);
+ }
+ }
+ catch (Exception)
+ {
+ // Return whatever descriptors we've managed to parse
+ }
+
+ return descriptors;
+ }
+
+ ///
+ /// Parses the exported functions using the export directory information
+ ///
+ private void ParseExportedFunctions(BinaryReader reader)
+ {
+ if (ExportDirectory == null)
+ {
+ return;
+ }
+
+ // Read the array of function addresses (RVAs)
+ uint[] functionRVAs = new uint[ExportDirectory.NumberOfFunctions];
+ reader.BaseStream.Seek(RvaToOffset(ExportDirectory.AddressOfFunctions), SeekOrigin.Begin);
+ for (int i = 0; i < ExportDirectory.NumberOfFunctions; i++)
+ {
+ functionRVAs[i] = reader.ReadUInt32();
+ }
+
+ // Read the array of name RVAs
+ uint[] nameRVAs = new uint[ExportDirectory.NumberOfNames];
+ reader.BaseStream.Seek(RvaToOffset(ExportDirectory.AddressOfNames), SeekOrigin.Begin);
+ for (int i = 0; i < ExportDirectory.NumberOfNames; i++)
+ {
+ nameRVAs[i] = reader.ReadUInt32();
+ }
+
+ // Read the array of name ordinals
+ ushort[] nameOrdinals = new ushort[ExportDirectory.NumberOfNames];
+ reader.BaseStream.Seek(RvaToOffset(ExportDirectory.AddressOfNameOrdinals), SeekOrigin.Begin);
+ for (int i = 0; i < ExportDirectory.NumberOfNames; i++)
+ {
+ nameOrdinals[i] = reader.ReadUInt16();
+ }
+
+ // Create a dictionary to map ordinals to names
+ Dictionary ordinalToName = new Dictionary();
+ for (int i = 0; i < ExportDirectory.NumberOfNames; i++)
+ {
+ // Read the function name
+ reader.BaseStream.Seek(RvaToOffset(nameRVAs[i]), SeekOrigin.Begin);
+ List nameBytes = new List();
+ byte b;
+ while ((b = reader.ReadByte()) != 0)
+ {
+ nameBytes.Add(b);
+ }
+ string name = Encoding.ASCII.GetString(nameBytes.ToArray());
+
+ // Map the ordinal to the name
+ ordinalToName[nameOrdinals[i]] = name;
+ }
+
+ // Create the exported functions
+ for (ushort i = 0; i < ExportDirectory.NumberOfFunctions; i++)
+ {
+ uint functionRVA = functionRVAs[i];
+ if (functionRVA == 0)
+ {
+ continue; // Skip empty entries
+ }
+
+ ExportedFunction function = new ExportedFunction();
+ function.Ordinal = (ushort)(i + ExportDirectory.Base);
+ function.Address = functionRVA;
+
+ // Check if this function has a name
+ if (ordinalToName.TryGetValue(i, out string name))
+ {
+ function.Name = name;
+ }
+ else
+ {
+ function.Name = $"Ordinal_{function.Ordinal}";
+ }
+
+ // Check if this is a forwarder
+ uint exportDirStart = OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
+ uint exportDirEnd = exportDirStart + OptionalHeader.DataDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
+
+ if (functionRVA >= exportDirStart && functionRVA < exportDirEnd)
+ {
+ function.IsForwarder = true;
+
+ // Read the forwarder string
+ reader.BaseStream.Seek(RvaToOffset(functionRVA), SeekOrigin.Begin);
+ List forwarderBytes = new List();
+ byte b;
+ while ((b = reader.ReadByte()) != 0)
+ {
+ forwarderBytes.Add(b);
+ }
+ function.ForwarderName = Encoding.ASCII.GetString(forwarderBytes.ToArray());
+ }
+
+ ExportedFunctions.Add(function);
+ }
+ }
+
+ ///
+ /// Gets the raw data for a specific section
+ ///
+ /// Index of the section
+ /// Byte array containing the section data
+ public byte[] GetSectionData(int sectionIndex)
+ {
+ if (sectionIndex < 0 || sectionIndex >= SectionHeaders.Count)
+ {
+ throw new ArgumentOutOfRangeException(nameof(sectionIndex));
+ }
+
+ SectionHeader section = SectionHeaders[sectionIndex];
+ byte[] sectionData = new byte[section.SizeOfRawData];
+
+ Array.Copy(_fileData, section.PointerToRawData, sectionData, 0, section.SizeOfRawData);
+
+ return sectionData;
+ }
+
+ ///
+ /// Gets the raw data for a section by name
+ ///
+ /// Name of the section
+ /// Byte array containing the section data
+ public byte[] GetSectionData(string sectionName)
+ {
+ for (int i = 0; i < SectionHeaders.Count; i++)
+ {
+ if (SectionHeaders[i].Name == sectionName)
+ {
+ return GetSectionData(i);
+ }
+ }
+
+ throw new ArgumentException($"Section '{sectionName}' not found");
+ }
+
+ ///
+ /// Checks if a section contains code
+ ///
+ /// The section to check
+ /// True if the section contains code, false otherwise
+ public bool IsSectionContainsCode(SectionHeader section)
+ {
+ return (section.Characteristics & IMAGE_SCN_CNT_CODE) != 0 ||
+ (section.Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
+ }
+
+ ///
+ /// Gets all code sections
+ ///
+ /// List of section indices that contain code
+ public List GetCodeSections()
+ {
+ List codeSections = new List();
+
+ for (int i = 0; i < SectionHeaders.Count; i++)
+ {
+ if (IsSectionContainsCode(SectionHeaders[i]))
+ {
+ codeSections.Add(i);
+ }
+ }
+
+ return codeSections;
+ }
+
+ ///
+ /// Converts a Relative Virtual Address (RVA) to a file offset
+ ///
+ /// The RVA to convert
+ /// The corresponding file offset
+ public uint RvaToOffset(uint rva)
+ {
+ if (rva == 0)
+ {
+ return 0;
+ }
+
+ foreach (var section in SectionHeaders)
+ {
+ // Check if the RVA is within this section
+ if (rva >= section.VirtualAddress && rva < section.VirtualAddress + section.VirtualSize)
+ {
+ // Calculate the offset within the section
+ uint offsetInSection = rva - section.VirtualAddress;
+
+ // Make sure we don't exceed the raw data size
+ if (offsetInSection < section.SizeOfRawData)
+ {
+ return section.PointerToRawData + offsetInSection;
+ }
+ }
+ }
+
+ // If the RVA is not within any section, it might be in the headers
+ if (rva < OptionalHeader.SizeOfHeaders)
+ {
+ return rva;
+ }
+
+ throw new ArgumentException($"RVA {rva:X8} is not within any section");
+ }
+ }
+
+ #region PE Format Structures
+
+ ///
+ /// DOS Header structure
+ ///
+ public class DOSHeader
+ {
+ public ushort e_magic; // Magic number ("MZ")
+ public ushort e_cblp; // Bytes on last page of file
+ public ushort e_cp; // Pages in file
+ public ushort e_crlc; // Relocations
+ public ushort e_cparhdr; // Size of header in paragraphs
+ public ushort e_minalloc; // Minimum extra paragraphs needed
+ public ushort e_maxalloc; // Maximum extra paragraphs needed
+ public ushort e_ss; // Initial (relative) SS value
+ public ushort e_sp; // Initial SP value
+ public ushort e_csum; // Checksum
+ public ushort e_ip; // Initial IP value
+ public ushort e_cs; // Initial (relative) CS value
+ public ushort e_lfarlc; // File address of relocation table
+ public ushort e_ovno; // Overlay number
+ public ushort[] e_res; // Reserved words
+ public ushort e_oemid; // OEM identifier
+ public ushort e_oeminfo; // OEM information
+ public ushort[] e_res2; // Reserved words
+ public uint e_lfanew; // File address of new exe header
+ }
+
+ ///
+ /// File Header structure
+ ///
+ public class FileHeader
+ {
+ public ushort Machine; // Target machine type
+ public ushort NumberOfSections; // Number of sections
+ public uint TimeDateStamp; // Time stamp
+ public uint PointerToSymbolTable; // File offset of symbol table
+ public uint NumberOfSymbols; // Number of symbols
+ public ushort SizeOfOptionalHeader; // Size of optional header
+ public ushort Characteristics; // Characteristics
+ }
+
+ ///
+ /// Optional Header structure
+ ///
+ public class OptionalHeader
+ {
+ // Standard fields
+ public ushort Magic; // Magic number (PE32 or PE32+)
+ public byte MajorLinkerVersion; // Major linker version
+ public byte MinorLinkerVersion; // Minor linker version
+ public uint SizeOfCode; // Size of code section
+ public uint SizeOfInitializedData; // Size of initialized data
+ public uint SizeOfUninitializedData; // Size of uninitialized data
+ public uint AddressOfEntryPoint; // Entry point RVA
+ public uint BaseOfCode; // Base of code section
+ public uint BaseOfData; // Base of data section (PE32 only)
+
+ // Windows-specific fields
+ public dynamic ImageBase; // Preferred image base (uint for PE32, ulong for PE32+)
+ public uint SectionAlignment; // Section alignment
+ public uint FileAlignment; // File alignment
+ public ushort MajorOperatingSystemVersion; // Major OS version
+ public ushort MinorOperatingSystemVersion; // Minor OS version
+ public ushort MajorImageVersion; // Major image version
+ public ushort MinorImageVersion; // Minor image version
+ public ushort MajorSubsystemVersion; // Major subsystem version
+ public ushort MinorSubsystemVersion; // Minor subsystem version
+ public uint Win32VersionValue; // Win32 version value
+ public uint SizeOfImage; // Size of image
+ public uint SizeOfHeaders; // Size of headers
+ public uint CheckSum; // Checksum
+ public ushort Subsystem; // Subsystem
+ public ushort DllCharacteristics; // DLL characteristics
+ public dynamic SizeOfStackReserve; // Size of stack reserve (uint for PE32, ulong for PE32+)
+ public dynamic SizeOfStackCommit; // Size of stack commit (uint for PE32, ulong for PE32+)
+ public dynamic SizeOfHeapReserve; // Size of heap reserve (uint for PE32, ulong for PE32+)
+ public dynamic SizeOfHeapCommit; // Size of heap commit (uint for PE32, ulong for PE32+)
+ public uint LoaderFlags; // Loader flags
+ public uint NumberOfRvaAndSizes; // Number of data directories
+
+ // Data directories
+ public DataDirectory[] DataDirectories; // Data directories
+ }
+
+ ///
+ /// Data Directory structure
+ ///
+ public class DataDirectory
+ {
+ public uint VirtualAddress; // RVA of the directory
+ public uint Size; // Size of the directory
+ }
+
+ ///
+ /// Section Header structure
+ ///
+ public class SectionHeader
+ {
+ public string Name; // Section name
+ public uint VirtualSize; // Virtual size
+ public uint VirtualAddress; // Virtual address (RVA)
+ public uint SizeOfRawData; // Size of raw data
+ public uint PointerToRawData; // File pointer to raw data
+ public uint PointerToRelocations; // File pointer to relocations
+ public uint PointerToLinenumbers; // File pointer to line numbers
+ public ushort NumberOfRelocations; // Number of relocations
+ public ushort NumberOfLinenumbers; // Number of line numbers
+ public uint Characteristics; // Characteristics
+ }
+
+ #endregion
+
+ #region Export and Import Structures
+
+ ///
+ /// Export Directory structure
+ ///
+ public class ExportDirectory
+ {
+ public uint Characteristics;
+ public uint TimeDateStamp;
+ public ushort MajorVersion;
+ public ushort MinorVersion;
+ public uint Name; // RVA to the DLL name
+ public string DllName; // Actual DLL name
+ public uint Base; // Ordinal base
+ public uint NumberOfFunctions; // Number of exported functions
+ public uint NumberOfNames; // Number of exported names
+ public uint AddressOfFunctions; // RVA to function addresses
+ public uint AddressOfNames; // RVA to function names
+ public uint AddressOfNameOrdinals; // RVA to ordinals
+ }
+
+ ///
+ /// Represents an exported function
+ ///
+ public class ExportedFunction
+ {
+ public string Name; // Function name
+ public uint Address; // Function RVA
+ public ushort Ordinal; // Function ordinal
+ public bool IsForwarder; // True if this is a forwarder
+ public string ForwarderName; // Name of the forwarded function (if IsForwarder is true)
+ }
+
+ ///
+ /// Import Descriptor structure
+ ///
+ public class ImportDescriptor
+ {
+ public uint OriginalFirstThunk; // RVA to Import Lookup Table
+ public uint TimeDateStamp;
+ public uint ForwarderChain;
+ public uint Name; // RVA to the DLL name
+ public string DllName; // Actual DLL name
+ public uint FirstThunk; // RVA to Import Address Table
+ public List Functions; // List of imported functions
+
+ public ImportDescriptor()
+ {
+ Functions = new List();
+ }
+ }
+
+ ///
+ /// Represents an imported function
+ ///
+ public class ImportedFunction
+ {
+ public bool IsOrdinal; // True if imported by ordinal
+ public ushort Ordinal; // Ordinal value (if IsOrdinal is true)
+ public string Name; // Function name (if IsOrdinal is false)
+ public ushort Hint; // Hint value (if IsOrdinal is false)
+ public uint ThunkRVA; // RVA in the Import Address Table
+ }
+
+ #endregion
+}
diff --git a/X86Disassembler/Program.cs b/X86Disassembler/Program.cs
new file mode 100644
index 0000000..752401a
--- /dev/null
+++ b/X86Disassembler/Program.cs
@@ -0,0 +1,153 @@
+using System;
+using System.IO;
+
+namespace X86Disassembler
+{
+ internal class Program
+ {
+ // Path to the DLL file to disassemble
+ private const string DllPath = @"C:\Windows\SysWOW64\msvcrt.dll"; // Example path, replace with your target DLL
+
+ static void Main(string[] args)
+ {
+ Console.WriteLine("X86 Disassembler and Decompiler");
+ Console.WriteLine("--------------------------------");
+
+ Console.WriteLine($"Loading file: {DllPath}");
+
+ // Load the DLL file
+ byte[] binaryData = File.ReadAllBytes(DllPath);
+
+ Console.WriteLine($"Successfully loaded {DllPath}");
+ Console.WriteLine($"File size: {binaryData.Length} bytes");
+
+ // Parse the PE format
+ Console.WriteLine("\nParsing PE format...");
+ PEFormat peFile = new PEFormat(binaryData);
+
+ // Display basic PE information
+ DisplayPEInfo(peFile);
+
+ // Display exported functions
+ DisplayExportedFunctions(peFile);
+
+ // Display imported functions
+ DisplayImportedFunctions(peFile);
+
+ // Find code sections for disassembly
+ var codeSections = peFile.GetCodeSections();
+ Console.WriteLine($"\nFound {codeSections.Count} code section(s):");
+
+ foreach (int sectionIndex in codeSections)
+ {
+ var section = peFile.SectionHeaders[sectionIndex];
+ Console.WriteLine($" - {section.Name}: Size={section.SizeOfRawData} bytes, RVA=0x{section.VirtualAddress:X8}");
+
+ // Get the section data for disassembly
+ byte[] sectionData = peFile.GetSectionData(sectionIndex);
+
+ // TODO: Implement disassembling logic here
+ // This is where we would pass the section data to our disassembler
+ }
+
+ Console.WriteLine("\nPress any key to exit...");
+ Console.ReadKey();
+ }
+
+ private static void DisplayPEInfo(PEFormat peFile)
+ {
+ Console.WriteLine("\nPE File Information:");
+ Console.WriteLine($"Architecture: {(peFile.Is64Bit ? "64-bit" : "32-bit")}");
+ Console.WriteLine($"Entry Point: 0x{peFile.OptionalHeader.AddressOfEntryPoint:X8}");
+ Console.WriteLine($"Image Base: 0x{peFile.OptionalHeader.ImageBase:X}");
+ Console.WriteLine($"Number of Sections: {peFile.FileHeader.NumberOfSections}");
+
+ // Display section information
+ Console.WriteLine("\nSections:");
+ for (int i = 0; i < peFile.SectionHeaders.Count; i++)
+ {
+ var section = peFile.SectionHeaders[i];
+ string flags = "";
+
+ if ((section.Characteristics & 0x00000020) != 0) flags += "Code "; // IMAGE_SCN_CNT_CODE
+ if ((section.Characteristics & 0x20000000) != 0) flags += "Exec "; // IMAGE_SCN_MEM_EXECUTE
+ if ((section.Characteristics & 0x40000000) != 0) flags += "Read "; // IMAGE_SCN_MEM_READ
+ if ((section.Characteristics & 0x80000000) != 0) flags += "Write"; // IMAGE_SCN_MEM_WRITE
+
+ Console.WriteLine($" {i}: {section.Name,-8} VA=0x{section.VirtualAddress:X8} Size={section.SizeOfRawData,-8} [{flags}]");
+ }
+ }
+
+ private static void DisplayExportedFunctions(PEFormat peFile)
+ {
+ if (peFile.ExportDirectory == null)
+ {
+ Console.WriteLine("\nNo exported functions found.");
+ return;
+ }
+
+ Console.WriteLine("\nExported Functions:");
+ Console.WriteLine($"DLL Name: {peFile.ExportDirectory.DllName}");
+ Console.WriteLine($"Number of Functions: {peFile.ExportDirectory.NumberOfFunctions}");
+ Console.WriteLine($"Number of Names: {peFile.ExportDirectory.NumberOfNames}");
+
+ // Display the first 10 exported functions (if any)
+ int count = Math.Min(10, peFile.ExportedFunctions.Count);
+ for (int i = 0; i < count; i++)
+ {
+ var function = peFile.ExportedFunctions[i];
+ Console.WriteLine($" {i}: {function.Name} (Ordinal={function.Ordinal}, RVA=0x{function.Address:X8})");
+ }
+
+ if (peFile.ExportedFunctions.Count > 10)
+ {
+ Console.WriteLine($" ... and {peFile.ExportedFunctions.Count - 10} more");
+ }
+ }
+
+ private static void DisplayImportedFunctions(PEFormat peFile)
+ {
+ if (peFile.ImportDescriptors.Count == 0)
+ {
+ Console.WriteLine("\nNo imported functions found.");
+ return;
+ }
+
+ Console.WriteLine("\nImported Functions:");
+ Console.WriteLine($"Number of Imported DLLs: {peFile.ImportDescriptors.Count}");
+
+ // Display the first 5 imported DLLs and their functions
+ int dllCount = Math.Min(5, peFile.ImportDescriptors.Count);
+ for (int i = 0; i < dllCount; i++)
+ {
+ var descriptor = peFile.ImportDescriptors[i];
+ Console.WriteLine($" DLL: {descriptor.DllName}");
+
+ // Display the first 5 functions from this DLL
+ int funcCount = Math.Min(5, descriptor.Functions.Count);
+ for (int j = 0; j < funcCount; j++)
+ {
+ var function = descriptor.Functions[j];
+ if (function.IsOrdinal)
+ {
+ Console.WriteLine($" {j}: Ordinal {function.Ordinal}");
+ }
+ else
+ {
+ Console.WriteLine($" {j}: {function.Name} (Hint={function.Hint})");
+ }
+ }
+
+ if (descriptor.Functions.Count > 5)
+ {
+ Console.WriteLine($" ... and {descriptor.Functions.Count - 5} more");
+ }
+ }
+
+ if (peFile.ImportDescriptors.Count > 5)
+ {
+ Console.WriteLine($" ... and {peFile.ImportDescriptors.Count - 5} more DLLs");
+ }
+ }
+ }
+}
diff --git a/X86Disassembler/X86Disassembler.csproj b/X86Disassembler/X86Disassembler.csproj
new file mode 100644
index 0000000..91b464a
--- /dev/null
+++ b/X86Disassembler/X86Disassembler.csproj
@@ -0,0 +1,10 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+