国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > 綜合 > 正文

解剖SQLSERVER 第二篇 對數(shù)據(jù)頁面頭進行逆向(譯)

2024-07-21 02:48:59
字體:
供稿:網(wǎng)友
解剖SQLSERVER 第二篇 對數(shù)據(jù)頁面頭進行逆向(譯)解剖SQLSERVER 第二篇 對數(shù)據(jù)頁面頭進行逆向(譯)

http://imPRove.dk/reverse-engineering-sql-server-page-headers/

在開發(fā)OrcaMDF 的時候第一個挑戰(zhàn)就是解析數(shù)據(jù)頁面頭部,我們知道數(shù)據(jù)頁面分兩部分,96字節(jié)的頁面頭部和8096字節(jié)的數(shù)據(jù)行

大神Paul Randal 寫了一篇文章很好的描述了頁頭結(jié)構(gòu),然而,即使文章描述得很詳細,但是我還是找不出任何關(guān)于頁頭存儲的格式

每一個字段的數(shù)據(jù)類型和他們的順序

我們可以使用DBCC PAGE命令,我填充一些隨機數(shù)據(jù)進去數(shù)據(jù)頁面,然后把頁面dump出來

頁面號是(1:101):

DBCC TRACEON (3604)DBCC PAGE (TextTest, 1, 101, 2)

結(jié)果分兩部分,首先,我們獲得DBCC PAGE已經(jīng)格式化好的頁面內(nèi)容,dump出來的內(nèi)容的第二部分是96字節(jié)的頁面頭

開始動手了,我們需要找出頁面頭部的這些數(shù)據(jù)值對應(yīng)的數(shù)據(jù)類型是什么

為了簡單,我們需要關(guān)注一些唯一值以便我們不會獲取到某些存在含糊的數(shù)值

我們從m_freeCnt這個字段開始,我們看到m_freeCnt的值是4066,而數(shù)據(jù)行大小是8060,所以很明顯,m_freeCnt的數(shù)據(jù)類型不可能是tinyint

m_freeCnt不太可能使用int類型,一種有依據(jù)的猜測是m_freeCnt有可能使用smallint類型,這讓數(shù)據(jù)行足夠容納0-8060 字節(jié)空間的數(shù)據(jù)

smallint:從-2^15(-32,768)到2^15-1(32,767)的整數(shù)數(shù)據(jù)存儲大小為 2 個字節(jié),本人也覺得m_freeCnt這個字段的值不可能太大

現(xiàn)在,4066這個十進制數(shù)換成十六進制是0x0FE2. 字節(jié)交換,變成0xE20F,現(xiàn)在我們知道,我們已經(jīng)匹配到m_freeCnt的數(shù)據(jù)類型了

另外,我們已經(jīng)知道頁頭里面第一個字段的數(shù)據(jù)類型和位置

/*    Bytes    Content    -----    -------    00-27    ?    28-29    FreeCnt (smallint)    30-95    ?*/

繼續(xù)我們的查找,我們看到m_freeData =3895,換算成十六進制是0x0F37 字節(jié)交換后0x370F

我們發(fā)現(xiàn)m_freeCnt這個字段存儲在m_freeCnt的后面

使用這個技巧,我們能匹配存儲在頁頭的并且沒有含糊的唯一數(shù)據(jù)值

不過 ,對于m_level這個字段,他跟m_xactReserved字段,m_reservedCnt字段,m_GhostRecCnt字段的值是一樣的

我們怎麼知道0這個值哪個才屬于m_level字段? 并且我們怎麼找出他的數(shù)據(jù)類型呢?這有可能是tinyint 到bigint類型

我們請出Visual Studio大神,然后shutdown SQLSERVER

把mdf文件拖入VS,VS會打開hex編輯器,我們根據(jù)頁面偏移算出頁面位置

101 * 8192 = 827,392

看著紅色框給我們標出的字節(jié)內(nèi)容,他已經(jīng)標識出我們的頁面頭內(nèi)容,并且確定了我們已經(jīng)跳轉(zhuǎn)到正確的位置

