Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Скриптовые языки администрирования Windows » PowerShell - Поиск определенного регистра процессора

Ответить
Настройки темы
PowerShell - Поиск определенного регистра процессора

Забанен


Сообщения: 27
Благодарности: 2

Профиль | Цитировать


Проблема: есть дллка, корректность которой гарантируется за счёт наличия некоторых регистров процессора и которую планируется разворачивать в сети посредством PowerShell. На самом деле таких дллок много, и все они зависят от того или иного регистра процессора, то есть если цпу не имеет этого регистра, будет подобрана нужная в этом случае дллка и установлена (сами дллки написаны на асме лидтимом нашей конторы). Мне ж как админу поручено автоматизировать процесс развёртки. Основная трудность состоит в получении списка поддерживаемых регистров. Возможно ли это сделать средствами PowerShell? Сторонние тулзы в моем случае не вариант, так как в конторе с этим очень строго. Просьба хотя бы указать вектор куда копать.

Отправлено: 16:05, 20-11-2016

 

Забанен


Сообщения: 793
Благодарности: 260

Профиль | Цитировать


Все зависит от конечной цели. Если требуется проверить наличие, скажем, 3DNow, вполне можно обойтись WinAPI функцией IsProcessorFeaturePresent, экспортируемой из kernel32.dll. Правда стоит иметь в виду: из-за, мягко говоря, не совсем удачной реализации, функция может вполне возвращать ложное значение. Поэтому остаются два других варианта: через реестр и вызов cpuid посредством машинных кодов.

Через реестр
Сведения о характерных для процессора особенностях хранятся в значении реестра FeatureSet ключа HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\X (где X - номер процессора). Как расшифровывается данное значение Microsoft документировать наотрез отказывается, но ничего сложного там на самом деле нет - смещения да логические операции, - но вот объяснять как именно эти операции проводятся уж очень муторно. Кстати, значение FeatureSet также можно получить с помощью NtQuerySystemInformation, а именно SystemInformationClass = 1 и структуры SYSTEM_PROCESSOR_INFORMATION, имеющей одинаковый размер в x86 и x64 системах и равной 12 байтам.
Код: Выделить весь код
typedef _SYSTEM_PROCESSOR_INFORMATION {
   USHORT ProcessorArchitecture;
   USHORT ProcessorLevel;
   USHORT ProcessorRevision;
   USHORT Reserved;
   ULONG ProcessorFeatureBits;
} SYSTEM_PROCESSOR_INFORMATION, *PSYSTEM_PROCESSOR_INFORMATION;
Пример получения данного значения:
Код: Выделить весь код
try {
  $ptr = [Runtime.InteropServices.Marshal]::AllocHGlobal(0xC)
  
  if ([Regex].Assembly.GetType(
    'Microsoft.Win32.NativeMethods'
  ).GetMethod(
    'NtQuerySystemInformation'
  ).Invoke($null, @(1, $ptr, 0xC, $null)) -ne 0) {
    throw New-Object InvalidOperationException(
      'Could not get system processor information.'
    )
  }
  
  [BitConverter]::ToUInt32(
    [BitConverter]::GetBytes(
      [Runtime.InteropServices.Marshal]::ReadInt32($ptr, 8)
    ), 0
  )
}
catch { $_ }
finally {
  if ($ptr) {
    [Runtime.InteropServices.Marshal]::FreeHGlobal($ptr)
  }
}

