VC++ MFC如何获取CPU ID及硬盘的序列号

VC++ MFC如何获取CPU ID及硬盘的序列号,第1张

// “获得Intel CPU ID”按钮消息处理函数

void CIntelCPUIDDlg::OnBtnCPUID()

{

unsigned long s1,s2;

unsigned char vendor_id[]="------------";//CPU提供商ID

CString str1,str2,str3;

// 以下为获得CPU ID的汇编语言指令

_asm // 得到CPU提供商信息

{

xor eax,eax // 将eax清0

cpuid // 获取CPUID的指令

mov dword ptr vendor_id,ebx

mov dword ptr vendor_id[+4],edx

mov dword ptr vendor_id[+8],ecx

}

str1Format("%s",vendor_id);

_asm // 得到CPU ID的高32位

{

mov eax,01h

xor edx,edx

cpuid

mov s2,eax

}

str2Format("%08X-",s2);

_asm // 得到CPU ID的低64位

{

mov eax,03h

xor ecx,ecx

xor edx,edx

cpuid

mov s1,edx

mov s2,ecx

}

str3Format("%08X-%08X\n",s1,s2);

str2=str2+str3;

m_editVendorSetWindowText(str1);

m_editCPUIDSetWindowText(str2);

}

// GetHDSerialcpp: implementation of the CGetHDSerial class

//

//////////////////////////////////////////////////////////////////////

#include "stdafxh"

#include "GetHDSerialh"

char m_buffer[256];

WORD m_serial[256];

DWORD m_OldInterruptAddress;

DWORDLONG m_IDTR;

// 等待硬盘空闲

static unsigned int WaitHardDiskIdle()

{

BYTE byTemp;

Waiting:

_asm

{

mov dx, 0x1f7

in al, dx

cmp al, 0x80

jb Endwaiting

jmp Waiting

}

Endwaiting:

_asm

{

mov byTemp, al

}

return byTemp;

}

//中断服务程序

void _declspec( naked )InterruptProcess(void)

{

int byTemp;

int i;

WORD temp;

//保存寄存器值

_asm

{

push eax

push ebx

push ecx

push edx

push esi

}

WaitHardDiskIdle();//等待硬盘空闲状态

_asm

{

mov dx, 0x1f6

mov al, 0xa0

out dx, al

}

byTemp = WaitHardDiskIdle(); //若直接在Ring3级执行等待命令,会进入死循环

if ((byTemp&0x50)!=0x50)

{

_asm // 恢复中断现场并退出中断服务程序

{

pop esi

pop edx

pop ecx

pop ebx

pop eax

iretd

}

}

_asm

{

mov dx, 0x1f6 //命令端口1f6,选择驱动器0

mov al, 0xa0

out dx, al

inc dx

mov al, 0xec

out dx, al //发送读驱动器参数命令

}

byTemp = WaitHardDiskIdle();

if ((byTemp&0x58)!=0x58)

{

_asm // 恢复中断现场并退出中断服务程序

{

pop esi

pop edx

pop ecx

pop ebx

pop eax

iretd

}

}

//读取硬盘控制器的全部信息

for (i=0;i<256;i++)

{

_asm

{

mov dx, 0x1f0

in ax, dx

mov temp, ax

}

m_serial[i] = temp;

}

_asm

{

pop esi

pop edx

pop ecx

pop ebx

pop eax

iretd

}

}

//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////

CGetHDSerial::CGetHDSerial()

{

}

CGetHDSerial::~CGetHDSerial()

{

}

// 读取硬盘序列号函数

char CGetHDSerial::GetHDSerial()

