Wednesday, February 08, 2012

SQL Developer 3.1 and Obfuscation

SQL Developer 3.1 , SQL Developer Datamodeler 3.1, and the OTN DB VM were all released yesterday.  Now it's time to blog about some of the new features included in these releases.  Be sure to check out the various blogs the team has.  There's a listing on OTN here.

First up from me is PL/SQL Obfuscation.  The idea is to simply make the code unreadable.  This is done in various language mostly for protection of the intelectual property.  The website, http://perl.plover.com/obfuscated/ shows this examplefrom a contest that used to run for Perl.


@P=split//,".URRUU\c8R";@d=split//,"\nrekcah xinU / lreP rehtona tsuJ";sub p{
@p{"r$p","u$p"}=(P,P);pipe"r$p","u$p";++$p;($q*=2)+=$f=!fork;map{$P=$P[$f^ord
($p{$_})&6];$p{$_}=/ ^$P/ix?$P:close$_}keys%p}p;p;p;p;p;map{$p{$_}=~/^[P.]/&&
close$_}%p;wait until$?;map{/^r/&&<$_>}%p;$_=$d[$q];sleep rand(2)if/\S/;print

The PL/SQL one SQL Developer now has isn't to this extreme but does make the code quite difficult to read.  If someone obfuscated and then wrapped the code, that would be 2 hurdles in the way to assist licensing and other agreements to protect the IP invested.


Here's the steps to try it out.

1) Open a PL/SQL Object.  This is a package I have that mirror DBMS_OUTPUT but send to a pipe instead.  It allows me to basically do a tail -f on my code's log messages and watch it as it processes.  If anyone is interested in that I can write it up another time.




2) Right click and choose Obfuscate...


3) SQL Developer will prompt to save the non-obfuscated code so there is a readable copy.


4) Check out the sources.  It can be undone by a determined person quite easy with a lot of search and replace but at least it puts a hurdle in the way.

create or replace
PACKAGE BODY pipe_output IS
PROCEDURE set_pipeoutput_on IS
-- Opens the communication pipe
BEGIN
   pv_pipe_on_bln := TRUE;
END set_pipeoutput_on;

PROCEDURE put_line (p_pipe_name VARCHAR2,p_message_txt VARCHAR2) IS
-- Sends the username of the executing user and a message to the pipe
  "CpaX6WrU0YmLxF5r4E46dw==" PLS_INTEGER;
 "Y1QFM4yVoF5S9b7fNyG/YQ==" varchar2(4000);
BEGIN
    if ( pv_pipe_on_bln ) then
      "Y1QFM4yVoF5S9b7fNyG/YQ==" := to_char(systimestamp,'HH24:MI:SS.FF6') ||':'||p_message_txt;
      DBMS_PIPE.PACK_MESSAGE("Y1QFM4yVoF5S9b7fNyG/YQ==");
      "CpaX6WrU0YmLxF5r4E46dw==" := DBMS_PIPE.SEND_MESSAGE(p_pipe_name,0.0001);
    end if;
END put_line;

PROCEDURE put_line (p_message_txt VARCHAR2) IS
-- Sends the username of the executing user and a message to the pipe
  "CpaX6WrU0YmLxF5r4E46dw==" PLS_INTEGER;
BEGIN
   IF (pv_pipe_on_bln) THEN
      DBMS_PIPE.PACK_MESSAGE(USER);
      DBMS_PIPE.PACK_MESSAGE(p_message_txt);
      "CpaX6WrU0YmLxF5r4E46dw==" := DBMS_PIPE.SEND_MESSAGE('OUTPUT');
   END IF;
END put_line;

PROCEDURE get_line (p_waittime_num NUMBER := 1) IS
-- Monitors the pipe based on a specified wait time, reading and
-- displaying the username and messages as they are sent from the
-- executing process.
   "CpaX6WrU0YmLxF5r4E46dw=="            PLS_INTEGER;
   "cy5MsI3IbOrf1eySVcYcZQ=="          VARCHAR2(30);
   "9C7AbyOB7jrbTAPf3Xpm7w=="           VARCHAR2(2000);
   "=C7AbyOB7joas2oSfUfb6NF431LXcf" BOOLEAN := FALSE;
