@@ -8910,31 +8910,30 @@ struct VM {
89108910 */
89118911 [[nodiscard]] static bool firmware_scan () {
89128912#if (WINDOWS)
8913- #pragma warning (disable: 4459)
8913+ #pragma warning(disable: 4459)
89148914 typedef enum _SYSTEM_INFORMATION_CLASS {
89158915 SystemFirmwareTableInformation = 76
89168916 } SYSTEM_INFORMATION_CLASS;
8917-
8918- typedef enum _SYSTEM_FIRMWARE_TABLE_ACTION
8919- {
8917+ typedef enum _SYSTEM_FIRMWARE_TABLE_ACTION {
89208918 SystemFirmwareTableEnumerate,
89218919 SystemFirmwareTableGet,
89228920 SystemFirmwareTableMax
89238921 } SYSTEM_FIRMWARE_TABLE_ACTION;
8924-
8925- typedef struct _SYSTEM_FIRMWARE_TABLE_INFORMATION
8926- {
8922+ typedef struct _SYSTEM_FIRMWARE_TABLE_INFORMATION {
89278923 ULONG ProviderSignature;
89288924 SYSTEM_FIRMWARE_TABLE_ACTION Action;
89298925 ULONG TableID;
89308926 ULONG TableBufferLength;
89318927 _Field_size_bytes_ (TableBufferLength) UCHAR TableBuffer[1 ];
89328928 } SYSTEM_FIRMWARE_TABLE_INFORMATION, * PSYSTEM_FIRMWARE_TABLE_INFORMATION;
8933- #pragma warning (default : 4459)
8929+ #pragma warning(default: 4459)
89348930
89358931 typedef NTSTATUS (__stdcall* PNtQuerySystemInformation)(ULONG, PVOID, ULONG, PULONG);
89368932 constexpr ULONG STATUS_BUFFER_TOO_SMALL = 0xC0000023 ;
89378933 constexpr DWORD ACPI_SIG = ' ACPI' ;
8934+ constexpr DWORD ssdtSig = ' TDSS' ;
8935+ constexpr DWORD facpSig = ' PCAF' ;
8936+ constexpr DWORD dsdtSig = ' DSDT' ;
89388937
89398938 const HMODULE hNtdll = GetModuleHandle (_T (" ntdll.dll" ));
89408939 if (!hNtdll) return false ;
@@ -8945,76 +8944,94 @@ struct VM {
89458944 util::GetFunctionAddresses (hNtdll, functionNames, functionPointers, 1 );
89468945
89478946 const auto ntqsi = reinterpret_cast <PNtQuerySystemInformation>(functionPointers[0 ]);
8948- if (!ntqsi)
8949- return false ;
8947+ if (!ntqsi) return false ;
89508948
8951- constexpr const char * targets[] = {
8952- " Parallels Software International" , " Parallels(R)" , " innotek" ,
8953- " Oracle" , " VirtualBox" , " vbox" , " VBOX" , " VS2005R2" , " VMware, Inc. " ,
8954- " VMware" , " VMWARE " , " S3 Corp ." , " Virtual Machine " , " QEMU " , " WAET " ,
8955- " BOCHS " , " BXPC"
8949+ const char * targets[] = {
8950+ " Parallels Software International" ," Parallels(R)" ," innotek" ,
8951+ " Oracle" ," VirtualBox" ," vbox" ," VBOX" ," VS2005R2" ,
8952+ " VMware, Inc ." ," VMware " , " VMWARE " ,
8953+ " S3 Corp. " , " Virtual Machine " , " QEMU " , " WAET " , " BOCHS " , " BXPC"
89568954 };
89578955
89588956 PBYTE qsiBuffer = nullptr ;
89598957 ULONG qsiBufferSize = 0 ;
89608958
8959+ auto clear_buffer = [&]() {
8960+ if (qsiBuffer) {
8961+ free (qsiBuffer);
8962+ qsiBuffer = nullptr ;
8963+ qsiBufferSize = 0 ;
8964+ }
8965+ };
8966+
89618967 auto ensure_buffer = [&](ULONG needed) -> bool {
89628968 if (qsiBufferSize < needed) {
8963- free (qsiBuffer);
8964- qsiBuffer = static_cast <PBYTE>(malloc (needed));
8965- if (!qsiBuffer) {
8966- qsiBufferSize = 0 ;
8969+ PBYTE newBuf = static_cast <PBYTE>(realloc (qsiBuffer, needed));
8970+ if (!newBuf) {
89678971 return false ;
89688972 }
8973+ qsiBuffer = newBuf;
89698974 qsiBufferSize = needed;
89708975 }
89718976 return true ;
89728977 };
89738978
8974- auto query_table = [&](DWORD provider, DWORD tableID, PULONG outDataSize) -> PSYSTEM_FIRMWARE_TABLE_INFORMATION {
8975- const ULONG header = sizeof (SYSTEM_FIRMWARE_TABLE_INFORMATION);
8976- if (!ensure_buffer (header)) return nullptr ;
8979+ auto query_table = [&](DWORD provider, DWORD tableID, PULONG outSize) -> PSYSTEM_FIRMWARE_TABLE_INFORMATION {
8980+ ULONG header = FIELD_OFFSET (SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
8981+ if (!ensure_buffer (header)) {
8982+ clear_buffer ();
8983+ return nullptr ;
8984+ }
89778985
89788986 auto hdr = reinterpret_cast <PSYSTEM_FIRMWARE_TABLE_INFORMATION>(qsiBuffer);
89798987 hdr->ProviderSignature = provider;
89808988 hdr->Action = SystemFirmwareTableEnumerate;
89818989 hdr->TableID = _byteswap_ulong (tableID);
89828990 hdr->TableBufferLength = 0 ;
89838991
8984- NTSTATUS st = ntqsi (SystemFirmwareTableInformation, hdr, header, outDataSize);
8985- if (st != STATUS_BUFFER_TOO_SMALL)
8992+ NTSTATUS st = ntqsi (SystemFirmwareTableInformation, hdr, header, outSize);
8993+ if (st != STATUS_BUFFER_TOO_SMALL) {
8994+ clear_buffer ();
89868995 return nullptr ;
8996+ }
89878997
8988- ULONG fullSize = *outDataSize;
8989- if (!ensure_buffer (fullSize)) return nullptr ;
8998+ ULONG fullSize = *outSize;
8999+ if (!ensure_buffer (fullSize)) {
9000+ clear_buffer ();
9001+ return nullptr ;
9002+ }
89909003
89919004 hdr = reinterpret_cast <PSYSTEM_FIRMWARE_TABLE_INFORMATION>(qsiBuffer);
89929005 hdr->ProviderSignature = provider;
89939006 hdr->Action = SystemFirmwareTableEnumerate;
89949007 hdr->TableID = _byteswap_ulong (tableID);
89959008 hdr->TableBufferLength = fullSize - header;
89969009
8997- st = ntqsi (SystemFirmwareTableInformation, hdr, fullSize, outDataSize);
8998- if (!NT_SUCCESS (st))
9010+ st = ntqsi (SystemFirmwareTableInformation, hdr, fullSize, outSize);
9011+ if (!NT_SUCCESS (st)) {
9012+ clear_buffer ();
89999013 return nullptr ;
9014+ }
90009015
90019016 return hdr;
90029017 };
90039018
9004- auto check_firmware_table = [&](DWORD signature , DWORD tableID ) -> bool {
9019+ auto check_firmware_table = [&](DWORD sig , DWORD id ) -> bool {
90059020 ULONG gotSize = 0 ;
9006- auto info = query_table (signature, tableID , &gotSize);
9021+ auto info = query_table (sig, id , &gotSize);
90079022 if (!info) return false ;
90089023
90099024 const UCHAR* buf = info->TableBuffer ;
9010- const size_t bufLen = info->TableBufferLength ;
9025+ size_t len = info->TableBufferLength ;
90119026
90129027 for (auto target : targets) {
9013- size_t tlen = strlen (target);
9014- if (tlen > bufLen) continue ;
9015- for (size_t i = 0 ; i <= bufLen - tlen; ++i) {
9028+ const size_t tlen = strlen (target);
9029+ if (tlen > len) continue ;
9030+
9031+ for (size_t i = 0 ; i <= len - tlen; ++i) {
90169032 if (memcmp (buf + i, target, tlen) == 0 ) {
90179033 const char * brand = nullptr ;
9034+
90189035 if (!strcmp (target, " Parallels Software International" ) || !strcmp (target, " Parallels(R)" ))
90199036 brand = brands::PARALLELS;
90209037 else if (!strcmp (target, " innotek" ) || !strcmp (target, " VirtualBox" ) || !strcmp (target, " vbox" ) || !strcmp (target, " VBOX" ) || !strcmp (target, " Oracle" ))
@@ -9025,127 +9042,107 @@ struct VM {
90259042 brand = brands::QEMU;
90269043 else if (!strcmp (target, " BOCHS" ) || !strcmp (target, " BXPC" ))
90279044 brand = brands::BOCHS;
9028- else
9045+ else {
9046+ clear_buffer ();
90299047 return true ;
9048+ }
90309049
9050+ clear_buffer ();
90319051 return core::add (brand);
90329052 }
90339053 }
90349054 }
90359055
9036- // to detect VMAware's Hardener Loader
9037- if (bufLen >= 6 ) {
9038- for (size_t i = 0 ; i <= bufLen - 6 ; ++i) {
9039- if (buf[i] == ' 7' && buf[i + 1 ] == ' 7' && buf[i + 2 ] == ' 7' && buf[i + 3 ] == ' 7' && buf[i + 4 ] == ' 7' && buf[i + 5 ] == ' 7' ) {
9056+ const char marker[] = " 777777" ;
9057+ if (len >= sizeof (marker) - 1 ) {
9058+ for (size_t i = 0 ; i <= len - (sizeof (marker) - 1 ); ++i) {
9059+ if (memcmp (buf + i, marker, sizeof (marker) - 1 ) == 0 ) {
9060+ clear_buffer ();
90409061 return core::add (brands::VMWARE_HARD);
90419062 }
90429063 }
90439064 }
9065+
9066+ clear_buffer ();
90449067 return false ;
90459068 };
90469069
9047- // ACPI enumeration
90489070 ULONG totalLen = 0 ;
9049- auto listInfo = query_table (ACPI_SIG, 0UL , &totalLen);
9071+ auto listInfo = query_table (ACPI_SIG, 0 , &totalLen);
90509072 if (!listInfo) {
9051- free (qsiBuffer );
9073+ clear_buffer ( );
90529074 return false ;
90539075 }
90549076
90559077 const DWORD* tables = reinterpret_cast <const DWORD*>(listInfo->TableBuffer );
9056- ULONG tableCount = listInfo->TableBufferLength / sizeof (DWORD);
9057-
9058- if (tableCount < 4 ) { // idea by dmfrpro
9059- free (qsiBuffer);
9078+ const ULONG tableCount = listInfo->TableBufferLength / sizeof (DWORD);
9079+ if (tableCount < 4 ) {
9080+ clear_buffer ();
90609081 return true ;
90619082 }
90629083
9063- // count SSDT
9064- constexpr DWORD ssdtSig = ' TDSS' ;
90659084 ULONG ssdtCount = 0 ;
90669085 for (ULONG i = 0 ; i < tableCount; ++i) {
9067- if (tables[i] == ssdtSig)
9068- ++ssdtCount;
9069- if (ssdtCount == 2 )
9070- break ;
9086+ if (tables[i] == ssdtSig) ++ssdtCount;
9087+ if (ssdtCount == 2 ) break ;
90719088 }
90729089 if (ssdtCount < 2 ) {
9073- free (qsiBuffer );
9090+ clear_buffer ( );
90749091 return true ;
90759092 }
90769093
9077- constexpr DWORD facpSig = ' PCAF' ;
90789094 for (ULONG i = 0 ; i < tableCount; ++i) {
9079- ULONG sig = tables[i];
9080-
9081- if (sig == facpSig) {
9095+ if (tables[i] == facpSig) {
90829096 ULONG fSize = 0 ;
9083- auto fadt = query_table (ACPI_SIG, sig, &fSize );
9084- if (!fadt) continue ;
9085- BYTE* buf = reinterpret_cast <BYTE*>(fadt->TableBuffer );
9086- // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#preferred-pm-profile-system-types
9087- if (fSize >= 45 + 1 && buf[45 ] == 0 ) { // idea by dmfrpro
9088- free (qsiBuffer);
9097+ auto fadt = query_table (ACPI_SIG, tables[i], &fSize );
9098+ if (fadt && fSize > 45 && fadt->TableBuffer [45 ] == 0 ) {
9099+ clear_buffer ();
90899100 return true ;
90909101 }
90919102 }
9092- if (check_firmware_table (ACPI_SIG, sig )) {
9093- free (qsiBuffer);
9103+ if (check_firmware_table (ACPI_SIG, tables[i] )) {
9104+ clear_buffer ();
90949105 return true ;
90959106 }
90969107 }
90979108
9098- constexpr DWORD dsdtSig = ' DSDT' ;
9099- ULONG dsdtSize = 0 ;
9100- auto dsdt = query_table (ACPI_SIG, dsdtSig, &dsdtSize);
9101- if (dsdt) {
9102- const char * tb = reinterpret_cast <const char *>(dsdt->TableBuffer );
9103- bool foundCPU = false ;
9104-
9105- for (ULONG j = 0 ; j + 8 <= dsdtSize; ++j) {
9106- if (memcmp (tb + j, " ACPI0007" , 8 ) == 0 ) { // idea by dmfrpro
9107- foundCPU = true ;
9108- break ;
9109- }
9110- }
9109+ const ULONG dsdtSize = GetSystemFirmwareTable (ACPI_SIG, _byteswap_ulong (dsdtSig), nullptr , 0 );
9110+ if (dsdtSize == 0 ) {
9111+ clear_buffer ();
9112+ return false ;
9113+ }
91119114
9112- if (!foundCPU) {
9113- free (qsiBuffer);
9114- return true ;
9115- }
9115+ BYTE* dsdtData = static_cast <BYTE*>(malloc (dsdtSize));
9116+ if (!dsdtData) {
9117+ clear_buffer ();
9118+ return false ;
9119+ }
91169120
9117- constexpr const char * osi_targets[] = {
9118- " Windows 95" , " Windows 98" ,
9119- " Windows 2000" , " Windows 2000.1" ,
9120- " Windows ME: Millennium Edition" ,
9121- " Windows ME: Millennium Edition" , // some firmwares omit space
9122- " Windows XP" , " Windows 2001" ,
9123- " Windows 2006" , " Windows 2009" ,
9124- " Windows 2012" , " Windows 2015" ,
9125- " Windows 2020" , " Windows 2022" ,
9126- };
9127- constexpr size_t n_osi = sizeof (osi_targets) / sizeof (osi_targets[0 ]);
9128-
9129- bool foundOSI = false ;
9130- for (size_t t = 0 ; t < n_osi && !foundOSI; ++t) {
9131- const char * s = osi_targets[t];
9132- size_t len = strlen (s);
9133- for (ULONG j = 0 ; j + len <= dsdtSize; ++j) {
9134- if (memcmp (tb + j, s, len) == 0 ) {
9135- foundOSI = true ;
9136- break ;
9137- }
9138- }
9139- }
9121+ if (GetSystemFirmwareTable (ACPI_SIG, _byteswap_ulong (dsdtSig), dsdtData, dsdtSize) != dsdtSize) {
9122+ free (dsdtData);
9123+ clear_buffer ();
9124+ return false ;
9125+ }
91409126
9141- if (!foundOSI) {
9142- free (qsiBuffer);
9143- return true ;
9127+ const char * str = reinterpret_cast <const char *>(dsdtData);
9128+ const char * osi_targets[] = { " Windows 95" , " Windows 98" , " Windows 2000" , " Windows XP" , " Windows 2012" };
9129+ bool foundOSI = false ;
9130+
9131+ for (auto s : osi_targets) {
9132+ const size_t slen = strlen (s);
9133+ for (ULONG j = 0 ; j + slen <= dsdtSize; ++j) {
9134+ if (memcmp (str + j, s, slen) == 0 ) {
9135+ foundOSI = true ;
9136+ break ;
9137+ }
91449138 }
9139+ if (foundOSI) break ;
91459140 }
91469141
9147- free (qsiBuffer);
9148- return false ;
9142+ free (dsdtData);
9143+ clear_buffer ();
9144+
9145+ return !foundOSI;
91499146#elif (LINUX)
91509147 // Author: dmfrpro
91519148 if (!util::is_admin ()) {
0 commit comments