{

m_buffer[0]='\n';

// 得到当前 *** 作系统版本

OSVERSIONINFO OSVersionInfo;

OSVersionInfodwOSVersionInfoSize = sizeof(OSVERSIONINFO);

GetVersionEx( &OSVersionInfo);

if (OSVersionInfodwPlatformId != VER_PLATFORM_WIN32_NT)

{

// Windows 9x/ME下读取硬盘序列号

WORD m_wWin9xHDSerial[256];

Win9xReadHDSerial(m_wWin9xHDSerial);

strcpy (m_buffer, WORDToChar (m_wWin9xHDSerial, 10, 19));

}

else

{

// Windows NT/2000/XP下读取硬盘序列号

DWORD m_wWinNTHDSerial[256];

// 判断是否有SCSI硬盘

if ( ! WinNTReadIDEHDSerial(m_wWinNTHDSerial))

WinNTReadSCSIHDSerial(m_wWinNTHDSerial);

strcpy (m_buffer, DWORDToChar (m_wWinNTHDSerial, 10, 19));

}

return m_buffer;

}

// Windows9X/ME系统下读取硬盘序列号

void _stdcall CGetHDSerial::Win9xReadHDSerial(WORD buffer)

{

int i;

for(i=0;i<256;i++)

buffer[i]=0;

_asm

{

push eax

//获取修改的中断的中断描述符(中断门)地址

sidt m_IDTR

mov eax,dword ptr [m_IDTR+02h]

add eax,308h+04h

cli

//保存原先的中断入口地址

push ecx

mov ecx,dword ptr [eax]

mov cx,word ptr [eax-04h]

mov dword ptr m_OldInterruptAddress,ecx

pop ecx

//设置修改的中断入口地址为新的中断处理程序入口地址

push ebx

lea ebx,InterruptProcess

mov word ptr [eax-04h],bx

shr ebx,10h

mov word ptr [eax+02h],bx

pop ebx

//执行中断,转到Ring 0(类似CIH病毒原理)

int 3h

//恢复原先的中断入口地址

push ecx

mov ecx,dword ptr m_OldInterruptAddress

mov word ptr [eax-04h],cx

shr ecx,10h

mov word ptr [eax+02h],cx

pop ecx

sti

pop eax

}

for(i=0;i<256;i++)

buffer[i]=m_serial[i];

}

// Windows 9x/ME系统下,将字类型(WORD)的硬盘信息转换为字符类型(char)

char CGetHDSerial::WORDToChar (WORD diskdata [256], int firstIndex, int lastIndex)

{

static char string [1024];

int index = 0;

int position = 0;

// 按照高字节在前,低字节在后的顺序将字数组diskdata 中内容存入到字符串string中

for (index = firstIndex; index <= lastIndex; index++)

{

// 存入字中的高字节

string [position] = (char) (diskdata [index] / 256);

position++;

// 存入字中的低字节

string [position] = (char) (diskdata [index] % 256);

position++;

}

// 添加字符串结束标志

string [position] = '\0';

// 删除字符串中空格

for (index = position - 1; index > 0 && ' ' == string [index]; index--)

string [index] = '\0';

return string;

}

// Windows NT/2000/XP系统下,将双字类型(DWORD)的硬盘信息转换为字符类型(char)

char CGetHDSerial::DWORDToChar (DWORD diskdata [256], int firstIndex, int lastIndex)

{

static char string [1024];

int index = 0;

int position = 0;

// 按照高字节在前,低字节在后的顺序将双字中的低字存入到字符串string中

for (index = firstIndex; index <= lastIndex; index++)

{

// 存入低字中的高字节

string [position] = (char) (diskdata [index] / 256);

position++;

// 存入低字中的低字节

string [position] = (char) (diskdata [index] % 256);

position++;

}

// 添加字符串结束标志

string [position] = '\0';

// 删除字符串中空格

for (index = position - 1; index > 0 && ' ' == string [index]; index--)

string [index] = '\0';

return string;

}

// Windows NT/2000/XP下读取IDE硬盘序列号

BOOL CGetHDSerial::WinNTReadIDEHDSerial(DWORD buffer)

