SQL Server之旅(6):使用winHex利器加深理解數據頁

cwf8 9年前發布 | 9K 次閱讀 SQL Server 數據庫服務器

原文出處: 一線碼農

這篇我來介紹一個winhex利器,這個工具網上有介紹,用途大著呢,可以用來玩數據修復,恢復刪除文件等等。。。。它能夠將一個file解析成hex形式,這樣你就可以對hex進行修改,然后你就可以看到修復后的結果,為什么要在sqlserver系列中說這個呢???很簡單呀,sqlserver的DB本質上也是一個mdf文件,對吧,既然是文件,我就可以利用winhex對它進行隨意的修改,然后你也知道sqlserver的數據都是以數據頁的形式封裝的,那我就可以修改它的數據頁,對不對,這樣我就可以隨便改變記錄的順序,包括槽位,記錄,頁頭等等。。。說干就干吧!!!

一:準備數據

我計劃在數據庫中插入三條測試數據,如圖:

DROP TABLE dbo.Person

CREATE TABLE Person(ID INT IDENTITY,NAME VARCHAR(5),Age INT)

INSERT dbo.Person VALUES('amy',20)
INSERT dbo.Person VALUES('anna',25)
INSERT dbo.Person VALUES('smart',28)

SELECT * FROM dbo.Person

接下來通過上一章介紹的DBCC命令,查看下三條記錄的數據頁情況,如下圖:

DBCC TRACEON(3604)
DBCC IND(Ctrip,Person,-1)
DBCC PAGE(Ctrip,1,78,2)
DATA:


Memory Dump @0x00000000100EA000

00000000100EA000:   01010400 00800001 00000000 00000c00 ?................ 
00000000100EA010:   00000000 00000300 3f000000 551fa500 ?........?...U... 
00000000100EA020:   4e000000 01000000 8e000000 66000000 ?N...........f... 
00000000100EA030:   03000000 00000000 00000000 00000000 ?................ 
00000000100EA040:   01000000 00000000 00000000 00000000 ?................ 
00000000100EA050:   00000000 00000000 00000000 00000000 ?................ 
00000000100EA060:   30000c00 01000000 14000000 03000001 ?0............... 
00000000100EA070:   00160061 6d793000 0c000200 00001900 ?...amy0......... 
00000000100EA080:   00000300 00010017 00616e6e 6130000c ?.........anna0.. 
00000000100EA090:   00030000 001c0000 00030000 01001800 ?................ 
00000000100EA0A0:   736d6172 74000000 00000000 00000000 ?smart........... 
00000000100EA0B0:   00000000 00000000 00000000 00000000 ?................ 

....

