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

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS SQL Server,基础系列 2核4GB
简介: 原文:Sql Server之旅——第六站 使用winHex利器加深理解数据页           这篇我来介绍一个winhex利器,这个工具网上有介绍,用途大着呢,可以用来玩数据修复,恢复删除文件等等。
原文: Sql Server之旅——第六站 使用winHex利器加深理解数据页

  

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

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

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

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

 

一:准备数据

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

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 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 @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 030000010............... 
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 030000010............... 
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 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语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
12天前
|
SQL 安全 数据处理
揭秘数据脱敏神器:Flink SQL的神秘力量,守护你的数据宝藏!
【9月更文挑战第7天】在大数据时代,数据管理和处理尤为重要,尤其在保障数据安全与隐私方面。本文探讨如何利用Flink SQL实现数据脱敏,为实时数据处理提供有效的隐私保护方案。数据脱敏涉及在处理、存储或传输前对敏感数据进行加密、遮蔽或替换,以遵守数据保护法规(如GDPR)。Flink SQL通过内置函数和表达式支持这一过程。
32 2
|
18天前
|
Java 网络架构 数据格式
Struts 2 携手 RESTful:颠覆传统,重塑Web服务新纪元的史诗级组合!
【8月更文挑战第31天】《Struts 2 与 RESTful 设计:构建现代 Web 服务》介绍如何结合 Struts 2 框架与 RESTful 设计理念,构建高效、可扩展的 Web 服务。Struts 2 的 REST 插件提供简洁的 API 和约定,使开发者能快速创建符合 REST 规范的服务接口。通过在 `struts.xml` 中配置 `<rest>` 命名空间并使用注解如 `@Action`、`@GET` 等,可轻松定义服务路径及 HTTP 方法。
30 0
|
18天前
|
测试技术 Java
全面保障Struts 2应用质量:掌握单元测试与集成测试的关键策略
【8月更文挑战第31天】Struts 2 的测试策略结合了单元测试与集成测试。单元测试聚焦于单个组件(如 Action 类)的功能验证,常用 Mockito 模拟依赖项;集成测试则关注组件间的交互,利用 Cactus 等框架确保框架拦截器和 Action 映射等按预期工作。通过确保高测试覆盖率并定期更新测试用例,可以提升应用的整体稳定性和质量。
32 0
|
18天前
|
数据库 Java 监控
Struts 2 日志管理化身神秘魔法师,洞察应用运行乾坤,演绎奇幻篇章!
【8月更文挑战第31天】在软件开发中,了解应用运行状况至关重要。日志管理作为 Struts 2 应用的关键组件,记录着每个动作和决策,如同监控摄像头,帮助我们迅速定位问题、分析性能和使用情况,为优化提供依据。Struts 2 支持多种日志框架(如 Log4j、Logback),便于配置日志级别、格式和输出位置。通过在 Action 类中添加日志记录,我们能在开发过程中获取详细信息,及时发现并解决问题。合理配置日志不仅有助于调试,还能分析用户行为,提升应用性能和稳定性。
35 0
|
18天前
|
Java 测试技术 容器
从零到英雄:Struts 2 最佳实践——你的Web应用开发超级变身指南!
【8月更文挑战第31天】《Struts 2 最佳实践:从设计到部署的全流程指南》深入介绍如何利用 Struts 2 框架从项目设计到部署的全流程。从初始化配置到采用 MVC 设计模式,再到性能优化与测试,本书详细讲解了如何构建高效、稳定的 Web 应用。通过最佳实践和代码示例,帮助读者掌握 Struts 2 的核心功能,并确保应用的安全性和可维护性。无论是在项目初期还是后期运维,本书都是不可或缺的参考指南。
29 0
|
18天前
|
测试技术 Java
揭秘Struts 2测试的秘密:如何打造无懈可击的Web应用?
【8月更文挑战第31天】在软件开发中,确保代码质量的关键在于全面测试。对于基于Struts 2框架的应用,结合单元测试与集成测试是一种有效的策略。单元测试聚焦于独立组件的功能验证,如Action类的执行逻辑;而集成测试则关注组件间的交互,确保框架各部分协同工作。使用JUnit进行单元测试,可通过简单示例验证Action类的返回值;利用Struts 2 Testing插件进行集成测试,则可模拟HTTP请求,确保Action方法正确处理请求并返回预期结果。这种结合测试的方法不仅提高了代码质量和可靠性,还保证了系统各部分按需协作。
9 0
|
2月前
|
SQL JSON 数据库
influxdb 端点使用http进行sql查询,写数据
influxdb 端点使用http进行sql查询,写数据
157 0
|
1月前
|
SQL 存储 分布式计算
|
30天前
|
SQL 分布式计算 DataWorks
DataWorks产品使用合集之sql查询如何导出全量数据
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。