{

BYTE IdOutCmd [sizeof (SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1];

BOOL bFlag = FALSE;

int drive = 0;

char driveName [256];

HANDLE hPhysicalDriveIOCTL = 0;

sprintf (driveName, "\\\\\\PhysicalDrive%d", drive);

// Windows NT/2000/XP下创建文件需要管理员权限

hPhysicalDriveIOCTL = CreateFile (driveName,

GENERIC_READ | GENERIC_WRITE,

FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,

OPEN_EXISTING, 0, NULL);

if (hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)

{

GETVERSIONOUTPARAMS VersionParams;

DWORD cbBytesReturned = 0;

// 得到驱动器的IO控制器版本

memset ((void) &VersionParams, 0, sizeof(VersionParams));

if(DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_GET_VERSION,

NULL, 0, &VersionParams,

sizeof(VersionParams),

&cbBytesReturned, NULL) )

{

if (VersionParamsbIDEDeviceMap > 0)

{

BYTE bIDCmd = 0; // IDE或者ATAPI识别命令

SENDCMDINPARAMS scip;

// 如果驱动器是光驱,采用命令IDE_ATAPI_IDENTIFY, command,

// 否则采用命令IDE_ATA_IDENTIFY读取驱动器信息

bIDCmd = (VersionParamsbIDEDeviceMap >> drive & 0x10)

IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;

memset (&scip, 0, sizeof(scip));

memset (IdOutCmd, 0, sizeof(IdOutCmd));

// 获取驱动器信息

if (WinNTGetIDEHDInfo (hPhysicalDriveIOCTL,

&scip,

(PSENDCMDOUTPARAMS)&IdOutCmd,

(BYTE) bIDCmd,

(BYTE) drive,

&cbBytesReturned))

{

int m = 0;

USHORT pIdSector = (USHORT )

((PSENDCMDOUTPARAMS) IdOutCmd) -> bBuffer;

for (m = 0; m < 256; m++)

buffer[m] = pIdSector [m];

bFlag = TRUE; // 读取硬盘信息成功

}

}

}

CloseHandle (hPhysicalDriveIOCTL); // 关闭句柄

}

return bFlag;

}

// WindowsNT/2000/XP系统下读取SCSI硬盘序列号

BOOL CGetHDSerial::WinNTReadSCSIHDSerial (DWORD buffer)

{

buffer[0]='\n';

int controller = 0;

HANDLE hScsiDriveIOCTL = 0;

char driveName [256];

sprintf (driveName, "\\\\\\Scsi%d:", controller);

// Windows NT/2000/XP下任何权限都可以进行

hScsiDriveIOCTL = CreateFile (driveName,

GENERIC_READ | GENERIC_WRITE,

FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,

OPEN_EXISTING, 0, NULL);

if (hScsiDriveIOCTL != INVALID_HANDLE_VALUE)

{

int drive = 0;

DWORD dummy;

for (drive = 0; drive < 2; drive++)

{

char buffer [sizeof (SRB_IO_CONTROL) + SENDIDLENGTH];

SRB_IO_CONTROL p = (SRB_IO_CONTROL ) buffer;

SENDCMDINPARAMS pin =

(SENDCMDINPARAMS ) (buffer + sizeof (SRB_IO_CONTROL));

// 准备参数

memset (buffer, 0, sizeof (buffer));

p -> HeaderLength = sizeof (SRB_IO_CONTROL);

p -> Timeout = 10000;

p -> Length = SENDIDLENGTH;

p -> ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;

strncpy ((char ) p -> Signature, "SCSIDISK", 8);

pin -> irDriveRegsbCommandReg = IDE_ATA_IDENTIFY;

pin -> bDriveNumber = drive;

// 得到SCSI硬盘信息

if (DeviceIoControl (hScsiDriveIOCTL, IOCTL_SCSI_MINIPORT,

buffer,

sizeof (SRB_IO_CONTROL) +

sizeof (SENDCMDINPARAMS) - 1,

buffer,

sizeof (SRB_IO_CONTROL) + SENDIDLENGTH,

&dummy, NULL))

{

SENDCMDOUTPARAMS pOut =

(SENDCMDOUTPARAMS ) (buffer + sizeof (SRB_IO_CONTROL));

IDSECTOR pId = (IDSECTOR ) (pOut -> bBuffer);

if (pId -> sModelNumber [0])

{

int n = 0;

USHORT pIdSector = (USHORT ) pId;

for (n = 0; n < 256; n++)

buffer[n] =pIdSector [n];

return TRUE; // 读取成功

}

}

}

CloseHandle (hScsiDriveIOCTL); // 关闭句柄

}

return FALSE; // 读取失败

}

