代码之家  ›  专栏  ›  技术社区  ›  Jason Kleban

C中的x86/x64 CPUID#

  •  30
  • Jason Kleban  · 技术社区  · 14 年前

    有关 my other question

    此代码基于此 article's sample 还有这个 python code 它在python中工作。我也不能让代码示例正常工作(同样的例外),但我希望它只是有点过时或什么的。

    编辑:如果你关心我们是如何来到这里的,请查看编辑历史记录,这很无趣。

    完成的工作版本:

    public static class CpuID
    {
        public static byte[] Invoke(int level)
        {
            IntPtr codePointer = IntPtr.Zero;
            try
            {
                // compile
                byte[] codeBytes;
                if (IntPtr.Size == 4)
                {
                    codeBytes = x86CodeBytes;
                }
                else
                {
                    codeBytes = x64CodeBytes;
                }
    
                codePointer = VirtualAlloc(
                    IntPtr.Zero,
                    new UIntPtr((uint)codeBytes.Length),
                    AllocationType.COMMIT | AllocationType.RESERVE,
                    MemoryProtection.EXECUTE_READWRITE
                );
    
                Marshal.Copy(codeBytes, 0, codePointer, codeBytes.Length);
    
                CpuIDDelegate cpuIdDelg = (CpuIDDelegate)Marshal.GetDelegateForFunctionPointer(codePointer, typeof(CpuIDDelegate));
    
                // invoke
                GCHandle handle = default(GCHandle);
                var buffer = new byte[16];
    
                try
                {
                    handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
                    cpuIdDelg(level, buffer);
                }
                finally
                {
                    if (handle != default(GCHandle))
                    {
                        handle.Free();
                    }
                }
    
                return buffer;
            }
            finally
            {
                if (codePointer != IntPtr.Zero)
                {
                    VirtualFree(codePointer, 0, 0x8000);
                    codePointer = IntPtr.Zero;
                }
            }
        }
    
        [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
        private delegate void CpuIDDelegate(int level, byte[] buffer);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, AllocationType flAllocationType,
            MemoryProtection flProtect);
    
        [DllImport("kernel32")]
        private static extern bool VirtualFree(IntPtr lpAddress, UInt32 dwSize, UInt32 dwFreeType);
    
        [Flags()]
        private enum AllocationType : uint
        {
            COMMIT = 0x1000,
            RESERVE = 0x2000,
            RESET = 0x80000,
            LARGE_PAGES = 0x20000000,
            PHYSICAL = 0x400000,
            TOP_DOWN = 0x100000,
            WRITE_WATCH = 0x200000
        }
    
        [Flags()]
        private enum MemoryProtection : uint
        {
            EXECUTE = 0x10,
            EXECUTE_READ = 0x20,
            EXECUTE_READWRITE = 0x40,
            EXECUTE_WRITECOPY = 0x80,
            NOACCESS = 0x01,
            READONLY = 0x02,
            READWRITE = 0x04,
            WRITECOPY = 0x08,
            GUARD_Modifierflag = 0x100,
            NOCACHE_Modifierflag = 0x200,
            WRITECOMBINE_Modifierflag = 0x400
        }
    
        // Basic ASM strategy --
        // void x86CpuId(int level, byte* buffer) 
        // {
        //    eax = level
        //    cpuid
        //    buffer[0] = eax
        //    buffer[4] = ebx
        //    buffer[8] = ecx
        //    buffer[12] = edx
        // }
    
        private readonly static byte[] x86CodeBytes = {
            0x55,                   // push        ebp  
            0x8B, 0xEC,             // mov         ebp,esp
            0x53,                   // push        ebx  
            0x57,                   // push        edi
    
            0x8B, 0x45, 0x08,       // mov         eax, dword ptr [ebp+8] (move level into eax)
            0x0F, 0xA2,              // cpuid
    
            0x8B, 0x7D, 0x0C,       // mov         edi, dword ptr [ebp+12] (move address of buffer into edi)
            0x89, 0x07,             // mov         dword ptr [edi+0], eax  (write eax, ... to buffer)
            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
        };
    
        private readonly static byte[] x64CodeBytes = {
            0x53,                       // push rbx    this gets clobbered by cpuid
    
            // rcx is level
            // rdx is buffer.
            // Need to save buffer elsewhere, cpuid overwrites rdx
            // Put buffer in r8, use r8 to reference buffer later.
    
            // Save rdx (buffer addy) to r8
            0x49, 0x89, 0xd0,           // mov r8,  rdx
    
            // Move ecx (level) to eax to call cpuid, call cpuid
            0x89, 0xc8,                 // mov eax, ecx
            0x0F, 0xA2,                 // cpuid
    
            // Write eax et al to buffer
            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
        };
    }
    

    请注意,CPUID0需要按正确的顺序读取:

    //a twelve character ASCII string stored in EBX, EDX, ECX - in that order
    var cpuid0s = new string(ASCIIEncoding.ASCII.GetChars(
        cpuid0.Skip(4).Take(4).Concat(
        cpuid0.Skip(12).Take(4)).Concat(
        cpuid0.Skip(8).Take(4)).ToArray()));
    
    7 回复  |  直到 7 年前
        1
  •  18
  •   Jesse C. Slicer    11 年前

    我很肯定你被 DEP x_CPUIDy_INSNS 字节数组位于标记为数据且不可执行的内存段中。

    编辑:

    编辑2:

    我想我现在有了正确的价值观。请随意验证。

    namespace CPUID
    {
        using System;
        using System.Globalization;
        using System.Linq;
        using System.Reflection;
        using System.Runtime.InteropServices;
        using System.Text;
    
        internal static class Program
        {
            [Flags]
            private enum AllocationTypes : uint
            {
                Commit = 0x1000,
                Reserve = 0x2000,
                Reset = 0x80000,
                LargePages = 0x20000000,
                Physical = 0x400000,
                TopDown = 0x100000,
                WriteWatch = 0x200000
            }
    
            [Flags]
            private enum MemoryProtections : uint
            {
                Execute = 0x10,
                ExecuteRead = 0x20,
                ExecuteReadWrite = 0x40,
                ExecuteWriteCopy = 0x80,
                NoAccess = 0x01,
                ReadOnly = 0x02,
                ReadWrite = 0x04,
                WriteCopy = 0x08,
                GuartModifierflag = 0x100,
                NoCacheModifierflag = 0x200,
                WriteCombineModifierflag = 0x400
            }
    
            [Flags]
            private enum FreeTypes : uint
            {
                Decommit = 0x4000,
                Release = 0x8000
            }
    
            [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
            private unsafe delegate void CPUID0Delegate(byte* buffer);
    
            [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
            private unsafe delegate void CPUID1Delegate(byte* buffer);
    
            private static void Main()
            {
                Console.WriteLine("CPUID0: {0}", string.Join(", ", CPUID0().Select(x => x.ToString("X2", CultureInfo.InvariantCulture))));
                Console.WriteLine("CPUID0: {0}", new string(ASCIIEncoding.ASCII.GetChars(CPUID0())));
                Console.WriteLine("CPUID1: {0}", string.Join(", ", CPUID1().Select(x => x.ToString("X2", CultureInfo.InvariantCulture))));
                Console.ReadLine();
            }
    
            private static unsafe byte[] CPUID0()
            {
                byte[] buffer = new byte[12];
    
                if (IntPtr.Size == 4)
                {
                    IntPtr p = NativeMethods.VirtualAlloc(
                        IntPtr.Zero,
                        new UIntPtr((uint)x86_CPUID0_INSNS.Length),
                        AllocationTypes.Commit | AllocationTypes.Reserve,
                        MemoryProtections.ExecuteReadWrite);
                    try
                    {
                        Marshal.Copy(x86_CPUID0_INSNS, 0, p, x86_CPUID0_INSNS.Length);
    
                        CPUID0Delegate del = (CPUID0Delegate)Marshal.GetDelegateForFunctionPointer(p, typeof(CPUID0Delegate));
    
                        fixed (byte* newBuffer = &buffer[0])
                        {
                            del(newBuffer);
                        }
                    }
                    finally
                    {
                        NativeMethods.VirtualFree(p, 0, FreeTypes.Release);
                    }
                }
                else if (IntPtr.Size == 8)
                {
                    IntPtr p = NativeMethods.VirtualAlloc(
                        IntPtr.Zero,
                        new UIntPtr((uint)x64_CPUID0_INSNS.Length),
                        AllocationTypes.Commit | AllocationTypes.Reserve,
                        MemoryProtections.ExecuteReadWrite);
                    try
                    {
                        Marshal.Copy(x64_CPUID0_INSNS, 0, p, x64_CPUID0_INSNS.Length);
    
                        CPUID0Delegate del = (CPUID0Delegate)Marshal.GetDelegateForFunctionPointer(p, typeof(CPUID0Delegate));
    
                        fixed (byte* newBuffer = &buffer[0])
                        {
                            del(newBuffer);
                        }
                    }
                    finally
                    {
                        NativeMethods.VirtualFree(p, 0, FreeTypes.Release);
                    }
                }
    
                return buffer;
            }
    
            private static unsafe byte[] CPUID1()
            {
                byte[] buffer = new byte[12];
    
                if (IntPtr.Size == 4)
                {
                    IntPtr p = NativeMethods.VirtualAlloc(
                        IntPtr.Zero,
                        new UIntPtr((uint)x86_CPUID1_INSNS.Length),
                        AllocationTypes.Commit | AllocationTypes.Reserve,
                        MemoryProtections.ExecuteReadWrite);
                    try
                    {
                        Marshal.Copy(x86_CPUID1_INSNS, 0, p, x86_CPUID1_INSNS.Length);
    
                        CPUID1Delegate del = (CPUID1Delegate)Marshal.GetDelegateForFunctionPointer(p, typeof(CPUID1Delegate));
    
                        fixed (byte* newBuffer = &buffer[0])
                        {
                            del(newBuffer);
                        }
                    }
                    finally
                    {
                        NativeMethods.VirtualFree(p, 0, FreeTypes.Release);
                    }
                }
                else if (IntPtr.Size == 8)
                {
                    IntPtr p = NativeMethods.VirtualAlloc(
                        IntPtr.Zero,
                        new UIntPtr((uint)x64_CPUID1_INSNS.Length),
                        AllocationTypes.Commit | AllocationTypes.Reserve,
                        MemoryProtections.ExecuteReadWrite);
                    try
                    {
                        Marshal.Copy(x64_CPUID1_INSNS, 0, p, x64_CPUID1_INSNS.Length);
    
                        CPUID1Delegate del = (CPUID1Delegate)Marshal.GetDelegateForFunctionPointer(p, typeof(CPUID1Delegate));
    
                        fixed (byte* newBuffer = &buffer[0])
                        {
                            del(newBuffer);
                        }
                    }
                    finally
                    {
                        NativeMethods.VirtualFree(p, 0, FreeTypes.Release);
                    }
                }
    
                return buffer;
            }
    
            private static class NativeMethods
            {
                [DllImport("kernel32.dll", SetLastError = true)]
                internal static extern IntPtr VirtualAlloc(
                    IntPtr lpAddress,
                    UIntPtr dwSize,
                    AllocationTypes flAllocationType,
                    MemoryProtections flProtect);
    
                [DllImport("kernel32")]
                [return: MarshalAs(UnmanagedType.Bool)]
                internal static extern bool VirtualFree(
                    IntPtr lpAddress,
                    uint dwSize,
                    FreeTypes flFreeType);
            }
    
            #region ASM
            private static readonly byte[] x86_CPUID0_INSNS = new byte[]
                {
                    0x53,                      // push   %ebx
                    0x31, 0xc0,                // xor    %eax,%eax
                    0x0f, 0xa2,                // cpuid
                    0x8b, 0x44, 0x24, 0x08,    // mov    0x8(%esp),%eax
                    0x89, 0x18,                // mov    %ebx,0x0(%eax)
                    0x89, 0x50, 0x04,          // mov    %edx,0x4(%eax)
                    0x89, 0x48, 0x08,          // mov    %ecx,0x8(%eax)
                    0x5b,                      // pop    %ebx
                    0xc3                       // ret
                };
    
            private static readonly byte[] x86_CPUID1_INSNS = new byte[]
                {
                    0x53,                   // push   %ebx
                    0x31, 0xc0,             // xor    %eax,%eax
                    0x40,                   // inc    %eax
                    0x0f, 0xa2,             // cpuid
                    0x5b,                   // pop    %ebx
                    0xc3                    // ret
                };
    
            private static readonly byte[] x64_CPUID0_INSNS = new byte[]
                {
                    0x49, 0x89, 0xd8,       // mov    %rbx,%r8
                    0x49, 0x89, 0xc9,       // mov    %rcx,%r9
                    0x48, 0x31, 0xc0,       // xor    %rax,%rax
                    0x0f, 0xa2,             // cpuid
                    0x4c, 0x89, 0xc8,       // mov    %r9,%rax
                    0x89, 0x18,             // mov    %ebx,0x0(%rax)
                    0x89, 0x50, 0x04,       // mov    %edx,0x4(%rax)
                    0x89, 0x48, 0x08,       // mov    %ecx,0x8(%rax)
                    0x4c, 0x89, 0xc3,       // mov    %r8,%rbx
                    0xc3                    // retq
                };
    
            private static readonly byte[] x64_CPUID1_INSNS = new byte[]
                {
                    0x53,                     // push   %rbx
                    0x48, 0x31, 0xc0,         // xor    %rax,%rax
                    0x48, 0xff, 0xc0,         // inc    %rax
                    0x0f, 0xa2,               // cpuid
                    0x5b,                     // pop    %rbx
                    0xc3                      // retq
                };
            #endregion
        }
    }
    
        2
  •  12
  •   antiduh    13 年前

    我决定改进你的答案。它不再需要不安全的编译,它只需要两个汇编块就可以读取任何和所有cpuid块,因为它只将eax/ebx/ecx/edx写入一个16字节的数组。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reflection;
    using System.Runtime.InteropServices;
    
    namespace CpuID
    {
        public class CpuID : IDisposable
        {
            [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
            public delegate void CpuIDDelegate(int level, byte[] buffer);
    
            [DllImport("kernel32.dll", SetLastError = true)]
            private static extern IntPtr VirtualAlloc(
                IntPtr lpAddress,
                UIntPtr dwSize,
                AllocationType flAllocationType, 
                MemoryProtection flProtect
            );
    
            [DllImport("kernel32")]
            private static extern bool VirtualFree(
                    IntPtr lpAddress,
                    UInt32 dwSize,
                    UInt32 dwFreeType
            );
    
            [Flags()]
            public enum AllocationType : uint
            {
                COMMIT = 0x1000,
                RESERVE = 0x2000,
                RESET = 0x80000,
                LARGE_PAGES = 0x20000000,
                PHYSICAL = 0x400000,
                TOP_DOWN = 0x100000,
                WRITE_WATCH = 0x200000
            }
    
            [Flags()]
            public enum MemoryProtection : uint
            {
                EXECUTE = 0x10,
                EXECUTE_READ = 0x20,
                EXECUTE_READWRITE = 0x40,
                EXECUTE_WRITECOPY = 0x80,
                NOACCESS = 0x01,
                READONLY = 0x02,
                READWRITE = 0x04,
                WRITECOPY = 0x08,
                GUARD_Modifierflag = 0x100,
                NOCACHE_Modifierflag = 0x200,
                WRITECOMBINE_Modifierflag = 0x400
            }
    
            private CpuIDDelegate cpuIdDelg;
    
            private IntPtr codePointer;
    
            // void x86CpuId(int level, byte* buffer) 
            // {
            //    eax = level
            //    cpuid
            //    buffer[0] = eax
            //    buffer[4] = ebx
            //    buffer[8] = ecx
            //    buffer[12] = edx
            // }
            private byte[] x86CodeBytes = 
            {
                0x55,                   // push        ebp  
                0x8B, 0xEC,             // mov         ebp,esp
                0x53,                   // push        ebx  
                0x57,                   // push        edi
    
                0x8B, 0x45, 0x08,       // mov         eax, dword ptr [ebp+8] (move level into eax)
                0x0F, 0xA2,              // cpuid
    
                0x8B, 0x7D, 0x0C,       // mov         edi, dword ptr [ebp+12] (move address of buffer into edi)
                0x89, 0x07,             // mov         dword ptr [edi+0], eax  (write eax, ... to buffer)
                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
            };
    
            private byte[] x64CodeBytes = 
            {
                0x53,                       // push rbx    this gets clobbered by cpuid
    
                // rcx is level
                // rdx is buffer.
                // Need to save buffer elsewhere, cpuid overwrites rdx
                // Put buffer in r8, use r8 to reference buffer later.
    
                // Save rdx (buffer addy) to r8
                0x49, 0x89, 0xd0,           // mov r8,  rdx
    
                // Move ecx (level) to eax to call cpuid, call cpuid
                0x89, 0xc8,                 // mov eax, ecx
                0x0F, 0xA2,                 // cpuid
    
                // Write eax et al to buffer
                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
            };
    
            public CpuID()
            {
                Compile();
            }
    
            ~CpuID()
            {
                Dispose(false);
            }
    
            private void Compile()
            {
                byte[] codeBytes;
    
                if (IntPtr.Size == 4)
                {
                    codeBytes = x86CodeBytes;
                }
                else
                {
                    codeBytes = x64CodeBytes;
                }
    
                this.codePointer = VirtualAlloc(
                    IntPtr.Zero,
                    new UIntPtr((uint)codeBytes.Length),
                    AllocationType.COMMIT | AllocationType.RESERVE,
                    MemoryProtection.EXECUTE_READWRITE
                );
    
                Marshal.Copy(codeBytes, 0, this.codePointer, codeBytes.Length);
    
                this.cpuIdDelg = (CpuIDDelegate)Marshal.GetDelegateForFunctionPointer(this.codePointer, typeof(CpuIDDelegate));
            }
    
            public void Invoke(int level, byte[] buffer)
            {
                GCHandle handle = default(GCHandle);
                if (buffer.Length < 16)
                {
                    throw new ArgumentException("buffer must be at least 16 bytes long");
                }
    
                try
                {
                    handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
    
                    this.cpuIdDelg(level, buffer);
                }
                finally
                {
                    if (handle != default(GCHandle))
                    {
                        handle.Free();
                    }
                }
            }
    
            public void Dispose()
            {
                Dispose(true);
            }
    
            public void Dispose(bool disposing)
            {
                if (this.codePointer != IntPtr.Zero)
                {
                    VirtualFree(this.codePointer, 0, 0x8000);
                    this.codePointer = IntPtr.Zero;
                }
            }
    
        }
    }
    
        3
  •  6
  •   adam smith    13 年前

    我接受了@antiduh的代码并将其重构为一个静态方法,因此没有对象生命周期需要管理。这会比较慢,因为在调用Invoke()之间不会重用ASM代码,但是在我的用例中,为了简单起见在速度上进行权衡是有意义的。这个新版本在我的机器上可以在15毫秒内调用CPUID 1000次。

    谢谢你那些出色的代码员!

    public static class CpuID {
    
        public static byte[] Invoke(int level) {
            IntPtr codePointer = IntPtr.Zero;
            try {
                // compile
                byte[] codeBytes;
                if (IntPtr.Size == 4) {
                    codeBytes = x86CodeBytes;
                } else {
                    codeBytes = x64CodeBytes;
                }
    
                codePointer = VirtualAlloc(
                    IntPtr.Zero,
                    new UIntPtr((uint)codeBytes.Length),
                    AllocationType.COMMIT | AllocationType.RESERVE,
                    MemoryProtection.EXECUTE_READWRITE
                );
    
                Marshal.Copy(codeBytes, 0, codePointer, codeBytes.Length);
    
                CpuIDDelegate cpuIdDelg = (CpuIDDelegate)Marshal.GetDelegateForFunctionPointer(codePointer, typeof(CpuIDDelegate));
    
                // invoke
                GCHandle handle = default(GCHandle);
                var buffer = new byte[16];
    
                try {
                    handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
                    cpuIdDelg(level, buffer);
                } finally {
                    if (handle != default(GCHandle)) {
                        handle.Free();
                    }
                }
    
                return buffer;
            } finally {
                if (codePointer != IntPtr.Zero) {
                    VirtualFree(codePointer, 0, 0x8000);
                    codePointer = IntPtr.Zero;
                }
            }
        }
    
        [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
        private delegate void CpuIDDelegate(int level, byte[] buffer);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, AllocationType flAllocationType,
            MemoryProtection flProtect);
    
        [DllImport("kernel32")]
        private static extern bool VirtualFree(IntPtr lpAddress, UInt32 dwSize, UInt32 dwFreeType);
    
        [Flags()]
        private enum AllocationType : uint {
            COMMIT = 0x1000,
            RESERVE = 0x2000,
            RESET = 0x80000,
            LARGE_PAGES = 0x20000000,
            PHYSICAL = 0x400000,
            TOP_DOWN = 0x100000,
            WRITE_WATCH = 0x200000
        }
    
        [Flags()]
        private enum MemoryProtection : uint {
            EXECUTE = 0x10,
            EXECUTE_READ = 0x20,
            EXECUTE_READWRITE = 0x40,
            EXECUTE_WRITECOPY = 0x80,
            NOACCESS = 0x01,
            READONLY = 0x02,
            READWRITE = 0x04,
            WRITECOPY = 0x08,
            GUARD_Modifierflag = 0x100,
            NOCACHE_Modifierflag = 0x200,
            WRITECOMBINE_Modifierflag = 0x400
        }
    
        // Basic ASM strategy --
        // void x86CpuId(int level, byte* buffer) 
        // {
        //    eax = level
        //    cpuid
        //    buffer[0] = eax
        //    buffer[4] = ebx
        //    buffer[8] = ecx
        //    buffer[12] = edx
        // }
    
        private readonly static byte[] x86CodeBytes = {
            0x55,                   // push        ebp  
            0x8B, 0xEC,             // mov         ebp,esp
            0x53,                   // push        ebx  
            0x57,                   // push        edi
    
            0x8B, 0x45, 0x08,       // mov         eax, dword ptr [ebp+8] (move level into eax)
            0x0F, 0xA2,              // cpuid
    
            0x8B, 0x7D, 0x0C,       // mov         edi, dword ptr [ebp+12] (move address of buffer into edi)
            0x89, 0x07,             // mov         dword ptr [edi+0], eax  (write eax, ... to buffer)
            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
        };
    
        private readonly static byte[] x64CodeBytes = {
            0x53,                       // push rbx    this gets clobbered by cpuid
    
            // rcx is level
            // rdx is buffer.
            // Need to save buffer elsewhere, cpuid overwrites rdx
            // Put buffer in r8, use r8 to reference buffer later.
    
            // Save rdx (buffer addy) to r8
            0x49, 0x89, 0xd0,           // mov r8,  rdx
    
            // Move ecx (level) to eax to call cpuid, call cpuid
            0x89, 0xc8,                 // mov eax, ecx
            0x0F, 0xA2,                 // cpuid
    
            // Write eax et al to buffer
            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
        };
    }
    
        4
  •  3
  •   user2936547    6 年前

    我知道这根线很旧,但我非常喜欢这根线。 所以,我在x64CodeBytes中添加“mov ecx,0”。

    private readonly static byte[] x64CodeBytes = {
        0x53,                         // push rbx    this gets clobbered by cpuid
    
        // rcx is level
        // rdx is buffer.
        // Need to save buffer elsewhere, cpuid overwrites rdx
        // Put buffer in r8, use r8 to reference buffer later.        
    
        // Save rdx (buffer addy) to r8
        0x49, 0x89, 0xd0,             // mov r8,  rdx
    
        // Move ecx (level) to eax to call cpuid, call cpuid
        0x89, 0xc8,                   // mov eax, ecx
        0xB9, 0x00, 0x00, 0x00, 0x00, // mov ecx, 0
        0x0F, 0xA2,                   // cpuid
    
        // Write eax et al to buffer
        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
        };
    
        5
  •  2
  •   mirh AAAfarmclub    4 年前

    我能推荐下一页吗: http://community.devpinoy.org/blogs/cvega/archive/2006/04/07/2658.aspx

    本页将向您展示CPUID的汇编源代码、如何将其编译成DLL以及如何从C#调用它。

    http://www.codeproject.com/KB/system/GetHardwareInformation.aspx

    此页显示如何获取信息,如主板信息、硬盘信息、cpu信息、显卡信息等。

        6
  •  1
  •   John    7 年前

    这里是如何得到CPUID0,CPUID1,CPUID2,CPUID4的。

    byte[] cpuid0 = Invoke(0, 0);
    byte[] cpuid1 = Invoke(1, 0);
    byte[] cpuid2 = Invoke(2, 0);
    
    List<byte[]> cpuid4L = new List<byte[]>();
    for (int i = 0; true; i++)
    {
        byte[] cpuid4 = Invoke(4, (uint)i);
        if ( (cpuid4[0] & 0x0F) == 0)
            break;
        cpuid4L.Add(cpuid4);
    }
    
    private static byte[] Invoke(uint functionNum, uint ecx)
    {
        IntPtr codePointer = IntPtr.Zero;
    
        try
        {
            // Select a code
            byte[] codeBytes;
            if (IntPtr.Size == 4)
                codeBytes = x86CodeBytes;
            else
                codeBytes = x64CodeBytes;
    
            codePointer = NativeMethods.VirtualAlloc(IntPtr.Zero, new UIntPtr((uint)codeBytes.Length), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
            Marshal.Copy(codeBytes, 0, codePointer, codeBytes.Length);
            CpuIdDelegate cpuIdDelg = (CpuIdDelegate)Marshal.GetDelegateForFunctionPointer(codePointer, typeof(CpuIdDelegate));
    
            // Invoke the code
            GCHandle handle = default(GCHandle);
            var buffer = new byte[16];
    
            try
            {
                handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
                cpuIdDelg(ecx, functionNum, buffer);  // Run the assembly code.
            }
            finally
            {
                if (handle != default(GCHandle))
                {
                    handle.Free();
                }
            }
    
            return buffer;
        }
        finally
        {
            if (codePointer != IntPtr.Zero)
            {
                NativeMethods.VirtualFree(codePointer, (UIntPtr) 0, MEM_RELEASE);
                codePointer = IntPtr.Zero;
            }
        }
    }
    
    private readonly static byte[] x86CodeBytes = {
        0x55,                   
        0x8B, 0xEC,             
        0x53,                   
        0x57,                   
        0x8B, 0x4D, 0x08,
        0x8B, 0x45, 0x0C,
        0x0F, 0xA2,      
        0x8B, 0x7D, 0x10,
        0x89, 0x07,      
        0x89, 0x5F, 0x04,
        0x89, 0x4F, 0x08,
        0x89, 0x57, 0x0C,
        0x5F,                   
        0x5B,                   
        0x8B, 0xE5,             
        0x5D,                   
        0xc3                    
    };
    
    private readonly static byte[] x64CodeBytes = {
        0x53,
        0x89, 0xD0,
        0x0F, 0xA2,
        0x41, 0x89, 0x40, 0x00,
        0x41, 0x89, 0x58, 0x04,
        0x41, 0x89, 0x48, 0x08,
        0x41, 0x89, 0x50, 0x0c,
        0x5b,
        0xc3
    };
    
        7
  •  0
  •   mistika    7 年前

    为了获得更好的可用性,我将对Invoke签名进行一点修改,如下所示,这样就不需要将get结果作为一组寄存器进行分配

        // This is a modification to https://stackoverflow.com/a/7964376/725903
        [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
        private delegate void CpuIDDelegate(int level, IntPtr ptr);
    
        [StructLayout(LayoutKind.Sequential, Size = 16)]
        public struct CpuIdResult
        {
            public int Eax;
            public int Ebx;
            public int Ecx;
            public int Edx;
        }
    
        public CpuIdResult Invoke(int level)
        {
            CpuIdResult result;
            IntPtr buffer = Marshal.AllocHGlobal(16);
            try
            {
                this.cpuIdDelg(level, buffer);
                result = (CpuIdResult)Marshal.PtrToStructure(buffer, typeof(CpuIdResult));
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
            return result;
        }