共找到4條詞條名為hive的結果 展開

hive

Windows註冊表HIVE文件

hive,指的是Windows註冊表HIVE文件。

Windows註冊表HⅣE文件


hive
hive
相信大家對Windows系統的註冊表(registry)一定都不陌生了,我們可以用系統提供的註冊表編輯器(regedit)來訪問和修改註冊表中的數據。直觀的講,註冊表呈現出來的是圖1所示的形式,它由根鍵(rootkey)、子鍵(subkey)、鍵值(value)和數據(data)組成。數據之間有 類型的分別,常見的有:REG_SZ、字元串型,REG_BINARY、二進位型, REG_DWORD、雙字型,REG_MULTI_SZ、多字元串值型和REG_EXPAND_SZ、長度可變的數據串型。
註冊表相當於Windows系統中所有32位硬體/驅動和32位應用程序的數據文件,是一個系統信息的資料庫。既然是數據文件,那在磁碟上就一定有註冊表的影子的存在。Windows 2000/XP的註冊表文件在系統設置和預設用戶配置數據的情況下,是存放在\系統文件夾 \SYSTEM32\CONFIG目錄下的6個文件,DEFAULT、SAM、SECURITY、SOFTWARE、USERDIFF和SYSTEM中,而用戶的配置信息存放在系統所在磁碟的\Documents and Setting\目錄,包括ntuser.dat,ntuser.ini和ntuser.dat.log。其中每個文件的路徑都由註冊表項HKLM \SYSTEM\CurrentControlSet\Control\HⅣElist下的鍵值指出。
我們看到的註冊表結構是經過註冊表編輯器讀取之後呈現給我們的,其磁碟形式並不是一個簡單的大文件,而是一組稱被為HⅣE的單獨文件形式,HⅣE中文名曰“儲巢”。每個HⅣE文件可以被理解為一棵單獨註冊表樹,就像Windows的PE格式一樣,它也有自己的組織形式。本文的任務就是要分析HⅣE文件的組織形式並完成一個HⅣE格式的分析程序。

註冊表API工作原理簡述


Windows系統提供了大量的API給用戶訪問和修改註冊表中的數據,regedit就是基於這些API所實現的。註冊表API大致分為用戶空間的與內核空間的兩類,一般用戶調用前者,層層調用轉移,由內核的註冊表API再調用文件系統的驅動等,去訪問磁碟上的HⅣE文件,並最終返回請求的數據結果。這個過程有點冗長,但是為了註冊表裡存放數據的安全考慮,損失一些性能表現還是值得的。

HⅣE結構解析


在認識真正的HⅣE文件之前,我們先列舉HⅣE文件的幾個主要特徵。先入為主的將它們呈現出來將有助於我們對其文件組織和數據結構的理解。

註冊表由多個HⅣE文件組成。

一個HⅣE文件由多個巢箱(BIN)組成

HⅣE文件的首部有一個文件頭(基本塊、base block),用於描述這個HⅣE文件的一些全局信息

一個BIN由多個巢室(CELL)組成,

