LenovoLegionToolkit
167 строк · 5.4 Кб
1using System;
2using System.Runtime.InteropServices;
3using System.Threading.Tasks;
4using LenovoLegionToolkit.Lib.Utils;
5using Windows.Win32;
6using Windows.Win32.Security;
7
8namespace LenovoLegionToolkit.Lib.Features;
9
10public abstract class AbstractUEFIFeature<T> : IFeature<T> where T : struct, Enum, IComparable
11{
12private readonly string _guid;
13private readonly string _scopeName;
14private readonly uint _scopeAttribute;
15
16protected AbstractUEFIFeature(string guid, string scopeName, uint scopeAttribute)
17{
18_guid = guid;
19_scopeName = scopeName;
20_scopeAttribute = scopeAttribute;
21}
22
23public async Task<bool> IsSupportedAsync()
24{
25try
26{
27_ = await GetStateAsync().ConfigureAwait(false);
28return true;
29}
30catch
31{
32return false;
33}
34}
35
36public Task<T[]> GetAllStatesAsync() => Task.FromResult(Enum.GetValues<T>());
37
38public abstract Task<T> GetStateAsync();
39
40public abstract Task SetStateAsync(T state);
41
42protected unsafe Task<TS> ReadFromUefiAsync<TS>() where TS : struct => Task.Run(() =>
43{
44if (Log.Instance.IsTraceEnabled)
45Log.Instance.Trace($"Reading from UEFI... [feature={GetType().Name}]");
46
47var ptr = Marshal.AllocHGlobal(Marshal.SizeOf<TS>());
48
49try
50{
51if (!SetPrivilege(true))
52{
53if (Log.Instance.IsTraceEnabled)
54Log.Instance.Trace($"Cannot set UEFI privileges [feature={GetType().Name}]");
55
56throw new InvalidOperationException("Cannot set privileges UEFI");
57}
58
59var ptrSize = (uint)Marshal.SizeOf<TS>();
60if (PInvoke.GetFirmwareEnvironmentVariableEx(_scopeName, _guid, ptr.ToPointer(), ptrSize, null) != 0)
61{
62var result = Marshal.PtrToStructure<TS>(ptr);
63
64if (Log.Instance.IsTraceEnabled)
65Log.Instance.Trace($"Read from UEFI successful [feature={GetType().Name}]");
66
67return result;
68}
69else
70{
71if (Log.Instance.IsTraceEnabled)
72Log.Instance.Trace($"Cannot read variable {_scopeName} from UEFI [feature={GetType().Name}]");
73
74throw new InvalidOperationException($"Cannot read variable {_scopeName} from UEFI");
75}
76}
77finally
78{
79Marshal.FreeHGlobal(ptr);
80SetPrivilege(false);
81}
82});
83
84protected unsafe Task WriteToUefiAsync<TS>(TS structure) where TS : struct => Task.Run(() =>
85{
86var ptr = Marshal.AllocHGlobal(Marshal.SizeOf<TS>());
87
88try
89{
90if (!SetPrivilege(true))
91{
92if (Log.Instance.IsTraceEnabled)
93Log.Instance.Trace($"Cannot set UEFI privileges [feature={GetType().Name}]");
94
95throw new InvalidOperationException("Cannot set UEFI privileges");
96}
97
98Marshal.StructureToPtr(structure, ptr, false);
99var ptrSize = (uint)Marshal.SizeOf<TS>();
100if (!PInvoke.SetFirmwareEnvironmentVariableEx(_scopeName, _guid, ptr.ToPointer(), ptrSize, _scopeAttribute))
101{
102if (Log.Instance.IsTraceEnabled)
103Log.Instance.Trace($"Cannot write variable {_scopeName} to UEFI [feature={GetType().Name}]");
104
105throw new InvalidOperationException($"Cannot write variable {_scopeName} to UEFI");
106}
107else
108{
109if (Log.Instance.IsTraceEnabled)
110Log.Instance.Trace($"WriteAsync to UEFI successful [feature={GetType().Name}]");
111}
112}
113finally
114{
115Marshal.FreeHGlobal(ptr);
116SetPrivilege(false);
117}
118});
119
120private unsafe bool SetPrivilege(bool enable)
121{
122try
123{
124using var handle = PInvoke.GetCurrentProcess_SafeHandle();
125
126if (!PInvoke.OpenProcessToken(handle, TOKEN_ACCESS_MASK.TOKEN_QUERY | TOKEN_ACCESS_MASK.TOKEN_ADJUST_PRIVILEGES, out var token))
127{
128if (Log.Instance.IsTraceEnabled)
129Log.Instance.Trace($"Could not open process token [feature={GetType().Name}]");
130
131return false;
132}
133
134if (!PInvoke.LookupPrivilegeValue(null, "SeSystemEnvironmentPrivilege", out var luid))
135{
136if (Log.Instance.IsTraceEnabled)
137Log.Instance.Trace($"Could not look up privilege value [feature={GetType().Name}]");
138
139return false;
140}
141
142var state = new TOKEN_PRIVILEGES { PrivilegeCount = 1 };
143state.Privileges._0 = new LUID_AND_ATTRIBUTES
144{
145Luid = luid,
146Attributes = enable ? TOKEN_PRIVILEGES_ATTRIBUTES.SE_PRIVILEGE_ENABLED : 0
147};
148
149if (!PInvoke.AdjustTokenPrivileges(token, false, state, 0, null, null))
150{
151if (Log.Instance.IsTraceEnabled)
152Log.Instance.Trace($"Could not adjust token privileges [feature={GetType().Name}]");
153
154return false;
155}
156
157return true;
158}
159catch (Exception ex)
160{
161if (Log.Instance.IsTraceEnabled)
162Log.Instance.Trace($"Exception while setting privilege. [feature={GetType().Name}]", ex);
163
164return false;
165}
166}
167}
168