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

I know this horse has been beaten and there is plenty of info out there.

I'm curious if anyone is using obfuscation via Acme::Eyedrops for production code. I've been doing it for a long while now and I'm looking for liabilities in doing so. I do have some complicated code, but have not had anything blow up. I'm using TrapEvalDie and I created a shape that is nothing more than 60 '#' in one line. In my build process I've created a dependency of .pl to .eye. I'vw written a utility that converts the .pl to .eye vua eyedrops. It creaets a new file with the shebang, copy wright info, date/time converted, and contact info. Below that is the conversion. The covnersion can make the code 10x greater in size. The code runs on an embedded device and loads from a lzma squashfs ram disk. So far the only liability I've found is longer load time.

I'm not too concerened about the users attempting a reverse enginner. I'm practicing sercurtry thru obsecurity. The conversion process also allows me to run a syntax check on the code at build time and prevents me from sending wrong code to the device.

So, I'm want to know issues of Acme::Eyedrops in production and waht liabilities I need to be aware that when converted could cause me issue.

Thanks, Chris

Replies are listed 'Best First'.
Re: Production obfuscation
by eyepopslikeamosquito (Bishop) on Apr 20, 2012 at 21:38 UTC

    I know this horse has been beaten and there is plenty of info out there
    Actually, I don't think it has. As the author of Acme::EyeDrops, the only animal I'm aware of being harmed for production obfuscation is not a horse but a frolicking wombat, proposed by `/anick in 2002 to enhance "psychological obfuscation" because "surely the script dealing with super-secret FBI passwords isn't that ASCII picture of a frolicking wombat".

    So, I'm want to know issues of Acme::EyeDrops in production and what liabilities I need to be aware that when converted could cause me issue
    If you haven't already done so, read the "EyeDropping" section in the Acme::EyeDrops documentation and follow the advice there. As that section indicates, (a non-trivial module) has been successfully converted into 151 camels and all tests still pass. At that time, I was considering distributing the module itself in EyeDrop'ed form but decided against it not because it didn't work but because it was four times slower. Also note that if you set the PERL_SMOKE environment variable before running "make test", the test suite will automatically convert and the test suite itself into camels and run them again. Which passes. So I have fair confidence that you won't hit any serious problems with your approach and if you do, you should be able to work around them (as was done with the "eval-hostile" line in, described in the "EyeDropping" section). Having said that, it would be prudent to have a test suite for your code and to run it both before and after EyeDrop-ification.

      I've wondered what's the difference (functionality-wise) between Acme::EyeDrops and Acme::Bleach?

      Has this been covered elsewhere? Filters are interesting.

        I've wondered what's the difference (functionality-wise) between Acme::EyeDrops and Acme::Bleach?
        I'm not aware of a detailed comparison between them. So I might write one as a top level node in the next week or so, if I can find the time (update: new top level node is The History of Acme::Bleach and Acme::EyeDrops).

        Both EyeDrops and Bleach encode the source code. Bleach does so by converting the stream of bits in each source code character to spaces (0) and tabs (1) as indicated by this snippet from its source code:

        sub whiten { local $_ = unpack "b*", pop; tr/01/ \t/; ... }
        In contrast, EyeDrops encodes each "unsightly" (i.e. alphanumeric) character by using a bitwise operator on two or more "sightly" (i.e. non-alphanumeric) ones. This is done via a lookup table as indicated by this snippet from its source code:
        my @C = ( q Z('!'^'!')Z,q Z('('^')')Z,q Z('<'^'>')Z,q Z('>'^'=')Z, q Z('>'^':')Z,q Z('>'^';')Z,q Z('+'^'-')Z,q Z('*'^'-')Z, q Z('+'^'#')Z,q Z('*'^'#')Z,q Z('!'^'+')Z,q Z('!'^'*')Z, q Z('!'^'-')Z,q Z('!'^',')Z,q Z('!'^'/')Z,q Z('!'^'.')Z, q Z('?'^'/')Z,q Z('<'^'-')Z,q Z('-'^'?')Z,q Z('.'^'=')Z, q Z('+'^'?')Z,q Z('*'^'?')Z,q Z('?'^')')Z,q Z('<'^'+')Z, q Z('%'^'=')Z,q Z('&'^'?')Z,q Z('?'^'%')Z,q Z('>'^'%')Z, q Z('&'^':')Z,q Z('<'^'!')Z,q Z('?'^'!')Z,q Z('%'^':')Z, q Z('{'^'[')Z,q Z'!'Z,q Z'\\\\'.'"'Z,q Z'#'Z, q Z'\\\\'.'$'Z,q Z'%'Z,q Z'&'Z,q Z"'"Z,q Z'('Z,q Z')'Z, q Z'*'Z,q Z'+'Z,q Z','Z,q Z'-'Z,q Z'.'Z,q Z'/'Z, q Z('^'^('`'|'.'))Z,q Z('^'^('`'|'/'))Z,q Z('^'^('`'|','))Z, q Z('^'^('`'|'-'))Z,q Z('^'^('`'|'*'))Z,q Z('^'^('`'|'+'))Z, q Z('^'^('`'|'('))Z,q Z('^'^('`'|')'))Z,q Z(':'&'=')Z, q Z(';'&'=')Z,q Z':'Z,q Z';'Z,q Z'<'Z,q Z'='Z,q Z'>'Z,q Z'?'Z, q Z'\\\\'.'@'Z,q Z('`'^'!')Z,q Z('`'^'"')Z,q Z('`'^'#')Z, q Z('`'^'$')Z,q Z('`'^'%')Z,q Z('`'^'&')Z,q Z('`'^"'")Z, q Z('`'^'(')Z,q Z('`'^')')Z,q Z('`'^'*')Z,q Z('`'^'+')Z, q Z('`'^',')Z,q Z('`'^'-')Z,q Z('`'^'.')Z,q Z('`'^'/')Z, q Z('{'^'+')Z,q Z('{'^'*')Z,q Z('{'^')')Z,q Z('{'^'(')Z, q Z('{'^'/')Z,q Z('{'^'.')Z,q Z('{'^'-')Z,q Z('{'^',')Z, q Z('{'^'#')Z,q Z('{'^'"')Z,q Z('{'^'!')Z,q Z'['Z, q Z'\\\\'.'\\\\'Z,q Z']'Z,q Z'^'Z,q Z'_'Z, q Z'`'Z,q Z('`'|'!')Z,q Z('`'|'"')Z,q Z('`'|'#')Z, q Z('`'|'$')Z,q Z('`'|'%')Z,q Z('`'|'&')Z,q Z('`'|"'")Z, q Z('`'|'(')Z,q Z('`'|')')Z,q Z('`'|'*')Z,q Z('`'|'+')Z, q Z('`'|',')Z,q Z('`'|'-')Z,q Z('`'|'.')Z,q Z('`'|'/')Z, q Z('['^'+')Z,q Z('['^'*')Z,q Z('['^')')Z,q Z('['^'(')Z, q Z('['^'/')Z,q Z('['^'.')Z,q Z('['^'-')Z,q Z('['^',')Z, q Z('['^'#')Z,q Z('['^'"')Z,q Z('['^'!')Z,q Z'\\\\'.'{'Z, q Z'|'Z,q Z'\\\\'.'}'Z,q Z'~'Z,q Z('!'^'^')Z ); push @C, map(join('.', q#'\\\\'#, $C[120], map($C[$_], unpack('C*', sprintf('%x', $_)))), 128..255); sub ascii_to_sightly { join '.', map($C[$_], unpack('C*', $_[0])) }
        (See also the "Sightly Encoding" section in the Acme::EyeDrops documentation).

        The big difference between the two approaches lies in the decoding. Because EyeDrops encodes into a form that perl can execute unaided, it simply lets perl decode it via eval and so does not require Acme::EyeDrops to be installed on the target system.

        In contrast, perl by itself cannot make sense of a raw stream of spaces and tabs and so requires Acme::Bleach to be installed on the target system to decode and eval the "bitstream" of spaces and tabs.

        As a consequence, Bleach has to be involved at compile time (which is why it overwrites the file and fiddles with $0). EyeDrops, on the other hand, does not mangle the original file, simply reads it and writes a new (encoded and shaped) one.

        Put another way, Bleach is a Perl "source filter" (e.g. see Filter::Simple), while EyeDrops is not. EyeDrops is simply an encoder and shaper of the bytes in a source code file. The hardest part of writing EyeDrops was not the (sightly) encoding, but the heuristics required to pour the encoded bytes into a wide variety of shapes.

Re: Production obfuscation
by JavaFan (Canon) on Apr 20, 2012 at 19:21 UTC
    I don't see any advantages. But I can see some liabilities:
    • Your boss might fire you when she finds out.
    • Any line numbers from warnings/errors will not be very useful.
    • You've added a build stage. That increases the time between development and roll out.
      Can not fire myself. If compile time were an issue preventing roll out then I'd be rich and not even asking these questions :) These programs are ran in a system where editing is not really possible.
Re: Production obfuscation
by eyepopslikeamosquito (Bishop) on Apr 21, 2012 at 12:22 UTC

    The conversion can make the code 10x greater in size
    Yes, the sightly encoding is not very compact. Have you considered adding an extra conversion step before feeding the code to Acme::EyeDrops? Even something fairly simple, like removing all comments or unnecessary whitespace may make a significant difference. Of course, there is a risk this pre-processing step may break your code, especially with things like "here documents". There may be tools that can help here, Perl::Tidy or PPI for example, or even more specialized ones that replace long identifiers with very short ones, though I have little experience in this domain.

      Perltidy's -dac -mangle switches should do it.
Re: Production obfuscation
by Anonymous Monk on Apr 20, 2012 at 18:15 UTC

    :) What do you think the liabilities are?

Re: Production obfuscation
by cavac (Curate) on Apr 26, 2012 at 13:36 UTC

    I'm not too concerened about the users attempting a reverse enginner. I'm practicing sercurtry thru obsecurity.

    Sorry? This is supposed to be irony, isn't it?

    Security through obscurity basically means you don't have any security. Anyone who is well versed enough in Perl to do serious reverse engineering would have no problem at all of either writing a "decoder" or just plug the script into a debugger and see whats happening instruction by instruction.

    "You have reached the Monastery. All our helpdesk monks are busy at the moment. Please press "1" to instantly donate 10 currency units for a good cause or press "2" to hang up. Or you can dial "12" to get connected directly to second level support."

      "Anyone who is well versed enough in Perl to do serious reverse engineering would have no problem at all..."

      Or for those who aren't familiar with perl a google search would provide techniques/code to do it for them.