CELL可以分為具體的5種(後面介紹),用於存儲不同的註冊表數據。
本文中,我們並不統一使用HⅣE、BIN和CELL的英文單詞,而是和對應的中文辭彙交替出現。在中文裡,它們分別對應儲巢、巢箱和巢室三個名詞。
一個儲巢被看成是一些稱為塊(block)的分配單元,類似於將磁碟分為簇的形式。根據定義,每一個註冊表塊的大小為4096位元組(4KB),當新的數據要加入到一個儲巢中來時,該儲巢總是按照塊的粒度來增加。一個儲巢的第一個塊是基本塊(base block),包含了有關該儲巢的全局信息,包括一個特徵簽名“regf”,更新序列號,儲巢上一次寫操作發生的時間戳,儲巢格式版本號、檢驗和,以及該儲巢文件的內部文件名等等。下面的_HBASE_BLOCK就是一個基本塊的數據結構還原。
typedef struct _HBASE_BLOCK
{
ULONG Signature;
ULONG Sequence1;
ULONG Sequence2;
LARGE_INTEGER TimeStamp;
ULONG Major;
ULONG Minor;
ULONG Type;
ULONG Format;
ULONG RootCell;
ULONG Length;
ULONG Cluster;
UCHAR name[64];
ULONG Reserved1[99];
ULONG CheckSum;
ULONG Reserved2[894];
ULONG BootType;
ULONG BootRecover;
} HBASE_BLOCK,*PHBASE_BLOCK;
Windows將一個儲巢所存儲的註冊表條目組織在一種稱為巢室的容器中,當一個巢室加入到一個儲巢中,而且該巢室必須經過擴展才能容納該巢室時,系統將創建一個巢箱的分配單元。巢箱是新巢室正好擴展到下一個塊的邊界的大小,系統將巢室的尾部和巢箱的尾部之間的任何空間都看作是空閑空間,因而可以分配其他的巢室。
巢箱也有頭部的標識,包含了一個特殊的簽名“hbin”,一個記錄了該巢箱在儲巢文件中偏移量的域,以及該巢箱的大小。下面是巢箱的數據結構。
typedef struct_HBIN
{
ULONG Signature;
ULONG FileOffset;
ULONG Size;
ULONG Reserved1[2];
LARGE_INTEGERTimeStamp;
ULONG Spare;
} HBIN,*PHBIN;
一個巢室可以容納一個鍵、一個值、一個安全描述符、一列子鍵或者一列鍵值,分別有對應的巢室來存儲數據。在巢室數據的開始之處,有一個數據域描述了該巢室數據的類型,具體的數據結構如下:
鍵巢室,包含了一個註冊表鍵(也稱為鍵節點)的巢室,一個鍵巢室包含一個特徵簽名(對於一個鍵是kn,一個符號鏈接是kl)、該鍵最近一次更新的時間戳、該鍵父鍵巢室的巢室索引、代表該鍵的子鍵的子鍵列表巢室的索引、該鍵的安全描述符巢室索引、一個代表該鍵類名的字元串鍵巢室索引,以及該鍵的名稱。
typedef struct _CM_KEY_NODE
{
USHORT Signature;
USHORT Flags;
LARGE_INTEGER LastWriteTime;
ULONG Spare;
ULONG Parent;
ULONG SubKeyCounts[2];
union
{
struct
{
ULONG SubKeyLists[2];
CHILD_LIST ValueList;
};
ULONG ChildHiveReference[4];
};
ULONG Security;
ULONG Class;
ULONG MaxNameLen: 16;
ULONG UserFlags: 4;
ULONG VirtControlFlags: 4;
ULONG Debug: 8;
ULONG MaxClassLen;
ULONG MaxValueNameLen;
ULONG MaxValueDataLen;
ULONG WorkVar;
USHORT NameLength;
USHORT ClassLength;
PBYTE Name;
}CM_KEY_NODE,*PCM_KEY_NODE;
值巢室,一個巢室,包含了關於一個鍵的值的信息,該巢室包含一個簽名kv,該值的類型,如REG_DWORD或REG_BINARY,以及該值的名稱。一個值巢室也包含了另一個值巢室的索引,後者包含了對前者的數據。
typedef struct _CM_KEY_VALUE
{
WORD Signature;
WORD NameLength;
ULONG DataLength;
ULONG Data;
ULONG Type;
WORD Flags;
WORD Spare;
PWCHAR Name;
} CM_KEY_VALUE,*PCM_KEY_VALUE;
子鍵列表巢室,有一系列的鍵巢室的巢室索引構成的巢室,這些鍵巢室是同一個父鍵下面的所有子鍵。
typedef struct _CM_KEY_INDEX
{
WORD Signature;
WORD Count;
ULONG List[1];
} CM_KEY_INDEX,*PCM_KEY_INDEX;
如果Signature==CM_KEY_FAST_LEAF,簽名為“fl”,或者Signature==CM_KEY_HASH_LEAF,簽名為“hl”,那麼List后是一個結構體:
struct
{
ULONG offset;
ULONG HashKey;
}
否則為:ULONG offset;
值列表巢室,有一系列的值巢室的巢室索引構成的巢室,這些值巢室是同一個父鍵下面的所有值。其數據結構即上文說到的結構。即上面 _CM_KEY_NODE的聯合體中ValueList數據域。
typedef struct _CHILD_LIST
{
ULONG Count;
ULONG List;
} CHILD_LIST,*PCHILD_LIST;
安全描述符巢室,包含了一個安全描述符巢室,其首部的特徵簽名為ks,以及一個引用計數,該引用計數值記錄了所有共享安全描述符的鍵節點數目,多個鍵巢室可以共享同樣的安全描述符巢室。
typedef struct _CM_KEY_SECURITY
{
WORD Signature;
WORD Reserved;
ULONG Flink;
ULONG Blink;
ULONG ReferenceCount;
ULONG DescriptorLength;
SECURITY_DESCRIPTOR_RELATⅣE Descriptor;
} CM_KEY_SECURITY,*PCM_KEY_SECURITY;
儲巢的結構是通過一些鏈接建立起來的,這些鏈接稱為巢室索引(cell index)。每個巢室索引是一個巢室在儲巢文件中的偏移。因此,巢室索引就像是一個指針,從一個巢室指向另一個巢室,配置管理器將巢室索引解釋為相對於儲巢起始處的偏移。因此,假如你想找到子鍵A的鍵巢室,並且A的父鍵是B,那麼就必須先利用B的巢室中的子鍵列表巢室索引,找到包含B的所有子鍵列表的那個巢室,然後再利用該子鍵列表巢室中的巢室索引列表,找到B的每個子鍵的巢室,隨即找到A。
巢室,巢箱和塊之間的區別很容易讓人混淆,所以我們來看一個簡單的註冊表儲巢的布局示例,如圖5。該示例中包含了一個基本塊和兩個巢箱,第一個巢箱是空的,第二個巢箱包含了幾個巢室。該巢室有兩個鍵,一個是根鍵Root,另一個是Root的子鍵——SubKey。Root有兩個值,Val1和 Val2,通過一個子鍵列表巢室,可以定位到根鍵的子鍵,通過一個值列表巢室,可以定位到根鍵的值。第二個巢箱中,空閑的空間屬於空的巢室。