現(xiàn)在我們會填一些數(shù)值進去mdf文件里面然后保存文件,請不要胡亂在生產(chǎn)數(shù)據(jù)庫上進行測試

現(xiàn)在我們啟動SQLSERVER,然后再次運行DBCC PAGE命令

DBCC TRACEON (3604)DBCC PAGE (TextTest, 1, 101, 2)

可以注意到,現(xiàn)在頁面頭變成了這樣

有幾個數(shù)值變了,m_xactReserved 字段先前的數(shù)值是0,現(xiàn)在變成了30806,將這個數(shù)字轉(zhuǎn)換成十六進制并進行字節(jié)交換得到0x5678

看一下頁面頭,現(xiàn)在我們已經(jīng)識別出另外一個字段的值和數(shù)據(jù)類型(smallint)

我們更新一下我們頁頭表格

/*    Bytes    Content    -----    -------    00-27    ?    28-29    FreeCnt (smallint)    30-49    ?    50-51    XactReserved (smallint)    30-95    ?*/

沿著這種方法繼續(xù),把頁頭進行混亂修改,將修改后的頁頭和DBCC PAGE的輸出進行關(guān)聯(lián),有可能找出這些字段的數(shù)據(jù)類型

如果你看到下面的消息,你就知道已經(jīng)把頁面頭部搞混亂了

你應(yīng)該覺得自豪的,沒有人能修好你胡亂修改出來的錯誤

我已經(jīng)編好了一個頁頭結(jié)構(gòu)表

/*    Bytes    Content    -----    -------    00    HeaderVersion (tinyint)    01    Type (tinyint)    02    TypeFlagBits (tinyint)    03    Level (tinyint)    04-05    FlagBits (smallint)    06-07    IndexID (smallint)    08-11    PreviousPageID (int)    12-13    PreviousFileID (smallint)    14-15    Pminlen (smallint)    16-19    NextPageID (int)    20-21    NextPageFileID (smallint)    22-23    SlotCnt (smallint)    24-27    ObjectID (int)    28-29    FreeCnt (smallint)    30-31    FreeData (smallint)    32-35    PageID (int)    36-37    FileID (smallint)    38-39    ReservedCnt (smallint)    40-43    Lsn1 (int)    44-47    Lsn2 (int)    48-49    Lsn3 (smallint)    50-51    XactReserved (smallint)    52-55    XdesIDPart2 (int)    56-57    XdesIDPart1 (smallint)    58-59    GhostRecCnt (smallint)    60-95    ?*/

我不確定頁頭的其他字節(jié)跟DBCC PAGE輸出的字段對應(yīng)關(guān)系,我測試過的所有頁面這些字節(jié)似乎都存儲為0

我認為這些應(yīng)該都是為將來某種用途使用的保留字節(jié)。好了, 我們已經(jīng)獲得頁頭格式,讀取每個字段就很簡單了

HeaderVersion = header[0];Type = (PageType)header[1];TypeFlagBits = header[2];Level = header[3];FlagBits = BitConverter.ToInt16(header, 4);IndexID = BitConverter.ToInt16(header, 6);PreviousPage = new PagePointer(BitConverter.ToInt16(header, 12), BitConverter.ToInt32(header, 8));Pminlen = BitConverter.ToInt16(header, 14);NextPage = new PagePointer(BitConverter.ToInt16(header, 20), BitConverter.ToInt32(header, 16));SlotCnt = BitConverter.ToInt16(header, 22);ObjectID = BitConverter.ToInt32(header, 24);FreeCnt = BitConverter.ToInt16(header, 28);FreeData = BitConverter.ToInt16(header, 30);Pointer = new PagePointer(BitConverter.ToInt16(header, 36), BitConverter.ToInt32(header, 32));ReservedCnt = BitConverter.ToInt16(header, 38);Lsn = "(" + BitConverter.ToInt32(header, 40) + ":" + BitConverter.ToInt32(header, 44) + ":" + BitConverter.ToInt16(header, 48) + ")";XactReserved = BitConverter.ToInt16(header, 50);XdesID = "(" + BitConverter.ToInt16(header, 56) + ":" + BitConverter.ToInt32(header, 52) + ")";GhostRecCnt = BitConverter.ToInt16(header, 58);

