Simple Machine Check for License

Share your advanced PureBasic knowledge/code with the community.
Booger
Enthusiast
Enthusiast
Posts: 146
Joined: Tue Sep 04, 2007 2:18 pm

Simple Machine Check for License

Post by Booger »

Very simple, almost useless.

Windows.

Code: Select all

EnableExplicit ; Best practice, forces variable definition

; -------------------------------------------
; --- [ADDED] Manual Definition for MAC Address
; -------------------------------------------

#TH32CS_SNAPPROCESS = $00000002

; Note: Enable "Thread-Safe" in Compiler Options for COM
CompilerIf #PB_Compiler_Thread = 0
  CompilerError "Please enable 'Thread-Safe' in Compiler Options"
CompilerEndIf

; -------------------------------------------
; --- Missing Structure for MAC Address Check
; -------------------------------------------

Structure IP_ADAPTER_INFO
  Next.i
  ComboIndex.l
  AdapterName.a[260]
  Description.a[132]
  AddressLength.l
  Address.a[8]
  Index.l
  Type.l
  DhcpEnabled.l
  CurrentIpAddress.i
  IpAddressList.IP_ADDR_STRING
  GatewayList.IP_ADDR_STRING
  DhcpServer.IP_ADDR_STRING
  HaveWins.l
  PrimaryWinsServer.IP_ADDR_STRING
  SecondaryWinsServer.IP_ADDR_STRING
  LeaseObtained.l
  LeaseExpires.l
EndStructure

