获取传感器温度-硬盘温度篇

    最近在研究硬盘温度的获取。看来ata spec,疯狂的在网上查找资料,还有就是分析hwmonitor.exe(这个帮助最大)。刚开始的时候什么都不会,到什么地方获取数据呢。在之前获取dmi中,有在spec中看到有温度。但是这个一般的主板商是不会写温度数据到里面的。而wmi很多就是读取dmi数据的。所以在获取cpu温度等上面,都是读不出数据的。因此,首先打消这个念头。

    在疯狂的在网上搜寻资料之后,得到了一些有用的东西,那就是温度是在硬盘的SMART属性中有保存的。到这里我们知道了,硬盘温度保存的地方。如何获取到这部分数据呢。是怎样的一个数据结构呢?真正的问题来了。用smart获取硬盘温度,你可以再codeproject中会找一个工程。实例就是如何获取smart信息。很详细。建议看看这部分代码。他是通过读取//./PhysicalDrive0(第一块硬盘,之后一次类推)。但是有时候根本获取不到详细的属性信息。特别是在多硬盘的机器上,很可能会出现获取数据不正确的问题,主要的原因就是sata硬盘的问题。在使用codeproject中的样例就获取不到了,到这里这能另寻它路了。没有别的办法只有看spec了。看这书,我是有点看晕了。只能求救于网络了。很幸运,找到新大陆了,可以通过wmi方式得到属性值。既然这样那就用wmitools看看吧。下面把网上找到的内容粘上给大家参考一下:

   检测硬盘温度的工具或软件,都是通过 S.M.A.R.T来读取,对硬盘直接 DeviceIoControl 或者 WMI 都可以得到SMART值.SMART 数据存储于 WMI 中 ROOT/WMI/MSStorageDriver_ATAPISmartData 命名空间中,其中属性 'VendorSpecific' 包含有硬盘温度的数据,这是ATA标准定义的。可能你读出这些数据来会有些困惑,其实这是一个结构,第一个和第二个字节代表 SMART 版本信息,从第三个字节起定义 SMART 的属性,每个属性为12字节长,每个属性的第一字节为当前属性定义,0x09 定义已经使用的小时数, 0xc2 为温度属性,第五字节表示当前温度。结构如下

        struct SmartAttriubtes
        {
            char attrib;
            char flags;
            char worst;
            char normal;
            char current;
            char current1;
            char current2;
            char current3;
            char current4;
            char current5;
            char current6;
            char current7;
        }

 struct VendorSpecific
        {
            unsigned short version;
            SmartAttriubtes smartattrib [1];
        }

       如笔者硬盘读取如下数值,有些就省略了 {0xa, 0x00, 0x09, 0x32, 0, 0x63, 0x63, 0xc2, 0x03, 0, 0, 0, 0, 0, 0xc2, 0x22, 0, 0x2e, 0x3b, 0x2e, 0, 0, 0, 0x05, 0, 0, ...};
      

  排列如下
       {
          0xa, 0x00 版本信息
          0x09, 0x32, 0, 0x63, 0x63, [0xc2, 0x03], 0, 0, 0, 0, 0 硬盘使用小时数 这里是 0x3c2 = 962 小时
          0xc2, 0x22, 0, 0x2e, 0x3b, [0x2e], 0, 0, 0, 0x05, 0, 0 这是当前温度 数值为 0x2e = 46 度
       }

       win2000 不支持此 WMI 属性,只能通过 DeviceIoControl 得到,如何实现请看考附录 SMART 的OpenSource 连接

    

     确实如上面说的,2000下面没有这个东西。但是用wmi方式同样和用codeproject中的样例一样会有相同的问题。这下真的让人很郁闷。

    只有最后一招了,调试分析hwmonitor了(逆向,还好一点点还是会的)。下面是主要分析:

//获取当前系统上的存储设备信息
InBuffer:
0012EDC4  00 00 00 00 00 00 00 00 E0 ED 12 00              ....?