大家可以看一下我寫的pageheader類

using System;using System.Text;namespace OrcaMDF.Core.Engine.Pages{public class PageHeader{public short FreeCnt { get; private set; }public short FreeData { get; private set; }public short FlagBits { get; private set; }public string Lsn { get; private set; }public int ObjectID { get; private set; }public PageType Type { get; private set; }public short Pminlen { get; private set; }public short IndexID { get; private set; }public byte TypeFlagBits { get; private set; }public short SlotCnt { get; private set; }public string XdesID { get; private set; }public short XactReserved { get; private set; }public short ReservedCnt { get; private set; }public byte Level { get; private set; }public byte HeaderVersion { get; private set; }public short GhostRecCnt { get; private set; }public PagePointer NextPage { get; private set; }public PagePointer PreviousPage { get; private set; }public PagePointer Pointer { get; private set; }public PageHeader(byte[] header){if (header.Length != 96)throw new ArgumentException("Header length must be 96.");/*                Bytes    Content                -----    -------                00        HeaderVersion (tinyint)                01        Type (tinyint)                02        TypeFlagBits (tinyint)                03        Level (tinyint)                04-05    FlagBits (smallint)                06-07    IndexID (smallint)                08-11    PreviousPageID (int)                12-13    PreviousFileID (smallint)                14-15    Pminlen (smallint)                16-19    NextPageID (int)                20-21    NextPageFileID (smallint)                22-23    SlotCnt (smallint)                24-27    ObjectID (int)                28-29    FreeCnt (smallint)                30-31    FreeData (smallint)                32-35    PageID (int)                36-37    FileID (smallint)                38-39    ReservedCnt (smallint)                40-43    Lsn1 (int)                44-47    Lsn2 (int)                48-49    Lsn3 (smallint)                50-51    XactReserved (smallint)                52-55    XdesIDPart2 (int)                56-57    XdesIDPart1 (smallint)                58-59    GhostRecCnt (smallint)                60-63    Checksum/Tornbits (int)                64-95    ?            */HeaderVersion = header[0];Type = (PageType)header[1];TypeFlagBits = header[2];Level = header[3];FlagBits = BitConverter.ToInt16(header, 4);IndexID = BitConverter.ToInt16(header, 6);PreviousPage = new PagePointer(BitConverter.ToInt16(header, 12), BitConverter.ToInt32(header, 8));Pminlen = BitConverter.ToInt16(header, 14);NextPage = new PagePointer(BitConverter.ToInt16(header, 20), BitConverter.ToInt32(header, 16));SlotCnt = BitConverter.ToInt16(header, 22);ObjectID = BitConverter.ToInt32(header, 24);FreeCnt = BitConverter.ToInt16(header, 28);FreeData = BitConverter.ToInt16(header, 30);Pointer = new PagePointer(BitConverter.ToInt16(header, 36), BitConverter.ToInt32(header, 32));ReservedCnt = BitConverter.ToInt16(header, 38);Lsn = "(" + BitConverter.ToInt32(header, 40) + ":" + BitConverter.ToInt32(header, 44) + ":" + BitConverter.ToInt16(header, 48) + ")";XactReserved = BitConverter.ToInt16(header
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 荣成市| 洪江市| 黄冈市| 遵义县| 英超| 惠水县| 西青区| 深水埗区| 南昌市| 星子县| 晋江市| 维西| 苏尼特左旗| 涿州市| 洪江市| 化德县| 德阳市| 海阳市| 普兰店市| 措美县| 徐州市| 濮阳市| 两当县| 仙居县| 祁阳县| 彭水| 固安县| 诏安县| 兴隆县| 华坪县| 巩义市| 天镇县| 马龙县| 鸡泽县| 康马县| 财经| 井陉县| 四川省| 班戈县| 延庆县| 镇原县|