spoof: spoof-mode master fork (none/hyperv/vbs/physical) + microsoft-vm persona

Phase 0. Replace the spoof-hv knob with spoof-mode, a first-class selector modeled as
two axes (persona x presence) exposed as 4 presets:
- none: stock (spoof_on now requires mode != none, killing half-spoof states)
- hyperv: Microsoft Virtual Machine persona + Hyper-V presence (honest child VM)
- vbs (seeded default): real-OEM persona + Hyper-V presence (mimic physical Win11+VBS)
- physical: real-OEM persona + bare metal

Engine: spoof_mode()/spoof_persona_msvm()/spoof_presence_hyperv() in spoof-core; the
hv/waet/pvpanic/vmgenid policies now derive from the mode. microsoft-vm persona wired
across platform (ACPI OEM VRTUAL/MICROSFT, Microsoft Corporation), system type1
(Virtual Machine), storage (Virtual HD / Msft Virtual DVD-ROM) and EDID (MSF/Hyper-V).
New getters spoof_system_manufacturer/product (type1, real-OEM or Hyper-V). Patches:
0002 registers spoof-mode; 0024 now also forces type1 system identity. spoof-hv kept
as a back-compat alias. Inert without a seed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-11 23:15:15 +03:00
parent 3268fe11e1
commit ec27a8f4e5
10 changed files with 131 additions and 46 deletions
+16 -10
View File
@@ -1,14 +1,15 @@
qemu-spoof: register per-VM anti-detect machine properties
Adds string machine properties spoof-seed / spoof-hv / spoof-waet /
spoof-vmgenid / spoof-pvpanic on the x86 machine, backed by X86MachineState
fields. The qemu-spoof module (hw/misc/spoof*) reads them via
object_property_get_str(current_machine, "spoof-*"). Inert unless set.
Adds string machine properties spoof-seed / spoof-mode / spoof-hv / spoof-waet /
spoof-vmgenid / spoof-pvpanic on the x86 machine, backed by X86MachineState fields.
The qemu-spoof module (hw/misc/spoof*) reads them via
object_property_get_str(current_machine, "spoof-*"). spoof-mode (none|hyperv|vbs|
physical) is the master fork; spoof-hv is the legacy knob. Inert unless set.
diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index 01872cb..66400fe 100644
index 01872cb..702b327 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -372,6 +372,26 @@ static void x86_machine_initfn(Object *obj)
@@ -372,6 +372,27 @@ static void x86_machine_initfn(Object *obj)
x86ms->above_4g_mem_start = 4 * GiB;
}
@@ -27,6 +28,7 @@ index 01872cb..66400fe 100644
+ x86ms->field = g_strdup(value); \
+ }
+X86_SPOOF_PROP(spoof_seed)
+X86_SPOOF_PROP(spoof_mode)
+X86_SPOOF_PROP(spoof_hv)
+X86_SPOOF_PROP(spoof_waet)
+X86_SPOOF_PROP(spoof_vmgenid)
@@ -35,7 +37,7 @@ index 01872cb..66400fe 100644
static void x86_machine_class_init(ObjectClass *oc, const void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -426,6 +446,27 @@ static void x86_machine_class_init(ObjectClass *oc, const void *data)
@@ -426,6 +447,31 @@ static void x86_machine_class_init(ObjectClass *oc, const void *data)
"in ACPI table header."
"The string may be up to 8 bytes in size");
@@ -43,10 +45,14 @@ index 01872cb..66400fe 100644
+ x86_machine_get_spoof_seed, x86_machine_set_spoof_seed);
+ object_class_property_set_description(oc, "spoof-seed",
+ "qemu-spoof: per-VM persona seed (empty = stock QEMU)");
+ object_class_property_add_str(oc, "spoof-mode",
+ x86_machine_get_spoof_mode, x86_machine_set_spoof_mode);
+ object_class_property_set_description(oc, "spoof-mode",
+ "qemu-spoof: identity mode (none|hyperv|vbs|physical)");
+ object_class_property_add_str(oc, "spoof-hv",
+ x86_machine_get_spoof_hv, x86_machine_set_spoof_hv);
+ object_class_property_set_description(oc, "spoof-hv",
+ "qemu-spoof: hypervisor mode (off|hyperv|hidden)");
+ "qemu-spoof: legacy hv knob (off|hyperv|hidden); prefer spoof-mode");
+ object_class_property_add_str(oc, "spoof-waet",
+ x86_machine_get_spoof_waet, x86_machine_set_spoof_waet);
+ object_class_property_set_description(oc, "spoof-waet",
@@ -64,7 +70,7 @@ index 01872cb..66400fe 100644
x86_machine_get_bus_lock_ratelimit,
x86_machine_set_bus_lock_ratelimit, NULL, NULL);
diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h
index 71fe6b5..a80700f 100644
index 71fe6b5..c1f5f7e 100644
--- a/include/hw/i386/x86.h
+++ b/include/hw/i386/x86.h
@@ -79,6 +79,9 @@ struct X86MachineState {
@@ -73,7 +79,7 @@ index 71fe6b5..a80700f 100644
char *oem_table_id;
+
+ /* qemu-spoof: per-VM anti-detect config, read by hw/misc/spoof*.c */
+ char *spoof_seed, *spoof_hv, *spoof_waet, *spoof_vmgenid, *spoof_pvpanic;
+ char *spoof_seed, *spoof_mode, *spoof_hv, *spoof_waet, *spoof_vmgenid, *spoof_pvpanic;
/*
* Address space used by IOAPIC device. All IOAPIC interrupts
* will be translated to MSI messages in the address space.
+15 -11
View File
@@ -1,25 +1,29 @@
qemu-spoof: SMBIOS type0 BIOS vendor / version / date
qemu-spoof: SMBIOS type0 BIOS + type1 system identity
Stock QEMU leaves type0 vendor/version/date unset, so the guest reads an empty or
firmware-default ("SeaBIOS") BIOS identity via WMI Win32_BIOS / dmidecode -- a tell.
Force a real, platform-anchored OEM BIOS identity (vendor coheres with the board;
version uses the vendor's real format) through smbios_set_defaults, so an explicit
-smbios type=0 still wins and an un-seeded VM stays stock. (spoof.h include added by
Stock QEMU leaves type0 vendor/version/date unset (guest reads an empty/firmware-
default "SeaBIOS" BIOS via WMI/dmidecode) and type1 system manufacturer/product fall
back to the bare machine values. Force the persona identity through smbios_set_defaults:
- real-OEM persona: vendor-formatted BIOS + board-brand system manufacturer/product;
- hyperv persona: Microsoft "Virtual Machine".
Config (-smbios) still wins; an un-seeded VM stays stock. (spoof.h include added by
0015-smbios-vm-bit.)
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index 7d71418..13ffa93 100644
index 7d71418..8321f10 100644
--- a/hw/smbios/smbios.c
+++ b/hw/smbios/smbios.c
@@ -1027,6 +1027,12 @@ void smbios_set_defaults(const char *manufacturer, const char *product,
@@ -1027,6 +1027,15 @@ void smbios_set_defaults(const char *manufacturer, const char *product,
{
smbios_have_defaults = true;
+ /* qemu-spoof: a real OEM BIOS identity (type0). Stock leaves vendor/version/date
+ * unset, so the guest reads an empty / firmware-default ("SeaBIOS") BIOS — a tell.
+ * Platform-anchored so the BIOS vendor coheres with the board. Inert without a seed. */
+ /* qemu-spoof: a real OEM (or Hyper-V) BIOS + system identity. Stock leaves type0
+ * vendor/version/date unset (guest reads empty/"SeaBIOS") and type1 falls back to
+ * the bare machine manufacturer/product; force the persona's values. Platform-
+ * anchored; config (-smbios) still wins; inert without a seed. */
+ SMBIOS_SET_DEFAULT(smbios_type0.vendor, spoof_bios_vendor(NULL));
+ SMBIOS_SET_DEFAULT(smbios_type0.version, spoof_bios_version(NULL));
+ SMBIOS_SET_DEFAULT(smbios_type0.date, spoof_bios_date(NULL));
+ SMBIOS_SET_DEFAULT(smbios_type1.manufacturer, spoof_system_manufacturer(NULL));
+ SMBIOS_SET_DEFAULT(smbios_type1.product, spoof_system_product(NULL));
SMBIOS_SET_DEFAULT(smbios_type1.manufacturer, manufacturer);
SMBIOS_SET_DEFAULT(smbios_type1.product, product);
SMBIOS_SET_DEFAULT(smbios_type1.version, version);
+2 -2
View File
@@ -11,7 +11,7 @@ match exactly. Naming: `0002` = infra, `0010+` = one aspect each.
| patch | covers |
|---|---|
| 0002-x86-machine-spoof-properties | register `spoof-seed` / `spoof-hv` / `spoof-waet` / `spoof-vmgenid` / `spoof-pvpanic` machine props |
| 0002-x86-machine-spoof-properties | register `spoof-seed` / `spoof-mode` / `spoof-hv` / `spoof-waet` / `spoof-vmgenid` / `spoof-pvpanic` machine props |
| 0010-acpi-table-header | ACPI OEM id / table id / creator + FADT hypervisor-vendor |
| 0011-acpi-policy-waet-vmgenid | drop the WAET table; skip the vmgenid SSDT when policy = hide |
| 0012-acpi-device-hids | vmgenid `_HID` (mask), pvpanic `_HID` (hide), fw_cfg `_HID` |
@@ -25,7 +25,7 @@ match exactly. Naming: `0002` = infra, `0010+` = one aspect each.
| 0021-smbios-identity | SMBIOS type3 chassis / type4 socket + cpu-mfr / type11 OEM / type17 memory |
| 0022-storage-extra | IDE WWN + rotation rate; NVMe EUI-64 + NGUID |
| 0023-cpu-microcode | CPU microcode revision (IA32_UCODE_REV), vendor-positioned |
| 0024-smbios-bios-type0 | SMBIOS type0 BIOS vendor / version / date (platform-anchored OEM firmware) |
| 0024-smbios-bios-type0 | SMBIOS type0 BIOS vendor/version/date + type1 system manufacturer/product (real-OEM or Hyper-V persona) |
## The PCI-id problem (why 0018 is careful)