关于如何清点计算机硬件的信息很多,但是我对检索有关特定CPU寄存器的信息感到很感兴趣。可以使用PowerShell吗?我不是在谈论发明CPUID,是否需要专业人员的意见。有人可以给我一个建议,如果可能的话,如何实施这个想法?
答案 0 :(得分:1)
下面的脚本是我获取cpuid的旧实现。我不记得我停止开发它的原因。似乎根本没有空闲时间,没关系。此脚本应在 PowerShell v5 中正确运行。您可以将其用作研究的起点,并根据需要进行修改。希望这会有所帮助。
using namespace System.Reflection
using namespace System.Reflection.Emit
using namespace System.Runtime.InteropServices
# Brief : delegates "creator"
function Set-Delegate {
[OutputType([Type])]
param(
[Parameter(Mandatory, Position=0)]
[ValidateScript({$_ -ne [IntPtr]::Zero})]
[IntPtr]$ProcAddress,
[Parameter(Mandatory, Position=1)]
[ValidateNotNull()]
[Type]$Prototype,
[Parameter(Position=2)]
[ValidateNotNullOrEmpty()]
[CallingConvention]$CallingConvention = 'StdCall'
)
$method = $Prototype.GetMethod('Invoke')
$returntype, $paramtypes = $method.ReturnType, $method.GetParameters().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{$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)
}
# Brief : wrapper for reflected GetModuleHandle and GetProcAddress functions
# This is required to establish and invoke VirtualAlloc and VirtuallFree functions
# without creating dynamic assembly into current AppDomain. Be warned, this technique
# can be used in malware.
function Get-ProcAddress {
[OutputType([Hashtable])]
param(
[Parameter(Mandatory, Position=0)]
[ValidateNotNullOrEmpty()]
[String]$Module,
[Parameter(Mandatory, Position=1)]
[ValidateNotNull()]
[String[]]$Function
)
begin {
[Object].Assembly.GetType('Microsoft.Win32.Win32Native').GetMethods(
[BindingFlags]'Static, NonPublic'
).Where{$_.Name -cmatch '\AGet(ProcA|ModuleH)'}.ForEach{Set-Variable $_.Name $_}
if (($mod = $GetModuleHandle.Invoke($null, @($Module))) -eq [IntPtr]::Zero) {
throw (New-Object ComponentModel.Win32Exception(0x7E)).Message
}
}
process {}
end {
$table = @{}
$Function.ForEach{
if (($$ = $GetProcAddress.Invoke($null, @($mod, $_))) -ne [IntPtr]::Zero) {$table.$_ = $$}
}
$table
}
}
# Brief : sets functons addresses into delegates
function New-Delegate {
[OutputType([Hashtable])]
param(
[Parameter(Mandatory, Position=0)]
[ValidateNotNullOrEmpty()]
[String]$Module,
[Parameter(Mandatory, Position=1)]
[ValidateNotNull()]
[Hashtable]$Signature
)
$scope, $fname = @{}, (Get-ProcAddress -Module $Module -Function $Signature.Keys)
$fname.Keys.ForEach{$scope.$_ = Set-Delegate $fname.$_ $Signature.$_}
$scope
}
# Brief : helper function for pasrsing bytes
function Get-Blocks {
[OutputType([Hashtable])]
param(
[Parameter(Mandatory, Position=0)]
[ValidateNotNull()]
[Byte[]]$Bytes,
[Parameter()][Switch]$AsInteger,
[Parameter()][switch]$AsString
)
$tmp, $reg = @{}, @{eax = $Bytes[0..3];ebx = $Bytes[4..7];ecx = $Bytes[8..11];edx = $Bytes[12..15]}
if ($AsInteger) {
$reg.Keys.ForEach{$tmp.$_ = [BitConverter]::ToInt32($reg.$_, 0)}
}
if ($AsString) {
$reg.Keys.ForEach{$tmp.$_ = -join [Char[]]$reg.$_}
}
$tmp
}
# Brief : helper function for dumping features
function Set-MapFeatures {
begin {
function private:New-Hashtable([String[]]$Regs, [Int32[]]$Bits) {
$out = @{}
for ($i = 0; $i -lt $Regs.Length; $i++) {
$Out.Add($Regs[$i], $Bits[$i])
}
$out
}
$chk = for ($i = 0; $i -le 31; $i++) {1 -shl $i}
# excluding
$edx_low, $ecx_low, $ecx_high = (0x00000400, 0x00100000), 0x00010000, (
0x00004000, 0x00040000, 0x00100000, 0x02000000, 0x20000000, 0x40000000, 0x80000000
)
# common
$edx_high = (
0x00000800, 0x00080000, 0x00100000, 0x00400000, 0x02000000,
0x04000000, 0x08000000, 0x20000000, 0x40000000, 0x80000000
)
# registers
$edx_low_reg = ('fpu;vme;de;pse;tsc;msr;pae;mce;cx8;apic;sep;mtrr;pge;mca;cmov;pat;' +
'pse36;psn;clfsh;ds;acpi;mmx;fxsr;sse;sse2;ss;htt;tm;ia64;pbe').Split(';')
$ecx_low_reg = ('sse3;pclmulqdq;dtes64;monitor;ds_cpl;vmx;smx;est;tm2;ssse3;cnxt_id;' +
'sdbg;fma;cx16;xtpr;pdcm;pcid;dca;sse4_1;sse4_2;x2apic;movbe;popcnt;tsc_deadline;' +
'aes;xsave;osxsave;avx;f16c;rdrnd;hypervisor').Split(';')
$edx_high_reg = 'syscall;mp;nx;mmxext;fxsr_opt;pdpe1gb;rdtscp;lm;3dnowext;3dnow'.Split(';')
$ecx_high_reg = ('lahf_lm;cmp_legacy;svm;extapic;cr8_legacy;abm;sse4a;misalignsse;' +
'3dnowprefetch;osvw;ibs;xop;skinit;wdt;lwp;fma4;tce;nodeid_msr;tbm;topoext;' +
'perfctr_core;perfctr_nb;dbx;perftsc;pcx_l2i').Split(';')
$set = @()
}
process {}
end {
# checkers
$edx_low = $chk.Where{$edx_low -notcontains $_}
$ecx_low = $chk.Where{$ecx_low -notcontains $_}
$ecx_high = $chk.Where{$ecx_high -notcontains $_}
$set += New-Hashtable $edx_low_reg $edx_low
$set += New-Hashtable $ecx_low_reg $ecx_low
$set += New-Hashtable $edx_high_reg $edx_high
$set += New-Hashtable $ecx_high_reg $ecx_high
$set
}
}
# Brief : gets CPUID (CPU name and registers)
function Get-CpuId {
begin {
$kernel32 = New-Delegate kernel32 -Signature @{
VirtualAlloc = [Func[IntPtr, UIntPtr, UInt32, UInt32, IntPtr]]
VirtualFree = [Func[IntPtr, UIntPtr, UInt32, Boolean]]
}
[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
0x57, # 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
}
} # cpuid
}
process {
try {
$ptr = $kernel32.VirtualAlloc.Invoke(
[IntPtr]::Zero, (New-Object UIntPtr($bytes.Length)), (0x1000 -bor 0x2000), 0x40
)
# __cpuid via generic delegate
$cpuid = Set-Delegate $ptr -Prototype ([Action[Int32, [Byte[]]]]) -CallingConvention 'Cdecl'
[Marshal]::Copy($bytes, 0, $ptr, $bytes.Length) # copy required bytes
# shake it, baby! extracting data
$map = Set-MapFeatures # map of features
[Byte[]]$buf = New-Object Byte[] 16
$cpuid.Invoke(0, $buf)
$features, $vendor = @{}, "$(($str = Get-Blocks $buf -AsString).ebx)$($str.edx)$($str.ecx)"
# low leaves
$ids = (Get-Blocks $buf -AsInteger).eax
for ($i = 0; $i -le $ids; $i++) {
$cpuid.Invoke($i, $buf)
if ($i -eq 1) {
$reg = Get-Blocks $buf -AsInteger
$map[0].Keys.ForEach{$features.$_ = $reg.edx -band $map[0].$_}
$map[1].Keys.ForEach{$features.$_ = $reg.ecx -band $map[1].$_}
}
}
# top leaves
$cpuid.Invoke(0x80000000, $buf)
$ids, $name = (Get-Blocks $buf -AsInteger).eax, ''
for ($i = 0x80000000; $i -le $ids; $i++) {
$cpuid.Invoke($i, $buf)
if ($i -eq 0x80000001) {
$reg = Get-Blocks $buf -AsInteger
$map[2].Keys.ForEach{$features.$_ = $reg.edx -band $map[2].$_}
$map[3].Keys.ForEach{$features.$_ = $reg.ecx -band $map[3].$_}
}
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)"
}
}
# wrap data into PSObject
New-Object PSObject -Property @{
Vendor = $vendor
Name = $name
Features = $features.Keys.ForEach{if ($features.$_) {$_}}
}
}
catch { $_ }
finally {
if ($ptr) { [void]$kernel32.VirtualFree.Invoke($ptr, [UIntPtr]::Zero, 0x8000) }
}
}
end {}
}