Archive for the SMBIOS Category

Note: new version DumpSMBIOS for Win7/Win8 , use GetSystemFirmwareTable() API

Posted in BIOS, SMBIOS with tags , on 2014 年 12 月 28 日 by Kun-Yi

多年前, 我剛開始學習BIOS 的相關資訊時, 曾經寫過一個DumpSMBIOS, 程式基本是建立在Legacy BIOS 下面的設定, 所以是從 0xE000 ~ 0xF000 Segments 中去查找相關資訊,

最近因為工作需求, 需要讀取SMBIOS Table 內的相關資訊, 而執行環境又限定在Win7 跟Win 8之上, 所以採用了 GetSystemFirmwareTable() 去讀取, 因為如果是XP SP2 (32bits) 則只能透過WMI介面去讀取了

而GetSystemFiremwareTable MSDN 沒有太多的資訊說明(要自己看memory dump資料判斷), 所以寫了一個測試用的code 放在 github 上, 有需要的人歡迎自取! 基本上是把之前寫的code 稍微改一下就可以用了, 主要是增加 Unicode 的支援, 跟為了相容 VC2013 的型態檢查

下面的資訊是程式在 Win7 32bit/VisualBox 4.3 執行的結果, 也在實機上測試過 Win7/Win8 執行 x64

———————————————————————————————————————————————————–

We need prepare 457 bytes for recevie SMBIOS/DMI Table
SMBIOS version:2.5
DMI Revision:25
Total length: 449
DMI at address aa390
-=======================================================-
========== BIOS information ==========
Vendor: innotek GmbH
Version: VirtualBox
BIOS Starting Segment: 0xE000
Release Date: 12/01/2006
Image Size: 128K
-=======================================================-
========== System information ==========
Manufacturer: innotek GmbH
Product Name: VirtualBox
Version: 1.2
Serial Number: 0
UUID: 0A04CA8F-8B0E-45BD-AB29-F975CACECE29
SKU Number: Null String
Family: Virtual Machine
-=======================================================-
========== Base Board information ==========
Length: 0xF
Manufacturer: Oracle Corporation
Product Name: VirtualBox
Version: 1.2
Serial Number: 0
Asset Tag Number: Null String
Location in Chassis: Null String
-=======================================================-
========== System Enclosure information ==========
Length: 0xD
Manufacturer: Oracle Corporation
Version: Null String
Serial Number: Null String
Asset Tag Number: Null String
-=======================================================-
========== OEM String ==========
OEM String: vboxRev_96996
-=======================================================-
========== BIOS information ==========
Vendor: Null String
Version:
BIOS Starting Segment: 0x6E00
Release Date: i
Image Size: 14080K
System BIOS version: 0.9
EC Firmware version: 0.0

廣告

Note: Dump some SMBIOS information.

Posted in BIOS, SMBIOS on 2010 年 02 月 09 日 by Kun-Yi

字串定址也搞定, 剛剛看了新的 spec.  ver2.6 才發現原本 PNP BIOS的介面已經不被建議(將被捨棄), 以後都採用這種Table/Structure 的結構方式取得系統相關資訊!, 但是Entry Point Structure 在 UEFI系統上有對應的 SMBIOS_GUID 去取得, 而不一定是 F0000h ~ FFFFFh 這個64K 的segment裡了!, 不過我猜應該目前都會在, 維持相容性很重要的!

Update : the program source code & VC2005 project can download from DumpSMBIOS Source

The program use SysInfo driver from CrystalCPUID

// DumpSMBIOS.cpp : Defines the entry point for the console application.
//

#include “stdafx.h"
#include “.SysInfoISysInfo.h"
#include “.SysInfoItemID.h"

typedef ISysInfo* (*_CreateSysInfo) (DWORD);
typedef void (*_DestroySysInfo) (ISysInfo*);
typedef ULONG    (*_MemReadBlock) (ULONG address, UCHAR* data, ULONG count, ULONG unitsize);
_MemReadBlock pfMemReadBlock = NULL;

#pragma pack(push)
#pragma pack(1)

typedef struct {
UCHAR    Signature[4];
UCHAR    Chksum;
UCHAR    Length;
UCHAR    VerMajor;
UCHAR    VerMinor;
UINT16    MaxSize;
UCHAR    EPSRevision;
UCHAR    Formatter[5];
UCHAR    DMISignature[5];
UCHAR    DMIChksum;
UINT16    StructLength;
ULONG    StructAddress;
UINT16    NumStruct;
UCHAR    BCDRevision;
} SMBIOS_EPS, *PSMBIOS_EPS;

