Monday, October 12, 2015

Oracle How to unwrap PL/SQL

Dear readers
my reference in this post from Pete Finnigan book How to unwrap PL/SQL



How to unwrap PL/SQL
Pete Finnigan,


 Why is there a problem with wrapped PL/SQL
Intellectual property can be revealed if PL/SQL is un-
wrapped
This can include
Your own application source code
Oracle shipped features hidden by the wrapper
In 9i and lower wrapped PL/SQL revealed symbols
Finding SQL injection bugs just became easier
There are PL/SQL unwrapping tools available
 PL/SQL language compilation structure
PL/SQL source code
PL/SQL compiler front end
DIANA – An intermediate language for ADA
Compiler back end
Virtual machine M-Code
 DIANA is the key for 9i and lower
PL/SQL is based on ADA
DIANA – Descriptive intermediate language for ADA
DIANA is an abstract data type
DIANA is an intermediate form of PL/SQL programs
Intended to communicate between the front end and
back ends of a PL/SQL compiler
Each defining DIANA entity represents a PL/SQL entity
Two trees –
Abstract syntax tree constructed prior to semantic analysis
Attributed tree (the DIANA structure)
 IDL – Interface description language
DIANA is written down as IDL
What is IDL? – Interface description language – Also
derived from ADA
IDL is stored in the database in 4 dictionary tables
IDL_CHAR$, IDL_SB4$, IDL_UB1$ and IDL_UB2$
Wrapped PL/SQL is simply DIANA written down as IDL
Oracle say that wrapped PL/SQL is simply encoded
Therefore the
wrap
program is the front end of a PL/SQL
compiler.
Is wrapped PL/SQL – DIANA – reversible?
 A book about DIANA
DIANA – An Intermediate Language
Quote from page 165:
for ADA
Editors: G. Goos, W.A. Wulf
“Appendix III – Reconstructing the
A. Evans, Jr and K.J. Butler
source”
Springer-Verlag
“One of the basic principals of
DIANA is that the structure of the
ISBN : 0387126953
original source program is to be
Revised Edition (December 1983)
retained in the DIANA
representation…..”
“There is a close correspondence
between ADA’s syntax and DIANA’s
structural attributes… It is this
correspondence that permits source
code reconstruction.”
 From Oracle’s own documentation
PL/SQL User's Guide and Reference
10
g
Release 1 (10.1)
Part Number B10807-01
“PL/SQL is based on ADA, as a result PL/SQL uses a variant
of DIANA, a tree structured language….”
“It is defined using a meta notation called IDL (Interface
Definition Language)…”
“DIANA is used internally by compilers and other tools…..”
“At compile time PL/SQL is translated into M-Code. Both
DIANA and M-Code are stored in the database….”
 A Sample PL/SQL procedure – 9i
SQL>connect sys/change_on_install as sysdba
Connected.
SQL>create or replace procedure AA as

begin
null;
end;
/
Procedure created.
SQL> Save the PL/SQL and wrap the code
Wrapping is simple. Save the PL/SQL
SQL>save aa.sql
to a file and run the
wrap
utility.
Created file aa.sql
d:\orant\bin>wrap iname=aa.sql oname=aa.pls
PL/SQL Wrapper: Release 9.2.0.1.0- Production on Mon Jun
19 18:05:57 2006
Copyright (c) Oracle Corporation 1993, 2001.  All Rights
Reserved.
Processing aa.sql to aa.pls
create or replace procedure
0
AA wrapped
0
0
f
abcd
2
{snipped 15 identical lines}
0 9a b4 55 6a 4f b7 a4
3
b1 11 68 4f 1d 17 b5
7
f
9200000
2
1
0 3 17 18 1c 20 22 24
4
28 2a 36 3a 3c 3d 46
0
{file contents snipped}
1
2 :e:
What is the meaning of this encoded file? –
1AA:
Note the highlights – we will see them again
0
 9i and below wrapped PL/SQL weaknesses
SQL>create or replace procedure encode (credit_card in varchar2,
str out varchar2) is

