好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

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

 1   DROP   TABLE   dbo.Person
  2  
 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   03000001  † 0  ............... 
  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   20202020   †                 
  22  00000000100EBFD0:    20202020   20200000   00000000   00000000   †      .......... 
  23  00000000100EBFE0:    00000000   00000000   00000000   00000000   †................ 
  24  00000000100EBFF0:    00000000   00000000  1f0b 8d00  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 )   

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

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

  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   @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 :    001600 61     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 :    001700 61     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 :    001800 73     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之旅——第六站 使用winHex利器加深理解数据页

标签:

查看更多关于Sql Server之旅——第六站 使用winHex利器加深理解数据页的详细内容...

  阅读:31次