// Windows NT/2000/XP下读取IDE设备信息

BOOL CGetHDSerial::WinNTGetIDEHDInfo (HANDLE hPhysicalDriveIOCTL, PSENDCMDINPARAMS pSCIP,

PSENDCMDOUTPARAMS pSCOP, BYTE bIDCmd, BYTE bDriveNum,

PDWORD lpcbBytesReturned)

{

// 为读取设备信息准备参数

pSCIP -> cBufferSize = IDENTIFY_BUFFER_SIZE;

pSCIP -> irDriveRegsbFeaturesReg = 0;

pSCIP -> irDriveRegsbSectorCountReg = 1;

pSCIP -> irDriveRegsbSectorNumberReg = 1;

pSCIP -> irDriveRegsbCylLowReg = 0;

pSCIP -> irDriveRegsbCylHighReg = 0;

// 计算驱动器位置

pSCIP -> irDriveRegsbDriveHeadReg = 0xA0 | ((bDriveNum & 1) << 4);

// 设置读取命令

pSCIP -> irDriveRegsbCommandReg = bIDCmd;

pSCIP -> bDriveNumber = bDriveNum;

pSCIP -> cBufferSize = IDENTIFY_BUFFER_SIZE;

// 读取驱动器信息

return ( DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_GET_DRIVE_INFO,

(LPVOID) pSCIP,

sizeof(SENDCMDINPARAMS) - 1,

(LPVOID) pSCOP,

sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1,

lpcbBytesReturned, NULL) );

}

#include<stdioh>

#include<stdlibh>

#include<timeh>

int main()

{

srand(time(0));

for(int i=0;i<10;i++)

printf("%3d",rand()%100+1);

printf("\n");

return 0;

}

生成10个1-100的随机整数。

示例代码如下:

procedure TForm1Button1Click(Sender: TObject);

  type

    TCPUID = array[14] of longint;

  function GetCPUID: TCPUID;

  asm

    PUSH    EBX

   PUSH    EDI

   MOV     EDI,EAX    

   MOV     EAX,1

   DW      $A20F      

   STOSD

   MOV     EAX,EBX

   STOSD

   MOV     EAX,ECX

   STOSD

   MOV     EAX,EDX

   STOSD

   POP     EDI

   POP     EBX

  end;

var

  aCpuId: TCpuID;

begin

  aCpuId := GetCPUID;

  ShowMessage('CPU 序列号是: ' + IntToHex(aCpuId[4],8) + IntToHex(aCpuId[1],8));

end;

代码运行截图:

与实际的对比:

恩,上面的代码没错只是取的东西不对

public static ArrayList GetCPUId()

{

ArrayList IdList = new ArrayList();

ManagementClass cimobject = new ManagementClass("Win32_Processor");

ManagementObjectCollection moc = cimobjectGetInstances();

foreach (ManagementObject mo in moc)

{

IdListAdd(moProperties["ProcessorId"]ValueToString());

}

return IdList;

}

应该取ProcessorId

最近测试反馈了一个问题,每次重启服务器,我们某个版本的业务系统中的机器码都会改变,导致根据机器码算出来的许可证失效,从而使软件无法使用。 这个问题反馈了有一段时间了,但是本地一直没复现。然后前几天测试说又复现了,马上去看了下测试环境,服务器是一台国产化FT S2500服务器,验证了下,果然如此,马上去看了下关键代码。

这下明白了,它是取的CPU序列号作为机器码。dmidecode的输出中有多个Serial Number,它只取了第一个,恰恰就是Processor Information,也就是我们常说的CPU序列号。