; -------------------------------------------
; --- WMI Function
; -------------------------------------------
Procedure.s GetWMIProperty(WmiClass$, WmiProperty$)
  Protected.s ResultString, WmiQuery
  Protected *pLocator.IWbemLocator
  Protected *pServices.IWbemServices
  Protected *pEnum.IEnumWbemClassObject
  Protected *pObject.IWbemClassObject
  Protected NumReturned.l
  Protected v.VARIANT
  
  CoInitializeEx_(0, #COINIT_APARTMENTTHREADED)
  
  If CoCreateInstance_(?CLSID_WemLocator, 0, #CLSCTX_INPROC_SERVER, ?IID_IWbemLocator, @*pLocator) = #S_OK
    If *pLocator\ConnectServer(SysAllocString_("root\cimv2"), 0, 0, 0, 0, 0, 0, @*pServices) = #S_OK
      CoSetProxyBlanket_(*pServices, #RPC_C_AUTHN_WINNT, #RPC_C_AUTHZ_NONE, 0, #RPC_C_AUTHN_LEVEL_CALL, #RPC_C_IMP_LEVEL_IMPERSONATE, 0, #EOAC_NONE)
      WmiQuery = "SELECT " + WmiProperty$ + " FROM " + WmiClass$
      If *pServices\ExecQuery(SysAllocString_("WQL"), SysAllocString_(WmiQuery), #WBEM_FLAG_FORWARD_ONLY | #WBEM_FLAG_RETURN_IMMEDIATELY, 0, @*pEnum) = #S_OK
        If *pEnum\Next(#WBEM_INFINITE, 1, @*pObject, @NumReturned) = #S_OK And NumReturned > 0
          If *pObject\Get(SysAllocString_(WmiProperty$), 0, @v, 0, 0) = #S_OK
            If v\vt = #VT_BSTR
              ResultString = PeekS(v\bstrVal, -1, #PB_Unicode)
            EndIf
            VariantClear_(v)
          EndIf
          *pObject\Release()
        EndIf
        *pEnum\Release()
      EndIf
      *pServices\Release()
    EndIf
    *pLocator\Release()
  EndIf
  CoUninitialize_()
  
  ProcedureReturn ResultString
EndProcedure

; -------------------------------------------
; --- Manual Data Section for COM GUIDs
; -------------------------------------------
DataSection
  CLSID_WemLocator: ; {4590F811-1D3A-11D0-891F-00AA004B2E24}
  Data.l $4590F811
  Data.w $1D3A, $11D0
  Data.b $89, $1F, $00, $AA, $00, $4B, $2E, $24
  IID_IWbemLocator: ; {DC12A687-737F-11CF-884D-00AA004B2E24}
  Data.l $DC12A687
  Data.w $737F, $11CF
  Data.b $88, $4D, $00, $AA, $00, $4B, $2E, $24
EndDataSection

; -------------------------------------------
; --- Hashing Helper Function
; -------------------------------------------
Procedure.s HashString(InputString.s)
  Protected Hash.s = ""
  Protected *StringBuff
  Protected Size.i
  
  Size = StringByteLength(InputString, #PB_UTF8)
  *StringBuff = AllocateMemory(Size)
  
  If *StringBuff
    PokeS(*StringBuff, InputString, -1, #PB_UTF8)
    UseSHA2Fingerprint() 
    Hash = Fingerprint(*StringBuff, Size, #PB_Cipher_SHA2, 256)
    FreeMemory(*StringBuff)
  EndIf
  
  ProcedureReturn Hash
EndProcedure

; -------------------------------------------
; --- Advanced VM Check Functions
; -------------------------------------------

Procedure.i CheckVMProcesses()
  Protected hSnapshot.i, pe.PROCESSENTRY32, VmProcessList.s
  VmProcessList = "vmtoolsd.exe|vboxservice.exe|vboxtray.exe|qemu-ga.exe|vmtools.exe"
  
  hSnapshot = CreateToolhelp32Snapshot_(#TH32CS_SNAPPROCESS, 0)
  If hSnapshot <> #INVALID_HANDLE_VALUE
    pe\dwSize = SizeOf(PROCESSENTRY32)
    If Process32First_(hSnapshot, @pe)
      Repeat
        If FindString(VmProcessList, LCase(PeekS(@pe\szExeFile, -1, #PB_Ascii)))
          CloseHandle_(hSnapshot)
          ProcedureReturn 1 ; VM Process Found
        EndIf
      Until Process32Next_(hSnapshot, @pe) = 0
    EndIf
    CloseHandle_(hSnapshot)
  EndIf
  ProcedureReturn 0
EndProcedure

Procedure.i CheckVMMacAddress()
  Protected *AdapterInfo.IP_ADAPTER_INFO, *StartInfo.IP_ADAPTER_INFO
  Protected OutBufLen.l, MacPrefix.s
  Protected VmMacList.s = "00:05:69|00:0c:29|00:50:56|08:00:27|00:03:ff|52:54:00"

  GetAdaptersInfo_(0, @OutBufLen)
  *StartInfo = AllocateMemory(OutBufLen)
  If *StartInfo
    If GetAdaptersInfo_(*StartInfo, @OutBufLen) = #NO_ERROR
      *AdapterInfo = *StartInfo
      While *AdapterInfo
        If *AdapterInfo\AddressLength = 6 
          MacPrefix = LCase(Hex(*AdapterInfo\Address[0], #PB_Byte) + ":" + Hex(*AdapterInfo\Address[1], #PB_Byte) + ":" + Hex(*AdapterInfo\Address[2], #PB_Byte))
          If FindString(VmMacList, MacPrefix)
            FreeMemory(*StartInfo)
            ProcedureReturn 1
          EndIf
        EndIf
        *AdapterInfo = *AdapterInfo\Next
      Wend
    EndIf
    FreeMemory(*StartInfo)
  EndIf
  ProcedureReturn 0
EndProcedure

Procedure.i CheckCPUIDHypervisor()
  Protected ecx_result.l, ebx_result.l, edx_result.l
  Protected *vendor_buffer
  Protected vendor_string.s
  
  !MOV eax, 1
  !CPUID
  !MOV [p.v_ecx_result], ecx
  
  If ecx_result & (1 << 31)
    !MOV eax, $40000000
    !CPUID
    !MOV [p.v_ebx_result], ebx
    !MOV [p.v_ecx_result], ecx
    !MOV [p.v_edx_result], edx
    
    *vendor_buffer = AllocateMemory(13)
    If *vendor_buffer
      PokeL(*vendor_buffer, ebx_result)
      PokeL(*vendor_buffer + 4, ecx_result)
      PokeL(*vendor_buffer + 8, edx_result)
      vendor_string = LCase(PeekS(*vendor_buffer, 12, #PB_Ascii))
      FreeMemory(*vendor_buffer)
    EndIf
    
    Debug "CPUID: Hypervisor bit set! Vendor: '" + vendor_string + "'"
    
    Select vendor_string
      Case "vmwarevmware", "vboxvboxvbox", "kvmkvmkvm", "xenxenvmmxenvmm"
        ProcedureReturn 1 ; It's a VM
      Case "microsoft hv", "hyper-v"
        ProcedureReturn 2 ; It's Microsoft
      Default
        Debug "CPUID: Unknown hypervisor vendor!"
        ProcedureReturn 1
    EndSelect
    
  EndIf
  
  ProcedureReturn 0 ; Hypervisor bit is NOT set
EndProcedure

Procedure.i CheckVMTiming()
  Protected.q StartTime, EndTime, Freq, Overhead, Delta
  Protected i.i, total.l
  
  QueryPerformanceFrequency_(@Freq)
  
  QueryPerformanceCounter_(@StartTime)
  QueryPerformanceCounter_(@EndTime)
  Overhead = EndTime - StartTime
  
  QueryPerformanceCounter_(@StartTime)
  For i = 0 To 1000
    total + i
  Next
  QueryPerformanceCounter_(@EndTime)
  
  Delta = (EndTime - StartTime) - Overhead
  
  If Delta > 20000 
    ProcedureReturn 1
  EndIf
  ProcedureReturn 0
EndProcedure

Procedure.i CheckVMRegistry()
  Protected hKey.i
  
  If RegOpenKeyEx_(#HKEY_LOCAL_MACHINE, "SOFTWARE\VMware, Inc.\VMware Tools", 0, #KEY_READ, @hKey) = #ERROR_SUCCESS
    RegCloseKey_(hKey)
    ProcedureReturn 1
  EndIf
  
  If RegOpenKeyEx_(#HKEY_LOCAL_MACHINE, "SOFTWARE\Oracle\VirtualBox Guest Additions", 0, #KEY_READ, @hKey) = #ERROR_SUCCESS
    RegCloseKey_(hKey)
    ProcedureReturn 1
  EndIf
  
  If RegOpenKeyEx_(#HKEY_LOCAL_MACHINE, "HARDWARE\Description\System\SystemBiosVersion", 0, #KEY_READ, @hKey) = #ERROR_SUCCESS
    Protected Value.s, ValueType.l, ValueSize.l = 1024
    Value = Space(ValueSize)
    If RegQueryValueEx_(hKey, "SystemBiosVersion", 0, @ValueType, @Value, @ValueSize) = #ERROR_SUCCESS
      If FindString(LCase(Value), "qemu")
        RegCloseKey_(hKey)
        ProcedureReturn 1
      EndIf
    EndIf
    RegCloseKey_(hKey)
  EndIf
  
  ProcedureReturn 0
EndProcedure

Procedure.i CheckVMFiles()
  Protected ProgFiles.s = Space(#MAX_PATH)
  Protected WinDir.s = Space(#MAX_PATH)
  
  GetEnvironmentVariable_("ProgramFiles", ProgFiles, #MAX_PATH)
  GetEnvironmentVariable_("SystemRoot", WinDir, #MAX_PATH)
  
  If GetFileAttributes_(ProgFiles + "\VMware\VMware Tools") & #FILE_ATTRIBUTE_DIRECTORY
    ProcedureReturn 1
  EndIf
  If FileSize(WinDir + "\system32\drivers\vmmouse.sys") > 0
    ProcedureReturn 1
  EndIf
  
  If GetFileAttributes_(ProgFiles + "\Oracle\VirtualBox Guest Additions") & #FILE_ATTRIBUTE_DIRECTORY
    ProcedureReturn 1
  EndIf
  If FileSize(WinDir + "\system32\drivers\VBoxGuest.sys") > 0
    ProcedureReturn 1
  EndIf

  ProcedureReturn 0
EndProcedure


; --- [THIS PROCEDURE IS CORRECTED] ---
Procedure.i IsRunningInVM_Advanced()
  Protected CpuCheckResult.i
  
  Debug "Running advanced VM checks..."
  
  CpuCheckResult = CheckCPUIDHypervisor()
  
  If CpuCheckResult = 1
    ; CPU reports a non-Microsoft hypervisor (VMware, VBox, etc.)
    Debug "VM Check: FAILED (CPUID reported a non-Microsoft hypervisor)"
    ProcedureReturn 1 ; Definitely a VM
  EndIf
  
  If CpuCheckResult = 2
    ; CPU reports a Microsoft hypervisor (VBS).
    ; We trust this and PASS immediately to avoid false positives.
    Debug "VM Check: PASSED (CPUID reported Microsoft Hypervisor. Ignoring other checks.)"
    ProcedureReturn 0 ; Not a VM
  EndIf
  
  ; --- If we get here, CpuCheckResult was 0 (no hypervisor bit) ---
  
  If CheckVMProcesses()
    Debug "VM Check: FAILED (VM Guest Tools process found)"
    ProcedureReturn 1
  EndIf
  
  If CheckVMRegistry()
    Debug "VM Check: FAILED (VM Registry keys found)"
    ProcedureReturn 1
  EndIf
  
  If CheckVMFiles()
    Debug "VM Check: FAILED (VM Guest files/drivers found)"
    ProcedureReturn 1
  EndIf
  
  If CheckVMMacAddress()
    Debug "VM Check: FAILED (VM MAC Address prefix found)"
    ProcedureReturn 1
  EndIf
  
  If CheckVMTiming()
    Debug "VM Check: FAILED (Suspicious timing detected)"
    ProcedureReturn 1
  EndIf
  
  Debug "VM Check: PASSED (All checks clear)"
  ProcedureReturn 0
EndProcedure


; -------------------------------------------
; --- ELABORATED DEMO
; -------------------------------------------
Define MachineID.s, CurrentMachineHash.s, YourLicenseKeyHash.s
Define SystemUUID.s, CurrentUUIDHash.s, YourUUIDLicenseKeyHash.s

Debug "--- License Check Demo ---"
Debug " "

; --- Step 0: Advanced Virtual Machine Check ---
Debug "--- Step 0: Advanced Virtual Machine Check ---"
If IsRunningInVM_Advanced()
  Debug " "
  Debug "RESULT: Virtual Machine DETECTED."
Else
  Debug " "
  Debug "RESULT: Virtual Machine NOT detected. (Physical Machine)"
EndIf

Debug " "
Debug "-----------------------------------------------------"
Debug " "

; --- Option 1: Check using Motherboard Serial ---
Debug "--- Option 1: Motherboard Serial (Win32_BaseBoard) ---"
MachineID = GetWMIProperty("Win32_BaseBoard", "SerialNumber")
If MachineID = ""
  Debug "MOTHERBOARD ID: Not found or empty."
Else
  Debug "1. Raw ID Found: " + MachineID
  CurrentMachineHash = HashString(MachineID)
  Debug "2. Hashed ID (SHA256): " + CurrentMachineHash
  YourLicenseKeyHash = "PASTE-YOUR-MOTHERBOARD-HASH-HERE"
  Debug "3. Checking against license: " + YourLicenseKeyHash
  If CurrentMachineHash = YourLicenseKeyHash
    Debug "RESULT: Motherboard License is VALID."
  Else
    Debug "RESULT: Motherboard License is INVALID."
  EndIf
EndIf

Debug " "
Debug "-----------------------------------------------------"
Debug " "

; --- Option 2: Check using System UUID ---
Debug "--- Option 2: System UUID (Win32_ComputerSystemProduct) ---"
SystemUUID = GetWMIProperty("Win32_ComputerSystemProduct", "UUID")
If SystemUUID = ""
  Debug "SYSTEM UUID: Not found or empty."
Else
  Debug "1. Raw ID Found: " + SystemUUID
  CurrentUUIDHash = HashString(SystemUUID)
  Debug "2. Hashed ID (SHA256): " + CurrentUUIDHash
  YourUUIDLicenseKeyHash = "PASTE-YOUR-UUID-HASH-HERE"
  Debug "3. Checking against license: " + YourUUIDLicenseKeyHash
  If CurrentUUIDHash = YourUUIDLicenseKeyHash
    Debug "RESULT: System UUID License is VALID."
  Else
    Debug "RESULT: System UUID License is INVALID."
  EndIf
EndIf