Sql Server之旅——第六站 使用winHex利器加深理解数据页

来源:互联网 发布:百度软件助手 skype 编辑:程序博客网 时间:2024/05/22 12:16

   这篇我来介绍一个winhex利器,这个工具网上有介绍,用途大着呢,可以用来玩数据修复,恢复删除文件等等。。。。它能够将一个file解析成

hex形式,这样你就可以对hex进行修改,然后你就可以看到修复后的结果,为什么要在sqlserver系列中说这个呢???很简单呀,sqlserver的DB本

质上也是一个mdf文件,对吧,既然是文件,我就可以利用winhex对它进行随意的修改,然后你也知道sqlserver的数据都是以数据页的形式封装的,

那我就可以修改它的数据页,对不对,这样我就可以随便改变记录的顺序,包括槽位,记录,页头等等。。。说干就干吧!!!

 

一:准备数据

  我计划在数据库中插入三条测试数据,如图:

复制代码
1 DROP TABLE dbo.Person2 3 CREATE TABLE Person(ID INT IDENTITY,NAME VARCHAR(5),Age INT)4 5 INSERT dbo.Person VALUES('amy',20)6 INSERT dbo.Person VALUES('anna',25)7 INSERT dbo.Person VALUES('smart',28)8 9 SELECT * FROM dbo.Person
复制代码

接下来通过上一章介绍的DBCC命令,查看下三条记录的数据页情况,如下图:

