这个perl代码如何打印输出?

时间:2013-03-06 12:33:40

标签: perl obfuscation

任何人都可以解释这段代码如何打印输出?

代码

#!/usr/bin/perl
use warnings;
use strict;
       my          
      ($j,$        
   a,$p,$h);$      
   j=sub{print(    
  chr($p+=$a->[$   
  h++]));$j};;;$a  
 =[0,        split 
 "[:         \n]+", 
q/43         -002:1
-084         065:13
0001         000005
-0012        -00003
000013   -82 00048 
21:13:-6.00:-76:72 
 -007.:02:00008.00 
  :::-6.00:::013  
  -70:3::-70:.64   
    /];$p=0x4a     
      ;;$h=0;      
$j->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->();

输出:

Just another perl hacker

3 个答案:

答案 0 :(得分:6)

这实际上是一个相当简单的JAPH。它的两个最大特点是分割构成大部分"图像"和半递归打印的数据字符串。

这是我清理格式时得到的代码

my ($j,$a,$p,$h);
$j = sub {
    print( chr( $p += $a->[$h++] ) );
    $j
};
;;

$a = [0, split "[: \n]+",   # the split regex
q/43         -002:1         # input string start: q/ ...
-084         065:13
0001         000005
-0012        -00003
000013   -82 00048 
21:13:-6.00:-76:72 
 -007.:02:00008.00 
  :::-6.00:::013  
  -70:3::-70:.64   
    /];                     # input string end:   .../   
# print Dumper $a;  # <--- this is my line
$p = 0x4a;;
$h=0;      

$j->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->();

第一部分是4个主要变量的声明和分配:

<强> $Ĵ

$j是打印字符的代码引用,然后返回对自身的引用。印刷品包括几个步骤:

  1. $a->[$h++]遍历@$a数组,返回一个元素
  2. $p += ...该元素已添加到$p
  3. print chr( $p ... )然后将$p返回到chr()并打印生成的字符。
  4. 子块中的最后一个是$j,这意味着每次迭代时,sub的返回值将是对它自己的引用。这是允许半递归功能的部分。

    $ A

    $a是对数组的引用,该数组由0和输入字符串上的拆分结果组成。在这里,一行代码中也发生了一些事情:

    • q/43 .../这是带有分隔符斜杠q()的常规/单引号字符串。它在表示数组引用的右括号]之前结束。
    • split "[: \n]+",这是对字符类的拆分,重复1次或更多次。其中有额外的空间(我已经删除了这里)来填充JAPH本身的空间。基本上这将删除所有冒号,空格和换行符并返回结果列表。
    • $a = [0, ... ]将拆分列表添加到0列表中(只有一个元素),所有内容都用括号括起来表示数组引用,然后将其存储在{{1}中}。

    我认为该列表以$a开头,因为代码有一次性错误,因为0的原始值是输出中的第一个字母。

    这是$p的{​​{1}}输出:

    Data::Dumper

    $ p和$ h

    $a$VAR1 = [ 0, '43', '-002', '1', '-084', '065', '13', '0001', '000005', '-0012', '-00003', '000013', '-82', '00048', '21', '13', '-6.00', '-76', '72', '-007.', '02', '00008.00', '-6.00', '013', '-70', '3', '-70', '.64' ]; 只是数字,它们在此中的作用是$p函数的源编号和$h数组的迭代器。

    最后一行是运行chr()子例程并打印JAPH的部分。链式@$a语法意味着每个先前迭代的返回值用于下一次执行。并且$j返回对自身的引用,这使得它成为半递归事件,只有值发生变化。

    我想这与此相似:

    ->()

    让我们逐步完成前几个步骤

    • $j执行
    • $x = $j->(); $y = $x->(); $z = $y->(); ... $j->()递增为1,返回0到$a->[$h++]子行程,返回$h的第一个元素,即$a。< / LI>
    • $a0已添加到$p += 0,这会将0(74)的值返回给chr
    • $p现在会将$p打印到标准输出
    • print chr(74)已退回。
    • J对返回值执行另一次执行,因此再次运行$j
    • ->() $j增加到2,返回1到$a->[$h++],返回第二个元素$h
    • $a 74 + 43 = 117返回43
    • $p += 43这会打印chr

    print chr(117)的元素既有正面也有负面,将数字移动到需要的位置。最后,所有打印的字母均为u

    以下是10次首次执行的简要说明:

    $a

答案 1 :(得分:5)

使用perl -MO=Deparse运行它以查看Perl看到的内容:

use warnings;
use strict 'refs';
my($j, $a, $p, $h);
$j = sub {
    print chr($p += $$a[$h++]);
    $j;
}
;
$a = [0, split(/[:         \n]+/, "43         -002:1\n-084         065:13\n0001         000005\n-0012        -00003\n000013   -82 00048 \n21:13:-6.00:-76:72 \n -007.:02:00008.00 \n  :::-6.00:::013  \n  -70:3::-70:.64   \n    ", 0)];
$p = 74;
$h = 0;
&$j()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->();

基本上,$j是一个子引用,它返回另一个子引用,依此类推。在返回之前,它会打印一个字符并将“指针”移动到要打印的字符数组中。

答案 2 :(得分:1)

小评论。

数字块中的最后一行应为此

-68:3::-70:.64

而不是

-70:3::-70:.64   

打印一段时间需要-68,-70打印一个逗号。

(该行的其余部分,“:3 :: - 70:.64”只是噪音。这些数字永远不会传递给$ j中的匿名函数。)