public unsafe static EfiLoadOption MarshalFromNative(IntPtr data) { var result = new EfiLoadOption(); result.Attributes = *(uint *)data; result.FilePathListLength = *(ushort *)(data + 4); result.Description = Marshal.PtrToStringUni(data + 6); return(result); }
static void Main(string[] args) { // Parse options new Mono.Options.OptionSet { { "y|sysprep", "Operate on SysPrep variables, not Boot Variables.", n => VariableType = UefiLoadOptionType.SysPrep }, { "r|driver", "Operate on Driver variables, not Boot Variables.", n => VariableType = UefiLoadOptionType.Driver }, { "v|verbose", "print additional information", n => ErrorHandling.Verbosity++ }, }.Parse(args); if (!IsElevated) { Console.WriteLine("Administrative privileges are needed."); return; } Privileges.EnablePrivilege(Privileges.SecurityEntity.SE_SYSTEM_ENVIRONMENT_NAME); if (VariableType == UefiLoadOptionType.Boot) { ErrorHandling.HandleWarning(() => Console.WriteLine($"BootNext: {read_u16("BootNext")}"), "Could not read variable 'BootNext'", verbosity: 2); ErrorHandling.HandleWarning(() => Console.WriteLine($"BootCurrent: {read_u16("BootCurrent"):X4}"), "Could not read variable 'BootCurrent'", verbosity: 2); ErrorHandling.HandleWarning(() => Console.WriteLine($"Timeout : {read_u16("Timeout")}"), "Could not read variable 'Timeout'", verbosity: 2); } /* * ErrorHandling.HandleWarning(() => Console.WriteLine($"{Enum.GetName(typeof(UefiLoadOptionType), VariableType)}Order: {string.Join(",", read_order(VariableType).Select(y => $"{y:X4}"))}"), * VariableType == UefiLoadOptionType.Boot ? "No BootOrder is set; firmware will attempt recovery" : $"No { Enum.GetName(typeof(UefiLoadOptionType), VariableType)}Order is set", * verbosity: 2); */ // Windows does not provide any documented function to iterate over all available firmware variables // An undocumented function NtEnumerateBootEntries ntdll.dll returns all boot options in Windows specific struct // It internally calls HalEnumerateEnvironmentVariablesEx from hal.dll, which actually returns all variables, // filters them to only show Boot#### variables, and do additional parsing for convenience and Windows specific options. var BootEntryNames = read_all_boot_entry_names(); foreach (var variableName in BootEntryNames) { var buffer = IntPtr.Zero; uint size = 0; try { (buffer, size) = read_dyn(variableName); var loadOption = EfiLoadOption.MarshalFromNative(buffer); Console.WriteLine(variableName + ((loadOption.Attributes & EfiLoadOption.LOAD_OPTION_ACTIVE) != 0 ? "* " : " ") + loadOption.Description); } catch (Win32Exception win32exeption) { if (win32exeption.NativeErrorCode == 203) //not exist, skip { continue; } } finally { Marshal.FreeHGlobal(buffer); } } //show_mirror?? #if DEBUG Console.ReadLine(); #endif }