cpuid
Крайне непопулярная техника, так как требует специфических навыков и знаний (в частности языка Ассемблера). В системе целочисленных команд процессора есть cpuid, которая получает информацию о текущем процессоре; для получения информации необходимо в регистр EAX поместить параметр (одно из значений 0, 1 или 2). Если EAX = 0, то в регистрах EAX, EBX, EDX и ECX формируется следующая информация:
EAX = n, где n - максимально допустимое значение параметра, которое может быть помещено в регистр EAX для задания режима сбора информации;
EBX, EDX, ECX - в них будет содержаться строка-идентификатор процессора, наприер, AuthenticAMD.
Если EAX = 1, формируется следующая информация:
EAX = n - информация о процессоре (SteppingId, Model, Family, Type);
EDX = n, ECX = n - собственно, информация о фичах процессора.
Ну и к слову, если EAX = 2, в регистрах EAX, EBX, ECX и EDX формируется информация о кэш-памяти первого уровня и TLB-буферах.
Если все это перевести в PowerShell, то получим примерно следующее:
Код: Выделить весь код
function Get-CpuId {
  begin {
    @(
      [Runtime.InteropServices.CallingConvention],
      [Runtime.InteropServices.GCHandle],
      [Runtime.InteropServices.Marshal],
      [Reflection.Emit.OpCodes]
    ) | ForEach-Object {
      $keys = ($ta = [PSObject].Assembly.GetType(
        'System.Management.Automation.TypeAccelerators'
      ))::Get.Keys
      $collect = @()
    }{
      if ($keys -notcontains $_.Name) { $ta::Add($_.Name, $_) }
      $collect += $_.Name
    } # accelerators
    
    function private:Get-ProcAddress {
      param(
        [Parameter(Mandatory=$true, Position=0)]
        [ValidateNotNullOrEmpty()]
        [String]$Module,
        
        [Parameter(Mandatory=$true, Position=1)]
        [ValidateNotNullOrEmpty()]
        [String[]]$Function
      )
      
      begin {
        [Object].Assembly.GetType(
          'Microsoft.Win32.Win32Native'
        ).GetMethods(
          [Reflection.BindingFlags]40
        ) | Where-Object {
          $_.Name -cmatch '\AGet(ProcA|ModuleH)'
        } | ForEach-Object {
          Set-Variable $_.Name $_
        }
      }
      process {}
      end {
        if (($ptr = $GetModuleHandle.Invoke(
          $null, @($Module)
        )) -eq [IntPtr]::Zero) {
          throw New-Object InvalidOperationException(
            'Could not find specified module.'
          )
        }
        
        $Function | ForEach-Object {$ret = @{}}{
          $ret[$_] = $GetProcAddress.Invoke(
            $null, @($ptr, [String]$_)
          )
        }{$ret}
      }
    } # Get-ProcAddress
    
    function private:New-Delegate {
      param(
        [Parameter(Mandatory=$true, Position=0)]
        [ValidateScript({$_ -ne [IntPtr]::Zero})]
        [IntPtr]$ProcAddress,
        
        [Parameter(Mandatory=$true, Position=1)]
        [ValidateNotNullOrEmpty()]
        [Type]$Prototype,
        
        [Parameter(Position=2)]
        [ValidateNotNullOrEmpty()]
        [CallingConvention]$CallingConvention = 'StdCall'
      )
      
      $method = $Prototype.GetMethod('Invoke')
      
      $returntype = $method.ReturnType
      $paramtypes = $method.GetParameters() |
                   Select-Object -ExpandProperty ParameterType
      
      $holder = New-Object Reflection.Emit.DynamicMethod(
        'Invoke', $returntype, $(
          if (!$paramtypes) { $null } else { $paramtypes }
        ), $Prototype
      )
      $il = $holder.GetILGenerator()
      if ($paramtypes) {
        0..($paramtypes.Length - 1) | ForEach-Object {
          $il.Emit([OpCodes]::Ldarg, $_)
        }
      }
      
      switch ([IntPtr]::Size) {
        4 { $il.Emit([OpCodes]::Ldc_I4, $ProcAddress.ToInt32()) }
        8 { $il.Emit([OpCodes]::Ldc_I8, $ProcAddress.ToInt64()) }
      }
      $il.EmitCalli(
        [OpCodes]::Calli, $CallingConvention, $returntype,
        $(if (!$paramtypes) { $null } else { $paramtypes })
      )
      $il.Emit([OpCodes]::Ret)
      
      $holder.CreateDelegate($Prototype)
    } # New-Delegate
    
    function private:Get-Blocks {
      param(
        [Parameter(Mandatory=$true, Position=0)]
        [ValidateNotNull()]
        [Byte[]]$Bytes,
        
        [Parameter()]
        [Switch]$AsInteger,
        
        [Parameter()]
        [Switch]$AsString
      )
      
      $reg = @{
        eax = $Bytes[0..3]
        ebx = $Bytes[4..7]
        ecx = $Bytes[8..11]
        edx = $Bytes[12..15]
      }
      
      if ($AsInteger) {
        $reg.Keys | ForEach-Object {$num = @{}}{
          $num[$_] = [BitConverter]::ToInt32($reg[$_], 0)
        }
        $reg = $num
      }
      
      if ($AsString) {
        $reg.Keys | ForEach-Object {$str = @{}}{
          $str[$_] = -join [Char[]]$reg[$_]
        }
        $reg = $str
      }
      
      $reg
    } # Get-Blocks
    
    # вспомогательная функция (имитация операторов -shr и -shl для PS v2)
    function private:Set-Shift {
      param(
        [Parameter(Position=0)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('Left', 'Right')]
        [String]$Direction = 'Right',
        
        [Parameter(Position=1)]
        [ValidateNotNull()]
        [Object]$Type = [Int32]
      )
      
      @(
        'Ldarg_0'
        'Ldarg_1'
        'Ldc_I4_S, 31'
        'And'
        $(if ($Direction -eq 'Right') { 'Shr' } else { 'Shl' })
        'Ret'
      ) | ForEach-Object {
        $def = New-Object Reflection.Emit.DynamicMethod(
          $Direction, $Type, @($Type, $Type)
        )
        $il = $def.GetILGenerator()
      }{
        if ($_ -notmatch ',') { $il.Emit([OpCodes]::$_) }
        else {
          $il.Emit(
            [OpCodes]::(($$ = $_.Split(','))[0]), ($$[1].Trim() -as $Type)
        )}
      }
      
      $def.CreateDelegate((
        Invoke-Expression "[Func[$($Type.Name), $($Type.Name), $($Type.Name)]]"
      ))
    } # Invoke-Shift
    
    $kernel32 = Get-ProcAddress kernel32 ('VirtualAlloc', 'VirtualFree')
    ($sig = @{
      VirtualAlloc = [Func[IntPtr, UIntPtr, UInt32, UInt32, IntPtr]]
      VirtualFree  = [Func[IntPtr, UIntPtr, UInt32, Boolean]]
    }).Keys | ForEach-Object {
      Set-Variable $_ (New-Delegate $kernel32.$_ $sig[$_])
    }
    
    [Byte[]]$bytes = switch ([IntPtr]::Size) {
      4 {
        0x55,                   #push  ebp
        0x8B, 0xEC,             #mov   ebp,  esp
        0x53,                   #push  ebx
        0x57,                   #push  edi
        0x8B, 0x45, 0x08,       #mov   eax,  dword ptr[ebp+8]
        0x0F, 0xA2,             #cpuid
        0x8B, 0x7D, 0x0C,       #mov   edi,  dword ptr[ebp+12]
        0x89, 0x07,             #mov   dword ptr[edi+0],  eax
        0x89, 0x5F, 0x04,       #mov   dword ptr[edi+4],  ebx
        0x89, 0x4F, 0x08,       #mov   dword ptr[edi+8],  ecx
        0x89, 0x57, 0x0C,       #mov   dword ptr[edi+12], edx
        0x5F,                   #pop   edi
        0x5B,                   #pop   ebx
        0x8B, 0xE5,             #mov   esp,  ebp
        0x5D,                   #pop   ebp
        0xC3                    #ret
      }
      8 {
        0x53,                   #push  rbx
        0x49, 0x89, 0xD0,       #mov   r8,  rdx
        0x89, 0xC8,             #mov   eax, ecx
        0x0F, 0xA2,             #cpuid
        0x41, 0x89, 0x40, 0x00, #mov   dword ptr[r8+0],  eax
        0x41, 0x89, 0x58, 0x04, #mov   dword ptr[r8+4],  ebx
        0x41, 0x89, 0x48, 0x08, #mov   dword ptr[r8+8],  ecx
        0x41, 0x89, 0x50, 0x0C, #mov   dword ptr[r8+12], edx
        0x5B,                   #pop   rbx
        0xC3                    #ret
      }
    }
    
    $features = @{}
  }
  process {
    $func = $ExecutionContext.SessionState.InvokeCommand.GetCommand(
      'New-Delegate', [Management.Automation.CommandTypes]::Function
    ).ScriptBlock
    $shr = Set-Shift
    
    try {
      $ptr = $VirtualAlloc.Invoke(
        [IntPtr]::Zero, (New-Object UIntPtr($bytes.Length)),
        (0x1000 -bor 0x2000), 0x40
      )
      
      $cpuid = {
        param([Int32]$Level, [Byte[]]$Bytes)
        
        $func.Invoke(
          $ptr, [Action[Int32, [Byte[]]]], 'Cdecl'
        )[0].Invoke($Level, $Bytes)
      }
      
      [Marshal]::Copy($bytes, 0, $ptr, $bytes.Length)
      [Byte[]]$buf = New-Object Byte[](16)
      $cpuid.Invoke(0, $buf)
      $vendor = "$(( # вендор
        $str = Get-Blocks $buf -AsString
      ).ebx)$($str.edx)$($str.ecx)"
      # low leaves
      $ids = (Get-Blocks $buf -AsInteger).eax
      $low = @()
      for ($i = 0; $i -le $ids; $i++) {
        $cpuid.Invoke($i, $buf)
        
        if ($i -eq 1) {
          $reg = Get-Blocks $buf -AsInteger
          
          $stepping = $reg.eax -band 0xF
          $model    = $shr.Invoke($reg.eax, 4) -band 0xF
          $family   = $shr.Invoke($reg.eax, 8) -band 0xF
          $logiccpu = $shr.Invoke($reg.ebx, 16) -band 0xFF
          
          $features['fpu']          = $reg.edx -band 0x00000001
          $features['vme']          = $reg.edx -band 0x00000002
          $features['de']           = $reg.edx -band 0x00000004
          $features['pse']          = $reg.edx -band 0x00000008
          $features['tsc']          = $reg.edx -band 0x00000010
          $features['msr']          = $reg.edx -band 0x00000020
          $features['pae']          = $reg.edx -band 0x00000040
          $features['mce']          = $reg.edx -band 0x00000080
          $features['cx8']          = $reg.edx -band 0x00000100
          $features['apic']         = $reg.edx -band 0x00000200
          $features['sep']          = $reg.edx -band 0x00000800
          $features['mtrr']         = $reg.edx -band 0x00001000
          $features['pge']          = $reg.edx -band 0x00002000
          $features['mca']          = $reg.edx -band 0x00004000
          $features['cmov']         = $reg.edx -band 0x00008000
          $features['pat']          = $reg.edx -band 0x00010000
          $features['pse36']        = $reg.edx -band 0x00020000
          $features['psn']          = $reg.edx -band 0x00040000
          $features['clflush']      = $reg.edx -band 0x00080000
          $features['ds']           = $reg.edx -band 0x00200000
          $features['acpi']         = $reg.edx -band 0x00400000
          $features['mmx']          = $reg.edx -band 0x00800000
          $features['fxsr']         = $reg.edx -band 0x01000000
          $features['sse']          = $reg.edx -band 0x02000000
          $features['sse2']         = $reg.edx -band 0x04000000
          $features['ss']           = $reg.edx -band 0x08000000
          $features['htt']          = $reg.edx -band 0x10000000
          $features['tm']           = $reg.edx -band 0x20000000
          $features['ia64']         = $reg.edx -band 0x40000000
          $features['pbe']          = $reg.edx -band 0x80000000
          
          $features['sse3']         = $reg.ecx -band 0x00000001
          $features['pclmulqdq']    = $reg.ecx -band 0x00000002
          $features['dtes64']       = $reg.ecx -band 0x00000004
          $features['monitor']      = $reg.ecx -band 0x00000008
          $features['ds_cpl']       = $reg.ecx -band 0x00000010
          $features['vmx']          = $reg.ecx -band 0x00000020
          $features['smx']          = $reg.ecx -band 0x00000040
          $features['est']          = $reg.ecx -band 0x00000080
          $features['tm2']          = $reg.ecx -band 0x00000100
          $features['ssse3']        = $reg.ecx -band 0x00000200
          $features['cntx_id']      = $reg.ecx -band 0x00000400
          $features['sdbg']         = $reg.ecx -band 0x00000800
          $features['fma']          = $reg.ecx -band 0x00001000
          $features['cx16']         = $reg.ecx -band 0x00002000
          $features['xtpr']         = $reg.ecx -band 0x00004000
          $features['pdcm']         = $reg.ecx -band 0x00008000
          $features['pcid']         = $reg.ecx -band 0x00020000
          $features['dca']          = $reg.ecx -band 0x00040000
          $features['sse4_1']       = $reg.ecx -band 0x00080000
          $features['sse4_2']       = $reg.ecx -band 0x00100000
          $features['x2apic']       = $reg.ecx -band 0x00200000
          $features['movbe']        = $reg.ecx -band 0x00400000
          $features['popcnt']       = $reg.ecx -band 0x00800000
          $features['tsc_deadline'] = $reg.ecx -band 0x01000000
          $features['aes']          = $reg.ecx -band 0x02000000
          $features['xsave']        = $reg.ecx -band 0x04000000
          $features['osxsave']      = $reg.ecx -band 0x08000000
          $features['avx']          = $reg.ecx -band 0x10000000
          $features['f16c']         = $reg.ecx -band 0x20000000
          $features['rdrnd']        = $reg.ecx -band 0x40000000
          $features['hypervisor']   = $reg.ecx -band 0x80000000
        }
        
        $leave = New-Object PSObject -Property (Get-Blocks $buf -AsInteger)
        $low += $leave
      }
      # high leaves
      $cpuid.Invoke(0x80000000, $buf)
      $ids = (Get-Blocks $buf -AsInteger).eax
      $top = @()
      $name = '' # брэндовая строка
      for ($i = 0x80000000; $i -le $ids; $i++) {
        $cpuid.Invoke($i, $buf)
        
        if ($i -eq 0x80000001) {
          $reg = Get-Blocks $buf -AsInteger
          
          $features['syscall']       = $reg.edx -band 0x00000800
          $features['mp']            = $reg.edx -band 0x00080000
          $features['nx']            = $reg.edx -band 0x00100000
          $features['mmxext']        = $reg.edx -band 0x00400000
          $features['fxsr_opt']      = $reg.edx -band 0x02000000
          $features['pdpe1gb']       = $reg.edx -band 0x04000000
          $features['rdtscp']        = $reg.edx -band 0x08000000
          $features['lm']            = $reg.edx -band 0x20000000
          $features['3dnowext']      = $reg.edx -band 0x40000000
          $features['3dnow']         = $reg.edx -band 0x80000000
          
          $features['lahf_lm']       = $reg.ecx -band 0x00000001
          $features['cmp_legacy']    = $reg.ecx -band 0x00000002
          $features['svm']           = $reg.ecx -band 0x00000004
          $features['extapic']       = $reg.ecx -band 0x00000008
          $features['cr8_legacy']    = $reg.ecx -band 0x00000010
          $features['abm']           = $reg.ecx -band 0x00000020
          $features['sse4a']         = $reg.ecx -band 0x00000040
          $features['misalingsse']   = $reg.ecx -band 0x00000080
          $features['3dnowprefetch'] = $reg.ecx -band 0x00000100
          $features['osvw']          = $reg.ecx -band 0x00000200
          $features['ibs']           = $reg.ecx -band 0x00000400
          $features['xop']           = $reg.ecx -band 0x00000800
          $features['skinit']        = $reg.ecx -band 0x00001000
          $features['wdt']           = $reg.ecx -band 0x00002000
          $features['lwp']           = $reg.ecx -band 0x00008000
          $features['fma4']          = $reg.ecx -band 0x00010000
          $features['tce']           = $reg.ecx -band 0x00020000
          $features['nodeid_msr']    = $reg.ecx -band 0x00080000
          $features['tbm']           = $reg.ecx -band 0x00200000
          $features['topoext']       = $reg.ecx -band 0x00400000
          $features['perfctr_core']  = $reg.ecx -band 0x00800000
          $features['perfctr_nb']    = $reg.ecx -band 0x01000000
          $features['dbx']           = $reg.ecx -band 0x04000000
          $features['perftsc']       = $reg.ecx -band 0x08000000
          $features['pcx_l2i']       = $reg.ecx -band 0x10000000
        }
        
        if ($i -eq 0x80000002 -or $i -eq 0x80000003 -or $i -eq 0x80000004) {
          $name += "$((
            $reg = Get-Blocks $buf -AsString
          ).eax)$($reg.ebx)$($reg.ecx)$($reg.edx)"
        }
        
        $leave = New-Object PSObject -Property (Get-Blocks $buf -AsInteger)
        $top += $leave
      }
      
      $cpuid = New-Object PSObject -Property @{
        Vendor          = $vendor
        Name            = $name.Trim()
        SteppingId      = $stepping
        Model           = $model
        Family          = $family
        LogicalCPUCount = $logiccpu
        Features        = $features.Keys | ForEach-Object {
          if ($features[$_]) { $_ }
        } | Sort-Object
        LowLeaves       = $low
        HighLeaves      = $top
      } | Select-Object (
        'Vendor', 'Name', 'SteppingId', 'Model', 'Family',
        'LogicalCPUCount', 'Features', 'LowLeaves', 'HighLeaves'
      )
    }
    catch { $_ }
    finally {
      if ($ptr) { [void]$VirtualFree.Invoke($ptr, [UIntPtr]::Zero, 0x8000) }
    }
  }
  end {
    $cpuid
    $collect | ForEach-Object { [void]$ta::Remove($_) }
  }
}
Пример:
Код: Выделить весь код
PS C:\> $cpuid = Get-CpuId
PS C:\> $cpuid.Features
# вывод фич процессора
...
Надеюсь это поможет.