key varchar2(16):='01234567890ABCDEF';
begin
null;
end;
/
Procedure created.
SQL>save encode.sql
01234567890ABCDEF
:
G:\orant\bin>wrap iname=encode.sql oname=encode.plb
PL/SQL Wrapper: Release 9.2.0.1.0- Production on Fri Jun 23 15:43:47
2006
Copyright (c) Oracle Corporation 1993, 2001.  All Rights Reserved.
Processing encode.sql to encode.plb
 Hacking wrapped PL/SQL – pre-9i
The symbol table is visible
For the previous example it is possible to
Deduce the purpose of the procedure
Find out the encryption algorithm used using
DBA_DEPENDENCIES unless it is implemented
internally to the procedure
Decrypt Credit Cards – in this case
Trojans can be planted
Wrapped source can be modified without un-wrapping
Example: Fixed DBMS_OUTPUT limits problem
SQL injection identification is possible / DDL can be altered
 The relationships in 9i
PL/SQL Source
Diana and M-Code
IDL_CHAR$
Wrap utility
IDL_UB1$
IDL_UB2$
IDL_SB4$
Wrapped File
Source Code
SOURCE$
create or replace procedure aa
wrapped
0
DBA_SOURCE
abcd
abcd
ALL_SOURCE
abcd
abcd
abcd
Abcd
….
 The dictionary tables and views
SQL> desc idl_ub1$
SYS.IDL_CHAR$
Name          Null?    Type
SYS.IDL_UB1$
------------- -------- ----------
SYS.IDL_UB2$
OBJ#          NOT NULL NUMBER
SYS.IDL_SB4$
PART          NOT NULL NUMBER
SYS.SOURCE$
VERSION                NUMBER
PIECE#        NOT NULL NUMBER
SQL> desc source$
LENGTH        NOT NULL NUMBER
Name             Null?    Type
PIECE         NOT NULL LONG RAW
--------------- -------- ----------
-------
From $OH/rdbms/admin/sql.bsq
OBJ#             NOT NULL NUMBER
/*
part: 0 = diana,
1 = portable
LINE             NOT NULL NUMBER
pcode, 2 = machine-dependent pcode
SOURCE           VARCHAR2(4000)
*/
 Recursive SQL
What is recursive SQL? – background supporting SQL
needed to execute the submitted statement
When compiling PL/SQL there are other background SQL
statements that need to run as SYS
Check for user’s privileges and roles
Triggers
Retrieving the PL/SQL code to run
Indexes
How can we see the complete picture?
Using traces, dumps and events
 Trace the compilation of PL/SQL
SQL>alter session set events '10046 trace name context forever, level 12';
Session altered.
SQL>create or replace procedure aa is
 begin
 null;
end;
/
Procedure created.
SQL>alter session set events '10046 trace name context off';
Session altered.
SQL> Locate the trace file and check the contents
PARSING IN CURSOR #2 len=106 dep=1 uid=0 oct=6 lid=0 tim=465432930704 hv=1545875908
ad='66f37b44'
update idl_ub2$ set piece#=:1 ,length=:2 , piece=:3 where obj#=:4 and part=:5 and
piece#=:6 and version=:7
END OF STMT
PARSE #2:c=0,e=42,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=465432930696
BINDS #2:
bind 0: dty=2 mxl=22(22) mal=00 scl=00 pre=00 oacflg=08 oacfl2=1 size=24 offset=0
bfp=04822394 bln=24 avl=02 flg=05
value=4
bind 1: dty=2 mxl=22(22) mal=00 scl=00 pre=00 oacflg=08 oacfl2=1 size=24 offset=0
bfp=04822364 bln=24 avl=03 flg=05
value=123
bind 2: dty=25 mxl=4000(4000) mal=00 scl=00 pre=00 oacflg=12 oacfl2=1 size=4000 offset=0
bfp=04c67ff4 bln=4000 avl=246 flg=09
value=
Those numbers
Dump of memory from 0x04C67FF4 to 0x04C680EA
4C67FF0          00030000 000D000C 00250011      [..........%.]
look familiar!
4C68000 002A0029 0038002C 003E003A 00000040  [).*.,.8.:.>.@...]
4C68010
001D0017 009A0068 00B40055 001100B5
[....h...U.......]
4C68020
00A400B1 004F00B7
00010000 00010001  [......O.........]
4C68030 00010001 00010001 00010001 00010001  [................]
4C68040 00000001 00010001 000B0001 00010001  [................]
 DIANA for package bodies is not stored (idl.sql)