00414272  |> /57            push    edi                              ; /pOverlapped
00414273  |. |8D5424 38     lea     edx, dword ptr [esp+38]          ; |
00414277  |. |52            push    edx                              ; |pBytesReturned
00414278  |. |8B5424 1C     mov     edx, dword ptr [esp+1C]          ; |
0041427C  |. |68 00020000   push    200                              ; |OutBufferSize = 200 (512.)
00414281  |. |8D4424 50     lea     eax, dword ptr [esp+50]          ; |
00414285  |. |50            push    eax                              ; |OutBuffer
00414286  |. |6A 0C         push    0C                               ; |InBufferSize = C (12.)
00414288  |. |8D4C24 4C     lea     ecx, dword ptr [esp+4C]          ; |
0041428C  |. |51            push    ecx                              ; |InBuffer
0041428D  |. |68 00142D00   push    2D1400                           ; |IoControlCode = 2D1400(IOCTL_STORAGE_QUERY_PROPERTY)
00414292  |. |52            push    edx                              ; |hDevice
00414293  |. |897C24 58     mov     dword ptr [esp+58], edi          ; |
00414297  |. |897C24 5C     mov     dword ptr [esp+5C], edi          ; |
0041429B  |. |FF15 BC034A00 call    dword ptr [<&KERNEL32.DeviceIoCo>; /DeviceIoControl

 

 


//获取smart版本


00414365  |> /57            push    edi                              ; /pOverlapped
00414366  |.  8D4C24 34     lea     ecx, dword ptr [esp+34]          ; |
0041436A  |.  51            push    ecx                              ; |pBytesReturned
0041436B  |.  6A 18         push    18                               ; |OutBufferSize = 18 (24.)
0041436D  |.  33C0          xor     eax, eax                         ; |
0041436F  |.  8D5424 24     lea     edx, dword ptr [esp+24]          ; |
00414373  |.  52            push    edx                              ; |OutBuffer
00414374  |.  57            push    edi                              ; |InBufferSize
00414375  |.  57            push    edi                              ; |InBuffer
00414376  |.  894424 30     mov     dword ptr [esp+30], eax          ; |
0041437A  |.  894424 34     mov     dword ptr [esp+34], eax          ; |
0041437E  |.  894424 38     mov     dword ptr [esp+38], eax          ; |
00414382  |.  894424 3C     mov     dword ptr [esp+3C], eax          ; |
00414386  |.  894424 40     mov     dword ptr [esp+40], eax          ; |
0041438A  |.  894424 44     mov     dword ptr [esp+44], eax          ; |
0041438E  |.  8B4424 2C     mov     eax, dword ptr [esp+2C]          ; |
00414392  |.  68 80400700   push    74080                            ; |IoControlCode = SMART_GET_VERSION
00414397  |.  50            push    eax                              ; |hDevice
00414398  |.  897C24 50     mov     dword ptr [esp+50], edi          ; |
0041439C  |.  FF15 BC034A00 call    dword ptr [<&KERNEL32.DeviceIoCo>; /DeviceIoControl

0012ED6C   00000148  |hDevice = 00000148
0012ED70   00074080  |IoControlCode = SMART_GET_VERSION
0012ED74   00000000  |InBuffer = NULL
0012ED78   00000000  |InBufferSize = 0
0012ED7C   0012EDA4  |OutBuffer = 0012EDA4
0012ED80   00000018  |OutBufferSize = 18 (24.)
0012ED84   0012EDBC  |pBytesReturned = 0012EDBC
0012ED88   00000000  /pOverlapped = NULL


.text:004143AC                 mov     ecx, [esp+254h+var_238] ; GETVERSIONINPARAMS.fCapabilities
.text:004143B0                 shr     ecx, 2   
.text:004143B3                 and     ecx, 1
.text:004143B6                 mov     [ebx+718h], ecx
.text:004143BC                 jmp     short loc_4143C0

if(GETVERSIONINPARAMS.fCapabilities & CAP_SMART_CMD ) == CAP_SMART_CMD)
{

}

 

 

//发送smart命令

0012EDF0  00 00 00 00 D8 01 01 4F C2 A0 B0 00 00 00 00 00  ..ǘ企?°..
0012EE00  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ........

 


.text:00414195                 mov     [eax+6], dl
.text:00414198                 mov     edx, [esp+1Ch+lpOutBuffer]
.text:0041419C                 push    edx             ; lpOutBuffer
.text:0041419D                 push    20h             ; nInBufferSize
.text:0041419F                 push    eax             ; lpInBuffer
.text:004141A0                 mov     [eax], esi
.text:004141A2                 mov     esi, [esp+28h+hObject]
.text:004141A6                 or      bl, 0FAh
.text:004141A9                 push    7C084h          ; dwIoControlCode  SMART_SEND_DRIVE_COMMAND
.text:004141AE                 shl     bl, 4
.text:004141B1                 push    esi             ; hDevice
.text:004141B2                 mov     byte ptr [eax+4], 0D8h
.text:004141B6                 mov     byte ptr [eax+7], 4Fh
.text:004141BA                 mov     byte ptr [eax+8], 0C2h
.text:004141BE                 mov     [eax+9], bl
.text:004141C1                 mov     byte ptr [eax+0Ah], 0B0h
.text:004141C5                 call    ds:DeviceIoControl ; Sends a control code directly to a specified device driver,
.text:004141C5                                         ; causing the corre


//接受smart数据

0012EDF0  00 02 00 00 D0 01 01 4F C2 A0 B0 00 00 00 00 00  ?.ǐ企?°..
0012EE00  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ........

.text:004145B5                 call    _memset
.text:004145BA                 add     esp, 0Ch
.text:004145BD                 push    0               ; lpOverlapped
.text:004145BF                 lea     edx, [esp+288h+BytesReturned]
.text:004145C3                 push    edx             ; lpBytesReturned
.text:004145C4                 push    210h            ; nOutBufferSize
.text:004145C9                 lea     eax, [esp+290h+Dst]
.text:004145CD                 push    eax             ; lpOutBuffer
.text:004145CE                 push    20h             ; nInBufferSize
.text:004145D0                 lea     ecx, [esp+298h+InBuffer]
.text:004145D4                 push    ecx             ; lpInBuffer
.text:004145D5                 push    7C088h          ; dwIoControlCode  SMART_REV_DRIVE_DATA
.text:004145DA                 push    ebp             ; hDevice
.text:004145DB                 call    ds:DeviceIoControl ; Sends a control code directly to a specified device driver,
.text:004145DB                                         ; causing the corresponding dev

 


while(SetupDiEnumDeviceInterfaces())
{
 //获取所需的缓存大小
 if(SetupDiGetDeviceInterfaceDetail())
 {
  //获取所需的数据
  if(SetupDiGetDeviceInterfaceDetail())
  {
   //打开设备,设备名为获取buffer+4
    hFile = CreateFile();
    if(hFile != INVAILD_VALUE_HANDLE)
    {
     CloseHanle(hFile);
    } 
   
  }
 }
}

 

上面的inbuffer内容,具体的要看ata spec了。

 

可以尝试的调试分析一下,你会知道,在获取smart之前是打开设备。分析中你会知道它不是打开//./PhysicalDrive0之类的设备,而是首先通过存储设备类,知道有哪些可用的存储设备,使用SetDixxxxxxx函数可以得到具体设备名。然后GetPowerState得到设备是否正在运行,以及通过smart版本是否支持smart命令。如果这些都成立的话,那么就可以通过send smart命令进行下面的操作了。这个存储设备类的guid是{0x53f56307,0xb6bf,0x11do,0x94,0xf2,0x00,0xa0,0xc9,0x1e,0xfb,0x8b}.

 

    在得到了smart属性之后就是解析的问题的。每个smart属性都是0xc字节大小,这个上面有说的。属性type为0xC2就是温度属性了。在偏移为5的地方就是当前温度值。在到每个属性之前有0x12字节的数据(这个是什么我就不管了)。上面还有一点没有说到的就是设备属性的获取。可以得到vendorid,和products,这个我是用来表示硬盘名称的。

 

  说的还不是很详细。就说到这里吧。大致东西都说到了。

  

 

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
S.M.A.R.T.解释 https://zh.wikipedia.org/wiki/S.M.A.R.T. S.M.A.R.T.,全称为“Self-Monitoring Analysis and Reporting Technology”,即“自我监测、分析及报告技术”,是一种自动的硬盘状态检测与预警系统和规范。通过在硬盘硬件内的检测指令对硬盘的硬件如磁头、盘片、马达、电路的运行情况进行监控、记录并与厂商所设定的预设安全值进行比较,若监控情况将或已超出预设安全值的安全范围,就可以通过主机的监控硬件或软件自动向用户作出警告并进行轻微的自动修复,以提前保障硬盘xx的安全。除一些出厂时间极早的硬盘外,现在大部分硬盘均配备该项技术。 运行原理 该技术所需xx被存放在硬盘物理盘面最前面的磁道中,由硬盘制作商将相关管理程序和xx该磁道中,包括加解密程序,自监控程序,自修复程序等,主机的监控软件可以通过“SMART RETURN STATUS”的命令读取S.M.A.R.T.信息,且这些信息不允许被用户修改。 ———————————————— SMART原始格式 参考链接:http://blog.csdn.net/u014183302/article/details/41289451 命名空间root/wmi下MSStorageDriver_ATAPISmartData类的子集VendorSpecific内存放了硬盘内部芯片存储的所有SMART讯息大小为512Bytes。 第1,2个Byte位置代表SMART版本号(如图为10,0)。第3Byte开始往后全部为SMART attributes,每12个Bytes为一组代表一个分类Item。 ———————————————— 使用DeviceIoControl APi 获取 IOCTL_STORAGE_PREDICT_FAILURE 产品信息中的 VendorSpecific 也可以使用 命名空间root/wmi下MSStorageDriver_ATAPISmartData类的子集VendorSpecific内存放了硬盘内部芯片存储的所有SMART讯息大小为512Bytes。
获取CPU温度需要调用操作系统提供的API,因此不同操作系统获取方式可能不同。以下是在Windows操作系统下获取CPU温度的示例代码: ```c #include <Windows.h> #include <stdio.h> int main() { // 获取CPU温度 DWORD temperature = 0; DWORD bufferSize = sizeof(temperature); if (RegGetValueA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "~\\Thermal Zone Temperature", RRF_RT_DWORD, NULL, &temperature, &bufferSize) == ERROR_SUCCESS) { float temp = temperature * 0.01 - 273.15; // 将温度值转换为摄氏度 printf("CPU temperature: %.2f ℃\n", temp); } else { printf("Failed to get CPU temperature.\n"); } // 获取硬盘温度 // TODO: 暂未实现 return 0; } ``` 以上代码通过调用`RegGetValueA`函数从注册表中读取CPU温度值,然后将其转换为摄氏度并输出。需要注意的是,不同CPU型号的温度传感器可能有不同的标定值,因此将读取到的数值乘以0.01再减去273.15才能得到正确的温度值。 获取硬盘温度也需要调用操作系统提供的API,以下是在Windows操作系统下获取硬盘温度的示例代码: ```c #include <Windows.h> #include <stdio.h> int main() { // 获取CPU温度 DWORD cpuTemp = 0; DWORD bufferSize = sizeof(cpuTemp); if (RegGetValueA(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "~\\Thermal Zone Temperature", RRF_RT_DWORD, NULL, &cpuTemp, &bufferSize) == ERROR_SUCCESS) { float temp = cpuTemp * 0.01 - 273.15; // 将温度值转换为摄氏度 printf("CPU temperature: %.2f ℃\n", temp); } else { printf("Failed to get CPU temperature.\n"); } // 获取硬盘温度 DWORD driveTemp = 0; HANDLE driveHandle = CreateFileA("\\\\.\\PhysicalDrive0", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (driveHandle != INVALID_HANDLE_VALUE) { if (DeviceIoControl(driveHandle, 0x0C, NULL, 0, &driveTemp, sizeof(driveTemp), NULL, NULL)) { float temp = driveTemp - 273.15; // 将温度值转换为摄氏度 printf("Drive temperature: %.2f ℃\n", temp); } else { printf("Failed to get drive temperature.\n"); } CloseHandle(driveHandle); } else { printf("Failed to open drive.\n"); } return 0; } ``` 以上代码通过调用`CreateFileA`函数打开物理硬盘的句柄,然后调用`DeviceIoControl`函数获取硬盘温度值。需要注意的是,不同硬盘型号的温度传感器可能有不同的标定值,因此需要根据具体硬盘型号进行转换。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值