It is common to buy software and need a key to then activate that software. We added dynamic obfuscation in this product so that we could easily add licensing to any PL/SQL. BUT, the dynamic obfuscation can also be used for other things as well to help protect your PL/SQL. This is what we intended when we added this feature; hence we can
- obfuscate PL/SQL code that normally would not be possible to obfuscate; for example if your code calls DBMS_OUTPUT.PUT_LINE() then you cannot obfuscate it to GGFDAD.HASDFAD() for instance as the database doesn't know what that is and we cannot change the name of DBMS_OUTPUT.PUT_LINE TO this as no other code that uses this SYS package would work.
- Standard string obfuscation is simple in PFCLObfuscate but it is better to do much stronger string obfuscations and we can do this via the dynamic obfuscation
- Locking the PL/SQL to a database. The standard license protection can limit the use of PL/SQL to a date/time limit. This is the simplest protection method for licensing. We can also lock PL/SQL to a database so that you can deploy the PL/SQL code and it is initially restricted and your customer runs an activation piece of code that generates hex strings. You then use this to create a license package and deploy that to your customer. Then the PL/SQL will be unlocked and work at the customer site. If someone takes the PL/SQL code and even the license key as well the protected PL/SQL won't work in the wrong database
- Target the beginning and end of code blocks or target the start or end of a declare block. Any PL/SQL can then be injected into your PL/SQL code
- Targeted comments; you can add a special PL/SQL comment to your PL/SQL code and then use dynamic obfuscation to inject any PL/SQL at obfuscation time to the exact place it's needed. This is a great feature as the developers do not write this code; the security team or others can inject the code at deploy time
Our dynamic obfuscation is very powerful and at a high level works with hook points that control when Lua scripts are executed by PFCLObfuscate. You control these Lua scripts and you can write any Lua you need and generate any PL/SQL that you need. This is incredibly flexible
You can combine together any of these dynamic obfuscation features for instance you can inject the standard license using the special PL/SQL comment feature and this is what I want to demo here.
NOTE: For this example I assume that the reserved.txt has been populated already. I am also using the command line to keep the contents much smaller so I don't need to include a lot of screen shots here.
First here is the sample PL/SQL I want to license:
C:\_aa\PD>type sam2.sql
create or replace procedure TEST_PROC( PV_NUM in NUMBER,
PV_VAR in VARCHAR2, PV_VAR3 in out INTEGER) IS
L_NUM NUMBER:=3;
L_VAR NUMBER;
J NUMBER:=1;
procedure NESTED( PV_LEN in out NUMBER) is
X NUMBER;
begin
X:= PV_LEN * 5;
end;
begin
case L_NUM
when 1 then
L_VAR:=3;
DBMS_OUTPUT.PUT_LINE('This is a header');
DBMS_OUTPUT.PUT_LINE('The number is ' || L_VAR);
DBMS_OUTPUT.PUT_LINE('The case var is ' || L_NUM);
when 2 then
L_VAR:=4;
DBMS_OUTPUT.PUT_LINE('This is a header');
DBMS_OUTPUT.PUT_LINE('The number is ' || L_VAR);
DBMS_OUTPUT.PUT_LINE('The case var is ' || L_NUM);
when 3 then
L_VAR:=6;
DBMS_OUTPUT.PUT_LINE('This is a header');
DBMS_OUTPUT.PUT_LINE('The number is ' || L_VAR);
DBMS_OUTPUT.PUT_LINE('The case var is ' || L_NUM);
else
DBMS_OUTPUT.PUT_LINE('wrong choice');
end case;
if ( ( J = 1) and ( J = 3)) then
DBMS_OUTPUT. PUT_LINE('here is IF');
elsif ( ( J = 2) or ( J != 3)) then
DBMS_OUTPUT.PUT_LINE('The elsif clause');
else
DBMS_OUTPUT.PUT_LINE('else clause');
end if;
J:=4;
NESTED( J);
DBMS_OUTPUT.PUT_LINE('nested=:' || J);
for J in reverse 1.. PV_NUM loop
if MOD( J,2) = 0 then
DBMS_OUTPUT.PUT_LINE('for loop with reverse');
end if;
end loop;
end;
/
C:\_aa\PD>
Install this code to the database:
C:\_aa\PD>sqlplus orablog/orablog@//192.168.56.77:1521/orclpdb.localdomain
SQL*Plus: Release 19.0.0.0.0 - Production on Tue Mar 29 19:49:37 2022
Version 19.12.0.0.0
Copyright (c) 1982, 2021, Oracle. All rights reserved.
Last Successful login time: Mon Mar 21 2022 16:07:58 +01:00
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
SQL>
Test the code to show that it works:
SQL> @sam2.sql
Procedure created.
SQL>
SQL> set serveroutput on
SQL> declare
2 lv_num number;
3 begin
4 test_proc(1,'hello',lv_num);
5 end;
6 /
This is a header
The number is 6
The case var is 3
The elsif clause
nested=:4
PL/SQL procedure successfully completed.
SQL>
Now add the special comment to the PL/SQL; I show only the code to where the special comment (--++TESTCOMMENT) is added:
C:\_aa\PD>type sam2.sql
create or replace procedure TEST_PROC( PV_NUM in NUMBER,
PV_VAR in VARCHAR2, PV_VAR3 in out INTEGER) IS
L_NUM NUMBER:=3;
L_VAR NUMBER;
J NUMBER:=1;
procedure NESTED( PV_LEN in out NUMBER) is
X NUMBER;
begin
X:= PV_LEN * 5;
end;
begin
--++TESTCOMMENT
case L_NUM
when 1 then
L_VAR:=3;
...
Now edit the functionfile.txt to add the comment processing rules:
C:\_aa\PD>type functionfile.txt
6|COMMENT|--++TESTCOMMENT|dbms_lic_begin_new.lua|dbms_lic_begin_fwd.lua|dbms_lic_begin_func.lua|1|1|0
C:\_aa\PD>
I only want the comment line in my dynamic obfuscation setup and also I use the existing Lua from the license code. I could write my own Lua if I wished or edit this Lua. Any valid Lua syntax can be used BUT the three Lua files do this:
1 - add the forward declaration of a function to do the work
2 - Add an actual function declaration to do the work
3 - add the "call". This calls the function that is declared above.
The PL/SQL added from the Lua must be valid PL/SQL; it will also be obfuscated as its injected into the parse stream
Edit the config file ob.conf to turn on dynamic obfuscation. I show just the dynamic settings here, nothing else changed
C:\_aa\PD>type ob.conf
...
# The function and string hide file. This file specifies a package to "hide" or
# strings to hide and then specifies the code to add new PL/SQL processing to
# deal with this and also PL/SQL substitute for the actual located string. This
# is detailed in the help
#
functionfile=functionfile.txt
#
# This parameter controls whether the intermediate files generated via any lua
# scripts are saved or not. This is useful for debugging.
#
#keepintermediate=yes
#
# This parameter controls whether the source code file containing the injected
# PL/SQL code is kept for debugging. The Injected code file contains all inserted
# headers, functions and the calls where the replace packages or strings. These
# are encased with {{n:n:n}} variables for removal.
#
#keepinsert=yes
#
# This parameter is the file extension used for the intermediate files. This
# can be changed.
#
intermediatefile=.imm
#
...
Add the procedure name TEST_PROC to the omit.txt so that the public name remains the same:
C:\_aa\PD>type omit.txt
TEST_PROC
C:\_aa\PD>
Update the license.txt to add the license rules:
C:\_aa\PD>type license.txt
expire_days=30
expire_date=27-MAR-2022
start_date=01-MAR-2022
license_type=trial
C:\_aa\PD>
Now obfuscate the code:
C:\_aa\PD>obs -v -c ob.conf -i sam2.sql -o sam2.opf
PFCLObfuscate: Release 2.1.46.1031 - Production on Tue Mar 29 21:38:33 2022
Copyright (c) 2017 PeteFinnigan.com Limited. All rights reserved.
[2022 Mar 29 20:38:33] obs: Starting PFCLObfuscate...
[2022 Mar 29 20:38:33] obs: Pre-Load Keywords from [key.txt]
[2022 Mar 29 20:38:33] obs: Pre-Load Omit words from [omit.txt]
[2022 Mar 29 20:38:33] obs: Pre-Load StringOmit words from [string.txt]
[2022 Mar 29 20:38:33] obs: Pre-Load Reserved words from [reserved.txt]
[2022 Mar 29 20:38:33] obs: Pre-Load force words from [force.txt]
[2022 Mar 29 20:38:33] obs: Pre-Load function file list from [functionfile.txt]
[2022 Mar 29 20:38:33] obs: Pre-Load map file list from [map.txt]
[2022 Mar 29 20:38:33] obs: Initialise the string file list...
[2022 Mar 29 20:38:33] obs: Version 2.0 Initialisation...
[2022 Mar 29 20:38:33] obs: Initialise the file list...
[2022 Mar 29 20:38:33] obs: Initialise the Depth Stack...
[2022 Mar 29 20:38:33] obs: Initialise the FWD Function list...
[2022 Mar 29 20:38:33] obs: Initialise the FUNC function list...
[2022 Mar 29 20:38:33] obs: Initialise the NEW function list...
[2022 Mar 29 20:38:33] obs: Running PFCLObfuscate PL/SQL Obfuscator
[2022 Mar 29 20:38:33] obs: Obfuscating PL/SQL Input File [ sam2.sql ]
[2022 Mar 29 20:38:33] obs: Save the transposed variables
[2022 Mar 29 20:38:33] obs: Process intermediate file...
[2022 Mar 29 20:38:33] obs: Closing Down PFCLObfuscate
C:\_aa\PD>
Put the PL/SQL obfuscated code in the database:
C:\_aa\PD>sqlplus orablog/orablog@//192.168.56.77:1521/orclpdb.localdomain
SQL*Plus: Release 11.2.0.4.0 Production on Tue Mar 29 21:48:41 2022
Copyright (c) 1982, 2013, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
SQL> @sam2.opf
Procedure created.
SQL>
Test the code; it should be blocked by the license as its expired; the license is set from 01-03-2022 to 27-03-2022 and its the 29th today
SQL> set serveroutput on
SQL> declare
2 lv_num number;
3 begin
4 test_proc(1,'hello',lv_num);
5 end;
6 /
declare
*
ERROR at line 1:
ORA-20095: invalid license(3)
ORA-06512: at line 1
ORA-06512: at "ORABLOG.TEST_PROC", line 1636713768
ORA-06512: at "ORABLOG.TEST_PROC", line 44
ORA-06512: at line 4
SQL>
change the license to end on the 30th March:
C:\_aa\PD>type license.txt
expire_days=30
expire_date=30-MAR-2022
start_date=01-MAR-2022
license_type=trial
C:\_aa\PD>
obfuscate again
C:\_aa\PD>obs -v -c ob.conf -i sam2.sql -o sam2.opf
PFCLObfuscate: Release 2.1.46.1031 - Production on Tue Mar 29 21:53:45 2022
Copyright (c) 2017 PeteFinnigan.com Limited. All rights reserved.
[2022 Mar 29 20:53:45] obs: Starting PFCLObfuscate...
[2022 Mar 29 20:53:45] obs: Pre-Load Keywords from [key.txt]
[2022 Mar 29 20:53:45] obs: Pre-Load Omit words from [omit.txt]
[2022 Mar 29 20:53:45] obs: Pre-Load StringOmit words from [string.txt]
[2022 Mar 29 20:53:45] obs: Pre-Load Reserved words from [reserved.txt]
[2022 Mar 29 20:53:45] obs: Pre-Load force words from [force.txt]
[2022 Mar 29 20:53:45] obs: Pre-Load function file list from [functionfile.txt]
[2022 Mar 29 20:53:45] obs: Pre-Load map file list from [map.txt]
[2022 Mar 29 20:53:45] obs: Initialise the string file list...
[2022 Mar 29 20:53:45] obs: Version 2.0 Initialisation...
[2022 Mar 29 20:53:45] obs: Initialise the file list...
[2022 Mar 29 20:53:45] obs: Initialise the Depth Stack...
[2022 Mar 29 20:53:45] obs: Initialise the FWD Function list...
[2022 Mar 29 20:53:45] obs: Initialise the FUNC function list...
[2022 Mar 29 20:53:45] obs: Initialise the NEW function list...
[2022 Mar 29 20:53:45] obs: Running PFCLObfuscate PL/SQL Obfuscator
[2022 Mar 29 20:53:45] obs: Obfuscating PL/SQL Input File [ sam2.sql ]
[2022 Mar 29 20:53:45] obs: Save the transposed variables
[2022 Mar 29 20:53:45] obs: Process intermediate file...
[2022 Mar 29 20:53:45] obs: Closing Down PFCLObfuscate
C:\_aa\PD>
Put the obfuscatedPL/SQL back in the database and test:
SQL> @sam2.opf
Procedure created.
SQL>
SQL> declare
2 lv_num number;
3 begin
4 test_proc(1,'hello',lv_num);
5 end;
6 /
This is a header
The number is 6
The case var is 3
The elsif clause
nested=:4
PL/SQL procedure successfully completed.
SQL>
Now it works of course as the license is valid.
If anyone would like more details or a demo please email me on pete at petefinnigan dot com