Skip to content

Commit 9510abd

Browse files
authored
Implement advanced ACPI scan for generic sandbox & QEMU (#288)
Signed-off-by: dmfrpro <[email protected]>
1 parent 623b752 commit 9510abd

File tree

5 files changed

+95
-20
lines changed

5 files changed

+95
-20
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ Please, if you encounter any of the anti-analysis tricks which you have seen in
214214
- SMBIOS string checks (VMWare)
215215
- SMBIOS string checks (Qemu)
216216
- SMBIOS number of tables (Qemu, VirtualBox)
217-
- ACPI string checks (WAET table)
217+
- ACPI string checks (WAET table, PNP devices, PM state with battery checks)
218218
- ACPI string checks (VirtualBox)
219219
- ACPI string checks (VMWare)
220220
- ACPI string checks (Qemu)

al-khaser/Al-khaser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ int main(int argc, char* argv[])
216216
exec_check(&registry_services_disk_enum, TEXT("Checking Services\\Disk\\Enum entries for VM strings "));
217217
exec_check(&registry_disk_enum, TEXT("Checking Enum\\IDE and Enum\\SCSI entries for VM strings "));
218218
exec_check(&number_SMBIOS_tables, TEXT("Checking SMBIOS tables "));
219-
exec_check(&firmware_ACPI_WAET, TEXT("Checking if ACPI WAET table is present "));
219+
exec_check(&firmware_ACPI, TEXT("Checking ACPI table strings "));
220220
}
221221

222222
/* VirtualBox Detection */

al-khaser/AntiVM/Generic.cpp

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2046,13 +2046,12 @@ BOOL number_SMBIOS_tables()
20462046
}
20472047

20482048
/*
2049-
Check for Windows ACPI Emulated devices Table (WAET)
2050-
https://download.microsoft.com/download/7/E/7/7E7662CF-CBEA-470B-A97E-CE7CE0D98DC2/WAET.docx
2049+
Check for generic
20512050
*/
2052-
BOOL firmware_ACPI_WAET()
2051+
BOOL firmware_ACPI()
20532052
{
20542053
BOOL result = FALSE;
2055-
2054+
BOOL foundWSMT = FALSE;
20562055
PDWORD tableNames = static_cast<PDWORD>(malloc(4096));
20572056

20582057
if (tableNames) {
@@ -2070,29 +2069,79 @@ BOOL firmware_ACPI_WAET()
20702069
}
20712070
else
20722071
{
2072+
// Windows ACPI Emulated devices Table (WAET)
2073+
// https://download.microsoft.com/download/7/E/7/7E7662CF-CBEA-470B-A97E-CE7CE0D98DC2/WAET.docx
2074+
PBYTE waetString = (PBYTE)"WAET";
2075+
size_t waetStringLen = 4;
2076+
2077+
PBYTE batteryDevice = (PBYTE)"PNP0C0A"; // Control Method Battery
2078+
size_t batteryDeviceLen = 7;
2079+
BOOL needsBatteryCheck = false;
2080+
2081+
const char *requiredDevices[] = {
2082+
"PNP0000", // 8259-compatible Programmable Interrupt Controller
2083+
"PNP0C0C", // Power Button Device
2084+
"PNP0C0E", // Sleep Button Device
2085+
"PNP0C14", // Windows Management Instrumentation Device
2086+
"PNP0D80", // Windows-compatible System Power Management Controller
2087+
};
2088+
2089+
restart:
20732090
for (DWORD i = 0; i < tableCount; i++)
20742091
{
20752092
DWORD tableSize = 0;
20762093
PBYTE table = get_system_firmware(static_cast<DWORD>('ACPI'), tableNames[i], &tableSize);
20772094

20782095
if (table) {
20792096

2080-
PBYTE waetString = (PBYTE)"WAET";
2081-
size_t StringLen = 4;
2097+
if (tableNames[i] == static_cast<DWORD>('TMSW'))
2098+
{
2099+
foundWSMT = TRUE;
2100+
}
2101+
2102+
// Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue (in hex)
2103+
// [02Dh 0045 001h ] PM Profile : 0 [Unspecified] or 1 [Desktop] or 2 [Mobile]
2104+
if (!needsBatteryCheck && tableNames[i] == static_cast<DWORD>('PCAF') && tableSize > 45) {
2105+
if ((BYTE)table[45] == (BYTE)0 /* Mobile == 2 */)
2106+
{
2107+
needsBatteryCheck = true;
2108+
free(table);
2109+
goto restart;
2110+
}
2111+
}
2112+
2113+
if (find_str_in_data(waetString, waetStringLen, table, tableSize))
2114+
{
2115+
free(table);
2116+
result = TRUE;
2117+
goto out;
2118+
}
20822119

2083-
if (find_str_in_data(waetString, StringLen, table, tableSize))
2120+
if (needsBatteryCheck && !find_str_in_data(waetString, waetStringLen, table, tableSize))
20842121
{
2122+
free(table);
20852123
result = TRUE;
2124+
goto out;
2125+
}
2126+
2127+
for (DWORD j = 0; j < sizeof(requiredDevices) / sizeof(char*); j++)
2128+
{
2129+
if (!find_str_in_data((PBYTE)requiredDevices[j], strlen(requiredDevices[j]), table, tableSize))
2130+
{
2131+
free(table);
2132+
result = TRUE;
2133+
goto out;
2134+
}
20862135
}
20872136

20882137
free(table);
20892138
}
20902139
}
20912140
}
2092-
2141+
out:
20932142
free(tableNames);
20942143
}
2095-
return result;
2144+
return result || !foundWSMT;
20962145
}
20972146