// ref. section 3.1.2 in spec.
typedef struct {
UCHAR    Type;
UCHAR    Length;
UINT16    Handle;
} SMBIOS_STRUCT_HEADER, *PSMBIOS_STRUCT_HEADER;

typedef struct _TYPE_0_ {
SMBIOS_STRUCT_HEADER    Header;
UCHAR    Vendor;
UCHAR    Version;
UINT16    StartingAddrSeg;
UCHAR    ReleaseDate;
UCHAR    ROMSize;
ULONG64 Characteristics;
UCHAR    Extension[2]; // spec. 2.3
UCHAR    MajorRelease;
UCHAR    MinorRelease;
UCHAR    ECFirmwareMajor;
UCHAR    ECFirmwareMinor;
} BIOSInfo, *PBIOSInfo;

typedef struct _TYPE_1_ {
SMBIOS_STRUCT_HEADER    Header;
UCHAR    Manufacturer;
UCHAR    ProductName;
UCHAR    Version;
UCHAR    SN;
UCHAR    UUID[16];
UCHAR    WakeUpType;
UCHAR    SKUNumber;
UCHAR    Family;
} SystemInfo, *PSystemInfo;

typedef struct _TYPE_2_ {
SMBIOS_STRUCT_HEADER    Header;
UCHAR    Manufacturer;
UCHAR    Product;
UCHAR    Version;
UCHAR    SN;
UCHAR    AssetTag;

} BoardInfo, *PBoardInfo;

#pragma pack(pop)

UCHAR* toString(const UCHAR* src, int len)
{
static UCHAR buff[256];
memcpy(buff, src, len);
buff[len] = 0;
return buff;
}