BEGIN
   LOOP
      "CpaX6WrU0YmLxF5r4E46dw==" := DBMS_PIPE.RECEIVE_MESSAGE('OUTPUT',
         p_waittime_num);
      EXIT WHEN ("CpaX6WrU0YmLxF5r4E46dw==" != 0);
      "=C7AbyOB7joas2oSfUfb6NF431LXcf" := TRUE;
      DBMS_PIPE.UNPACK_MESSAGE("cy5MsI3IbOrf1eySVcYcZQ==");
      DBMS_PIPE.UNPACK_MESSAGE("9C7AbyOB7jrbTAPf3Xpm7w==");
      DBMS_OUTPUT.PUT_LINE(RPAD('USER: '||"cy5MsI3IbOrf1eySVcYcZQ==",30)||
                           'MESSAGE: '||"9C7AbyOB7jrbTAPf3Xpm7w==");
   END LOOP;
   IF NOT "=C7AbyOB7joas2oSfUfb6NF431LXcf" THEN
      DBMS_OUTPUT.PUT_LINE('No output in pipe.');
   END IF;
END get_line;

   PROCEDURE get_line (p_pipe_name VARCHAR2,p_waittime_num NUMBER := 1) IS
-- Monitors the pipe based on a specified wait time, reading and
-- displaying the username and messages as they are sent from the
-- executing process.
   "CpaX6WrU0YmLxF5r4E46dw=="            PLS_INTEGER;
   "cy5MsI3IbOrf1eySVcYcZQ=="          VARCHAR2(30);
   "9C7AbyOB7jrbTAPf3Xpm7w=="           VARCHAR2(2000);
   "=C7AbyOB7joas2oSfUfb6NF431LXcf" BOOLEAN := FALSE;
BEGIN
   LOOP
      "CpaX6WrU0YmLxF5r4E46dw==" := DBMS_PIPE.RECEIVE_MESSAGE(p_pipe_name,
         p_waittime_num);
      EXIT WHEN ("CpaX6WrU0YmLxF5r4E46dw==" != 0);
      "=C7AbyOB7joas2oSfUfb6NF431LXcf" := TRUE;
      DBMS_PIPE.UNPACK_MESSAGE("cy5MsI3IbOrf1eySVcYcZQ==");
      DBMS_PIPE.UNPACK_MESSAGE("9C7AbyOB7jrbTAPf3Xpm7w==");
      DBMS_OUTPUT.PUT_LINE('MESSAGE: '||"9C7AbyOB7jrbTAPf3Xpm7w==");
   END LOOP;
   IF NOT "=C7AbyOB7joas2oSfUfb6NF431LXcf" THEN
      DBMS_OUTPUT.PUT_LINE('No output in pipe.');
   END IF;
END get_line;
PROCEDURE get_line (p_pipe_name IN VARCHAR2,p_waittime_num IN NUMBER := 1,p_message OUT VARCHAR2)
IS
-- Monitors the pipe based on a specified wait time, reading and
-- displaying the username and messages as they are sent from the
-- executing process.
   "CpaX6WrU0YmLxF5r4E46dw=="            PLS_INTEGER;
   "9C7AbyOB7jrbTAPf3Xpm7w=="           VARCHAR2(2000);
BEGIN
   LOOP
     PUT_LINE('KLRICE','Recieving');
      "CpaX6WrU0YmLxF5r4E46dw==" := DBMS_PIPE.RECEIVE_MESSAGE(p_pipe_name, p_waittime_num);
      EXIT WHEN ("CpaX6WrU0YmLxF5r4E46dw==" != 0);
      PUT_LINE('KLRICE','got something');
      DBMS_PIPE.UNPACK_MESSAGE("9C7AbyOB7jrbTAPf3Xpm7w==");
      p_message :="9C7AbyOB7jrbTAPf3Xpm7w==";
   END LOOP;
END get_line;


END pipe_output;