序
写这篇文章主要是有助于加深了解数据块的结构,行数据是怎么在块中进行存储的,通过使用bbed和非bbed的方式来修改块
首先找到这行数据存储的位置
set lines 222
col c2_hex for a50
select c2,dump(c2,16) c2_hex,
dbms_rowid.rowid_relative_fno(rowid) file#,
dbms_rowid.rowid_block_number(rowid) block#,
dbms_rowid.rowid_row_number(rowid) row#
from test_char
where c2=' zhang san ';
C2 C2_HEX FILE# BLOCK# ROW#
-------------------- -------------------------------------------------- ---------- ---------- ----------
zhang san Typ=1 Len=11: 20,7a,68,61,6e,67,20,73,61,6e,20 2 150 0
块结构
struct kcbh, 20 bytes @0 ub1 type_kcbh @0 ub1 frmt_kcbh @1 ub2 wrp2_kcbh @2 ub4 rdba_kcbh @4 ub4 bas_kcbh @8 ub2 wrp_kcbh @12 ub1 seq_kcbh @14 ub1 flg_kcbh @15 ub2 chkval_kcbh @16 ub2 spare3_kcbh @18 struct ktbbh, 72 bytes @20 ub1 ktbbhtyp @20 union ktbbhsid, 4 bytes @24 struct ktbbhcsc, 8 bytes @28 sb2 ktbbhict @36 ub1 ktbbhflg @38 ub1 ktbbhfsl @39 ub4 ktbbhfnx @40 struct ktbbhitl[2], 48 bytes @44 struct kdbh, 14 bytes @100 ub1 kdbhflag @100 sb1 kdbhntab @101 sb2 kdbhnrow @102 sb2 kdbhfrre @104 sb2 kdbhfsbo @106 sb2 kdbhfseo @108 sb2 kdbhavsp @110 sb2 kdbhtosp @112 struct kdbt[1], 4 bytes @114 sb2 kdbtoffs @114 sb2 kdbtnrow @116 sb2 kdbr[2] @118 ub1 freespace[7999] @122 ub1 rowdata[67] @8121 ub4 tailchk @8188
修改数据
有bbed情况下修改
1.找到数据块file# 2 ,block# 150
2.找到row# 0的偏移量kdbr[0]
3.找到col1的偏移量
4.修改数据
# 设置当前数据块,2号文件150号块
BBED> set dba 2,150
DBA 0x00800096 (8388758 2,150)
# 设置第0行数据位置
BBED> p *kdbr[0]
rowdata[31]
-----------
ub1 rowdata[31] @8152 0x2c
# 查看第0行数据,可以看到col1的数据和dump出的内容一致
BBED> x /r
rowdata[31] @8152
-----------
flag@8152: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8153: 0x01
cols@8154: 2
col 0[20] @8155: 0x20 0x7a 0x68 0x61 0x6e 0x67 0x20 0x73 0x61 0x6e
0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20
col 1[11] @8176: 0x20 0x7a 0x68 0x61 0x6e 0x67 0x20 0x73 0x61 0x6e
0x20
# 可以格式化内容查看
col data_type for a40
select '/r'||listagg(
case data_type
when 'NUMBER' then 'n'
when 'DATE' then 't'
else 'c'
end,
''
) within group (order by column_id) as data_type
from dba_tab_columns where table_name='TEST_CHAR';
DATA_TYPE
----------------------------------------
/rcc
BBED> x /rcc
rowdata[31] @8152
-----------
flag@8152: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8153: 0x01
cols@8154: 2
col 0[20] @8155: zhang san
col 1[11] @8176: zhang san
# 现在我们修改第二个字段内容,将` zhang san `,修改为`li si`,张冠李戴一下,修改的数据不要超过原有数据长度
# 设置第二个字段的数据位置
BBED> set offset 8176
OFFSET 8176
# dump查看一下数据是否正确,第一个字节为数据长度0x0b为11个字节
BBED> d /v count 12
File: /oradata/ORCL/bbed.dbf (2)
Block: 150 Offsets: 8176 to 8187 Dba:0x00800096
-------------------------------------------------------
0b207a68 616e6720 73616e20 l . zhang san
<16 bytes per line>
# 现在让我们获取下li si的16进制
SQL> select dump('li si',16) from dual;
DUMP('LISI',16)
----------------------------
Typ=96 Len=5: 6c,69,20,73,69
# 修改字节太多报错,把它拆开修改吧
BBED> m /x 0x056c69207369
BBED-00209: invalid number (0x056c69207369)
# 修改前3个字节
BBED> m /x 0x056c69
Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) y
File: /oradata/ORCL/bbed.dbf (2)
Block: 150 Offsets: 8176 to 8186 Dba:0x00800096
------------------------------------------------------------------------
056c6968 616e6720 73616e
<32 bytes per line>
# 修改后三个字节
BBED> m /x 0x207369 offset 8179
File: /oradata/ORCL/bbed.dbf (2)
Block: 150 Offsets: 8179 to 8189 Dba:0x00800096
------------------------------------------------------------------------
20736967 2073616e 200106
# 查看修改是否正确
BBED> d /v count 11 offset 8176
File: /oradata/ORCL/bbed.dbf (2)
Block: 150 Offsets: 8176 to 8186 Dba:0x00800096
-------------------------------------------------------
056c6920 73696720 73616e l .li sig san
<16 bytes per line>
# 应用修改
BBED> sum apply
Check value for File 2, Block 150:
current = 0xb9df, required = 0xb9df
# 现在让我们在数据库查询下下修改是否正确
SQL> alter system flush buffer_cache;
System altered.
SQL> select * from test_char;
C1 C2
-------------------- --------------------
zhang san li si
南昌 南昌
无bbed情况下修改
散修虽比不上名门正派,但也各有奇招,现在将li si重新修改为zhang san
1.找到kdbr的开始位置,开始位置为44 + ITC*24 + 8 + 14 + 4=70 + ITC*24,ITC记录在ktbbh.ktbbhict 也就是offset 36的位置,2个字节表示
2.找到有多少行数据,kdbh.kdbhnrow 位置44 + ITC*24 + 8 + 2 = 54 + ITC*24,2个字节表示
3.找到行数据存放位置,位置为kdbr 记录的位置+以下偏移量
对于ASSM:20+48+8+(ITC-1) *24 = 52 + ITC * 24
对于MSSM:20+48+ (ITC-1) *24 = 44 + ITC * 24
4.修改数据
5.修改checksum值
# 查看ITC数量,看到0x021f,怎么对不上,然后我去看了其他块,像3个ITC的显示0x0300,4个ITC的显示0x0400
# 这里应该是这个块是被复用的,所以有残留数据,这里还是2个事务槽
[oracle@cesdb3 ~]$ od -A x -t x1z -v -j $((8192 * 150 + 36)) -N 2 /oradata/ORCL/bbed.dbf
12c024 02 1f >..<
# 那么经过计算kdbr的开始位置是118=70 + ITC*24,那么多少行数据呢
行数是记录在kdbh.kdbhnrow,位置44 + ITC*24 + 8 + 2 = 54 + ITC*24
行数记录在kdbh.kdbhnrow,offset 102,2个字节表示
#这里是2行数据,0x0200
[oracle@cesdb3 ~]$ od -A x -t x1z -v -j $((8192 * 150 + 102)) -N 2 /oradata/ORCL/bbed.dbf
12c066 02 00 >..<
#那么数据行的存放字典我们就知道了
#从offset 118 - 121
[oracle@cesdb3 ~]$ od -A x -t x1z -v -j $((8192 * 150 + 118)) -N 4 /oradata/ORCL/bbed.dbf
12c076 74 1f 55 1f >t.U.< >....<
[oracle@cesdb3 ~]$ echo "74 1f" | awk '{printf "%d\n", strtonum("0x" $2 $1)}'
8052
# 需要在这基础上+100偏移量=52 + ITC * 24
[oracle@cesdb3 ~]$ od -A x -t x1z -v -j $((8192 * 150 + 8152)) -N 40 /oradata/ORCL/bbed.dbf
12dfd8 2c 01 02 14 20 7a 68 61 6e 67 20 73 61 6e 20 20 >,... zhang san <
12dfe8 20 20 20 20 20 20 20 20 05 6c 69 20 73 69 67 20 > .li sig <
12dff8 73 61 6e 20 01 06 ca e9 >san ....<
# 找到第二个字段的位置 8152 + 3 + 1 + 20 = 8176
flag lock cols collen data
1 1 1 1
[oracle@cesdb3 ~]$ od -A x -t x1z -v -j $((8192 * 150 + 8176)) -N 20 /oradata/ORCL/bbed.dbf
12dff0 05 6c 69 20 73 69 67 20 73 61 6e 20 01 06 ca e9 >.li sig san ....<
12e000 06 a2 00 00 >....<
#终于找到了,现在可以更新他了
#注意,修改的数据不要超过原有数据长度,不然会覆盖后面的数据导致块异常,这里我是修改回原有的数据
[oracle@cesdb3 ~]$ echo -n " zhang san " | xxd -p
207a68616e672073616e20
#前面加上字段长度0b
[oracle@cesdb3 ~]$ echo -n "0b207a68616e672073616e20" | xxd -r -p | dd of=/oradata/ORCL/bbed.dbf bs=1 seek=$((8192 * 150 + 8176)) conv=notrunc
12+0 records in
12+0 records out
12 bytes (12 B) copied, 5.883e-05 s, 204 kB/s
[oracle@cesdb3 ~]$ od -A x -t x1z -v -j $((8192 * 150 + 8176)) -N 20 /oradata/ORCL/bbed.dbf
12dff0 0b 20 7a 68 61 6e 67 20 73 61 6e 20 01 06 ca e9 >. zhang san ....<
12e000 06 a2 00 00 >....<
# 重新计算checksum
[oracle@cesdb3 ~]$ python kcbhxoro.py /oradata/ORCL/bbed.dbf 150
checksum int = 47824
checksum hex = 0xbad0
[oracle@cesdb3 ~]$ od -A x -t x1z -v -j $((8192 * 150 + 16)) -N 2 /oradata/ORCL/bbed.dbf
12c010 df b9 >..<
12c012
[oracle@cesdb3 ~]$ echo -n "d0ba" | xxd -r -p | dd of=/oradata/ORCL/bbed.dbf bs=1 seek=$((8192 * 150 + 16)) conv=notrunc
2+0 records in
2+0 records out
2 bytes (2 B) copied, 4.857e-05 s, 41.2 kB/s
[oracle@cesdb3 ~]$ od -A x -t x1z -v -j $((8192 * 150 + 16)) -N 2 /oradata/ORCL/bbed.dbf
12c010 d0 ba >..<
12c012
# 现在让我们在数据库查询下下修改是否正确
SQL> alter system flush buffer_cache;
System altered.
SQL> select * from test_char;
C1 C2
-------------------- --------------------
zhang san zhang san
南昌 南昌
附录
kcbhxoro.py这个计算checksum的脚本网上找的忘了作者了,深感抱歉
from struct import Struct
import sys, binascii
ushort = Struct("H")
ulong = Struct("Q")
file_name = sys.argv[1]
block_no = int(sys.argv[2])
block_size = 8192
dbf = open(file_name, "rb")
dbf.seek(block_size*block_no)
block = dbf.read(16)
block += b"\x00\x00"
dbf.seek(block_size*block_no + 18)
block += dbf.read(block_size - 18)
dbf.close()
checksum_value = 0
for i in range(int(block_size/8)):
checksum_value = checksum_value ^ ulong.unpack(block[i*8:i*8+8])[0]
tmp = checksum_value >> 32
checksum_value = checksum_value ^ tmp
tmp = checksum_value >> 16
checksum_value = checksum_value ^ tmp
final_checksum = ushort.unpack(ulong.pack(checksum_value)[0:2])[0]
print("checksum int = " + str(final_checksum))
print("checksum hex = " + str(hex(final_checksum)))
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