void printSMBIOSEPS(SMBIOS_EPS& eps, ULONG addr)
{
printf(“SMBIOS Signature: %s, at 0x%Xn", toString(eps.Signature, 4), addr);
printf(“Checksum: 0x%Xn", eps.Chksum);
printf(“Length: %d(0x%X)n", eps.Length, eps.Length);
printf(“Version: %d.%dn", eps.VerMajor, eps.VerMinor);
printf(“Maximum Structure Size: %d(0x%X)n", eps.MaxSize, eps.MaxSize);
printf(“Entry Point Structure Revision: %dn", eps.EPSRevision);
printf(“Formatter Area: 0x%02X,0x%02X,0x%02X,0x%02X,0x%02Xn",
eps.Formatter[0],eps.Formatter[1],eps.Formatter[2],
eps.Formatter[3],eps.Formatter[4]);
printf(“Intermediate anchor string: %sn", toString(eps.DMISignature, 5));
printf(“Intermediate Checksum: 0x%Xn", eps.DMIChksum);
printf(“Structure Table Length: %dn", eps.StructLength);
printf(“Structure Table Address: 0x%08Xn", eps.StructAddress);
printf(“Number of SMBIOS Structures: %dn", eps.NumStruct);
printf(“BCD Revision: 0x%02Xn", eps.BCDRevision);
}

bool LoadSysInfo(HMODULE &hSysInfoLib, ISysInfo* pISysInfo)
{
hSysInfoLib = LoadLibrary(_T(“SysInfo.dll"));

if (NULL != hSysInfoLib)
{
_CreateSysInfo pCreateSysInfo = (_CreateSysInfo)GetProcAddress(hSysInfoLib, “CreateSysInfo");

if (NULL != pCreateSysInfo)
{
pISysInfo = pCreateSysInfo(MODE_PCI); // request access memory spaces, MODE_PCI
}
else
{
printf(“ERR: Failed in GetProcAddress(“CreateSysInfo")n");
exit(-1);
return false;
}
}
else
{
printf(“Can’t find Sysinfo.dlln");
exit(-1);
return false;
}
return true;
}

bool UnloadSysInfo(HMODULE hSysInfoLib, ISysInfo* pISysInfo)
{
_DestroySysInfo pDestroySysInfo = (_DestroySysInfo)GetProcAddress(hSysInfoLib, “DestroySysInfo");
if (pDestroySysInfo)
{
pDestroySysInfo(pISysInfo);
pISysInfo = NULL;
}
else
{
printf(“ERR: Failed in GetProcAddress(“DestroySysInfo")n");
exit(-1);
return false;
}

FreeLibrary(hSysInfoLib);
hSysInfoLib = NULL;
return true;
}

bool FindSMBIOS(PSMBIOS_EPS& eps, UCHAR* buff, UINT size)
{
UCHAR *p = buff;

for (UINT i = 0; i < size; i+=16)
{
if (0 == memcmp(p, “_SM_", 4))
{
PSMBIOS_EPS psm = (PSMBIOS_EPS)p;

if (0 == memcmp(psm->DMISignature, “_DMI_",5))
{
UCHAR chk = 0;

// verify checksum
for(UINT i=0; i < psm->Length; i++)
{
chk+=*(p+i);
}

if (0 == chk)
{
eps = psm;
return true;
}
}
}
p+=16;
}
return false;
}

const UCHAR* LocateString(UCHAR* str, UINT i)
{
static const UCHAR strNull[] = “Null String";
if (0 == i || 0 == *str) return strNull;

while(–i)
{
str += strlen((char*)str) + 1;
}
return str;
}

UCHAR* toPointString(void* p)
{
return (UCHAR*)p+((PSMBIOS_STRUCT_HEADER)p)->Length;
}

bool ProcBIOSInfo(void* p)
{
PBIOSInfo pBIOSinfo = (PBIOSInfo)p;
UCHAR *str = toPointString(p);

printf(“=============== BIOS information =================n");
printf(“Vendor: %sn", LocateString(str, pBIOSinfo->Vendor));
printf(“Version: %sn", LocateString(str, pBIOSinfo->Version));
printf(“BIOS Starting Segment: 0x%Xn", pBIOSinfo->StartingAddrSeg);
printf(“Release Date: %sn", LocateString(str, pBIOSinfo->ReleaseDate));
printf(“Image Size: %dKn", (pBIOSinfo->ROMSize+1)*64);
if (pBIOSinfo->Header.Length > 0x14)
{   // for spec v2.4 and later
printf(“System BIOS version: %d.%dn", pBIOSinfo->MajorRelease, pBIOSinfo->MinorRelease);
printf(“EC Firmware version: %d.%dn", pBIOSinfo->ECFirmwareMajor, pBIOSinfo->ECFirmwareMinor);
}
return true;
}

bool ProcSysInfo(void* p)
{
PSystemInfo pSysinfo = (PSystemInfo)p;
UCHAR *str = toPointString(p);

printf(“============= System information =============n");
printf(“Manufacturer: %sn", LocateString(str, pSysinfo->Manufacturer));
printf(“Product Name: %sn", LocateString(str, pSysinfo->ProductName));
printf(“Version: %sn", LocateString(str, pSysinfo->Version));
printf(“Serial Number: %sn", LocateString(str, pSysinfo->SN));
// for v2.1 and later
printf(“UUID: %02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02Xn",
pSysinfo->UUID[0], pSysinfo->UUID[1], pSysinfo->UUID[2], pSysinfo->UUID[3],
pSysinfo->UUID[4], pSysinfo->UUID[5], pSysinfo->UUID[6], pSysinfo->UUID[7],
pSysinfo->UUID[8], pSysinfo->UUID[9], pSysinfo->UUID[10], pSysinfo->UUID[11],
pSysinfo->UUID[12], pSysinfo->UUID[13], pSysinfo->UUID[14], pSysinfo->UUID[15]);

if (pSysinfo->Header.Length > 0x19)
{
// fileds for spec. 2.4
printf(“SKU Number: %sn", LocateString(str, pSysinfo->SKUNumber));
printf(“Family: %sn", LocateString(str, pSysinfo->Family));
}
return true;
}

bool ProcBoardInfo(void* p)
{
PBoardInfo pBoardInfo = (PBoardInfo)p;
UCHAR *str = toPointString(p);

printf(“============= Base Board information =============n");
printf(“Manufacturer: %sn", LocateString(str, pBoardInfo->Manufacturer));
printf(“Product Name: %sn", LocateString(str, pBoardInfo->Product));
printf(“Version: %sn", LocateString(str, pBoardInfo->Version));
printf(“Serial Number: %sn", LocateString(str, pBoardInfo->SN));
printf(“Asset Tag Number: %sn", LocateString(str, pBoardInfo->AssetTag));
return true;
}

bool ProcOEMString(void* p)
{
PSMBIOS_STRUCT_HEADER pHdr = (PSMBIOS_STRUCT_HEADER)p;
UCHAR *str = toPointString(p);
printf(“============== OEM String =================n");
printf(“OEM String: %sn", LocateString(str,*(((UCHAR*)p)+4) ));

return true;
}

bool DispatchStructType(PSMBIOS_STRUCT_HEADER hdr)
{
typedef struct {
UCHAR    t;
bool (*Proc)(void* p);
} TPFUNC;

const TPFUNC    tpfunc[] = {
{    0, ProcBIOSInfo        },
{   1, ProcSysInfo        },
{   2, ProcBoardInfo    },
{    11, ProcOEMString    },
};

for (UINT i = 0; i < sizeof(tpfunc)/sizeof(TPFUNC); i++)
{
if (tpfunc[i].t == hdr->Type)
{
printf(“-==============================================-n");
tpfunc[i].Proc((void*)hdr);
return true;
}
}
return false;
}

void DumpSMBIOSStruct(ULONG Addr,UINT Len, UINT Num)
{
UCHAR *pData;
UCHAR *p = NULL;
pData = (UCHAR*)malloc(Len);
if (NULL != pData)
{
pfMemReadBlock(Addr, pData, Len, 1);
p = pData;
}
PSMBIOS_STRUCT_HEADER pHeader;
for (UINT n = 0; n < Num; n++) {
pHeader = (PSMBIOS_STRUCT_HEADER)p;

DispatchStructType(pHeader);

UCHAR *nt = p + pHeader->Length; // point to struct end
while (0 != (*nt | *(nt+1))) nt++;
nt+=2;
if (nt > pData+Len) break;
p = nt;
}

free(pData);
}

int _tmain(int argc, _TCHAR* argv[])
{
ISysInfo* pISysInfo = NULL;
HMODULE hSysInfoLib = NULL;
const ULONG MEM_RANGE = 64*1024; // 0xF0000 ~ 0xFFFFF, 64K
const ULONG MEM_START = 0xF0000;
UCHAR buff[MEM_RANGE];
PSMBIOS_EPS pSMBIOS = NULL;

if (false == LoadSysInfo(hSysInfoLib, pISysInfo))
return -1;

pfMemReadBlock = (_MemReadBlock) GetProcAddress(hSysInfoLib, “_MemReadBlock");
if (pfMemReadBlock)
{
pfMemReadBlock(MEM_START, buff, MEM_RANGE, 1);
FindSMBIOS(pSMBIOS, buff, MEM_RANGE);
}
else
{
printf(“ERR: failed in GetProcAddress(“_MemReadBlock")n");
}

if (pSMBIOS)
{
printf(“Find out the SMBIOS Entry Point Structure n");
printSMBIOSEPS(*pSMBIOS, ((UCHAR*)pSMBIOS – buff) + 0xF0000);
DumpSMBIOSStruct(pSMBIOS->StructAddress, pSMBIOS->StructLength, pSMBIOS->NumStruct);
}
UnloadSysInfo(hSysInfoLib, pISysInfo);
return 0;
}

Result is run the program on Lenovo X60

Find out the SMBIOS Entry Point Structure
SMBIOS Signature: _SM_, at 0xF6730
Checksum: 0x27
Length: 31(0x1F)
Version: 2.4
Maximum Structure Size: 86(0x56)
Entry Point Structure Revision: 0
Formatter Area: 0x00,0x00,0x00,0x00,0x00
Intermediate anchor string: _DMI_
Intermediate Checksum: 0x3E
Structure Table Length: 2241
Structure Table Address: 0x000E0010
Number of SMBIOS Structures: 67
BCD Revision: 0x00
-==============================================-
=============== BIOS information =================
Vendor: LENOVO
Version: 7BETD7WW (2.18 )
BIOS Starting Segment: 0xDC00
Release Date: 11/20/2008
Image Size: 2048K
System BIOS version: 2.24
EC Firmware version: 1.19
-==============================================-
============= System information =============
Manufacturer: LENOVO
Product Name: 1706B69
Version: ThinkPad X60
Serial Number: LVN1422
UUID: XXXXXXXX-XXXX-XXXX-C3117DD70E8C
SKU Number: Null String
Family: ThinkPad X60
-==============================================-
============= Base Board information =============
Manufacturer: LENOVO
Product Name: 1706B69
Version: Not Available
Serial Number: XXXXXXXXX
Asset Tag Number:
-==============================================-
============== OEM String =================
Count:1
OEM String: IBM ThinkPad Embedded Controller -[7BHT40WW-1.13    ]-

Note: Dump SMBIOS Entry Pointer Structure

Posted in BIOS, SMBIOS on 2010 年 02 月 08 日 by Kun-Yi

// DumpSMBIOS.cpp : Defines the entry point for the console
application.
//

#include “stdafx.h"
#include “.SysInfoISysInfo.h"
#include
“.SysInfoItemID.h"

typedef ISysInfo* (*_CreateSysInfo) (DWORD);
typedef void
(*_DestroySysInfo) (ISysInfo*);
typedef ULONG    (*_MemReadBlock) (ULONG
address, UCHAR* data, ULONG count, ULONG unitsize);
_MemReadBlock
pfMemReadBlock = NULL;

#pragma pack(push)
#pragma pack(1)

typedef struct {
UCHAR    Signature[4];
UCHAR    Chksum;

UCHAR    Length;
UCHAR    VerMajor;
UCHAR    VerMinor;

UINT16    MaxSize;
UCHAR    EPSRevision;
UCHAR
Formatter[5];
UCHAR    DMISignature[5];
UCHAR    DMIChksum;

UINT16    StructLength;
ULONG    StructAddress;
UINT16
NumStruct;
UCHAR    BCDRevision;
} SMBIOS_EPS, *PSMBIOS_EPS;

// ref. section 3.1.2 in spec.
typedef struct {
UCHAR
Type;
UCHAR    Length;
UINT16    Handle;
}
SMBIOS_STRUCT_HEADER, *PSMBIOS_STRUCT_HEADER;

typedef struct _TYPE_0_ {
SMBIOS_STRUCT_HEADER    Header;

UCHAR    Vendor;
UCHAR    Version;
UINT16    StartingAddrSeg;
}
BIOSInfo, *PBIOSInfo;

#pragma pack(pop)

UCHAR* toString(const UCHAR* src, int len)
{
static UCHAR
buff[256];
memcpy(buff, src, len);
buff[len] = 0;
return
buff;
}

void printSMBIOSEPS(SMBIOS_EPS& eps, ULONG addr)
{

printf(“SMBIOS Signature: %s, at 0x%Xn", toString(eps.Signature, 4),
addr);
printf(“Checksum: 0x%Xn", eps.Chksum);
printf(“Length:
%d(0x%X)n", eps.Length, eps.Length);
printf(“Version: %d.%dn",
eps.VerMajor, eps.VerMinor);
printf(“Maximum Structure Size: %d(0x%X)n",
eps.MaxSize, eps.MaxSize);
printf(“Entry Point Structure Revision: %dn",
eps.EPSRevision);
printf(“Formatter Area:
0x%02X,0x%02X,0x%02X,0x%02X,0x%02Xn",

eps.Formatter[0],eps.Formatter[1],eps.Formatter[2],

eps.Formatter[3],eps.Formatter[4]);
printf(“Intermediate anchor string:
%sn", toString(eps.DMISignature, 5));
printf(“Intermediate Checksum:
0x%Xn", eps.DMIChksum);
printf(“Structure Table Length: %dn",
eps.StructLength);
printf(“Structure Table Address: 0x%08Xn",
eps.StructAddress);
printf(“Number of SMBIOS Structures: %dn",
eps.NumStruct);
printf(“BCD Revision: 0x%02Xn", eps.BCDRevision);
}

bool LoadSysInfo(HMODULE &hSysInfoLib, ISysInfo* pISysInfo)
{

hSysInfoLib = LoadLibrary(_T(“SysInfo.dll"));

if (NULL != hSysInfoLib)
{
_CreateSysInfo
pCreateSysInfo = (_CreateSysInfo)GetProcAddress(hSysInfoLib, “CreateSysInfo");

if (NULL != pCreateSysInfo)
{
pISysInfo =
pCreateSysInfo(MODE_PCI); // request access memory spaces, MODE_PCI

}
else
{
printf(“ERR: Failed in
GetProcAddress(“CreateSysInfo")n");
exit(-1);

return false;
}
}
else
{

printf(“Can’t find Sysinfo.dlln");
exit(-1);
return
false;
}
return true;
}

bool UnloadSysInfo(HMODULE hSysInfoLib, ISysInfo* pISysInfo)
{

_DestroySysInfo pDestroySysInfo = (_DestroySysInfo)GetProcAddress(hSysInfoLib,
“DestroySysInfo");
if (pDestroySysInfo)
{

pDestroySysInfo(pISysInfo);
pISysInfo = NULL;
}

else
{
printf(“ERR: Failed in
GetProcAddress(“DestroySysInfo")n");
exit(-1);
return
false;
}

FreeLibrary(hSysInfoLib);
hSysInfoLib = NULL;
return
true;
}

bool FindSMBIOS(PSMBIOS_EPS& eps, UCHAR* buff, UINT size)
{

UCHAR *p = buff;

for (UINT i = 0; i < size; i+=16)
{
if (0 ==
memcmp(p, “_SM_", 4))
{
PSMBIOS_EPS psm =
(PSMBIOS_EPS)p;

if (0 == memcmp(psm->DMISignature, “_DMI_",5))

{
UCHAR chk = 0;

// verify checksum
for(UINT i=0; i <
psm->Length; i++)
{

chk+=*(p+i);
}

if (0 == chk)
{
eps
= psm;
return true;
}

}
}
p+=16;
}
return false;
}

void DumpSMBIOSStruct(ULONG Addr,UINT Len, UINT Num)
{
UCHAR
*pData;
UCHAR *p = NULL;
pData = (UCHAR*)malloc(Len);
if
(NULL != pData)
{
pfMemReadBlock(Addr, pData, Len,
1);
p = pData;
}
PSMBIOS_STRUCT_HEADER
pHeader;
for (UINT i = 0; i < Num; i++) {
pHeader =
(PSMBIOS_STRUCT_HEADER)p;
switch(pHeader->Type) {
case
0: {
PBIOSInfo pBIOSinfo = (PBIOSInfo)p;

printf(“BIOS Starting Segment: 0x%X",
pBIOSinfo->StartingAddrSeg);
}

break;
case 1:
break;
}
UCHAR
*nt = p + pHeader->Length; // point to struct end
while (0 != (*nt
| *(nt+1))) nt++;
nt+=2;
if (nt > pData+Len) break; //
over?
p = nt;
}

free(pData);
}

int _tmain(int argc, _TCHAR* argv[])
{
ISysInfo* pISysInfo =
NULL;
HMODULE hSysInfoLib = NULL;
const ULONG MEM_RANGE = 64*1024;
// 0xF0000 ~ 0xFFFFF, 64K
const ULONG MEM_START = 0xF0000;
UCHAR
buff[MEM_RANGE];
PSMBIOS_EPS pSMBIOS = NULL;

if (false == LoadSysInfo(hSysInfoLib, pISysInfo))
return -1;

pfMemReadBlock = (_MemReadBlock) GetProcAddress(hSysInfoLib,
“_MemReadBlock");
if (pfMemReadBlock)
{

pfMemReadBlock(MEM_START, buff, MEM_RANGE, 1);
FindSMBIOS(pSMBIOS,
buff, MEM_RANGE);
}
else
{
printf(“ERR: failed
in GetProcAddress(“_MemReadBlock")n");
}

if (pSMBIOS)
{
printf(“Find out the SMBIOS Entry Point
Structure n");
printSMBIOSEPS(*pSMBIOS, ((UCHAR*)pSMBIOS – buff) +
0xF0000);
DumpSMBIOSStruct(pSMBIOS->StructAddress,
pSMBIOS->StructLength, pSMBIOS->NumStruct);
}

UnloadSysInfo(hSysInfoLib, pISysInfo);
return 0;
}

Result is run the program on Lenovo X60

Find out the SMBIOS Entry Point Structure
SMBIOS Signature: _SM_, at
0xF6730
Checksum: 0x27
Length: 31(0x1F)
Version: 2.4
Maximum
Structure Size: 86(0x56)
Entry Point Structure Revision: 0
Formatter Area:
0x00,0x00,0x00,0x00,0x00
Intermediate anchor string: _DMI_
Intermediate
Checksum: 0x3E
Structure Table Length: 2241
Structure Table Address:
0x000E0010
Number of SMBIOS Structures: 67
BCD Revision: 0x00

這個執行結果SMBIOS Entry Point Structure 在 0F6730h, 而一共有 67個數據體, 頭一個在 0E0010h
的位址

解析 SMBIOS 數據體麻煩的地方是, 在數據體後面還有可能接數個字串(C string). 所以不能直接使用數據體 本身的
length來跳到下一個數據體. 看了 Spec. 的Example 還是有點模糊.需要在花點時間想想怎樣Dump才好!

把數據體與數據體定位搞定了!