SQL>select count(*),'CHAR$',part,object_type
 from idl_char$,dba_objects
 where obj#=object_id
and part=0
group by part,object_type
union
select count(*),'UB1$',part,object_type
from idl_ub1$,dba_objects
where obj#=object_id
and part=0
group by part,object_type
union
select count(*),'UB2$',part,object_type
from idl_ub2$,dba_objects
where obj#=object_id
and part=0
group by part,object_type
union
select count(*),'SB4$',part,object_type
from idl_sb4$,dba_objects
where obj#=object_id
and part=0
group by part,object_type
order by 2
SQL> select dbms_rowid.rowid_block_number(rowid)  blk,
SQL> @rowid
2  dbms_rowid.rowid_relative_fno(rowid) fno,
3  dbms_rowid.rowid_row_number(rowid) rnum,
BLK FNO RNUM 'CHAR       PART    VERSION     PIECE#     LENGTH
4  'CHAR$',part,version,piece#,length
------ --- ---- ----- ---------- ---------- ---------- ----------
5  from idl_char$
49951   1   24 sb4$           0  153092096          0         14
6  where obj#=(select obj# from obj$ where name = 'AA')
49951   1   48 sb4$           0  153092096          1          2
7  union
42671   1   21 ub1$           0  153092096          2          3
8  select dbms_rowid.rowid_block_number(rowid)  blk,
35792   1   36 CHAR$          0  153092096          3          5
9  dbms_rowid.rowid_relative_fno(rowid) fno,
50581   1    8 UB2$           0  153092096          4        123
10  dbms_rowid.rowid_row_number(rowid) rnum,
50581   1    9 UB2$           0  153092096          5         10
11  'UB2$',part,version,piece#,length
49951   1   50 sb4$           2  153092096          0         18
12  from idl_ub2$
42671   1   10 ub1$           2  153092096          1        112
13  where obj#=(select obj# from obj$ where name = 'AA')
42671   1   13 ub1$           2  153092096          2          1
14  union
`
15  select dbms_rowid.rowid_block_number(rowid)  blk,
9 rows selected.
16  dbms_rowid.rowid_relative_fno(rowid) fno,
17  dbms_rowid.rowid_row_number(rowid) rnum,
18  'ub1$',part,version,piece#,length
19  from idl_ub1$
20  where obj#=(select obj# from obj$ where name = 'AA')
21  union
22  select dbms_rowid.rowid_block_number(rowid)  blk,
23  dbms_rowid.rowid_relative_fno(rowid) fno,
24  dbms_rowid.rowid_row_number(rowid) rnum,
25  'sb4$',part,version,piece#,length
26  from idl_sb4$
27  where obj#=(select obj# from obj$ where name = 'AA')
28  order by part,piece#
SQL> save rowid.sql
 Dump the datablocks to find the DIANA
Why do we need to dump datablocks for the IDL$ tables?
SQL>select piece
from sys.idl_ub2$
where obj#=(select obj# from obj$ where name='AA')
and part=0
and piece#=4;
ERROR:
ORA-00932: inconsistent datatypes: expected %s got %s
no rows selected
SQL>alter system dump datafile 1 block 50581;
System altered.
The contents of the block dump for IDL_UB2$
tab 0, row 8, @0x11b1
tl: 271 fb: --H-FL-- lb: 0x1  cc: 6
Those values look familiar but
col  0: [ 4]  c3 04 05 0a
col  1: [ 1]  80
in a different order
col  2: [ 6]  c5 02 36 0a 15 61
col  3: [ 2]  c1 05
col  4: [ 3]  c2 02 18
col  5: [246]
00 00 03 00 0c 00 0d 00 11 00 25 00 29 00 2a 00 2c 00 38 00 3a 00 3e 00 40
00 00
00 17 00 1d 00 68 00 9a 00 55 00 b4 00 b5 00 11 00 b1 00 a4 00 b7 00
4f
00 00 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01 00 01
00 01 00 00 00 01 00 01 00 01 00 0b 00 01 00 01 00 01 00 01 00 01 00 01 00
00 00 01 00 00 00 00 00 00 00 02 00 03 00 07 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 04 00 05 00 08 00 01 00 01 00 05 00 08 00 00 00 00 00 04 00
00 00 00 00 ff 00 01 00 00 00 03 00 01 00 20 00 00 00 00 00 00 00 00 00 00
00 01 00 06 00 00 00 00 00 03 00 00 00 00 00 00 00 09 00 0b 00 0a 00 00 00
00 00 00 00 00 00 00 00 04 00 03 00 00 00 00 00 00 00 08 00 00 00 08 00 00
00 08 00 03 00 08 00 00 00 0b 00 00 00 00 00 00 00 01 00 0c 00
 IDL dependencies – (a detour)
SQL> select distinct owner,name,type
from dba_dependencies
where referenced_name like 'IDL_%';
OWNE NAME                 TYPE
---- -------------------- ------------
SYS  ALL_PROBE_OBJECTS    VIEW
SYS  CODE_PIECES          VIEW
SYS  INITJVMAUX           PACKAGE BODY
SYS  ORA_KGLR7_IDL_CHAR   VIEW
SYS  ORA_KGLR7_IDL_SB4    VIEW
SYS  ORA_KGLR7_IDL_UB1    VIEW
SYS  ORA_KGLR7_IDL_UB2    VIEW
SYS  PARSED_PIECES        VIEW
SYS  RMJVM                PACKAGE BODY
 How are IDL tables used?
SQL>desc code_pieces
SQL>set long 1000000
SQL>select text from dba_views
where view_name='CODE_PIECES'
SQL>select text from dba_source
where name='PIDL';
package     PIDL is
----------------------------------------------------------------------------
-- Persistent IDL datatypes
----------------------------------------------------------------------------
subtype ptnod     is binary_integer; -- generic IDL node type
TRENULL CONSTANT ptnod := 0;         -- a NULL node
subtype ub4       is binary_integer; -- Oracle C type, unsigned byte 4
subtype ub2       is binary_integer; -- Oracle C type, unsigned byte 2
{Output snipped to 550 lines}
SQL>select text from dba_source
where name='DIANA';
SQL>desc diutil
PROCEDURE ATTRIBUTE_USE_STATISTICS
Argument Name           Type                    In/Out Default?
----------------------- ----------------------- ------ --------
LIBUNIT_NODE            BINARY_INTEGER          IN
ATTRIBUTE_COUNT         BINARY_INTEGER          OUT
ATTRIBUTE_LIMIT         BINARY_INTEGER          OUT
PROCEDURE GET_D
Argument Name           Type                    In/Out Default?
----------------------- ----------------------- ------ --------
NAME                    VARCHAR2                IN
USR                     VARCHAR2                IN
DBNAME                  VARCHAR2                IN
DBOWNER                 VARCHAR2                IN
STATUS                  BINARY_INTEGER          IN/OUT
NOD                     BINARY_INTEGER          OUT
LIBUNIT_TYPE            NUMBER                  IN     DEFAULT
LOAD_SOURCE             NUMBER                  IN     DEFAULT
{snipped}
 Dumpdiana – a script to dump the DIANA
$ORACLE_HOME/rdbms/admin/dumpdian.sql
Not installed by default
Run the script as SYS
There are two bugs to fix – remove the lines REM ----
Ensure DIANA, PIDL and DIUTIL PL/SQL packages are
installed as well
Run for sample ‘AA’ procedure as SYS – (output to trace) :-
SQL>exec sys.dumpdiana.dump(aname => 'AA');
PL/SQL procedure successfully completed.
 Reconstructing PL/SQL source from DIANA - 1
Block syntax for PL/SQL
Block_statement ::=
[block_simple_name]
[
declare
declarative part]
begin
sequence of statements
[exception
exception handler {exception handler}]
end
[block_simple_name] ;
Diana Rules
block => as_item : DS_ITEM,
as_stm : D_STM,
as_alter : DS_ALTER;
See page 166 – Goos / Wulf et al
 An alternate DIANA dump
{output snipped}
PD3(4) : D_S_BODY: [
SRCPOS: row 1 col 1
A_D_: PD4(4) : DI_PROC: [...]
A_HEADER: PD5(4) : D_P_: [...]
A_BLOCK_: PD8(4) : D_BLOCK: [...]
A_UP: PD1(4) : <reference to D_COMP_U (262145)>
]
PD4(4) : DI_PROC: [
SQL>exec sys.dumpdiana.dump(aname =>
'AA',print_format => 1);
Declare
It is easy to see the close
<DS_ITEM>
relationship between PL/SQL
Begin
and DIANA
<DS_STM>
Then it is easy to see how
Exception
PL/SQL can be reconstructed
<DS_ALTER>
from DIANA
End;
 Mapping IDL to DIANA
Code Dec name
Take the node names from the
0   0 ?
DIANA tree or line dump
9a  154 DI_PROC
b4  180 DS_PARAM
Use the DIANA package
55  85 D_P_
constants
6a  106 D_S_DECL
4f  79 D_NULL_S
Convert dec numbers to Hex
b7  183 DS_STM
a4 164 DS_ALTER
These hex numbers are
b1  177 DS_ITEM
familiar?
11  17 D_BLOCK
68  104 D_S_BODY
Wrap file / idl / diana dumps
4f  79 D_NULL_S
are all the same
1d  29 D_CONTEX
17 23 D_COMP_U
Hence wrap format is DIANA
b5 181 DS_PRAGM
 Simple tree structure
D_COMP_U
DS_BODY
DI_PROC
D_P_ D_BLOCK
L_symrep = ‘AA’
DS_PARAM DS_ITEM
DS_STM
D_NULL_S
DS_ALTER
 DIANA utilities - pstub
SQL>
variable a varchar2(2000);
SQL>
variable b varchar2(2000);
SQL>
exec sys.pstub('AA',NULL,:a,:b);
PL/SQL procedure successfully completed.
SQL>
print :b
B
--------------------------------------------------------------------
------------
procedure AA is begin stproc.init('begin AA; end;'); stproc.execute;
end; procedure AA is begin stproc.init('begin AA; end;');
stproc.execute; end; procedure AA is begin stproc.init('begin AA;
end;'); stproc.execute; end;
SQL>
 DIANA utilities - subptxt
SQL>
variable a varchar2(2000);
SQL>
exec sys.subptxt('AA',NULL,NULL,:a);
PL/SQL procedure successfully completed.
SQL>
print :a
A
------------------------------------------------------
procedure AA;
SQL>
 PSTUB and SUBPTXT
PSTUB and SUBPTXT are demonstration programs that
use the IDL and DIANA API’s
PSTUB is used to allow the calling of V2 PL/SQL in the
server from V1 PL/SQL client tools such as Forms
SUBPTXT allows the describing of PL/SQL
Both read DIANA and not PL/SQL source code
Pistub.sql and the library diutil.sql are the only public
example programs to use the DIANA and PIDL packages
Diutil.exprtext (private function) is an excellent example of
how to use DIANA and PIDL package calls
 Writing a PL/SQL un-wrapper
To create an unwrapping tool we need
To understand the relationship between DIANA and
PL/SQL language constructs
A way to parse the DIANA in the correct order – API
calls?
A way to read and understand the DIANA node types –
API calls?
A way to read variable attributes for each node and to
read their type and value – API calls
Mapping PL/SQL to DIANA for some language constructs
can be done using test programs and dumpdiana
 Limitations of a PL/SQL API based un-wrapper
A comprehensive PL/SQL un-wrapper can be written using
the IDL and DIANA PL/SQL package API’s
The $OH/rdbms/admin/diutil.sql file indicates how
PIDL API’s do not emit the complete DIANA
The DIANA for the body of procedures and functions is not
available via the dumpdiana, PIDL, DIANA interfaces (see
the next slide)
The DIANA dump misses PL/SQL in the block section.
Local variables are also not included
It could be possible to write a complete un-wrapper in
PL/SQL and read the DIANA from SYS.SOURCE$
 PL/SQL API limitations
SQL>
create or replace procedure ah (i in number, j out
varchar2) is
PD13(7) : DS_STM: [
2  begin
SRCPOS: row 1 col 0
3  if i = 7 then
AS_LIST: PDa(7) : <sequence of 1 item:
4     j := 3;
PD14(7)>
5  else
A_UP: PD10(7) : <reference to D_BLOCK
(458768)>
6     j := 4;
]
7  end if;
PD14(7) : D_NULL_S: [
8  end;
SRCPOS: row 1 col 1
9  /
C_OFFSET: ub4: '0'
A_UP: PD13(7) : <reference to DS_STM
(458771)>
Procedure created.
]
SQL>
exec dumpdiana.dump(aname => 'AH',print_format => 1);
PL/SQL procedure successfully completed.
 Enumerating DIANA nodes and attributes
SQL>
exec attrib(23);
Node Type D_COMP_U
Num Attributes 9
See attrib.sql - Also at
0: 9:A_CONTEX:1: REF 1
http://www.petefinnigan.com/att
1: 40:A_UNIT_B:1: REF 1
rib.sql
2: 62:AS_PRAGM:1: REF 1
3: 114:SS_SQL:30: REF 0
Uses PIDL to enumerate
4: 113:SS_EXLST:30: REF 0
DIANA nodes and attributes
5: 111:SS_BINDS:30: REF 0
6: 41:A_UP:1: REF 0
7: 138:A_AUTHID:2: REF 0
8: 142:A_SCHEMA:2: REF 0
PL/SQL procedure successfully completed.
SQL>
 Creating a real PL/SQL un-wrapper
Can a complete un-wrapper be written? – Of course, yes
There are at least 4 unwrapping tools that I know of
The complete PL/SQL and SQL grammars are needed -
http://www.antlr.org/grammar/1107752678378/PLSQLGrammar.g
-
Also see “PL/SQL user reference guide”
It is necessary to understand all DIANA nodes and to map those to
PL/SQL – this is not fully documented (partly it is documented as ADA /
DIANA)
It is necessary to understand the wrap file format and to extract the
DIANA nodes and attributes from it
It may be possible to disassemble M-Code back to PL/SQL
The symbols are embedded in the M-Code
 Keywords
SQL>
desc v$reserved_words
Name                    Null?    Type
----------------------- -------- -------------------
KEYWORD                 VARCHAR2(64)
LENGTH                  NUMBER
SQL>
select count(*) from v$reserved_words;
COUNT(*)
----------
809
SQL> Showing the PL/SQL M-Code as assembler
SQL>create or replace procedure ab as
ae number:=1;
begin
ae:=ae+1;
end;
/
Procedure created.
SQL>alter session set events '10928 trace name context forever,
level 1';
Session altered.
SQL>exec ab;
PL/SQL procedure successfully completed.
SQL>alter session set events '10928 trace name context off';
Session altered.
SQL> The M-Code assembler
Entry #1
PL/SQL source is shown
00001: ENTER      4, 0
<source not available>
When wrapped –
source not
00007: XCAL       1, 1
available
– is shown
Entry #1
SYS.AB: 00001: ENTER      76, 0
M-Code is mapped to PL/SQL
SYS.AB: 00007: INFR       DS[0]+96
line numbers
Frame Desc Version = 2, Size = 22
# of locals = 2
This implies that the line and
TC_SSCALARi: FP+4, d=FP+12
column details are held in the M-
TC_SSCALARi: FP+8, d=FP+44
Code
[Line 2] ae number:=1;
SYS.AB: 00012: CVTIN      HS+0 =1=, FP+4
[Line 4]  ae:=ae+1;
SYS.AB: 00017: CVTIN      HS+0 =1=, FP+8
SYS.AB: 00022: ADDN       FP+4, FP+8, FP+4
SYS.AB: 00029: RET
00012: RET
 Native compilation and initialisation parameters
PL/SQL can be natively compiled
There are a number of initialisation parameters – “
sho
parameter
” in SQL*Plus
It is possible in some versions to use the native compilation
to hack Oracle
It could be possible to inject PL/SQL code via native
compilation
The generated C Code is M-Code VM calls for each
instruction
 Some sample code – getting started
SQL>set serveroutput on size
See unwrap.sql (also on
1000000
http://www.petefinnigan.com/unw
SQL>exec unwrap('AA');
rap.sql
Start up
Root Node :262145
Test program to
Root code (hex) :23
Familiarise with the API’s
Root Type :D_COMP_U
--
Walk the DIANA nodes
A_UNIT_B Node :262147
Read attributes
A_UNIT_B Type :D_S_BODY
A_UNIT_B code (hex) :104
It works! Next, work out the
--
PL/SQL that should be emitted
A_D_ Node :262148
for each node or node group
A_D_ Type :DI_PROC
A_D_ code (hex) :154
--
A_HEADER Node :262149
A_HEADER Type :D_P_
A_HEADER code (hex) :85
 PL/SQL code generation
“CREATE %{} END;\
DS_BODY
l_symrep => PROCEDURE ‘AA’
DI_PROC  = ‘AA’
{not implemented}
D_P_ = params
{not implemented}
DS_PARAM
“IS” “BEGIN” %{} “EXCEPTION” %{}
D_BLOCK
“END;”
DS_ITEM – local variable
{not implemented}
DS_STM
No output
D_NULL_S
NULL;
DS_ALTER
{not implemented}
 A proof of concept un-wrapper
SQL>set serveroutput on size 1000000
SQL>exec unwrap_r('AA');
Start up
Unwrap_r.sql – also available
CREATE OR REPLACE
from
PROCEDURE AA
http://www.petefinnigan.com/un
IS
wrap_r.sql
BEGIN
Implements the code
NULL;
generation to create PL/SQL
END;
\
from DIANA for a simple
procedure
PL/SQL procedure successfully completed.
Uses a simple recursive
descent parser
SQL>
 Unwrap_r.sql recursive function
create or replace procedure unwrap_r(aname varchar2)
is
root sys.pidl.ptnod;
status   sys.pidl.ub4;
procedure recurse (n sys.pidl.ptnod) is
seq sys.pidl.ptseqnd;
len integer;
begin
if(pidl.ptkin(n) = diana.d_comp_u) then
recurse(diana.a_unit_b(n));
elsif (pidl.ptkin(n) = diana.d_s_body) then
dbms_output.put_line('CREATE OR REPLACE ');
recurse(diana.a_d_(n));
recurse(diana.a_header(n));
recurse(diana.a_block_(n));
dbms_output.put_line('END;');
dbms_output.put_line('/');
{output snipped}
 10g – Different but the same?
New
A new wrap mechanism has been provided
The contents of symbol table are no longer visible
The encryption involves base64
10gR2 provides the ability to wrap from within the database using
DBMS_DDL
There is a new optimizing compiler for PL/SQL
Old
The IDL$ tables still contain DIANA and M-Code
The DIANA, PIDL, DIUTIL and DUMPDIANA packages are still
available
It is still possible to reverse simple procedures using the API’s
 The 10g wrapped procedure
SQL>select text from dba_source where name='AA';
TEXT
This is base64 character set
procedure aa wrapped
a000000
Using base64 decode does not
1
abcd
reveal the source
{identical output snipped}
abcd
The symbol table is not visible
7
21 55
tpZtVM0u7lC31uX+QfYfxhNmy+Awg5nnm7+fMr2ywFy49cOldIvAwDL+0oabmYEILYvAgcct
yaam9+Lntg==
 Create procedure and check IDL use in 10g
SQL>create or replace procedure aa is
begin
null;
end;
/
Procedure created.
Roughly the same IDL is
SQL>save aa.sql replace
Wrote file aa.sql
created in the database as 9i
SQL>!wrap iname=aa.sql oname=aa.pls
SQL>@aa.pls
Procedure created.
SQL>@rowid
BLK FNO RNUM 'CHAR       PART    VERSION     PIECE#     LENGTH
------ --- ---- ----- ---------- ---------- ---------- ----------
49722   1   22 sb4$           0  167772160          0         14
49722   1   23 sb4$           0  167772160          1          2
24966   1    7 ub1$           0  167772160          2          3
46407   1   14 CHAR$          0  167772160          3          5
52973   1    6 UB2$           0  167772160          4        131
52973   1    7 UB2$           0  167772160          5         10
49722   1   24 sb4$           2  167772160          0         18
15481   1    0 ub1$           2  167772160          1        174
15481   1    1 ub1$           2  167772160          2          1
9 rows selected.
 Simple unwrapping PL/SQL in 10g
SQL>exec dumpdiana.dump(aname => 'AA');
user: SYS
PL/SQL procedure successfully completed.
SQL>@unwrap_r
Running dumpdiana
Procedure created.
creates the same DIANA
SQL>exec unwrap_r('AA');
tree dump trace file as 9i
Start up
CREATE OR REPLACE
Running the proof of
PROCEDURE AA
concept un-wrapper still
IS
works in 10g
BEGIN
NULL;
The wrap process in 10g
END;
is different though
/
PL/SQL procedure successfully completed.

No comments:

Post a Comment