MarginalHacks.com DaveSource.com
perlc
Perl source code "compiler" / hider
 

What is it?

Converts perl code into either C code and/or an executable.

What's the point?

I'm a big fan of Perl. It's a great way to develop code. If you want to release Perl code, though, you generally have to release the source.

Lots of people want to release/distribute Perl scripts with the source code hidden, so how to do this without revealing the source is a FAQ.

Unfortunately the generally accepted answer is that you can't, or that it doesn't really work, or you shouldn't, or it costs lots of money. And no matter what you do, someone smart enough can extract the Perl code anyways, so don't bother.

These answers are mostly true, and also a big copout. Ignoring the practicality of hiding the code in most situations just because someone can get the code is like deciding to not lock your house anymore, just because locks can be picked. I can pick the lock on your house. Fortunately I won't, and it's difficult for most people to do, so I still suggest you lock your doors. Besides, if you make it hard enough to get to the code, than the person talented enough to extract it will probably be fully capable to write it themselves and won't bother. :)

So there are still plenty of things we can do to hide perl source code in most cases and against most users. Unfortunately there just haven't been any good tools to accomplish this. Here's a list of tools I found that failed to solve this problem for me:

perlcc
Buggy, unsupported, generally assumed to not work. (My own simple test script seg faulted when it saw the 'die()' construct)
perl2exe
Costs money. Evaluation version can only be used for 30 days, and executables print an "evaluation version" message with a 2 second pause on exit. For those willing to pay, this is evidently a good solution with cross-compilation capabilities.
perlapp
Commercial, though it does package required modules.
par/pp
The script is unpacked into a directory in temp.
  ... with filter Bleach
Very easy to reverse, change eval with print
  ... with filter Obfuscate
Just changes names, can still edit and manage code
  ... with filter Crypto
All you need is Filter::Crypto::Decrypt, and/or crypt_file!

Besides, any solution that uses the local installation of perl is easy to get around, simply temporarily replace the perl binary with something that prints and saves to a file.

Unfortunately this means you need to package perl with your script or else use libperl. If you use libperl they could still conceivably write a fake library to print out the script, alternatively you could statically compile libperl with your executable, making it far more difficult to reverse engineer.

Regardless, it IS possible to wrap your perl script into a C program that evals the script in a perl interpretor, and maybe even obfuscate the script a bit while we're at it. It's just that nobody seems to have made a tool for it...

Until now...

perlc

Takes a single perl script, converts the block using a simple encoding with an optionally defined key. The script is decoded at runtime and fed to the perl library, to avoid it getting in the hands of the user.

You can optionally run the PAR::Filter::Bleach on the code to make it even harder to extract. Bleach by itself is inadequate "obscurity" in this authors view, but it makes it harder to find and extract an already encoded script embedded in a C executable. It's a slight overhead in size and startup cost, plus another 'eval', but it's recommended if the output code still works.

Normally it creates a smaller executable that uses libperl, but this has two issues:

  1. Slightly easier to extract the perl script by supplying a fake libperl
  2. Requires that they have the correct version of libperl

There is the option to statically link libperl, it may or may not work for you - you may need to edit $LIBPERL at the top of the script.

Licensing support

Sometimes we also want to limit distribution of the script. Again, the answer is usually that this won't stop a motivated and intelligent hacker. True. But that's a small portion of the population. So, short of writing a complete licensing solution, we can do simple things like check the mac address (hoping that it hasn't been programmatically changed :-)

Any script converted by perlc will have access to the MACADDR (of the first NIC on the machine) available in $ENV{MACADDR}. Furthermore, you can specify a required MACADDR when you create the executable using the -mac option - this ends up in the C code instead of the perl code and is perhaps harder to modify or get around. Perhaps.

Future versions may have a simple licensing file with an encoded host id and expiration date, let me know if that idea inspires you

BUGS/CAVEATS

  • -static is kludgy at best, and probably will have problems with any modules you are using unless they are standard and put in standard locations. Consider figuring out ways to package them with the script or else adjust @INC in a BEGIN block.
  • Cross compilation not supported.
  • Would probably need to be modified to handle non-standard modules. I haven't tested it yet.
  • $0 in the script is set to '-e' and $^X is the executable, not perl Trying to change $0 in the script causes a segfault, this is a bug in perl.

    Instead, I suggest reading $0 into another variable like this:

    my $PROGNAME = $0 eq '-e' ? $^X : $0;

    Unfortunately, some libraries use $0 (such as ccopts in ExtUtils::Embed) and you can't get around that without changing the library. This is why, for example, you can't run perlc on perlc and get a working executable.

  • If you don't 'hide' the 'key' value that is sent to decode(key) in the C code, then it can easily be found with strings, and an adept programmer familiar with perlc could extract the code block and decode it. The key value to decode can't change, but you can construct it so that it isn't just a constant string in the executable.
  • The encoding is weak encryption, so you should remove the '#!perl' from the beginning of your script (it's unnecessary for perlc) and use a long random key so it's not trivial to figure the key out
  • Anyone with a debugger and some cleverness can still extract the script. Security via obscurity is never perfect. Don't use perlc if you don't like it.

Requires:

  1. Perl, which kicks ass

Kludges:

License:

This software is essentially free, but please read my payment spiel
Please read the full license

Download:

It's a single perl script.

I suppose I could also supply an executable... :)

Install

It's just a perl script. No install required.

Freshmeat?

You bet.