- Make sure you know about online commandline builder
for Perl-Obfus
- Prepare makefile
- Update use of symbol names in the modules
- Update the export tables for your modules and
'use vars' statements
- Test your original code with all modifications necessary
for protection applied
- Collect names of symbols that should not be modified.
- Test protection with "lite" protection applied
Steps in detail
Make sure you know about online commandline builder
for Perl-Obfus
Make sure you are aware of Stunnix interactive online
commandline builder. It not only helps to build command lines, but
can be used as a Table Of Content for the Perl-Obfus manual.
Prepare makefile
Prepare a Makefile for a Make utility or compose a script that will perform
protection for your entire project; make sure that it allows to edit
commandline options applied to all invokations of Perl-Obfus in a single
place. It will be very useful since you will have to run Perl-Obfus
on your entire project several times, with different settings.
Update use of symbol names in the modules
Find all places in your code that uses symbol names to make a reference.
Add the following lines to the begining of those files(or make sure
that the definitions of these functions are visible to your code from
some base module):
#the definition for SN and SNS
BEGIN{eval('sub SNS{@_;}sub SN{$_[0];}');}
Most typical is update necessary to 'use vars' statement:
#before
use vars qw($foo @bar %blah);
#after
use vars SNS(qw($foo @bar %blah));
Sometimes you may have to put that 'use vars' block inside BEGIN{} block
if 'use vars' block is at the topmost level in your file.
If the name of the symbol is a string constant, wrap it into the call of
SN subroutine:
#before
my $method = "process";
$obj->$method();
#after
my $method = SN("process");
$obj->$method();
#before
my $varname = "myvar";
eval("\$$varname = 23; \$blah = 15;");
#after
my $varname = SN("myvar");
eval("\$$varname = 23; \$" . SN('blah') . "=15;");
If your code uses some string that comes from external source as a name
of the symbol, list all possible names of symbols as exceptions.
E.g. the example below you will have to list 'f1' and 'f2' as exceptions
in the 'exceptions.txt' file, otherwise your code won't work once protected
since there won't be subroutines with names 'f1' and 'f2' (there would
be subs with names something like z343a1b034 and z5e915db6).
sub f1 {}
sub f2 {}
my $subnm = CGI::param('what');
&$f1();
Update the export tables for your modules and
'use vars' statements
Modify all modules that have @EXPORT variable defined and that use
Exporter.pm, to use SN and SNS subroutines (read previous step for more
information).
E.g. code before:
BEGIN {
use Exporter ();
use vars qw($VERSION @ISA @EXPORT %h1 @list1 $var2);
$VERSION = 1.00;
@ISA = qw(Exporter);
@EXPORT = qw(%h1 @list1 $var2);
};
The code should look like the following after your modifications:
sub SN { '';$_[0]; } #return 1st argument
sub SNS { '';@_; } #return all arguments
BEGIN {
use Exporter ();
use vars (SNS(qw($VERSION @ISA @EXPORT %h1 @list1 $var2)));
$VERSION = 1.00;
@ISA = qw(Exporter);
@EXPORT = SNS(qw(%h1 @list1 $var2));
};
Note that list of names of variables in 'use vars' was wrapped in call of SNS;
the initializer of @EXPORT was also wrapped in call of SNS();
Test your original code with all modifications necessary
for protection applied
Make sure your original code, after making all modifications described in
the steps above, works as the code before your modifications.
Collect names of symbols that should not be modified.
There can be several reasons a symbol should not be replaced with a meaningless
string - most frequently case is when the symbol is in external module
that is shipped in non-protected form (for perl, such modules are e.g. CGI).
Another case is when some symbols are used from the parts of your application,
that are not obfuscated - e.g. from html templates with embedded perl code.
There are several options available on how to do this:
-
Only for the first case (symbols from external Perl modules):
use 'gen-ident-exceptions.pl' utility shipped with Perl-Obfus, like this:
(command will save list of external symbols used by files
'file1.pl', 'file2.pl', 'file3.pm' to file named 'symlist.txt') -
for unix
(assuming you don't have any third-party modules in the directories
relative to current - i.e. if all third-party modules reside in /usr/):
gen-ident-exceptions.pl -d / symlist.txt file1.pl file2.pl file3.pm ..
for windows (assuming you don't have any third-party modules in the
directories relative to current - i.e. if all third-party modules reside
in 'c:\'):
perl gen-ident-exceptions.pl -d c: symlist.txt file1.pl file2.pl file3.pm ..
- For symbols that are defined in public interface of ActiveX or OLE
component, it's possible to extract names of these symbols using
Project Manager. Start Project Manager, go to the Tools menu
and select 'Extract symbols from ActiveX components' (this menuitem
is available only on Windows platforms). For each component your
project uses, select the component, click 'Extract' button, and you
will be prompted to
save a list of exceptions extracted from the component to the file
of your choice. Please note that Evaluation and Demo editions don't
offer this functionality (empty file will be produced).
- Produce list of exceptions manually. Sometimes this is necessary even
for symbols from external Perl modules too. Just add them to the
file (e.g. named 'symlist.txt') one per line.
Test protection with "lite" protection applied
Apply "lite" protection to your application, and test as much of your
app as possible (i.e. try to perform all operations, or at least
most common; try to visit links of all types on the site or all menuitems
in GUI app).
The 99% of the problems encountered when trying to run protected app is
that some symbol from external module was not listed as exception, and got
replaced with different name. Once run, you will get errors like
"Undefined subroutine CGI::z34ea8c" in places where original code calls
"CGI::param()" and "param" is not listed as exception. In order to easily
identify that "CGI::z34ea8c" should stand for "CGI::param()", one should
to use "lite" protection, that will make symbols only slightly less
understandable, but different from original, e.g. you will get errors like
"Undefined subroutine CGI::Z439Z_param", that will signal you that
"param" is not listed as exception. The following commandline will
stand for "lite" protection:
perl perl-obfus -i prefix -n none -s none -e 0
that will stand for
"Number of encoding iterations applied: 0 - don't encode",
"Obfuscation of symbol names: none",
"Obfuscation of integer constants: none",
"Obfuscation of strings: none" options in interactive online
commandline builder.
You can use find-undeclared-subs.pl
- utility shipped with Perl-Obfus, for finding calls of undeclared
subroutines instead of some fraction of manual testing of modules.
If your code uses 'use strict' pragma, it will help a lot too, since
undeclared variables will be detected at compile-time.
Once your app works correctly once such "lite" protection is applied,
you should apply "final" protection, using options you wish. It such
"finally-protected app" works differently, revert commandline options
back to "lite" protection, and turn on each type of protection
incrementally, e.g. turn on "Obfuscation of integer constants", then
"Obfuscation of string constants", then
"Number of encoding iterations applied: 10", testing your app one each
step. Make sure you are familiar with the
"BUGS" section in Perl-Obfus manual, that lists common bugs revealed
in the Perl interpreter itself when it runs protected code, and update your
orignal code accordingly.