internal static TStructure ReadStructure <TStructure>(this System.Diagnostics.Process process, IntPtr baseAddress) where TStructure : unmanaged
        {
            var block = process.ReadMemory(baseAddress, Unsafe.SizeOf <TStructure>());

            return(MemoryMarshal.Read <TStructure>(block.Span));
        }
        internal IEnumerable <Module> ReadModuleEntries()
        {
            if (_process.GetArchitecture() == Architecture.X86)
            {
                var wow64FilePathRegex = new Regex("System32", RegexOptions.IgnoreCase);

                // Read the loader data of the WOW64 PEB

                var loaderData = _process.ReadStructure <PebLdrData32>(_pebData.Loader);

                // Read the entries of the InMemoryOrder linked list

                var currentEntryAddress = loaderData.InMemoryOrderModuleList.Flink;

                var inMemoryOrderLinksOffset = Marshal.OffsetOf <LdrDataTableEntry32>("InMemoryOrderLinks");

                while (true)
                {
                    var entry = _process.ReadStructure <LdrDataTableEntry32>(new IntPtr(currentEntryAddress - inMemoryOrderLinksOffset.ToInt32()));

                    // Read the file path of the entry

                    var entryFilePathBytes = _process.ReadMemory(new IntPtr(entry.FullDllName.Buffer), entry.FullDllName.Length);

                    var entryFilePath = Encoding.Unicode.GetString(entryFilePathBytes.Span.ToArray());

                    if (Environment.Is64BitOperatingSystem)
                    {
                        entryFilePath = wow64FilePathRegex.Replace(entryFilePath, "SysWOW64");
                    }

                    // Read the name of the entry

                    var entryNameBytes = _process.ReadMemory(new IntPtr(entry.BaseDllName.Buffer), entry.BaseDllName.Length);

                    var entryName = Encoding.Unicode.GetString(entryNameBytes.Span.ToArray());

                    yield return(new Module(new IntPtr(entry.DllBase), entryName, entryFilePath));

                    if (currentEntryAddress == loaderData.InMemoryOrderModuleList.Blink)
                    {
                        break;
                    }

                    // Determine the address of the next entry

                    currentEntryAddress = entry.InMemoryOrderLinks.Flink;
                }
            }

            else
            {
                // Read the loader data of the PEB

                var loaderData = _process.ReadStructure <PebLdrData64>(_pebData.Loader);

                // Read the entries of the InMemoryOrder linked list

                var currentEntryAddress = loaderData.InMemoryOrderModuleList.Flink;

                var inMemoryOrderLinksOffset = Marshal.OffsetOf <LdrDataTableEntry64>("InMemoryOrderLinks");

                while (true)
                {
                    var entry = _process.ReadStructure <LdrDataTableEntry64>(new IntPtr(currentEntryAddress - inMemoryOrderLinksOffset.ToInt32()));

                    // Read the file path of the entry

                    var entryFilePathBytes = _process.ReadMemory(new IntPtr(entry.FullDllName.Buffer), entry.FullDllName.Length);

                    var entryFilePath = Encoding.Unicode.GetString(entryFilePathBytes.Span.ToArray());

                    // Read the name of the entry

                    var entryNameBytes = _process.ReadMemory(new IntPtr(entry.BaseDllName.Buffer), entry.BaseDllName.Length);

                    var entryName = Encoding.Unicode.GetString(entryNameBytes.Span.ToArray());

                    yield return(new Module(new IntPtr(entry.DllBase), entryName, entryFilePath));

                    if (currentEntryAddress == loaderData.InMemoryOrderModuleList.Blink)
                    {
                        break;
                    }

                    // Determine the address of the next entry

                    currentEntryAddress = entry.InMemoryOrderLinks.Flink;
                }
            }
        }