June 29, 2012

hack the core:bootstrap$, replace bootstrap$ with user's table

bootstrap$ is the most core table for database. It contains defination for oracle most critical dictinary tables such as: obj$, tab$, ts$ etc.

During an startup, oracle will read bootstrap$ to build dictionary for whole DB.
Any modification on bootstrap$ may destroy your database, and oracle support won't help anything on that.

Below is  bootstrap$ structure and one row in it:

SYS @ geded > select count(*) from bootstrap$;
  COUNT(*)
----------
        60

SYS @ geded > select * from bootstrap$ where line#=18;

     LINE#       OBJ#
---------- ----------
SQL_TEXT
-------------------------------------------------------------------------------------
        18         18
CREATE TABLE OBJ$("OBJ#" NUMBER NOT NULL,"DATAOBJ#" NUMBER,"OWNER#" NUMBER NOT NULL,"NAME" VARCHAR2(30) NOT NULL,"NAMESPACE" NUMBER NOT NULL,"SUBNAME" VARCHAR2(30),"TYPE#" NUMBER NOT NULL,"C
TIME" DATE NOT NULL,"MTIME" DATE NOT NULL,"STIME" DATE NOT NULL,"STATUS" NUMBER NOT NULL,"REMOTEOWNER" VARCHAR2(30),"LINKNAME" VARCHAR2(128),"FLAGS" NUMBER,"OID$" RAW(16),"SPARE1" NUMBER,"SP
ARE2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 STORAGE (  INITIAL 16K NEXT 104K MINEXTENTS 1 MAXEXT
ENTS 2147483645 PCTINCREASE 0 OBJNO 18 EXTENTS (FILE 1 BLOCK 240))

SYS @ geded > desc bootstrap$;
Name              Null?    Type
-------------- ---------- ---------------
LINE#          NOT NULL   NUMBER
OBJ#           NOT NULL   NUMBER
SQL_TEXT       NOT NULL   VARCHAR2(4000)

Below is one possible error for bootstrap$ failure during startup:
ORA-01092: ORACLE instance terminated. Disconnection forced
ORA-00704: bootstrap process failure.

Today, let's hack the bootstrap$, even replace it with our own table:
Kevin.Zhang >  select count(*) from bootstrap$;
  COUNT(*)
----------
        60

Kevin.Zhang > shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.

Kevin.Zhang > startup upgrade;
ORACLE instance started.
Total System Global Area  730714112 bytes
Fixed Size                  2230080 bytes
Variable Size             318769344 bytes
Database Buffers          322961408 bytes
Redo Buffers               86753280 bytes
Database mounted.
Database opened.

Kevin.Zhang > create table KILLBOOT as select * from bootstrap$;
Table created.

Kevin.Zhang > delete from KILLBOOT where LINE#=59;
1 row deleted.

Kevin.Zhang > commit;
Commit complete.

Kevin.Zhang > delete from bootstrap$;
60 rows deleted.

Kevin.Zhang > commit;
Commit complete.

Here we use an internal package DBMS_DDL_INTERNAL.SWAP_BOOTSTRAP to swap bootstrap$ to our new table KILLBOOT.
Infact package DBMS_DDL_INTERNAL.SWAP_BOOTSTRAP only do one thing, to update kcvfhrdb in super block(file 1 block 1):
Kevin.Zhang > exec DBMS_DDL_INTERNAL.SWAP_BOOTSTRAP('KILLBOOT');
PL/SQL procedure successfully completed.

Kevin.Zhang > update obj$ set name='BOOTSTRAP_DEL' where name='BOOTSTRAP$';
1 row updated.

Kevin.Zhang > commit;
Commit complete.

Kevin.Zhang > shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.

Kevin.Zhang > startup;
ORACLE instance started.
Total System Global Area  730714112 bytes
Fixed Size                  2230080 bytes
Variable Size             318769344 bytes
Database Buffers          322961408 bytes
Redo Buffers               86753280 bytes
Database mounted.
Database opened.

Kevin.Zhang > select count(*) from bootstrap$;
  COUNT(*)
----------
        59

Kevin.Zhang > select count(*) from bootstrap_del;
  COUNT(*)
----------
         0

Kevin.Zhang > select count(*) from KILLBOOT;
  COUNT(*)
----------
        59


We are done, let's prove that we have already succeeded in replacing bootstrap$ with our new table KILLBOOT:
Kevin.Zhang > select dbms_rowid.rowid_relative_fno(rowid) file_id,dbms_rowid.rowid_block_number(rowid) block_id from bootstrap$ where rownum<10;

   FILE_ID   BLOCK_ID
---------- ----------
         1      60817
         1      60817
         1      60817
         1      60817
         1      60817
         1      60817
         1      60817
         1      60817
         1      60817

9 rows selected.

From the block_id we can clearly identify since this block belong to KILLBOOT table.

0 Comments:

Post a Comment