In a prior
article on Oracles Block Browser and Editor tool (BBED), the installation
of the tool was covered. In this article, well look at starting a session
using a simple database and see how to view data. The database used in this
example is minimal in terms of structure. Use dbca to create a general purpose
database and pick a sample schema such as SCOTT to practice on. This simplifies
what you have to find.
The schema contains four
tables (EMP, DEPT, BONUS, and SALGRADE) and two indexes, all contained in the
USERS tablespace and further, only one database file to contend with (users01).
We dont care about the other two segment names (PK_EMP and PK_DEPT) because
they represent indexes, and really, why would you want to use bbed on an index?
Remember, use of bbed is a last resort measure, and there are so many other
ways of fixing or rescuing indexes that are much safer.
As an example, lets get the
rowid for Scott, the analyst (EMPNO=7788) from the EMP table. If not obvious,
the ROWID value you will see is likely to be different.
SQL> select rowid from emp where empno=7788;
Plugging the ROWID into a
customized get_rowinfo procedure (which is based on the DBMS_ROWID package
covered in the prior article) yields the following.
SQL> exec get_rowinfo('AAAMfMAAEAAAAAgAAH');
Data obj number: 51148
Relative fno: 4
Block number: 32
Row number: 7
PL/SQL procedure successfully completed.
Understanding the block
number and row number within the block is pretty straightforward. So is the
relative file number of 4, and this is easily confirmed via the following
SQL> select file#||' '||name||' '||bytes from v$datafile;
1 /opt/app/oracle/oradata/ORCL2/system01.dbf 503316480
2 /opt/app/oracle/oradata/ORCL2/undotbs01.dbf 36700160
3 /opt/app/oracle/oradata/ORCL2/sysaux01.dbf 272629760
4 /opt/app/oracle/oradata/ORCL2/users01.dbf 5242880
5 /opt/app/oracle/oradata/ORCL2/example01.dbf 104857600
What does type mean? The
short answer is that 1 = DATA and 2 = INDEX, so seeing the 1 is confirmation youre
working with the correct type. The data object number is for information and is
not essential, but can also be used for confirmation. Once you know the block
and file number, you can tie them together for the Data Block Address (dba), of
which, the dba value will be used quite extensively in all future bbed
As an alternative to
DBMS_ROWID, you could just decode the ROWID from the query based on what is
known as the Extended Rowid Format Oracle uses. The base-64 decomposition of 'AAAMfMAAEAAAAAgAAH'
works out to be the following.
Data Object ID
Relative File No
Oracle uses a conversion
table of A-Z being 0-25 in decimal form, and a-z being 26-51. Once you have the
decimal value, you can derive the binary value, and then string the binary
strings together to get the final value. For example, the M and f components
under the data object ID are decimal values 12 and 31, whose binary values are
001100 and 011111. AAAMfM is then represented as:
000000 000000 000000 001100 011111 001100
The decimal value of this is
then computed to be 51148 (and matches what was shown earlier). Of course, you
could also just query DBA_OBJECTS to get the DATA_OBJECT_ID value of the table.
Two other preliminary items
need to be mentioned at this point. The first concerns setting up a UNIX
environment. If you have the resources at work, where resources implies a
totally throw away database on a totally throw away ORACLE_HOME installation on
a server that can be down in case you have to reinstall Oracle, you have it
made. All you need to do is make the executable (if not already done).
If you dont have a UNIX
server, how do you get access to one (i.e., youre doing this on a home
computer)? One option is to use a virtual machine product, such as VMWare.
Another is to buy/use a bare bones PC and install Oracle Enterprise Linux on
it. Yet another is to install OEL on your current PC via a partitioning tool and
live with booting from multiple operating systems. The boot from multiple
systems on your main home PC is not the best choice, but you can make that
happen with relatively little effort. If you dont like having OEL or some
other brand of Linux on your PC, you can always remove it later and reclaim the
disk space it partitioned.
The second is using a
parameter file when starting bbed. Nothing new about what a parameter file is
and does as it is just like parameter files used elsewhere in Oracle (exp, imp,
sqlldr, etc.). What is new, however, are the parameters and their values or
options. Enter bbed help=y to see the list. In this example, bbed is located
in $ORACLE_HOME/bin after having been compiled elsewhere.
[oracle@oralinux ~]$ bbed help=y
PASSWORD - Required parameter
FILENAME - Database file name
BLOCKSIZE - Database block size
LISTFILE - List file name
MODE - [browse/edit]
SPOOL - Spool to logfile [no/yes]
CMDFILE - BBED command file name
LOGFILE - BBED log file name
PARFILE - Parameter file name
BIFILE - BBED before-image file name
REVERT - Rollback changes from BIFILE [no/yes]
SILENT - Hide banner [no/yes]
HELP - Show all valid parameters [no/yes]
Collect the file name
information as shown earlier. Identify the block size of the file(s), and for
the initial runs of using this tool, use the browse mode. The contents of a
parameter file are shown below.
[oracle@oralinux bbed]$ more bbed.par
Starting a session
To start a session using a
parameter file named bbed.par located in a directory named bbed, you would use
bbed parfile=bbed.par. Once inside a bbed session, you can invoke a help
command by specifying all to see everything, or by a keyword, such as help
set. The set command is useful (and necessary) for navigation between and
within blocks and files. If you start with a file based on an 8K blocksize, you
could set a new filename (or file number) and its blocksize by using the set
filename (or file) and set block commands.
Lets check out the contents
of a block. Well use the one block containing all of the EMP table (if you
used an 8K block size, it is highly likely all rows will be in the one block).
We know that someone in the list of employees is the president, so lets search
for PRESIDENT after setting the data block address, and also having set the
offset to 0. The set dba 4,32 refers to file number 4 and block number 32. We want
to start in the beginning of the block, so no offset is needed.
BBED> set dba 4,32
DBA 0x01000020 (16777248 4,32)
BBED> set offset 0
BBED> find /c PRESIDENT
File: /opt/app/oracle/oradata/ORCL2/users01.dbf (4)
Block: 32 Offsets: 7831 to 8191 Dba:0x01000020
50524553 4944454e 54ff0777 b50b1101 010102c2 33ff02c1 0b2c0108 03c24e59
0553434f 54540741 4e414c59 535403c2 4c430777 bb041301 010102c2 1fff02c1
152c0108 03c24e53 05434c41 524b074d 414e4147 455203c2 4f280777 b5060901
010103c2 1933ff02 c10b2c01 0803c24d 6305424c 414b4507 4d414e41 47455203
c24f2807 77b50501 01010103 c21d33ff 02c11f2c 010803c2 4d37064d 41525449
4e085341 4c45534d 414e03c2 4d630777 b5091c01 010103c2 0d3302c2 0f02c11f
2c010803 c24c4305 4a4f4e45 53074d41 4e414745 5203c24f 280777b5 04020101
0103c21e 4cff02c1 152c0108 03c24c16 04574152 44085341 4c45534d 414e03c2
4d630777 b5021601 010103c2 0d3302c2 0602c11f 2c010803 c24b6405 414c4c45
4e085341 4c45534d 414e03c2 4d630777 b5021401 010102c2 1102c204 02c11f2c
010803c2 4a460553 4d495448 05434c45 524b03c2 50030777 b40c1101 010102c2
09ff02c1 151006db bf
<32 bytes per line>
The supported datatypes you
can search for are shown via help find at the bbed prompt. Note the absence
of numeric and date datatypes.
If a hacker were looking for
sensitive employee data, this would be a jackpot. He found a block containing
PRESIDENT. To confirm his finding, he could dump the contents of the block at
that offset (position within the block, so to speak).
BBED> dump /v dba 4,32 offset 7831 count 32
File: /opt/app/oracle/oradata/ORCL2/users01.dbf (4)
Block: 32 Offsets: 7831 to 7862 Dba:0x01000020
50524553 4944454e 54ff0777 b50b1101 l PRESIDENT..wµ...
010102c2 33ff02c1 0b2c0108 03c24e59 l ...Â3..Á.,...ÂNY
<16 bytes per line>
How many records are there
in the table? Use the print command (or p for short) to print the metadata
about the block. This is where knowledge of data block structure comes in
handy. The struct (C-like data structure) of interest is kdbh. The following
tells you how many rows via the kdbhnrow value (14 in this case).
BBED> p kdbh
struct kdbh, 14 bytes @100
ub1 kdbhflag @100 0x00 (NONE)
b1 kdbhntab @101 1
b2 kdbhnrow @102 14
sb2 kdbhfrre @104 -1
sb2 kdbhfsbo @106 46
sb2 kdbhfseo @108 7521
b2 kdbhavsp @110 7475
b2 kdbhtosp @112 7475
Instead of examining each
and every row, you could set the pointer to the last row, and then examine (x
for short) each row while spooling output. With print, numbers and dates can be
displayed. As a simple example, (knowing ahead of time KING is in row 9 of the
EMP table), print the kdbr struct, where the use of kdbr includes the row
(starting at 0, not 1). Row 9 in the table is kdbr for our purposes.
BBED> print *kdbr
ub1 rowdata @7818 0x2c
Now that we are at offset
7818, it is a simple matter to examine the contents via the print (p for short)
and examine (x for short) commands, and use format flags. We know what the EMP
table looks like in terms of character (c), numeric (n) and date (t)
attributes. In bbed, use x /rnccntnnn to examine and format the output.
BBED> x /rnccntnnn
flag@7818: 0x2c (KDRHFL, KDRHFF, KDRHFH)
col 0 @7821: 7839
col 1 @7825: KING
col 2 @7830: PRESIDENT
col 3 @7840: *NULL*
col 4 @7841: 17-NOV-81
col 5 @7849: 5000
col 6 @7852: *NULL*
col 7 @7853: 10
From a hacking (or recovery)
standpoint, we know the president is named King. What are the column names?
Well, theyre not present here, but whats to stop you from deconstructing the
same thing with respect to the base tables represented by the data dictionary
views of DBA_TAB_COULMNS and DBA_OBJECTS? You have the data object ID, so
finding the object name is trivial, and with the object name (which becomes the
table name in this case), you can get the column names from DBA_TAB_COULMNS.
The only hard part in all of this is finding the block numbers within the file,
and we already know the file is related to the SYSTEM tablespace.
The USER$ table in Oracle
has a data object ID of 10. That has been the value from at least 8i
days. Who are the database users? What are their hashed passwords? That
information plus much more is easily extracted. All weve done so far is to
look at data, and with just that, you should be able to appreciate the enormous
power behind bbed.
See All Articles by Columnist Steve Callan