20982147
/*

al-khaser/AntiVM/Generic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,6 @@ BOOL pirated_windows();
5050
BOOL registry_services_disk_enum();
5151
BOOL registry_disk_enum();
5252
BOOL number_SMBIOS_tables();
53-
BOOL firmware_ACPI_WAET();
53+
BOOL firmware_ACPI();
5454
BOOL hosting_check();
5555
VOID looking_glass_vdd_processes();

al-khaser/AntiVM/Qemu.cpp

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -163,28 +163,54 @@ BOOL qemu_firmware_ACPI()
163163
}
164164
else
165165
{
166+
const char* strings[] = {
167+
"FWCF", // fw_cfg name
168+
"QEMU0002", // fw_cfg HID/CID
169+
"BOCHS", // OEM ID
170+
"BXPC" // OEM Table ID
171+
};
172+
166173
for (DWORD i = 0; i < tableCount; i++)
167174
{
168175
DWORD tableSize = 0;
169176
PBYTE table = get_system_firmware(static_cast<DWORD>('ACPI'), tableNames[i], &tableSize);
170177

171178
if (table) {
172179

173-
PBYTE qemuString1 = (PBYTE)"BOCHS";
174-
size_t StringLen = 4;
175-
PBYTE qemuString2 = (PBYTE)"BXPC";
176-
177-
if (find_str_in_data(qemuString1, StringLen, table, tableSize) ||
178-
find_str_in_data(qemuString2, StringLen, table, tableSize))
180+
for (DWORD j = 0; j < sizeof(strings) / sizeof(char*); j++)
179181
{
180-
result = TRUE;
182+
if (!find_str_in_data((PBYTE)strings[j], strlen(strings[j]), table, tableSize))
183+
{
184+
free(table);
185+
result = TRUE;
186+
goto out;
187+
}
181188
}
182189

183190
free(table);
184191
}
185192
}
186-
}
187193

194+
DWORD tableSize = 0;
195+
PBYTE table = get_system_firmware(static_cast<DWORD>('ACPI'), static_cast<DWORD>('PCAF'), &tableSize);
196+
197+
if (table) {
198+
if (tableSize < 45)
199+
{
200+
return FALSE; // Corrupted table
201+
}
202+
203+
// Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue (in hex)
204+
// [02Dh 0045 001h ] PM Profile : 00 [Unspecified] - hardcoded in QEMU src
205+
if ((BYTE) table[45] == (BYTE)0)
206+
{
207+
result = TRUE;
208+
}
209+
210+
free(table);
211+
}
212+
}
213+
out:
188214
free(tableNames);
189215
}
190216
return result;

0 commit comments

Comments
 (0)