1use crate::types::{HyperXState, Technique};
7use crate::{cpu, memo};
8
9pub fn is_unsupported(tech: Technique) -> bool {
14 use Technique::*;
15
16 #[cfg(windows)]
17 {
18 const LINUX_ONLY: &[Technique] = &[
20 SmbiosVmBit, Kmsg, Cvendor, QemuFwCfg, Systemd, Ctype, Dockerenv,
21 Dmidecode, Dmesg, Hwmon, LinuxUserHost, VmwareIomem, VmwareIoports,
22 VmwareScsi, VmwareDmesg, QemuVirtualDmi, QemuUsb, HypervisorDir,
23 UmlCpu, VboxModule, SysinfoProc, DmiScan, PodmanFile, WslProc,
24 FileAccessHistory, Mac, NsjailPid, BluestacksFolders, AmdSevMsr,
25 Temperature, Processes, ThreadCount,
26 MacMemsize, MacIokit, MacSip, IoregGrep, Hwmodel, MacSys,
27 ];
28 return LINUX_ONLY.contains(&tech);
29 }
30
31 #[cfg(all(target_os = "linux", not(windows)))]
32 {
33 const WIN_ONLY: &[Technique] = &[
35 GpuCapabilities, AcpiSignature, PowerCapabilities, DiskSerial,
36 Ivshmem, Drivers, Handles, VirtualProcessors, HypervisorQuery,
37 Audio, Display, Dll, VmwareBackdoor, Wine, VirtualRegistry,
38 Mutex, DeviceString, VpcInvalid, VmwareStr, Gamarue, CuckooDir,
39 CuckooPipe, BootLogo, Trap, Ud, Blockstep, DbvmHypercall,
40 KernelObjects, Nvram, Edid, CpuHeuristic, Clock, Msr,
41 KvmInterception, Breakpoint,
42 MacMemsize, MacIokit, MacSip, IoregGrep, Hwmodel, MacSys,
43 ];
44 return WIN_ONLY.contains(&tech);
45 }
46
47 #[cfg(target_os = "macos")]
48 {
49 const MACOS_EXCL: &[Technique] = &[
50 GpuCapabilities, AcpiSignature, PowerCapabilities, DiskSerial,
51 Ivshmem, Drivers, Handles, VirtualProcessors, HypervisorQuery,
52 Audio, Display, Dll, VmwareBackdoor, Wine, VirtualRegistry,
53 Mutex, DeviceString, VpcInvalid, VmwareStr, Gamarue, CuckooDir,
54 CuckooPipe, BootLogo, Trap, Ud, Blockstep, DbvmHypercall,
55 KernelObjects, Nvram, Edid, CpuHeuristic, Clock, Msr,
56 KvmInterception, Breakpoint,
57 SmbiosVmBit, Kmsg, Cvendor, QemuFwCfg, Systemd, Ctype, Dockerenv,
58 Dmidecode, Dmesg, Hwmon, LinuxUserHost, VmwareIomem, VmwareIoports,
59 VmwareScsi, VmwareDmesg, QemuVirtualDmi, QemuUsb, HypervisorDir,
60 UmlCpu, VboxModule, SysinfoProc, DmiScan, PodmanFile, WslProc,
61 FileAccessHistory, Mac, NsjailPid, BluestacksFolders, AmdSevMsr,
62 Temperature, Processes,
63 ];
64 return MACOS_EXCL.contains(&tech);
65 }
66
67 #[allow(unreachable_code)]
69 {
70 let cross = [
71 Technique::HypervisorBit, Technique::Vmid, Technique::ThreadMismatch,
72 Technique::Timer, Technique::CpuBrand, Technique::HypervisorStr,
73 Technique::CpuidSignature, Technique::BochsCpu, Technique::KgtSignature,
74 ];
75 !cross.contains(&tech)
76 }
77}
78
79pub fn exists(path: &str) -> bool {
83 std::path::Path::new(path).exists()
84}
85
86pub fn read_file(path: &str) -> Option<String> {
88 std::fs::read_to_string(path).ok()
89}
90
91pub fn file_contains(path: &str, needle: &str) -> bool {
93 read_file(path).map(|c| c.contains(needle)).unwrap_or(false)
94}
95
96pub fn is_admin() -> bool {
100 #[cfg(windows)]
101 {
102 use windows_sys::Win32::Security::{
103 GetTokenInformation, TOKEN_ELEVATION, TOKEN_QUERY, TokenElevation,
104 };
105 use windows_sys::Win32::System::Threading::{GetCurrentProcess, OpenProcessToken};
106 use windows_sys::Win32::Foundation::{CloseHandle, HANDLE};
107
108 unsafe {
109 let mut token: HANDLE = 0;
110 if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token) == 0 {
111 return false;
112 }
113 let mut elevation = TOKEN_ELEVATION { TokenIsElevated: 0 };
114 let mut ret_len: u32 = 0;
115 let ok = GetTokenInformation(
116 token,
117 TokenElevation,
118 &mut elevation as *mut _ as *mut _,
119 std::mem::size_of::<TOKEN_ELEVATION>() as u32,
120 &mut ret_len,
121 );
122 CloseHandle(token);
123 ok != 0 && elevation.TokenIsElevated != 0
124 }
125 }
126
127 #[cfg(not(windows))]
128 {
129 libc_uid() == 0
131 }
132}
133
134#[cfg(not(windows))]
135fn libc_uid() -> u32 {
136 #[cfg(unix)]
138 {
139 extern "C" {
141 fn getuid() -> u32;
142 }
143 unsafe { getuid() }
144 }
145 #[cfg(not(unix))]
146 {
147 1 }
149}
150
151pub fn get_logical_cpu_count() -> u32 {
155 #[cfg(windows)]
156 {
157 use windows_sys::Win32::System::SystemInformation::GetSystemInfo;
158 use windows_sys::Win32::System::SystemInformation::SYSTEM_INFO;
159 unsafe {
160 let mut si = std::mem::zeroed::<SYSTEM_INFO>();
161 GetSystemInfo(&mut si);
162 si.dwNumberOfProcessors
163 }
164 }
165
166 #[cfg(not(windows))]
167 {
168 std::thread::available_parallelism()
170 .map(|n| n.get() as u32)
171 .unwrap_or(1)
172 }
173}
174
175pub fn hyper_x() -> HyperXState {
180 if let Some(s) = memo::get_hyperx_state() {
182 return s;
183 }
184
185 let state = hyper_x_inner();
186 memo::set_hyperx_state(state);
187 state
188}
189
190fn hyper_x_inner() -> HyperXState {
191 #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
192 return HyperXState::Unknown;
193
194 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
195 {
196 use crate::cpu::{cpuid, is_leaf_supported};
197
198 let ecx1 = cpuid(1, 0).ecx;
200 let hypervisor_bit = (ecx1 >> 31) & 1 != 0;
201
202 if !hypervisor_bit {
203 return HyperXState::Unknown;
204 }
205
206 if is_leaf_supported(0x4000_0003) {
209 let ebx = cpuid(0x4000_0003, 0).ebx;
210 if ebx & 1 != 0 {
211 return HyperXState::Enlightenment;
212 }
213 }
214
215 let max_leaf = cpuid(0x4000_0000, 0).eax;
217
218 if max_leaf >= 0x4000_0005 {
219 HyperXState::RealVM
221 } else {
222 HyperXState::ArtifactVM
223 }
224 }
225}
226
227pub fn get_manufacturer_model() -> (String, String) {
232 if let Some(info) = memo::get_bios_info() {
234 return (info.manufacturer, info.model);
235 }
236
237 let result = get_manufacturer_model_inner();
238 memo::set_bios_info(memo::BiosInfo {
239 manufacturer: result.0.clone(),
240 model: result.1.clone(),
241 });
242 result
243}
244
245#[cfg(windows)]
246fn get_manufacturer_model_inner() -> (String, String) {
247 use winreg::enums::*;
248 use winreg::RegKey;
249
250 let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
251 if let Ok(key) = hklm.open_subkey("HARDWARE\\DESCRIPTION\\System\\BIOS") {
252 let mfr: String = key.get_value("SystemManufacturer").unwrap_or_default();
253 let mdl: String = key.get_value("SystemProductName").unwrap_or_default();
254 return (mfr, mdl);
255 }
256 (String::new(), String::new())
257}
258
259#[cfg(not(windows))]
260fn get_manufacturer_model_inner() -> (String, String) {
261 let mfr = read_file("/sys/class/dmi/id/sys_vendor")
262 .unwrap_or_default()
263 .trim()
264 .to_string();
265 let mdl = read_file("/sys/class/dmi/id/product_name")
266 .unwrap_or_default()
267 .trim()
268 .to_string();
269 (mfr, mdl)
270}
271
272pub fn str_contains_ci(haystack: &str, needle: &str) -> bool {
276 haystack.to_lowercase().contains(&needle.to_lowercase())
277}
278
279pub fn crc32c(data: &[u8]) -> u32 {
281 const POLY: u32 = 0x82F6_3B78;
282 let mut crc: u32 = 0xFFFF_FFFF;
283 for &byte in data {
284 crc ^= byte as u32;
285 for _ in 0..8 {
286 if crc & 1 != 0 {
287 crc = (crc >> 1) ^ POLY;
288 } else {
289 crc >>= 1;
290 }
291 }
292 }
293 !crc
294}
295
296#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
301pub fn is_smt_enabled() -> bool {
302 use cpu::{cpuid, is_leaf_supported};
303 if !is_leaf_supported(0x0B) {
304 return false;
305 }
306 let r = cpuid(0x0B, 0);
308 let level_type = (r.ecx >> 8) & 0xFF;
309 let threads_at_level = r.ebx & 0xFFFF;
310 level_type == 1 && threads_at_level > 1
312}
313
314#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
315pub fn is_smt_enabled() -> bool {
316 false
317}