DBCC TRACEON(3604)DBCC IND(Ctrip,Person,-1)DBCC PAGE(Ctrip,1,78,2)
复制代码
 1 DATA: 2  3  4 Memory Dump @0x00000000100EA000 5  6 00000000100EA000:   01010400 00800001 00000000 00000c00 †................  7 00000000100EA010:   00000000 00000300 3f000000 551fa500 †........?...U...  8 00000000100EA020:   4e000000 01000000 8e000000 66000000 †N...........f...  9 00000000100EA030:   03000000 00000000 00000000 00000000 †................ 10 00000000100EA040:   01000000 00000000 00000000 00000000 †................ 11 00000000100EA050:   00000000 00000000 00000000 00000000 †................ 12 00000000100EA060:   30000c00 01000000 14000000 030000010............... 13 00000000100EA070:   00160061 6d793000 0c000200 00001900 †...amy0......... 14 00000000100EA080:   00000300 00010017 00616e6e 6130000c †.........anna0.. 15 00000000100EA090:   00030000 001c0000 00030000 01001800 †................ 16 00000000100EA0A0:   736d6172 74000000 00000000 00000000 †smart........... 17 00000000100EA0B0:   00000000 00000000 00000000 00000000 †................ 18 19 ....20               21 00000000100EBFC0:   20202020 20202020 20202020 2020202022 00000000100EBFD0:   20202020 20200000 00000000 00000000 †      .......... 23 00000000100EBFE0:   00000000 00000000 00000000 00000000 †................ 24 00000000100EBFF0:   00000000 00000000 1f0b8d00 76006000 †............v.`. 25 26 OFFSET TABLE:27 28 Row - Offset                         29 2 (0x2) - 141 (0x8d)                 30 1 (0x1) - 118 (0x76)                 31 0 (0x0) - 96 (0x60)   
复制代码

  我想大家现在都清楚了,数据页中的一条条存储记录都是通过页尾的槽位指向的,具体可以参见前几篇对数据页的介绍,比如你看到页尾的:

8d0076006000了吗?要注意,这些都是按照字节逆序来的。

  1. 6000  这个就是slot0,也就是  (0x0) - 96 (0x60)

  2. 0x76  这个就是slot1,也就是(0x1) - 118 (0x76)  

  2. 0x8d  这个就是slot2,也就是(0x2) - 141 (0x8d)  

是不是有点意思,如果你一定要看到slot具体指向的内容,你可以继续用上一节介绍的DBCC命令,一清二楚。

1 DBCC PAGE(Ctrip,1,78,1)
复制代码
PAGE: (1:78)BUFFER:BUF @0x0000000083FD8E00bpage = 0x0000000083ADC000           bhash = 0x0000000000000000           bpageno = (1:78)bdbid = 8                            breferences = 0                      bUse1 = 2495bstat = 0x1c0000b                    blog = 0xbbbbbbbb                    bnext = 0x0000000000000000PAGE HEADER:Page @0x0000000083ADC000m_pageId = (1:78)                    m_headerVersion = 1                  m_type = 1m_typeFlagBits = 0x4                 m_level = 0                          m_flagBits = 0x8000m_objId (AllocUnitId.idObj) = 63     m_indexId (AllocUnitId.idInd) = 256  Metadata: AllocUnitId = 72057594042056704                                 Metadata: PartitionId = 72057594041204736                                 Metadata: IndexId = 0Metadata: ObjectId = 341576255       m_prevPage = (0:0)                   m_nextPage = (0:0)pminlen = 12                         m_slotCnt = 3                        m_freeCnt = 8021m_freeData = 165                     m_reservedCnt = 0                    m_lsn = (142:102:3)m_xactReserved = 0                   m_xdesId = (0:0)                     m_ghostRecCnt = 0m_tornBits = 0                       Allocation StatusGAM (1:2) = ALLOCATED                SGAM (1:3) = ALLOCATED               PFS (1:1) = 0x61 MIXED_EXT ALLOCATED  50_PCT_FULL                         DIFF (1:6) = CHANGEDML (1:7) = NOT MIN_LOGGED            DATA:Slot 0, Offset 0x60, Length 22, DumpStyle BYTERecord Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP VARIABLE_COLUMNSRecord Size = 22                     Memory Dump @0x000000000F7FC0600000000000000000:   30000c00 01000000 14000000 030000010............... 0000000000000010:   00160061 6d79††††††††††††††††††††††††...amy           Slot 1, Offset 0x76, Length 23, DumpStyle BYTERecord Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP VARIABLE_COLUMNSRecord Size = 23                     Memory Dump @0x000000000F7FC0760000000000000000:   30000c00 02000000 19000000 030000010............... 0000000000000010:   00170061 6e6e61††††††††††††††††††††††...anna          Slot 2, Offset 0x8d, Length 24, DumpStyle BYTERecord Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP VARIABLE_COLUMNSRecord Size = 24                     Memory Dump @0x000000000F7FC08D0000000000000000:   30000c00 03000000 1c000000 030000010............... 0000000000000010:   00180073 6d617274 †††††††††††††††††††...smart         OFFSET TABLE:Row - Offset                         2 (0x2) - 141 (0x8d)                 1 (0x1) - 118 (0x76)                 0 (0x0) - 96 (0x60)                  DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。
复制代码

仔细观察下上面的蓝色字体,有没有总结出各个slot槽位对应的记录内容,比如:

  slot0槽位指向的记录内容:  amy =>  616d79。

  slot1槽位指向的记录内容:  anna => 616e6e61。

  slot2槽位指向的记录内容:  smart => 736d617274。

这里你要知道,这里都是16进制表示的,所以2个16进制对应一个字节。

 

二:使用WinHex修改数据

  我们大家都知道,sqlserver引擎会通过扫描slot槽位来呈现数据,就像上面的记录那样,依次扫描slot0...slot1....slot2...来呈现数据,如下图:

上面这个截图没什么稀奇的地方,大家也觉得见怪不怪的,那下面就有一个想法来了,如果我通过winHex来交换slot0和slot1的顺序,那效果会是

怎样???按照常理说,这时候引擎还是按照slot槽位依次扫描,这时候应该会将ID=2的记录先喷出来,然后再喷出ID=1,ID=3。。。事实是不是

这样子呢?好奇吧,我们来看看。。。

 

三:相关步骤

1.  我们知道Ctrip数据库是联机的,我们要修改它必须先脱机,然后再关掉数据页的一致性校验(这个也是数据库的保护机制,防止第三方恶意的去篡

     改数据),这个应该大家都明白,如下图:

 

2.  从网上下载一个破解版的winhex,然后打开本地的Ctrip.mdf文件,调整winhex的编辑模式为默认的可读写,如图:

 

3. 我们知道一个数据页的大小是8KB=8192B,那么第78号数据页的起始位置的偏移量应该就是:78*8192=638976,然后通过快捷键

    Alt+G打开偏移量列表,键入638976,如下图:

 

找到记录的内容之后,我们再来找槽位,槽位的开始位置在78号数据页的末尾,那怎么算呢?这个算法也很简单,offset=79*8192-1=647167。

说干就干。

当你真的找到了偏移量,是不是很兴奋呢?下面要做的就是把60和76交换一下,也就是将slot0和slot1交换,看看怎么样????

 

4. 交换完毕后,ctrl+s保存,然后让Ctrip数据库联机,并使用Sql语句查看下现在的效果???

当你看到这张图的时候,是不是已经疯了。。。。这样我就非常肯定的论证了,引擎真的就是通过依次扫描slot的槽位来指向记录的,如果你

大概理解了上面的操作,现在你可以修改任意数据页的数据了,只要你找得到数据页的偏移量,然后任由你发挥啦~~~~感谢感谢。。。

 

分类: sql server
好文要顶 关注我 收藏该文  
一线码农
关注 - 56
粉丝 - 6490
荣誉:推荐博客
+加关注
9
0
关注我
« 上一篇:Sql Server之旅——第五站 确实不得不说的DBCC命令(文后附年会福利)
» 下一篇:Sql Server之旅——第七站 为什么都说状态少的字段不能建索引
posted @ 2015-01-27 00:55 一线码农 阅读(2075) 评论(13) 编辑 收藏

  
#1楼2015-01-27 07:13 zjeagle  
越来越看不懂了,只能顶一个。
支持(0)反对(0)
  
#2楼[楼主2015-01-27 08:28 一线码农  
@ zjeagle
就是通过winhex,把槽位1和槽位2的引用地址交换下。
支持(0)反对(0)
  
#3楼2015-01-27 09:09 cocosip  
这么做有哪些实际意义?应用场景?
支持(0)反对(0)
  
#4楼[楼主2015-01-27 12:16 一线码农  
@ cocosip
加深理解底层的数据页~
支持(0)反对(0)
  
#5楼2015-01-27 13:10 寻找和谐  
纯支持,确实有深度,暂时还没时间太深入了解,以后有机会再回来拜读
支持(0)反对(0)
  
#6楼2015-01-27 13:24 醉心  
曲高和寡啊
支持(0)反对(0)
  
#7楼2015-01-27 15:52 Jetlian  
已经看不懂了,点个推荐支持一下
支持(0)反对(0)
  
#8楼[楼主2015-01-27 18:06 一线码农  
@ Jetlian
基础知识熬过去了,对后面什么索引啥的会有比较深的理解
支持(0)反对(0)
  
#9楼2015-01-27 18:22 @清道夫  
虽然看不懂,但还是要赞一个
支持(0)反对(0)
  
#10楼2015-01-28 16:44 firstrose  
在LZ这个系列的的启发下,我刚刚修复了一个sql数据库

http://www.cnblogs.com/firstrose/p/4256257.html

请指教
支持(0)反对(0)
  
#11楼2015-02-15 14:44 我是大菠萝  
这在sqlserver的存储引擎中只是很小的一部分。实际应用对场景的限制较多;
首先,DBA不会这么去做,但就是用winhex打开一个上G的数据文件就有风险,更别提还要先脱机了;
其次,博主所修改的仅仅是slot,即便是对于数据,也只能是长度相同的信息,局限性很大;
最后,奉劝各位,这种研究只适用于非生产环境,属个人爱好,实际操作时还需三思;
支持(0)反对(0)
  
#12楼2015-03-29 15:00 pursuer.chen  
工具不错可以拿来玩玩。
支持(0)反对(0)
  
#13楼2015-07-21 16:42 ahdung  
收获良多,谢博主好文。

0 0
原创粉丝点击