獲得HⅣE文件


知道了HⅣE們的存放位置,自然就想到要把它們抓過來,逐個解剖。抓捕工作看似棘手,但解決起來也很簡單。HⅣE是Windows的重要資源,自啟動以來就只能被系統獨佔訪問。我們換一種思路,在另外一個系統中啟動,如同一台機器上的Linux,那目前系統的HⅣE文件不是就可以訪問了嗎?但是這裡如果你非要在當前系統訪問這個HⅣE文件,就只有求助於文件系統驅動了。後者已經超出了本文的討論範圍,故我們不作考慮。
不過,為了示例學習的需要,我們總希望HⅣE文件能相對簡單一些,讓我們把它的結構看個清楚明白。系統內部的HⅣE文件一般都不太適合,從其文件尺寸已經達到MB級別,就可看出其數據量的巨大。因此,初期我們需要自己建立一個小型的HⅣE以供學習之用。
為了以後敘述的方便,我們在HKLM\SAM下建立了子鍵test_root,然後在test_root下再建立兩個子鍵1test和2test,並且在 1test下新建了五種不同的值,並填寫了相應的數據。然後,用RegSaveKey函數編個小程序,把test_root保存為HⅣE文件。這樣 test_root就變成這個HⅣE文件的根鍵。接下來,我們就可以細細剖析HⅣE文件中每一個部分的結構和功能了。

HⅣE格式實例分析


我們用一個16進位編輯器打開test_root文件,首先就可以看到基本塊的簽名——“regf”字元串,這是registry file的縮寫,標誌它是個註冊表文件...

HⅣE文件讀取程序


基於上面的結構解釋和分析,我們可以寫出一個HⅣE文件的讀取程序。針對上述分析示例的讀取效果,test_root下有子鍵1test_subkey和2test,前者有1_REG_SZ、2_REG_BINARY、3_REG_DWORD、 4_REG_MULIT_SZ和5_REG_EXPAND_SZ 5個鍵值。[]內的是鍵值的類型,()內的是值的長度,以位元組為單位,對於REG_SZ型數據是列印出其unicode的編碼。