DBIx-Oracle-Unwrap
view release on metacpan or search on metacpan
lib/DBIx/Oracle/Unwrap.pm view on Meta::CPAN
package DBIx::Oracle::Unwrap;
use strict;
use MIME::Base64;
use IO::Uncompress::Inflate qw(inflate $InflateError);
use Readonly;
use File::Slurp;
=head1 NAME
DBIx::Oracle::Unwrap - Unwrap code obfuscated with the Oracle wrap command
=head1 VERSION
Version 0.06
=cut
our $VERSION = '0.06';
=head1 SYNOPSIS
This class unwraps text that has been obfuscated using the wrap utiltity
supplied with version 10 of Oracle and above. Note that it does not unwrap
text from earlier versions, as the method of obfuscation is different
How to unwrap code in a file
use DBIx::Oracle::Unwrap;
my $filename = "$HOME/plsql/mypackage.plb";
my $unwrapper = DBIx::Oracle::Unwrap->new();
my $unwrapped_text = $unwrapper->unwrap_file($filename);
How to unwrap code in the database.
use DBIx::Oracle::Unwrap;
use DBI;
my $dbh = DBI->connect('DBI:Oracle:orcl', 'scott', 'tiger');
my $source_sql = q/
SELECT text
FROM user_source
WHERE name = 'MYPACKAGE'
AND type = 'PACKAGE BODY'
ORDER BY line
/;
my $source = join("",@{$dbh->selectcol_arrayref($source_sql)});
my $unwrapper = DBIx::Oracle::Unwrap->new();
my $unwrapped_text = $unwrapper->unwrap($source);
=head1 METHODS
=cut
# this is the substituion table. All the characters in the base64 decoded text
# must be replaced with its lookup
Readonly::Array my @sub_table => (
0x3d, 0x65, 0x85, 0xb3, 0x18, 0xdb, 0xe2, 0x87, 0xf1, 0x52, 0xab, 0x63,
0x4b, 0xb5, 0xa0, 0x5f, 0x7d, 0x68, 0x7b, 0x9b, 0x24, 0xc2, 0x28, 0x67,
0x8a, 0xde, 0xa4, 0x26, 0x1e, 0x03, 0xeb, 0x17, 0x6f, 0x34, 0x3e, 0x7a,
0x3f, 0xd2, 0xa9, 0x6a, 0x0f, 0xe9, 0x35, 0x56, 0x1f, 0xb1, 0x4d, 0x10,
0x78, 0xd9, 0x75, 0xf6, 0xbc, 0x41, 0x04, 0x81, 0x61, 0x06, 0xf9, 0xad,
0xd6, 0xd5, 0x29, 0x7e, 0x86, 0x9e, 0x79, 0xe5, 0x05, 0xba, 0x84, 0xcc,
0x6e, 0x27, 0x8e, 0xb0, 0x5d, 0xa8, 0xf3, 0x9f, 0xd0, 0xa2, 0x71, 0xb8,
0x58, 0xdd, 0x2c, 0x38, 0x99, 0x4c, 0x48, 0x07, 0x55, 0xe4, 0x53, 0x8c,
0x46, 0xb6, 0x2d, 0xa5, 0xaf, 0x32, 0x22, 0x40, 0xdc, 0x50, 0xc3, 0xa1,
0x25, 0x8b, 0x9c, 0x16, 0x60, 0x5c, 0xcf, 0xfd, 0x0c, 0x98, 0x1c, 0xd4,
0x37, 0x6d, 0x3c, 0x3a, 0x30, 0xe8, 0x6c, 0x31, 0x47, 0xf5, 0x33, 0xda,
0x43, 0xc8, 0xe3, 0x5e, 0x19, 0x94, 0xec, 0xe6, 0xa3, 0x95, 0x14, 0xe0,
0x9d, 0x64, 0xfa, 0x59, 0x15, 0xc5, 0x2f, 0xca, 0xbb, 0x0b, 0xdf, 0xf2,
0x97, 0xbf, 0x0a, 0x76, 0xb4, 0x49, 0x44, 0x5a, 0x1d, 0xf0, 0x00, 0x96,
0x21, 0x80, 0x7f, 0x1a, 0x82, 0x39, 0x4f, 0xc1, 0xa7, 0xd7, 0x0d, 0xd1,
0xd8, 0xff, 0x13, 0x93, 0x70, 0xee, 0x5b, 0xef, 0xbe, 0x09, 0xb9, 0x77,
0x72, 0xe7, 0xb2, 0x54, 0xb7, 0x2a, 0xc7, 0x73, 0x90, 0x66, 0x20, 0x0e,
0x51, 0xed, 0xf8, 0x7c, 0x8f, 0x2e, 0xf4, 0x12, 0xc6, 0x2b, 0x83, 0xcd,
0xac, 0xcb, 0x3b, 0xc4, 0x4e, 0xc0, 0x69, 0x36, 0x62, 0x02, 0xae, 0x88,
0xfc, 0xaa, 0x42, 0x08, 0xa6, 0x45, 0x57, 0xd3, 0x9a, 0xbd, 0xe1, 0x23,
0x8d, 0x92, 0x4a, 0x11, 0x89, 0x74, 0x6b, 0x91, 0xfb, 0xfe, 0xc9, 0x01,
0xea, 0x1b, 0xf7, 0xce
);
sub _decode {
my $self = shift;
my $text = shift;
return unless $text;
# Decode text and ignore the SHA1 hash (first 20 characters)
my $decoded = substr(decode_base64($text), 20, length($text) - 1);
return unless $decoded;
my ($zipped, $source);
#Translate each character
foreach my $byte (split //, $decoded) {
$zipped .= chr($sub_table[ord($byte)]);
}
# Uncompress (inflate) the data
my $status = inflate \$zipped => \$source
or die "Can't decompress requested data: $InflateError\n";
return $source;
}
=head2 new
Create an instance of DBIx::Oracle::Unwrap:
my $unwrapper = DBIx::Oracle::Unwrap->new;
=cut
sub new {
my ($class, %args) = @_;
return bless \%args, $class;
}
=head2 unwrap
Unwrap the provided text:
my $unwrapped_text = $unwrapper->unwrap($mytext);
=cut
sub unwrap {
my $self = shift;
my $text = shift;
my @line = split("\n", $text);
# Line 20 marks the beginning the last line of the header. Everything
# beyond is the wrapped code. The second number on line 20 is the length of
# the base 64 encoded text. If the 20th line doesn't meet the pattern below
# then chances are the code is either not wrapped, or it uses the wrapper
# from Oracle 9
# The second line appears to be '0' in the older wrapper, so don't even
# try unwrapping if that's the case with the supplied text
return
unless (($line[19] =~ /^[0-9a-f]+ [0-9a-f]+$/)
&& ($line[1] ne '0')
&& ($line[0] =~ /\bwrapped\b/));
my $enc_source = join("", @line[20 .. scalar(@line) - 1]);
return $self->_decode($enc_source);
}
=head2 unwrap_file
Unwrap the text in the file provided:
$my $unwrapped_text = $unwrapper->unwrap_file($file_name);
=cut
( run in 2.188 seconds using v1.01-cache-2.11-cpan-df04353d9ac )