今回利用するサンプルデータは最初からサンプルスキーマとして
インストールしたHRスキーマのJOBSテーブルです。
ご覧の通り19件データが存在する。
sys@O11G2> select * from hr.jobs;
JOB_ID JOB_TITLE MIN_SALARY MAX_SALARY
AD_PRES President 20080 40000
AD_VP Administration Vice President 15000 30000
AD_ASST Administration Assistant 3000 6000
FI_MGR Finance Manager 8200 16000
FI_ACCOUNT Accountant 4200 9000
AC_MGR Accounting Manager 8200 16000
AC_ACCOUNT Public Accountant 4200 9000
SA_MAN Sales Manager 10000 20080
SA_REP Sales Representative 6000 12008
PU_MAN Purchasing Manager 8000 15000
PU_CLERK Purchasing Clerk 2500 5500
ST_MAN Stock Manager 5500 8500
ST_CLERK Stock Clerk 2008 5000
SH_CLERK Shipping Clerk 2500 5500
IT_PROG Programmer 4000 10000
MK_MAN Marketing Manager 9000 15000
MK_REP Marketing Representative 4000 9000
HR_REP Human Resources Representative 4000 9000
PR_REP Public Relations Representative 4500 10500
19 rows selected.
例としてVice PresidentのROWIDを調べてみます
sys@O11G2> select rowid from hr.jobs where JOB_ID='AD_VP';
ROWID
AAAR5TAAFAAAAC/AAB
ROWIDを分析するため、便利なプロシージャを実装します。
sys@O11G2> create or replace procedure get_rowinfo(rid in rowid) as
sm varchar2(9) := 'SMALLFILE';
rid_t number;
obj_n number;
file_n number;
block_n number;
row_n number;
begin
DBMS_ROWID.ROWID_INFO(rid, rid_t, obj_n, file_n, block_n, row_n, sm);
DBMS_OUTPUT.PUT_LINE('Type: ' || to_char(rid_t));
DBMS_OUTPUT.PUT_LINE('Data obj number: ' || to_char(obj_n));
DBMS_OUTPUT.PUT_LINE('Relative fno: ' || to_char(file_n));
DBMS_OUTPUT.PUT_LINE('Block number: ' || to_char(block_n));
DBMS_OUTPUT.PUT_LINE('Row number: ' || to_char(row_n));
end;
/
先ほどのROWIDを分析します。
sys@O11G2> exec get_rowinfo('AAAR5TAAFAAAAC/AAB');
Type: 1
Data obj number: 73299
Relative fno: 5
Block number: 191
Row number: 1
PL/SQL procedure successfully completed.
解説:
TYPEは1:DATA、2:INDEXです。
Data obj numberはあまり重要ではありませんので、説明を省略します。
Relative fnoとBlock numberが分かればDBA(Data Block Address)も分かります。
DBAはこれからのBBED操作上とても重要です。
*ここのDBAはデータベース管理者のことではありません。
おまけ:
ORACLE ROWIDの仕組みを少々触れます。
ROWIDはBASE64でencodeされています。
encodeの方法としては
A-Zを十進の0-25に、
a-zを十進の26-51に、
0-9を十進の52-61に、
+と/を十進の62と63に変換されます
(http://www.ietf.org/rfc/rfc2045.txt)
例:AAAR5Tの場合、
A:000000
R:010001
5:111001
T:010011
000000 000000 000000 010001 111001 010011=73299
となります。
ROWIDに下記の情報が含まれています。
1)データオブジェクト番号
2)データファイル番号
3)データブロック番号
4)行(ROW)位置
フォーマットは:OOOOOO.FFF.BBBBBB.RRR となっています
OOOOOO はオブジェクトID
FFF はデータファイル番号
BBBBBB はブロック番号
RRR は行番号
上記のROWIDをDECODEしてみると、
sys@O11G2> select 'AAAR5TAAFAAAAC/AAB' as therowid,
to_number(utl_encode.base64_decode(utl_raw.cast_to_raw(
lpad(substr('AAAR5TAAFAAAAC/AAB',1, 6), 8, 'A'))), 'XXXXXXXXXXXX') as objid,
to_number(utl_encode.base64_decode(utl_raw.cast_to_raw(
lpad(substr('AAAR5TAAFAAAAC/AAB', 7, 3), 4, 'A'))), 'XXXXXX') as filenum,
to_number(utl_encode.base64_decode(utl_raw.cast_to_raw(
lpad(substr('AAAR5TAAFAAAAC/AAB', 10, 6), 8, 'A'))), 'XXXXXXXXXXXX') as blocknum,
to_number(utl_encode.base64_decode(utl_raw.cast_to_raw(
lpad(substr('AAAR5TAAFAAAAC/AAB', 16, 3), 4, 'A'))), 'XXXXXX') as rowslot
from dual
;
THEROWID OBJID FILENUM BLOCKNUM ROWSLOT
AAAR5TAAFAAAAC/AAB 73299 5 191 1
一目瞭然でしょう。
DBをシャットダウンし、
bbedの設定ファイルを作成する。
sys@O11G2> select file#||' '||name||' '||bytes from v$datafile;
FILE#||''||NAME||''||BYTES
1 /u01/oracle/app/oradata/o11g2/system01.dbf 713031680
2 /u01/oracle/app/oradata/o11g2/sysaux01.dbf 555745280
3 /u01/oracle/app/oradata/o11g2/undotbs01.dbf 104857600
4 /u01/oracle/app/oradata/o11g2/users01.dbf 5242880
5 /u01/oracle/app/oradata/o11g2/example01.dbf 104857600
sys@O11G2> show parameter db_block_size;
NAME TYPE VALUE
db_block_size integer 8192
sys@O11G2> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
[oracle@CentOS53 bbed]$ more filelist.txt
1 /u01/oracle/app/oradata/o11g2/system01.dbf 713031680
2 /u01/oracle/app/oradata/o11g2/sysaux01.dbf 555745280
3 /u01/oracle/app/oradata/o11g2/undotbs01.dbf 104857600
4 /u01/oracle/app/oradata/o11g2/users01.dbf 5242880
5 /u01/oracle/app/oradata/o11g2/example01.dbf 104857600
[oracle@CentOS53 bbed]$ more par.bbd
blocksize=8192
listfile=filelist.txt
mode=edit
究極のツールを実行します。
[oracle@CentOS53 bbed]$ bbed parfile=par.bbd
Password:
BBED: Release 2.0.0.0.0 - Limited Production on Tue Oct 27 11:07:48 2009
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
************* !!! For Oracle Internal Use only !!! ***************
今回のデータベースでは8Kのブロックサイズで起動しましたが、
set filenameとset blockを使えば指定し直すことも可能です。
基本的に8Kのブロックサイズの場合特殊な型を使っていなければ
同じテーブルを一個のブロックに集中格納する可能性が高いです。
先ほどの調査でVice Presidentが存在するブロック情報を得ましたね。
まずそれを探すために、data block addressを指定し、最初から探すため
OFFSETも0に指定します。
BBED> set dba 5,191
DBA 0x014000bf (20971711 5,191)
BBED> set offset 0
OFFSET 0
検索する場合、対応するデータ型は下記の通りです。(help find)
x:16進
d:10進
u:符号なし10進
o:8進
c:キャラクタ
BBED> find /c Vice President
File: /u01/oracle/app/oradata/o11g2/example01.dbf (5)
Block: 191 Offsets: 8143 to 8191 Dba:0x014000bf
------------------------------------------------------------------------
50726573 6964656e 7403c302 3302c304 2c010407 41445f50 52455309 50726573
6964656e 7404c303 015102c3 05010606 88
<32 bytes per line>
極端な例として、ハッカーが秘密情報を探るため、
関連ブロックの情報をダンプします。
BBED> dump /v dba 5,191 offset 8143 count 128
File: /u01/oracle/app/oradata/o11g2/example01.dbf (5)
Block: 191 Offsets: 8143 to 8191 Dba:0x014000bf
-------------------------------------------------------
50726573 6964656e 7403c302 3302c304 l President.テ.3.テ.
2c010407 41445f50 52455309 50726573 l ,...AD_PRES.Pres
6964656e 7404c303 015102c3 05010606 l ident.テ..Q.テ....
88 l .
<16 bytes per line>
では、このテーブルのレコード数はいくつでしょうか?
ここでデータブロックの知識が必要ですが、
kdbhの構造体をみてみます。
BBED> print kdbh
struct kdbh, 14 bytes @100
ub1 kdbhflag @100 0x00 (NONE)
sb1 kdbhntab @101 1
sb2 kdbhnrow @102 19
sb2 kdbhfrre @104 -1
sb2 kdbhfsbo @106 56
sb2 kdbhfseo @108 7397
sb2 kdbhavsp @110 7341
sb2 kdbhtosp @112 7341
注目するのはkdbhnrowです。
この場合は19レコードが存在しますね。
なるほど、じゃ4行目のデータがほしいなら、
eXamineコマンドでポインタを移動しながらチェックします。
BBED> print *kdbr[3]
rowdata[541]
------------
ub1 rowdata[541] @8038 0x2c
今OFFSET=8038のところで止まっています。
eXamineコマンドで/rフォーマットを指定します。(文字列:c、数値:n)
BBED> x /rccnn
rowdata[541] @8038
------------
flag@8038: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8039: 0x01
cols@8040: 4
col 0[6] @8041: FI_MGR
col 1[15] @8048: Finance Manager
col 2[2] @8064: 8200
col 3[3] @8067: 16000
ハッキングの視点からFinance Managerの給料がわかることになります。
ここで質問が出ると思いますが、
そのテーブルのカラム名は何?
まぁ、ここに保存していませんね。
同じ方法でDBA_TAB_COULMNSとDBA_OBJECTSを調べればわからないこともないでしょう
オブジェクトIDが分かるから、
オブジェクト名称(テーブル名)も分かることになりますね。
DBA_TAB_COULMNSからカラム名称を抽出可能です。
ちょっと難しい部分はBlock番号とファイル番号を調べるところですね、
そしてSYSTEM表領域に属すことはもう分かるので・・・