首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

Windows 程式中讀取 BIOS 內容的實作指南

     編輯:關於VC++

前言

在 Windows NT/2000/XP 環境下,作業系統接管了實體記憶體的直接存取,而 BIOS 資料位於實體記憶體的 F000:0000 位置。本文將詳細說明如何透過系統底層 API 映射實體記憶體,從而在應用層讀取 BIOS 資訊。

核心原理

關鍵在於使用 ntdll.dll 中的三個原生 API:

  • ZwOpenSection:開啟實體記憶體區段
  • ZwMapViewOfSection:將實體記憶體映射至當前程序位址空間
  • ZwUnmapViewOfSection:解除映射關聯

關鍵結構定義

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;  // 指向 L"\\Device\\PhysicalMemory"
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;                    // 0x18
    HANDLE RootDirectory;            // 0
    PUNICODE_STRING ObjectName;      // 指向 UNICODE_STRING
    ULONG Attributes;                // 0x40
    PVOID SecurityDescriptor;        // 0
    PVOID SecurityQualityOfService;  // 0
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;

實作範例

以下程式碼示範如何映射 BIOS 區域 (F000:0000 - F000:FFFF):

// 全域函式指標宣告
typedef DWORD (__stdcall *ZWOS)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
typedef DWORD (__stdcall *ZWMV)(HANDLE, HANDLE, PVOID*, ULONG, ULONG, 
                                 PLARGE_INTEGER, PSIZE_T, DWORD, ULONG, ULONG);
typedef DWORD (__stdcall *ZWUMV)(HANDLE, PVOID);

// 主程式邏輯
UNICODE_STRING uStr = {0};
OBJECT_ATTRIBUTES objAttr = {0};
HANDLE hSection = NULL;
DWORD baseAddr = 0;
LARGE_INTEGER offset = {0};
SIZE_T viewSize = 0xFFFF;

wchar_t physMem[] = L"\\Device\\PhysicalMemory";
uStr.Buffer = physMem;
uStr.Length = 0x2C;
uStr.MaximumLength = 0x2E;

objAttr.Length = 24;
objAttr.Attributes = 64;
objAttr.ObjectName = &uStr;

// 載入 ntdll.dll 並取得函式位址
HMODULE hNtdll = LoadLibrary(L"ntdll.dll");
ZWOS ZwOpenS = (ZWOS)GetProcAddress(hNtdll, "ZwOpenSection");
ZWMV ZwMapV  = (ZWMV)GetProcAddress(hNtdll, "ZwMapViewOfSection");
ZWUMV ZwUnmapV = (ZWUMV)GetProcAddress(hNtdll, "ZwUnmapViewOfSection");

// 開啟實體記憶體區段
ZwOpenS(&hSection, 4, &objAttr);

// 映射 BIOS 區域 (0xF0000, 大小 64KB)
offset.LowPart = 0xF0000;
ZwMapV(hSection, (HANDLE)-1, &baseAddr, 0, 0xFFFF, 
       &offset, &viewSize, 1, 0, 2);

// 此時 baseAddr 指向映射後的虛擬位址,可直接讀取 BIOS 內容
// 使用完畢後需呼叫 ZwUnmapViewOfSection 解除映射

注意事項

  • 需具備系統管理員權限才能開啟 \Device\PhysicalMemory
  • Windows Vista 之後版本預設限制此裝置存取,可能需調整安全性原則
  • 直接操作實體記憶體風險極高,錯誤存取可能導致系統當機
  • 現代系統建議使用 WMI (Win32_BIOS) 或 SMBIOS 表格查詢替代

參考資源

本文靈感來源於聯想安裝驗證程式的逆向分析,感謝相關技術人員的間接貢獻。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved