http://www.perlmonks.org?node_id=183932

tame1 has asked for the wisdom of the Perl Monks concerning the following question:

Recently, my employer closed his doors. We were able to talk him into letting us take our laptops. Of course, we had to pay for them. Along with cash, I signed a contract to provide 6.5 hours of contracting services.

Anyhow, he has asked me to look into some methods to protect the source code we developed (all mod_perl/apache).

I tried Conway's Acme::Bleach, but it won't work and does some really STRANGE stuff to httpd.conf and other conf files, all on it's own. Not good.

perl2exe isn't gonna cut it, as I don't want the perl binary embedded into each and every module! The Zend Encoder is strictly PHP. Heck, I can't even find a nice script around here that will at least do a blanket removal of non-essential spaces and carriage returns. That won't really protect the code, but it'd be a real b*tch to undo.

Can anyone think of a product or script that would somehow secure perl source code (other than begging Damian and the other's to make perlcc work with more complex programs than "Hello World" - which won't work anyhow, now that I think about it, since the perl interpreter/compiler is in the apache.)?

What does this little button do . .<Click>; "USER HAS SIGNED OFF FOR THE DAY"

Replies are listed 'Best First'.
Re: Protecting perl source code
by grep (Monsignor) on Jul 22, 2002 at 06:05 UTC

    This is a FAQ.

    perldoc -f hide

    How can I hide the source for my Perl program?

    Delete it. :-) Seriously, there are a number of (mostly unsatisfactory) solutions with varying levels of ``secu­rity'' ...



    grep
    XP matters not. Look at me. Judge me by my XP, do you?
Re: Protecting perl source code
by Kanji (Parson) on Jul 22, 2002 at 05:30 UTC
    That won't really protect the code, but it'd be a real b*tch to undo.

    *cough* *cough* Perltidy *cough*

        --k.


      Aw sh*t! I hadn't thought about that, and I use perltidy a lot!

      What does this little button do . .<Click>; "USER HAS SIGNED OFF FOR THE DAY"
Re: Protecting perl source code
by dws (Chancellor) on Jul 22, 2002 at 03:49 UTC
    I signed a contract to provide 6.5 hours of contracting services. ... he has asked me to look into some methods to protect the source code we developed (all mod_perl/apache).

    Wow. You lucked out. It'll take you at least 6.5 hours of looking around before you tell him that a lot of people have chewed on this problem and have come up with very little.

      For standalone scripts, Acme::Bleach comes darned close to keeping out all but a darn good perl wizard. It'll take someone almost as good as Damian, I think, to reverse engineer a Bleached file, even with Bleach.pm to use to see how it was done. Unfortunately, I'm working in mod_perl, so these are not standalone scripts.

      What does this little button do . .<Click>; "USER HAS SIGNED OFF FOR THE DAY"
        Acme::Bleach comes darned close to keeping out all but a darn good perl wizard.

        That module already contains the debleaching ingredients and it wouldn't take a wizard to write a bleached debleaching script.

        use Acme::Bleach; $/ = undef; $_ = <>; s/.*^\s*use\s+Acme::Bleach\s*;\n//sm; print Acme::Bleach::brighten($_);
Re: Protecting perl source code
by Courage (Parson) on Jul 22, 2002 at 05:31 UTC
    I've developed a technology that allows me to stick all used *.pm files into single file, which optionally (but almost always) compressed using Compress::Zlib and can be used to hide source.

    I did that for simplier file packaging and not for hiding a source (which in my case can be revelaed by a special function) but is somewhat close to what you're searching for.

    Courage, the Cowardly Dog.

Re: Protecting perl source code
by JayBonci (Curate) on Jul 22, 2002 at 10:15 UTC
    The only real suggestion I have for you is take the code you want to protect, and throw it in a file as a data segment, and make a self-decripting perl file that takes one command line argument, the key. The entire point of this wrapper perl file would be to read the data in, decrypt, unpack it, and then eval it. To obscure a script language is difficult, no matter what you do, especially if it's heavily bound to the interpreter. If you need to hide stuff away, consider either packing away the string that contains the code (or using Storable to freeze it)and then encrypting with one of the major perl Crypt::* modules.

    Other than that, enjoy the time off. Keep the decryption key.

        --jb
