基于Win32的GetSystemFirmwareTable获取到的SMBIOS数据简析

我不是什么硬件专业的人员,可最近有个东西实在不能通过其他方式获取硬件信息,setupapi不行,注册表不行,NtQuerySystemInformation也不行,但是因为匹配需要必需要拿到CPU信息,比如CPU名称,实在无奈了。
纠结了很久,只能通过GetSystemFirmwareTable这个函数拿到SMBIOS的Raw数据,其中有CPU的名称,缓存等信息,可因为GetSystemFirmwareTable返回的数据是原始的SMBIOS数据,对我们不懂做硬件的人来说实在看得头大了,网上的资料不是针对的SMBIOS版本老,就是牛头不对马嘴,而且我也实在没心情去看SMBIOS的资料,就找了个最直接的方法,我发现win8的任务管理器有使用GetSystemFirmwareTable来获取系统信息,就操着OD上马了,小小的逆了点东西出来,还是能简单用的。

GetSystemFirmwareTable调用方法我就不说了,无非就是获取长度,然后malloc,再调用GetSystemFirmwareTable获取数据。
GetSystemFirmwareTable获取到的数据是一个RawSMBIOSData结构体:
struct RawSMBIOSData
{
    BYTE Used20CallingMethod;
    BYTE SMBIOSMajorVersion;
    BYTE SMBIOSMinorVersion;
    BYTE DmiRevision;
    DWORD Length;
    BYTE SMBIOSTableData[];
};

第一个BYTE不懂啥意思,后面3个BYTE都是版本标示,然后Length就是SMBIOSTableData的总长度,一般我们需要直接拿到SMBIOS的Raw,就直接忽略过RawSMBIOSData的前8个字节,就是SMBIOSTableData的开始了。
taskmgr是这样写的:
LEA EDI,DWORD PTR DS:[ECX+8]
//ECX = RawSMBIOSData*

忽略过去就是Raw数据,这一堆数据都有一个头,大概是这样的:
struct SMBios_Thunk
{
    BYTE flag;
    BYTE data_offset;
};

flag应该是硬件类型,raw+data_offset是指向一个字符串的指针。
一般一个数据段是这样的:
00 18 00 00 01 02 00 F0 03 0F 80 98 8B 37 01 00  ....?€構7.
00 00 83 0D 05 06 FF FF 41 6D 65 72 69 63 61 6E  ..?American
20 4D 65 67 61 74 72 65 6E 64 73 20 49 6E 63 2E   Megatrends Inc.
00 54 31 30 30 54 41 2E 32 32 30 00 31 31 2F 32  .T100TA.220.11/2
30 2F 32 30 31 33 00 00                          0/2013..


我们可以看到,flag==00,data_offset==0x18,假设PBYTE pv=这个数据段,那*pv=0,*(pv++)= 0x18,pv+ 0x18=American Megatrends Inc......
加上data_offset就是字符串,那中间的那长度0x18-2的数据是什么呢?这个我也不知道,应该就是关于这个硬件的信息吧。。。
那一个段的结尾是什么呢?就是从pv+0x18开始搜索 0x0000,也就是UNICODE字符串的那个结尾,所以我教你一招,直接pv+wcslen(pv+0x18)就是整个段的长度了。
这个段玩了,就是下一个段,还是跟上面这堆字节一样的,处理方式也相同,然后一直遍历到完了就行。
具体硬件通过flag来识别,这个flag的值代表的到底是啥我也不懂。。。

写完这文章后,网上找到一个OEM厂商的SMBIOS代码,我没仔细看,想深入研究的人可以看看:
http://linux.dell.com/libsmbios/main/SmbiosStrategy__Windows_8cpp-source.html

你可能感兴趣的:(基于Win32的GetSystemFirmwareTable获取到的SMBIOS数据简析)