web-dev-qa-db-ja.com

C#のx86 / x64 CPUID

他の質問 に関連して、「不明なモジュールで「System.AccessViolationException」タイプの未処理の例外が発生しました。追加情報:保護されたメモリの読み取りまたは書き込みを試みました。これは多くの場合、他のメモリが破損しています。」コードをステップスルーすると、del()が実際に呼び出されるまですべてが機能し、その行で失敗します。

このコードはこれに基づいています 記事のサンプル そしてこれ pythonコード これは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()));
32
Jason Kleban

[〜#〜] 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
    }
}
17
Jesse C. Slicer

私はあなたの答えを改善することにしました。コンパイルするのに危険はもう必要ありません。また、eax/ebx/ecx/edxを16バイトのバイト配列に書き込むだけなので、すべてのcpuidブロックを読み取るために必要なのは2つのAssemblyブロックだけです。

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;
            }
        }

    }
}
10
antiduh

@antiduhのコードを取得して静的メソッドにリファクタリングしたため、管理するオブジェクトのライフサイクルはありません。 ASMコードはInvoke()の呼び出し間で再利用されないため、これは遅くなりますが、速度と単純さのトレードオフは私のユースケースでは理にかなっています。この新しいバージョンは、私のマシンで15ミリ秒に1000回CPUIDを呼び出すことができます。

素晴らしいコードをありがとう!

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
    };
}
5
adam smith

次のページを提案できますか: http://devpinoy.org/blogs/cvega/archive/2006/04/07/2658.aspx

このページでは、CPUIDのアセンブリソースコード、それをDLL)にコンパイルする方法、およびC#から呼び出す方法を示します。

また、他のハードウェア識別手順が必要な場合は、このページをお勧めします: http://www.codeproject.com/KB/system/GetHardwareInformation.aspx

このページでは、マザーボード情報、ハードドライブ情報、CPU情報、ビデオカード情報などの情報を取得する方法を示します。

2
Icemanind

私はこのスレッドが古いことを知っていますが、私はこのスレッドがとても好きです。コーディング後、「EAX = 7、ECX = 0」のときにデータを取得するのに問題があることがわかったので、x64CodeBytesに「movecx、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
    };
1
user2936547

さらに、CPUID4を取得するには、もう1つの引数が必要です。 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
};
0
John

彼の解決策を提供してくれた@antiduhに感謝します。次のように、使いやすさを向上させるためにInvokeシグネチャを少し変更します。そのため、レジスタのセットとして結果を取得するために割り当てる必要はありません。

    // 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;
    }
0
mistika