Последний раз редактировалось greg zakharov, 21-11-2016 в 11:09.

Это сообщение посчитали полезным следующие участники:

Отправлено: 10:57, 21-11-2016 | #2



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля.


Забанен


Сообщения: 27
Благодарности: 2

Профиль | Цитировать


Спасибо! Думаю, вопрос решён.

Отправлено: 12:18, 21-11-2016 | #3


Новый участник


Сообщения: 1
Благодарности: 0

Профиль | Отправить PM | Цитировать


Доброго времени!
Подскажите пожалуйста такой момент:
Я использую в своей проге код на Ассемблере для получения CPUID. Беру только первый отрезок, т.к. остальные там просто нули.
Например на моей машине CPUID получается: 0001067А
Далее я беру из реестра FeatureSet: 559628286
Складываю CPUID+FeatureSet , Таким образом я получаю уникальный ID для каждой машины.
Вопрос: может ли FeatureSet быть одинаковым у похожих процессоров?
Могут ли у одинаковых процессоров совпадать FeatureSet ?

Другими словами может ли данный прием обеспечить мне уникальность каждой машины ?

Отправлено: 12:42, 26-04-2017 | #4



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Скриптовые языки администрирования Windows » PowerShell - Поиск определенного регистра процессора

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
CMD/BAT - [решено] Нахождение совпадения без учета регистра Mikle_home88 Скриптовые языки администрирования Windows 1 04-08-2015 15:20
2007 - [решено] Word| Из верхнего регистра в нижний sashok60 Microsoft Office (Word, Excel, Outlook и т.д.) 2 05-04-2010 11:24
[решено] Adobe FrameMaker - поиск и применение определенного стиля Vadikan AutoIt 1 01-12-2009 15:54
[решено] Поиск обновлений - загрузка процессора 100% Ser6720 Microsoft Windows 2000/XP 14 08-06-2007 19:02
Assm - assembler вывод содержимого регистра на экран Guest Программирование и базы данных 1 16-07-2004 16:32




 
Переход