00000000100EBFC0:   20202020 20202020 20202020 20202020 ?                 
00000000100EBFD0:   20202020 20200000 00000000 00000000 ?      .......... 
00000000100EBFE0:   00000000 00000000 00000000 00000000 ?................ 
00000000100EBFF0:   00000000 00000000 1f0b8d00 76006000 ?............v.`. 

OFFSET TABLE:

Row - Offset                         
2 (0x2) - 141 (0x8d)                 
1 (0x1) - 118 (0x76)                 
0 (0x0) - 96 (0x60)

我想大家現在都清楚了,數據頁中的一條條存儲記錄都是通過頁尾的槽位指向的,具體可以參見前幾篇對數據頁的介紹,比如你看到頁尾的:

8d0076006000了嗎?要注意,這些都是按照字節逆序來的。

1. 6000 這個就是slot0,也就是 (0×0) – 96 (0×60)

2. 0×76 這個就是slot1,也就是(0×1) – 118 (0×76)

2. 0x8d 這個就是slot2,也就是(0×2) – 141 (0x8d)

是不是有點意思,如果你一定要看到slot具體指向的內容,你可以繼續用上一節介紹的DBCC命令,一清二楚。

DBCC PAGE(Ctrip,1,78,1)
PAGE: (1:78)


BUFFER:


BUF @0x0000000083FD8E00

bpage = 0x0000000083ADC000           bhash = 0x0000000000000000           bpageno = (1:78)
bdbid = 8                            breferences = 0                      bUse1 = 2495
bstat = 0x1c0000b                    blog = 0xbbbbbbbb                    bnext = 0x0000000000000000

PAGE HEADER:


Page @0x0000000083ADC000

m_pageId = (1:78)                    m_headerVersion = 1                  m_type = 1
m_typeFlagBits = 0x4                 m_level = 0                          m_flagBits = 0x8000
m_objId (AllocUnitId.idObj) = 63     m_indexId (AllocUnitId.idInd) = 256  
Metadata: AllocUnitId = 72057594042056704                                 
Metadata: PartitionId = 72057594041204736                                 Metadata: IndexId = 0
Metadata: ObjectId = 341576255       m_prevPage = (0:0)                   m_nextPage = (0:0)
pminlen = 12                         m_slotCnt = 3                        m_freeCnt = 8021
m_freeData = 165                     m_reservedCnt = 0                    m_lsn = (142:102:3)
m_xactReserved = 0                   m_xdesId = (0:0)                     m_ghostRecCnt = 0
m_tornBits = 0                       

Allocation Status

GAM (1:2) = ALLOCATED                SGAM (1:3) = ALLOCATED               
PFS (1:1) = 0x61 MIXED_EXT ALLOCATED  50_PCT_FULL                         DIFF (1:6) = CHANGED
ML (1:7) = NOT MIN_LOGGED            

DATA:


Slot 0, Offset 0x60, Length 22, DumpStyle BYTE

Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS
Record Size = 22                     
Memory Dump @0x000000000F7FC060

0000000000000000:   30000c00 01000000 14000000 03000001 ?0............... 
0000000000000010:   00160061 6d79????????????????????????...amy           

Slot 1, Offset 0x76, Length 23, DumpStyle BYTE

Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS
Record Size = 23                     
Memory Dump @0x000000000F7FC076

0000000000000000:   30000c00 02000000 19000000 03000001 ?0............... 
0000000000000010:   00170061 6e6e61??????????????????????...anna          

Slot 2, Offset 0x8d, Length 24, DumpStyle BYTE

Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS
Record Size = 24                     
Memory Dump @0x000000000F7FC08D

0000000000000000:   30000c00 03000000 1c000000 03000001 ?0............... 
0000000000000010:   00180073 6d617274 ???????????????????...smart         

OFFSET TABLE:

Row - Offset                         
(0x2) - 141 (0x8d)                 
(0x1) - 118 (0x76)                 
(0x0) - 96 (0x60)                  


DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。

仔細觀察下上面的藍色字體,有沒有總結出各個slot槽位對應的記錄內容,比如:

slot0槽位指向的記錄內容: amy => 616d79。

slot1槽位指向的記錄內容: anna => 616e6e61。

slot2槽位指向的記錄內容: smart => 736d617274。

這里你要知道,這里都是16進制表示的,所以2個16進制對應一個字節。

二:使用WinHex修改數據

我們大家都知道,sqlserver引擎會通過掃描slot槽位來呈現數據,就像上面的記錄那樣,依次掃描slot0…slot1….slot2…來呈現數據,如下圖:

 SQL Server之旅(6):使用winHex利器加深理解數據頁

上面這個截圖沒什么稀奇的地方,大家也覺得見怪不怪的,那下面就有一個想法來了,如果我通過winHex來交換slot0和slot1的順序,那效果會是怎樣???按照常理說,這時候引擎還是按照slot槽位依次掃描,這時候應該會將ID=2的記錄先噴出來,然后再噴出ID=1,ID=3。。。事實是不是這樣子呢?好奇吧,我們來看看。。。

三:相關步驟

1. 我們知道Ctrip數據庫是聯機的,我們要修改它必須先脫機,然后再關掉數據頁的一致性校驗(這個也是數據庫的保護機制,防止第三方惡意的去篡改數據),這個應該大家都明白,如下圖:

 SQL Server之旅(6):使用winHex利器加深理解數據頁

2. 從網上下載一個破解版的winhex,然后打開本地的Ctrip.mdf文件,調整winhex的編輯模式為默認的可讀寫,如圖:

 SQL Server之旅(6):使用winHex利器加深理解數據頁

3. 我們知道一個數據頁的大小是8KB=8192B,那么第78號數據頁的起始位置的偏移量應該就是:78*8192=638976,然后通過快捷鍵Alt+G打開偏移量列表,鍵入638976,如下圖:

 SQL Server之旅(6):使用winHex利器加深理解數據頁

找到記錄的內容之后,我們再來找槽位,槽位的開始位置在78號數據頁的末尾,那怎么算呢?這個算法也很簡單,offset=79*8192-1=647167。說干就干。

 SQL Server之旅(6):使用winHex利器加深理解數據頁

當你真的找到了偏移量,是不是很興奮呢?下面要做的就是把60和76交換一下,也就是將slot0和slot1交換,看看怎么樣????

4. 交換完畢后,ctrl+s保存,然后讓Ctrip數據庫聯機,并使用Sql語句查看下現在的效果???

 SQL Server之旅(6):使用winHex利器加深理解數據頁

當你看到這張圖的時候,是不是已經瘋了。。。。這樣我就非常肯定的論證了,引擎真的就是通過依次掃描slot的槽位來指向記錄的,如果你大概理解了上面的操作,現在你可以修改任意數據頁的數據了,只要你找得到數據頁的偏移量,然后任由你發揮啦~~~~感謝感謝。。。

 本文由用戶 cwf8 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!