perl - 这个混淆的 Perl 是如何工作的?

标签 perl

    #!/bin/perl
    use strict;
    use warnings;
    my($japh,$q,$qq,%b)= "Just another Perl hacker\n";
    $_=join'',(
    07625127776,
    0122456410,
    03441733416,
    01420121552,
    04373570104,
    07143446334);s#9#f#;#s;#f#9#s;;
    s}9}b};$q=$_;*9=
    sub {
        $japh = "";
        print $japh;
    }; map { /^((?i)(?#q#;
    print $japh;#()[^
    for (my $(b) = 1; $(b) < $(q); \$b++;) {
        \/g])+[\](^.^)\[
    }
    ]*$/x?do{$qq=((ord)-96).(~~%b-$?)
    ;$/#;
    =$+;$q=~s/$qq/${\/}/g;}:9->({});
    }qw(
    a b c d e f g h i j k l m n o p q r s t u v w x y z
    );$qq=[$q,%b];$\=pack q*h\**
    ,qq$$.$$qq[0];9->();

我认为很多都是额外的/纯粹的混淆。我知道我们将“Just another Perl hacker”分配给 $japh,然后我们打印它,但在我们这样做之前我们将它分配给“”,所以我不明白它是如何工作的。有人可以解释这里发生了什么吗?谢谢!

最佳答案

了解混淆 Perl 的第 1 步:通过 -MO=Deparse 运行它.然后,我们得到这个输出:(删除了一个小的语法错误)

use warnings;
use strict;
my($japh, $q, $qq, %b) = "Just another Perl hacker\n";
$_ = join('', (1045737470, 21650696, 478656270, 205562730, 602861636, 965627100));
s/9/f/;
s/9/b/;
$q = $_;
*9 = sub {
    $japh = '';
    print $japh;
}
;
map {m{^((?i)(?#q#;
    print \$japh;#()[^
    for (my $(b) = 1; $(b) < $(q); \$b++;) {
        /g])+[\](^.^)\[
    }
    ]*$}x ? do {
    $qq = ord($_) - 96 . (~~%b - $?);
    $/ = $+;
    $q =~ s[$qq][$/]g
} : 9->({});} 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z';
$qq = [$q, %b];
$\ = pack('h*', '' . $$qq[0]);
9->();

仍然不漂亮,但更好。特别是,这个正则表达式看起来很有趣:

m{^((?i)(?#q#;
    print \$japh;#()[^
    for (my $(b) = 1; $(b) < $(q); \$b++;) {
        /g])+[\](^.^)\[
    }
    ]*$}x

(?# ... )是嵌入的注释,我们可以将其删除。接下来是字符类

[^
    for (my $(b) = 1; $(b) < $(q); \$b++;) {
        /g]

[\](^.^)\[
        }
        ]

在这里,它们等同于[^bfgmoqry][\[\]()^.}\s] , 但由于正则表达式只会与单个字符匹配,因此 [...]*将匹配零个字符。

因此,正则表达式等同于

m/^([^bfgmoqry])$/

在这个特例中(与 "a" .. "z" 匹配)。

*9 = sub {...}将 coderef 分配给 glob。因为9不是有效的子例程名称,但仍可与 -> 一起使用运算符(operator),9->()调用该代码引用。这就像 sub foo {...} 一样, foo()"foo"->()是一样的。

字符a编码为十进制 97作为 ASCII,所以 ord("a")-961 , 对于 z ,那就是 26。

$?是最后一个子错误,应该为零。 $+是最后一个捕获组的值(因此,$_)。 ~~%b双重否定空散列。空哈希的标量化是 0 , 所以双重按位否定再次产生零。

$/ = $+; $q =~ s[$qq][$/]g只是有点混淆;作为$+$_ ,我们可以直接写成$q =~ s/$qq/$_/g .

$qq = [$q, %b]; ... $$qq[0]很蹩脚,$\ = pack('h*', $q)足够了。

9 sub,将打印空字符串,后跟 $\ , 设置为倒数第二行之前的空字符串。移除这一级别的间接寻址、任何现在未使用的变量以及简单的替换,我们得到:

use warnings;
use strict;
my $q = '1045737470216506f6478656270205562730602861636b65627100';
for ("a" .. "z") {
    m/^([^bfgmoqry])$/ or next;
    my $qq = ord($_) - 96;
    $q =~ s/${qq}0/$_/g;
}
print pack('h*', $q);

s/${qq}0/$_/g替换只能匹配零,我们知道输出将是 pack 的一些十六进制数。 .可能匹配的位置是:

1045737470216506f6478656270205562730602861636b65627100
*^      *^   *^          *^*^     *^*^             *^^
 a       g    e           g b      c f              a

其中b, f, g由于正则表达式而被禁止。结果字符串是

a45737470216e6f64786562702055627c602861636b65627a0

解码为 JAPH。

关于perl - 这个混淆的 Perl 是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17381616/

相关文章:

regex - 使用 Perl 正则表达式重新排列时间戳

Perl 使用 File::Spec 删除 .. 和 .从路径

perl - 对于文件总和值中的每一行

arrays - 如何删除引用数组的元素?

linux - 命令行 : search and replace in all filenames matched by grep

regex - Perl 如何匹配 verilog 文件的注释 "//"?

perl - 在 Moose 中,如何对 arrayref setter 进行 uniq?

perl 比较两个文件并打印匹配的行

linux - 在 Perl 程序中访问 shell 变量

perl - 如何传递存储在变量中的xpath?