views:

182

answers:

8

I have a Perl script that gives a completely useless error message, is there a way to get perl to give a stack trace when the error occurs? I tried it this way but it did not work:

# Run command in the debbugger:
  perl -d /path/to/script.pl -my -normal -args
# Reset the die command to your own subroutine to do a stacktrace:
  DB<1> *CORE::GLOBAL::die = sub { require Carp; Carp::confess };
# continue the simulation
  DB<2> c

It just the same meaningless error message and no stack trace. Can anyone suggest what is wrong with my technique or a better way to do it?

Additional note: I have opene the script and it seems like the main body is either encrypted or compiled in some way that I cannot visually debug it:

   #!/usr/local/bin/perl
   use File::Basename;
   use lib dirname($0)."/libperl";
   use SimFilter;
   aDYBxolgYf1eunQ8XmleVAP
   aAP  
     ...
+1  A: 

You're going to have to get your hands on the Simfilter module and use it to go back to the original source code. It sounds like the author doesn't want you to get at the source, which isn't surprising if it is for something like encryption or copyright circumvention.

Ether
He must already have SimFilter or he couldn't run the code. Would `perl -MO=Deparse Foo.pm` be sufficient? (i.e. would Deparse take the results after SimFilter de-obfuscated it?)
Michael Carman
A: 

try using perlide, download from sourceforge.net

ddyer
+11  A: 

Look at Carp::Always to add stacktrace to your errors. See more variants in "How can I replace all ‘die’s with ‘confess’ in a Perl application?" question.

Try B::Deobfuscate to restore source code of obfuscated script

Ivan Nevostruev
+1  A: 

Use $SIG{__DIE__} = \&Carp::confess; instead of overriding die.

Unfortunately the "encryption" is likely to screw up any stack traces. The good news is that you must already have the key (SimFilter) or you wouldn't be able to run the script in the first place. Try deparsing it:

 perl -MO=Deparse scriptname.pl
Michael Carman
+7  A: 

Try Deparse:

 perl -MO=Deparse script.pl

You might also find B::Deobfuscate helpful:

An obfuscated program is already parsed and interpreted correctly by the B::Deparse program. Unfortunately, if the obfuscation involved variable renaming then the resulting program also has obfuscated symbols.

This module takes the last step and fixes names like $z5223ed336 to be a word from a dictionary. While the name still isn't meaningful it is at least easier to distinguish and read. Here are two examples - one from B::Deparse and one from B::Deobfuscate.

Now, for the program to run at all, the SimFilter module must have been included with it as well. In fact, the

use lib dirname($0)."/libperl";

line makes it clear that the SimFilter.pm file is in the libperl subdirectory of the directory where the script lives.

Clearly, it is encoding the source code and you can figure out how to decode it from the SimFilter source code, decode it once and for all and go from there.

For an example from which you can learn, see also Acme::Bleach.

Sinan Ünür
A: 

This may not be relevant but you could also use the "caller" function.

perldoc caller

Logan
+3  A: 

From the name SimFilter and the alphabet soup that follows, I'm guessing that this code is using something like a Filter::Util::Call or Filter::Simple pattern. Maybe SimFilter.pm even imports one of these modules.

Anyway, my guess is that somewhere in SimFilter.pm, there is a line like:

    FILTER { $_ = some_function($_) }

which is where the magic happens. You might be able to view the source if you run the debugger after changing that line to something like

    FILTER { $_ = some_function($_); $DB::single=1; return $_ }

If that works, you can examine $_ at the debugger prompt and you can see the decrypted source code. If SimFilter turns out to be an attempt to further obfuscate the inner workings of Filter::XXX, then it may take even more effort to find where the magic happens. But as I've learned, $DB::single=1 is your friend for debugging modules that get run at compile time.

mobrule
+1  A: 

Here's a trick (For the stack trace part, at least -- I use this quite frequently when troubleshooting others' scripts):

Make a file "ConfessAll.pm", which contains:

use Carp;
BEGIN { $SIG{__DIE__} = \&Carp::confess; }
1;

then run your script:

perl -I <directory of ConfessAll.pm> -MConfessAll <script and arguments>
jsegal