private static PebData ReadPebData(System.Diagnostics.Process process)
        {
            if (process.GetArchitecture() == Architecture.X86)
            {
                // Query the remote process for the address of its WOW64 PEB

                var wow64PebAddressBytes = new byte[IntPtr.Size];

                var ntStatus = Ntdll.NtQueryInformationProcess(process.SafeHandle, ProcessInformationClass.Wow64Information, ref wow64PebAddressBytes[0], wow64PebAddressBytes.Length, out _);

                if (ntStatus != NtStatus.Success)
                {
                    throw ExceptionBuilder.BuildWin32Exception("NtQueryInformationProcess", ntStatus);
                }

                var wow64PebAddress = MemoryMarshal.Read <IntPtr>(wow64PebAddressBytes);

                // Read the WOW64 PEB data

                var wow64Peb = process.ReadStructure <Peb32>(wow64PebAddress);

                return(new PebData(new IntPtr(wow64Peb.ApiSetMap), new IntPtr(wow64Peb.Ldr)));
            }

            else
            {
                // Query the remote process for its BasicInformation

                var processBasicInformationBytes = new byte[Unsafe.SizeOf <ProcessBasicInformation64>()];

                var ntStatus = Ntdll.NtQueryInformationProcess(process.SafeHandle, ProcessInformationClass.BasicInformation, ref processBasicInformationBytes[0], processBasicInformationBytes.Length, out _);

                if (ntStatus != NtStatus.Success)
                {
                    throw ExceptionBuilder.BuildWin32Exception("NtQueryInformationProcess", ntStatus);
                }

                var processBasicInformation = MemoryMarshal.Read <ProcessBasicInformation64>(processBasicInformationBytes);

                // Read the PEB data

                var peb = process.ReadStructure <Peb64>(new IntPtr(processBasicInformation.PebBaseAddress));

                return(new PebData(new IntPtr(peb.ApiSetMap), new IntPtr(peb.Ldr)));
            }
        }
        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;
                }
            }
        }