in reply to Re^2: using Safe.pm
in thread using Safe.pm

eval ('perl -MO=Deparse obfu3.pl'); The top part works; the bottom doesn't. Looking for tips. Thank you.

What do you mean? Capture::Tiny? Look inside O and B::Deparse , and maybe Safe::Hole (or Safe::World), https://metacpan.org/source/RGARCIA/Safe-2.35/t/safeuniversal.t, ) then copy/paste stuff so you can reval somehow safely? There is no Safe::Deparse on cpan :)

perltidy then manual inspection is about the only safe way to figure stuff out step by step without BEGIN{} or `qx//ing` or s///eevaling stuff running, just decoding the strings

Replies are listed 'Best First'.
Re^4: using Safe.pm ( Safe::Deparse )
by Aldebaran (Curate) on Jul 10, 2015 at 00:16 UTC

    Thanks for your response, I chased down those cpan modules and gave them a read. It's been suggested that I might not have my 'puter at eye level, and the answers might be right there on the screen, but I'm missing them usually for lack of comprehension. This is new territory for me, and the learning curve is steep. I do best with the modules that have examples and have worked up a few examples to show what is working and what isn't. I wrote the simplest of toy programs: toy1.pl, that only substitutes a phrase. It's safe and short. Let me list the latest of many incarnations of this script:

    #!/usr/bin/perl use warnings; use strict; use feature 'say'; use File::Slurp; use B::Deparse; # first trial without safe my $japh = read_file( 'toy1.pl' ) ; say "japh is $japh"; eval($japh); # second trial with safe and copy/paste my $deparse = B::Deparse->new(); my $body = $deparse->coderef2text(sub { my $name = 'Donald Trump'; $name =~ s/ / "in the sub" /; say "name is $name"; }); say "second trial is $body"; # third trial combines two methods my $deparse2 = B::Deparse->new(); my $body2 = $deparse2->coderef2text(sub { my $japh2 = read_file( 'toy1.pl' ) ; say "japh2 is $japh2"; eval($japh2); }); say "third trial is $body2"; # 4th trial uses backticks my $file = 'toy1.pl'; my $command = "perl -MO=Deparse $file"; say "command is $command"; my $output = `$command`; say "4th trial is $output"; # 5th trial looks at original obfu $file = 'obfu3.pl'; $command = "perl -MO=Deparse $file"; $output = `$command`; say "5th trial is $output";

    The problem seems to be how to get deparse to work when the file to be deparsed is being selected after the program begins to run. Hence copying and pasting into a sub is not possible. I thought I was going to go with system() and Capture::Tiny until I ended up going with backticks in the 4th trial with good results. On the fifth trial I directed the backend of perl toward the obfu in the thread of the obfu decoder ring from the original post. It appears to be a bunch of junk under closer inspection:

    japh is #!/usr/bin/perl use Modern::Perl qw/2010/; my $name = 'Donald Trump'; $name =~ s/ / "Perl is great" /; say "name is $name"; name is Donald "Perl is great" Trump second trial ia { use warnings; use strict; use feature 'say'; my $name = 'Donald Trump'; $name =~ s/ / "in the sub" /; say "name is $name"; } third trial is { use warnings; use strict; use feature 'say'; my $japh2 = read_file('toy1.pl'); say "japh2 is $japh2"; eval $japh2; } command is perl -MO=Deparse toy1.pl toy1.pl syntax OK 4th trial is use Modern::Perl ('2010'); use warnings; use strict; use feature 'say', 'state', 'switch'; my $name = 'Donald Trump'; $name =~ s/ / "Perl is great" /; say "name is $name"; obfu3.pl syntax OK 5th trial is $= = $'; $. | $| unless $; $_ = '*$(^@(%_+&~~;#~~/.~~;_);;.);;#);~~~~;_,.~~,.*+,./|~~;_);@-,.;.); +~~,./@@-__ );;.);;#,.;.~~@-);;#);;;);~~,.*+,.;#);;;;#-(@-__);;.);;#,.;.~~@-););,. +/.);~~,./| ,.*+,./|,.););;#;#-(@-__);;.);;#,.;.~~@-;;,.,.*+,./@,.;.;#__;#__;;,.,. +*+,./|,.;; ;#-(@-__@-__,.;_);@-,.;.,./|~~();.;#;.;;;;;;;;;.;.~~;.~~~~/@~~@-~~~~;# +/|;#/|~~~~ ~~/@~~@-~~~~~~;_,.;;,.;.);,.~~;_,./|);;.,./@,./@~~~~~~*+;#-(@-__,.,.,. +*+,./|,.;; ~~()~~@-);;#);;.,.~~~~@-);-(@-__@-*+);~~,..%,.;;,.*+);~~~~@-,.*+,.,.~~ +@-~~.%,.;; ~~@-,./.,./|,.;;~~@-~~.%););;#-(@-__@-*+);;.,./|,./@,.*+,./|,.-(~~@-,. +*+,.,.~~@- ~~.%,.,.~~@-,./.,./|,.;;~~@-~~.%););;#-(@-__);.%~~/@~~@-~~~~~~;_,.(),. +;_,..%,.;. ~~;_~~;;;#/|~~~~~~*+;#-(@-__);@-);~~,.*+,./|);;;~~@-~~~~;;__;;/.;.@-;; +();./@,./| ~~~~;#-(@-__&$#%^'; $__ = ' '; use arybase (); $___ = '````' | "$[`$[" | '`%",'; $~ = ("$___$__-$[``$__" | "$___" | "$___$__-$[.%") . (q['`] | "'$[" | +q['#]) . ' /.*?&([^&]*)&.*/$' . ++$= . ('/``' | "/$[`" | q[/#']) . (";`/[\\`\\`$_ +_]//`;" | ";$[/[\\$[\\`$__]//`;" | ";#/[\\\$\\.$__]//'") . '@:=("@-","/.","~~"," +;#",";;"," ;.",",.",");","()","*+","__","-(","/@",".%","/|",";_");@:{@:}=$%..$#:; +' . ('`' | "$[" | '#') . '/(..)(..)/' . ('```' | "``$[" | '#("') . '(($:{$' . $= + . '}<<' . (++$= + $=) . ')|($:{$' . $= . '}))/' . ('```;' | "``$[;" | q[%'#;]) +. ("````'$ __" | "%$[``" | '%&!,') . ${$[;}; `$~$__>&$=`;

    Since there isn't any output, my guess is that perl is clever enough to look at this program and say, "why define a bunch of screwy-looking variables, assign a bunch of junk, and do nothing, if there is no output? Let's not play at all." But if there were output, would perl assign values to all the odd-looking $ variables like $= , $. , $~ , $___ ?

    What symbols would I look for if there were something pernicious happening?

      ... What symbols would I look for if there were something pernicious happening?

      You mean aside from the stuff I already mentioned?

      ppi_dumper can always help tell you which parts are which parts

      ...

      Danger :) I don't know that that obfu ever did anyting, but its fairly standard fare, try to hide when you're doing something tricy, transform nonsense into a message (or evil)

      #!/usr/bin/perl -- use strict; use warnings; use B::Deparse(); use Safe(); use Data::Dump qw/ dd /; use Perl::Tidy(); use PPI(); use PPI::Dumper(); #~ [id://630435] on Aug 03, 2007 at 03:44 UTC my $obfu3raw = <<'__RAW__'; $==$';$;||$.|$|;$_='*$(^@(%_+&~~;#~~/.~~;_);;.);;#);~~~~;_,.~~,.*+,./| +~~;_);@-,.;.);~~,./@@-__);;.);;#,.;.~~@-);;#);;;);~~,.*+,.;#);;;;#-(@ +-__);;.);;#,.;.~~@-););,./.);~~,./|,.*+,./|,.););;#;#-(@-__);;.);;#,. +;.~~@-;;,.,.*+,./@,.;.;#__;#__;;,.,.*+,./|,.;;;#-(@-__@-__,.;_);@-,.; +.,./|~~();.;#;.;;;;;;;;;.;.~~;.~~~~/@~~@-~~~~;#/|;#/|~~~~~~/@~~@-~~~~ +~~;_,.;;,.;.);,.~~;_,./|);;.,./@,./@~~~~~~*+;#-(@-__,.,.,.*+,./|,.;;~ +~()~~@-);;#);;.,.~~~~@-);-(@-__@-*+);~~,..%,.;;,.*+);~~~~@-,.*+,.,.~~ +@-~~.%,.;;~~@-,./.,./|,.;;~~@-~~.%););;#-(@-__@-*+);;.,./|,./@,.*+,./ +|,.-(~~@-,.*+,.,.~~@-~~.%,.,.~~@-,./.,./|,.;;~~@-~~.%););;#-(@-__);.% +~~/@~~@-~~~~~~;_,.(),.;_,..%,.;.~~;_~~;;;#/|~~~~~~*+;#-(@-__);@-);~~, +.*+,./|);;;~~@-~~~~;;__;;/.;.@-;;();./@,./|~~~~;#-(@-__&$#%^';$__='`' +&'&';$___="````"|"$[`$["|'`%",';$~=("$___$__-$[``$__"|"$___"|("$___$_ +_-$[.%")).("'`"|"'$["|"'#").'/.*?&([^&]*)&.*/$'.++$=.("/``"|"/$[`"|"/ +#'").(";`/[\\`\\`$__]//`;"|";$[/[\\$[\\`$__]//`;"|";#/[\\\$\\.$__]//' +").'@:=("@-","/.","~~",";#",";;",";.",",.",");","()","*+","__","-("," +/@",".%","/|",";_");@:{@:}=$%..$#:;'.('`'|"$["|'#')."/(..)(..)/".("`` +`"|"``$["|'#("').'(($:{$'.$=.'}<<'.(++$=+$=).')|($:{$'.$=.'}))/'.("`` +`;"|"``$[;"|"%'#;").("````'$__"|"%$[``"|"%&!,").${$[}; return "$~$__>&$="; ##`$~$__>&$=`; __RAW__ my $obfushell = <<'__RAW__'; perl -0ne 's/.*?&([^&]*)&.*/$1/sg;s/[\t\n ]//g;@:=("@-","/.","~~",";#" +,";;",";.",",.",");","()","*+","__","-(","/@",".%","/|",";_");@:{@:}= +$%..$#:;s/(..)(..)/chr(($:{$1}<<4)|($:{$2}))/egs;eval' - >&2 perl -0ne ' s/.*?&([^&]*)&.*/$1/sg; s/[\t\n ]//g; @:=("@-","/.","~~",";#",";;",";.",",.",");","()","*+","__","-(","/@"," +.%","/|",";_"); @:{@:}=$%..$#:; s/(..)(..)/chr(($:{$1}<<4)|($:{$2}))/egs; eval ' - >&2 __RAW__ my $obfushelled = <<'__RAW__'; $/ = "\000"; $\ = undef; s/.*?&([^&]*)&.*/$1/sg;s/[\t\n ]//g;@:=("@-","/.","~~",";#",";;",";.", +",.",");","()","*+","__","-(","/@",".%","/|",";_");@:{@:}=$%..$#:;s/( +..)(..)/chr(($:{$1}<<4)|($:{$2}))/egs; $_; ##eval __RAW__ Dobfu( $obfu3raw ); Dobfu( $obfushelled ); exit( 0 ); sub Dobfu { my $dobfu = shift; print "\n\n##src2deparse\n", src2deparse( \$dobfu ), "\n\n##src2ppidumper\n", src2ppidumper( \$dobfu ), "\n\n##src2perltidy\n", src2perltidy( \$dobfu ), "\n\n##src2ppistrings\n", join "\n\n", src2ppistrings( \$dob +fu ), "\n\n##SafestUndumper src2ppistrings\n", SafestUndumper( "jo +in ',', ".join(',', src2ppistrings( \$dobfu ) ) ), "\n\n##SafestUndumper raw\n", join "\n\n", SafestUndumper( \ +$dobfu ), "\n\n"; } sub src2deparse { use Path::Tiny qw/ path /; use B::Deparse; my $modfile = shift or die "need one modfile or \'string'"; my $mod = ref $modfile ? $$modfile : path( $modfile )->slurp_raw; die "NO WAY STUPID!! " if $mod =~ /\b(?:BEGIN|CHECK|INIT|UNITCHECK +|END|sub)\b/; my $modsub = do { no strict; no warnings; eval " sub { return ; $ +mod } " or die $@ }; my $deparsed = B::Deparse->new( "-p", ## extra parens for disambiguation "-sC", ## cuddle elsif "-si2", ## indent by 2 instead of 4 )->coderef2text( $modsub ) ; return $deparsed; } sub src2ppidumper { use PPI(); use PPI::Dumper(); my $modfile = shift or die "need one modfile or \'string'"; my $Module = PPI::Document->new( $modfile, readonly => 1, ); my $errstr = PPI::Document->errstr ; my $Dumper = PPI::Dumper->new( $Module, memaddr => 0, indent => 2, class => ! 0, content => ! 0, whitespace => ! 1, comments => ! 0, locations => 0, ); $Dumper = $Dumper->string; ## grr wantarray ? return( $Dumper, $errstr ) : return( $Dumper );; } sub src2perltidy { use Perl::Tidy(); my $modfile = shift or die "need one modfile or \'string'"; my $html = ""; my $stderr = ""; Perl::Tidy::perltidy( source => $modfile, destination => \$html, stderr => \$stderr, ); wantarray ? return( $html, $stderr ) : return( $html ); } use PPIx::XPath; use Tree::XPathEngine; sub PPI::Token::xf { goto &PPI::Node::xf } sub PPI::Node::xf { my( $node, $query ) = @_; $query = PPIx::XPath->clean_xpath_expr( $query ); $::pxp ||= Tree::XPathEngine->new(); return $::pxp->findnodes( $query, $node ); } sub src2ppistrings { use PPI(); use PPI::Dumper(); my $modfile = shift or die "need one modfile or \'string'"; my $Module = PPI::Document->new( $modfile, readonly => 1, ); my $errstr = PPI::Document->errstr ; die "Could not parse [$modfile] for PPI: $errstr " if $errstr; return map { "$_" } $Module->xf( q{ //Token::Quote::Double | //Token::Quote::Single } ); ## | //Token::Quote::Interpolate ## the potential evil ones ## qq{ ## evil @{[ eval die ]} ## evil @{[ `exit` ]} ## } } sub SafestUndumper { use Safe; my $s = Safe->new; # http://perl5.git.perl.org/perl.git/blob?f=regen/opcodes $s->permit_only( "anonlist", "anonhash", "pushmark", # perlcall says "PUSHMARK macro tells Perl to make a mental note of th +e current stack pointer." "const", "undef", "list", "lineseq", "padany", "leaveeval", # needed for Safe to operate, is safe without +entereval # needed for self-referentialnes "sassign", "rv2sv", "rv2hv", "helem", # dd-style do-block self-referentialnes "enter", "null", ); local $@; my(@ret)=$s->reval( @_ ); warn $@ if $@; return @ret; } ## end sub SafestUndumper __END__