Re: Protecting perl source code
by ignatz (Vicar) on Jul 22, 2002 at 14:43 UTC
    I wonder how many copies of the source walked out the door with those laptops he sold to y'all. ;-)

    This sounds to me like he's paying you to chase your tail for six hours. The best way to "protect" the code is to get a lawyer to make sure that all the copyright details are taken care of for the code so that it will be on record as an asset to the company.

    If this was a priority for the manager, he made a real bonehead move in having the application written in Perl in the first place. Still, Microsoft and Sun haven't had much luck either "protecting" their code from poor security and disgruntled employees.

    ()-()
     \"/
      `                                                     
    
      Exactly 0 copies. After my experience there, the last thing I wanted was to be dealing with him in the future about software theft. These 6.5 hours are even annoying, as I had high hopes of never having to respond to an email of his.

      The initial idea was for the system to be either an appliance or an ASP. In either case, we controlled access. I guess for his next company he's planning something else.

      I can chase my tail for 6.5 hours very easily. Once that is done, I am done with him. Fini!

      What does this little button do . .<Click>; "USER HAS SIGNED OFF FOR THE DAY"
Re: Protecting perl source code
by BUU (Prior) on Jul 22, 2002 at 07:48 UTC
    What exactly are you trying to protect it from? If your distributing it, unless you turn it into a binary (theres the indigo perl2exe), or maybe embed it in a c script, theres really no way to do it. If your just using it on the web, it should be fairly simple to prevent anyone from getting a look at it..
Re: Protecting perl source code
by PhiRatE (Monk) on Jul 22, 2002 at 23:32 UTC
    Ok, so, ignoring the fact that code on a computer controlled by the person trying to break it is nearly impossible to hide (there is in fact a nice paper somewhere about agent platforms and how one can be developed to be cryptographically strong by making the actual operations performed on behalf of the agent non-obvious, but this requires a remote trusted server or something, I forget), lets just ponder Ways Of Making It Tricky.

    The first limitation is mod_perl. The first question is whether you have access to the mod_perl code for the server, or whether its running on client-installed mod_perls in which case no modification can be made to mod_perl itself.

    The second limitation is that any obscured perl source is subject to perltidy and Deparse. There isn't a lot that can be done in terms of obscuring to stop someone changing parts of the source. Making large-scale changes would be difficult without everything neat and tidy, but little changes wouldn't be too hard, the success people have in deconstructing a lot of the obscured stuff here is a good indication of that.

    Lets assume we have no access to the mod_perl installation. This means that our ultimate objective is to make life as difficult as possible for someone to understand what the perl code is doing to retrieve its source for mod_perl. This also means you're gonna get a hell of a performance hit, since there are going to have to be multiple execution phases as one version of the code is decoded and then eval()'d.

    Probably the most effective method without burning too much performance is to use a standard crypto algorithm like AES for the main perl source. This makes that part impractical to break, lacking the key. Of course, we need the key to decrypt the code for execution so our next task is to hide that as well as we can.

    To do this, we take a short section of perl that does the decryption and eval(). We then proceed to spend as much time possible making it miserably difficult to understand. Since its a much smaller piece of code than the original, its easier to obscure in many different ways, and the performance hit from multiple eval()s of this section shouldn't be great. It is, unfortunately, also easier to figure out what a small piece of code is doing, each layer of obscure+eval could be slowly peeled back by use of perltidy, Deparse, and worst of all, the debugger which could run through until the final decoding lap and retrieve the key.

    So the next thing to do is to discourage those as much as possible. At each layer, put in a different check for mod_perl, to make sure you're not being run under regular perl. When you find it, don't die, sleep. or throw a weird error, or loop, or delete yourself if you're really paranoid. You also want to check for the presence of the debugger, there are various ways of finding out whether you're running in debug mode under mod_perl, use as many different checks as you can and again, sleep or die or do random things when you find it.

    Now we have a nasty, hard to break little decoder, but we have a few more tricks up our sleeve yet. The first is to detect tampering with yourself. An MD5 in a higher layer of the decode routine can run a check against the code on the filesystem and kill itself if the code doesn't match. More importantly, the md5 should attempt to notify a pre-determined email address if such tampering is taking place. This gives you plenty of warning if someone is trying to modify your code.

    Next we attempt to make life even more miserable by doing things like converting the resulting perl to bytecode (I'm not sure if mod_perl will run bytecode automatically but I think it will), potentially adding checks against the hardware to see if it matches the system you installed on, possibly call out to a key server controlled by your company to gain part of the decryption key on initial startup (thus preventing the script from being run on unauthorised platforms/by unauthorised people) (sign the transaction usign public key crypto and a random session key so they can't fake it, SSL with a cert would work). If possibly, include any pure-perl modules you're going to use within the code itself rather than loading from the path, since those modules could be compromised with print()s and other thigns to attempt to access the plain, decoded source.

    Our remaining problem is very simply that somewhere, in memory, is a copy of the operable bytecode. Its not nearly as useful as source but its still there. Your remaining option here is to do progressive decrypts. Implement a function call wrapper that decrypts certain sections of the code as they are required and destroys old code as it becoems defunct, so that no one memory snapshot will give them all the souce.

    At this point, it'll be easier for them to write their own than break yours, which is essentially the point of the entire operation.

    I note for completion that I would never, ever accept code like this running on a system I admined. I think the entire thing is a pointless exercise in futility and firmly believe that open source software is by far the preferable form of distribution, even if I have to pay for the application in the first place.

    Still, it was fun to think about :)

    Additional notes:

    The key to the entire thing is misdirection. The more time you waste of the person trying to break in, the more likely it is that they'll give up. Thus, making things "appear" to work is more effective than giving a clear indication that it failed. The first attempt to break through the evals, say by adding a print() that is picked up by the md5 challenge could, for example, result in the activation of a sub that re-writes the perl file that was executed with a similar but subtly different perl file that will never ever work by corrupting the encrypted section of the code and buggering up the higher layers of the decoder routine. They'll spend hours trying to figure out what the hell went on, unless they're a professional (the AV guys always start with a fresh copy and keep it in a sandbox so they can see what file ops its doing).

    It is also possible under C (but not necessarily under perl) to subvert the ptrace mechanism. I'm not sure if its still possible but two years ago I wrote some code that, if you ran strace on it, managed to make a fork of itself the parent of strace and nuke the process. Such things are very platform specific however.