CPU支持过序列号功能,但是被人指责侵犯隐私,所以现在的规范中,CPU完全没有所谓的序列号。

关于CPU序列号,其实还有一段 历史 。在奔腾3中短暂地引入过这个功能,但是后来很快就被移除了。

EAX=3: Processor Serial Number

See also: Pentium III § Controversy about privacy issues(>

下面就是获得CPU特性的例子:boolCPUID::IsHyperThreading()//判断是否支持hyperthreading{Executecpuid(1);//执行cpuid指令,使用输入参数eax1returnm_edx(128);//返回edx的bit28}boolCPUID::IsEST()//判断是否支持speedstep{Executecpuid(1);//执行cpuid指令,使用输入参数eax1returnm_ecx(17);//返回ecx的bit7}boolCPUID::IsMMX()//判断是否支持MMX{Executecpuid(1);//执行cpuid指令,使用输入参数eax1returnm_edx(123);//返回edx的bit23}CPU的特性还有很多,这只是平时我们听到比较多的三个,更多的特性请参考intel的资料

耐心看看啊,运行通过啦,希望对你有帮助啊!

#include<stdioh>

unsigned int veax;

unsigned int vebx;

unsigned int vedx;

unsigned int vecx;

//执行CPUID指令

void cpuid(unsigned int veax1)

{

_asm{

mov eax,veax1

cpuid

mov veax,eax

mov vebx,ebx

mov vecx,ecx

mov vedx,edx

}

}

//做移位 *** 作,把寄存器中的ASCII码,以字符形式输出

void LeftMove(unsigned int var)

{

printf("%c",var);

for(int i=0;i<3;i++)

{

var=(var>>;

printf("%c",var);

}

}

//做移位 *** 作,把寄存器中的值以“%d”形式输出

void LM(unsigned int var)

{

printf("%d",var);

for(int i=0;i<3;i++)

{

var=(var>>;

printf("%d",var);

}

}

//得到CPU的生产厂商(当EAX值为0时),依次存放在EBX,EDX,ECX中

void getCpuName()

{

cpuid(0);

LeftMove(vebx);

LeftMove(vedx);

LeftMove(vecx);

printf("\n";

}

//得到CPU的商标,当EAX中的值为0x80000003和0x80000004时分别返回16个字符,组成商标

//依次存放在EAX,EBX,ECX,EDX中

void getCpuBrand()

{

for(int j=0;j<2;j++)

{

cpuid(0x80000003+j);

LeftMove(veax);

LeftMove(vebx);

LeftMove(vecx);

LeftMove(vedx);

}

printf("\n";

}

//获得CPU的特性,参数是eax = 1,返回值放在edx和ecx,通过验证edx或者ecx的某一个bit,

//可以获得CPU的一个特性是否被支持。比如说,edx的bit 32代表是否支持MMX,

//edx的bit 28代表是否支持Hyper-Threading,ecx的bit 7代表是否支持speed sted。

void getCpuFeature()

{//由于特性太多,无法一一编写,需要的时候再写,方法是一样的。

}

//获得CPU序列号,获得序列号需要两个步骤,首先用eax = 1做参数,返回的eax中存储序列号的高两个WORD。

//用eax = 3做参数,返回ecx和edx按从低位到高位的顺序存储前4个WORD。

void getCpuSeris()

{

cpuid(1);

LM(veax);

cpuid(3);

LM(vecx);

LM(vedx);

printf("\n";

}

void main()

{

getCpuName();

getCpuBrand();

getCpuSeris();

}

用 Delphi 得到 CPU 的序列号

unit Main;

interface

uses

 Windows,

 Messages,

 SysUtils,

 Classes,

 Graphics,

 Controls,

 Forms,

 Dialogs,

 ExtCtrls,

 StdCtrls,

 Buttons;

type

 TDemoForm = class(TForm)

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

Label4: TLabel;

GetButton: TBitBtn;

CloseButton: TBitBtn;

Bevel1: TBevel;

Label5: TLabel;

FLabel: TLabel;

MLabel: TLabel;

PLabel: TLabel;

SLabel: TLabel;

PValue: TLabel;

FValue: TLabel;

MValue: TLabel;

SValue: TLabel;

procedure GetButtonClick(Sender: TObject);

 end;

var

 DemoForm: TDemoForm;

implementation

{$R DFM}

const

ID_BIT = $200000; // EFLAGS ID bit

type

TCPUID = array[14] of Longint;

TVendor = array [011] of char;

function IsCPUID_Available : Boolean; register;

asm

PUSHFD {direct access to flags no possible, only via stack}

 POP EAX {flags to EAX}

 MOV EDX,EAX {save current flags}

 XOR EAX,ID_BIT {not ID bit}

 PUSHEAX {onto stack}

 POPFD {from stack to flags, with not ID bit}

 PUSHFD {back to stack}

 POP EAX {get back to EAX}

 XOR EAX,EDX {check if ID bit affected}

 JZ @exit {no, CPUID not availavle}

 MOV AL,True {Result=True}

@exit:

end;

function GetCPUID : TCPUID; assembler; register;

asm

 PUSHEBX {Save affected register}

 PUSHEDI

 MOV EDI,EAX {@Resukt}

 MOV EAX,1

 DW $A20F  {CPUID Command}

 STOSD{CPUID[1]}

 MOV EAX,EBX

 STOSD  {CPUID[2]}

 MOV EAX,ECX

 STOSD  {CPUID[3]}

 MOV EAX,EDX

 STOSD  {CPUID[4]}

 POP EDI {Restore registers}

 POP EBX

end;

function GetCPUVendor : TVendor; assembler; register;

asm

 PUSHEBX {Save affected register}

 PUSHEDI

 MOV EDI,EAX {@Result (TVendor)}

 MOV EAX,0

 DW $A20F {CPUID Command}

 MOV EAX,EBX

 XCHG EBX,ECX {save ECX result}

 MOV ECX,4

@1:

 STOSB

 SHR EAX,8

 LOOP@1

 MOV EAX,EDX

 MOV ECX,4

@2:

 STOSB

 SHR EAX,8

 LOOP@2

 MOV EAX,EBX

 MOV ECX,4

@3:

 STOSB

 SHR EAX,8

 LOOP@3

 POP EDI {Restore registers}

 POP EBX

end;

procedure TDemoFormGetButtonClick(Sender: TObject);

var

 CPUID : TCPUID;

 I : Integer;

 S : TVendor;

begin

for I := Low(CPUID) to High(CPUID) do CPUID := -1;

 if IsCPUID_Available then begin

 CPUID := GetCPUID;

 Label1Caption := ’CPUID[1] = ’ + IntToHex(CPUID[1],8);

  Label2Caption := ’CPUID[2] = ’ + IntToHex(CPUID[2],8);

 Label3Caption := ’CPUID[3] = ’ + IntToHex(CPUID[3],8);

  Label4Caption := ’CPUID[4] = ’ + IntToHex(CPUID[4],8);

  PValueCaption := IntToStr(CPUID[1] shr 12 and 3);

 FValueCaption := IntToStr(CPUID[1] shr 8 and $f);

  MValueCaption := IntToStr(CPUID[1] shr 4 and $f);

 SValueCaption := IntToStr(CPUID[1] and $f);

 S := GetCPUVendor;

  Label5Caption := ’Vendor: ’ + S; end

 else begin

  Label5Caption := ’CPUID not available’;

 end;

end;

以上就是关于VC++ MFC如何获取CPU ID及硬盘的序列号全部的内容,包括:VC++ MFC如何获取CPU ID及硬盘的序列号、在c语言中如何取得cpuid、如何用 DELPHI 获取 CPU 的序列号等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9533356.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-29
下一篇 2023-04-29

发表评论

登录后才能评论

评论列表(0条)

保存