Как правильно деобфусакте скрипт Perl?


я пытаюсь deobfuscate следующие Perl-код (источник):

#!/usr/bin/perl
(my$d=q[AA                GTCAGTTCCT
  CGCTATGTA                 ACACACACCA
    TTTGTGAGT                ATGTAACATA
      CTCGCTGGC              TATGTCAGAC
        AGATTGATC          GATCGATAGA
          ATGATAGATC     GAACGAGTGA
            TAGATAGAGT GATAGATAGA
              GAGAGA GATAGAACGA
                TC GATAGAGAGA
                 TAGATAGACA G
               ATCGAGAGAC AGATA
             GAACGACAGA TAGATAGAT
           TGAGTGATAG    ACTGAGAGAT
         AGATAGATTG        ATAGATAGAT
       AGATAGATAG           ACTGATAGAT
     AGAGTGATAG             ATAGAATGAG
   AGATAGACAG               ACAGACAGAT
  AGATAGACAG               AGAGACAGAT
  TGATAGATAG             ATAGATAGAT
  TGATAGATAG           AATGATAGAT
   AGATTGAGTG        ACAGATCGAT
     AGAACCTTTCT   CAGTAACAGT
       CTTTCTCGC TGGCTTGCTT
         TCTAA CAACCTTACT
           G ACTGCCTTTC
           TGAGATAGAT CGA
         TAGATAGATA GACAGAC
       AGATAGATAG  ATAGAATGAC
     AGACAGAGAG      ACAGAATGAT
   CGAGAGACAG          ATAGATAGAT
  AGAATGATAG             ACAGATAGAC
  AGATAGATAG               ACAGACAGAT
  AGACAGACTG                 ATAGATAGAT
   AGATAGATAG                 AATGACAGAT
     CGATTGAATG               ACAGATAGAT
       CGACAGATAG             ATAGACAGAT
         AGAGTGATAG          ATTGATCGAC
           TGATTGATAG      ACTGATTGAT
             AGACAGATAG  AGTGACAGAT
               CGACAGA TAGATAGATA
                 GATA GATAGATAG
                    ATAGACAGA G
                  AGATAGATAG ACA
                GTCGCAAGTTC GCTCACA
])=~s/s+//g;%a=map{chr $_=>$i++}65,84,67,
71;$p=join$;,keys%a;while($d=~/([$p]{4})/g
){next if$j++%96>=16;$c=0;for$d(0..3){$c+=
$a{substr(,$d,1)}*(4**$d)}$perl.=chr $c}
             eval $perl;

при запуске он выводит Just another genome hacker.

после запуска через код Deparse и perltidy (perl -MO=Deparse jagh.pl | perltidy) код выглядит так:

( my $d =
"AA...GCTCACAn" # snipped double helix part
) =~ s/s+//g;
(%a) = map( { chr $_, $i++; } 65, 84, 67, 71 );
$p = join( $;, keys %a );
while ( $d =~ /([$p]{4})/g ) {
    next if $j++ % 96 >= 16;
    $c = 0;
    foreach $d ( 0 .. 3 ) {
        $c += $a{ substr , $d, 1 } * 4**$d;
    }
    $perl .= chr $c;
}

вот что я смог расшифровать самостоятельно.

( my $d =
"AA...GCTCACAn" # snipped double helix part
) =~ s/s+//g;

удаляет все пробелы в $d (двойная спираль).

(%a) = map( { chr $_, $i++; } 65, 84, 67, 71 );

делает хэш с ключами A, T,C и G и как значения 0,1,2 и 3. Я обычно кодирую на Python, поэтому это переводится в словарь {'A': 0, 'B': 1, 'C': 2, 'D': 3} в Python.

$p = join( $;, keys %a );

соединяет ключи хэша с $; the разделитель индексов для эмуляции многомерных массивов. В документации говорится, что по умолчанию используется "34", то же самое, что и SUBSEP в awk, но когда я делаю:

my @ascii = unpack("C*", $p);
print @ascii[1];

я получаю значение 28? Кроме того, это не мне ясно, как это эмулирует многомерный массив. Это $p теперь что-то вроде [['A'], ['T'], ['C'], ['G']] в Python?

    while ( $d =~ /([$p]{4})/g ) {

пока $d игр ([$p]{4}), выполните код в блоке while. но так как я не совсем понимаю, что такое структура $p, мне также трудно понять, что здесь происходит.

next if $j++ % 96 >= 16;

продолжить, если the $j модуль 96 больше или равен 16. $j инкременты с каждым проходом цикла while (?).

$c = 0;
foreach $d ( 0 .. 3 ) {
    $c += $a{ substr , $d, 1 } * 4**$d;
}

на $d в границах от 0 до 3 извлеките некоторую подстроку, но на данный момент я полностью потерян. Последние несколько строк объединяют все и оценивают результат.

1 54

1 ответ:

осторожностью: не запускайте вслепую запутанный perl, особенно если есть eval, backticks,system,open и т. д. позвоните куда-нибудь в него и это может быть не слишком очевидно*. Де-запутывание его с Deparse и тщательно заменить evalS с операторами печати является обязательным, пока вы не поймете, что происходит. Запуск в песочнице/с непривилегированным пользователем / в виртуальной машине также следует учитывать.

*s&&$_ⅇ оценивает $_ для intance.


первое наблюдение: 034 - это восьмеричное. Он равен 28 (dec) или 0x1c (hex), поэтому ничего подозрительного там нет.

The $; вещь чисто запутывания, не могу найти причину, чтобы использовать это в частности. $p будет просто строка A.T.C.G. заменить на $;, что бы это ни было).
Так что в регулярном выражении [$p] совпадает с {'A', 'T', 'C', 'G', $;}. Так как $; не появляется в $d, это было бесполезно. В свою очередь [$p]{4} соответствует любой последовательности из четырех букв в приведенном выше наборе, как если бы это было использовано (игнорируя бесполезный $;):

while ( $d =~ /([ATCG]{4})/g ) { ... }

если бы вам пришлось написать это самостоятельно, после удаления пробелов, вы бы просто захватили каждую последующую подстроку $d длины четыре (предполагая, что нет других символов в $d).

теперь эта часть весело:

foreach $d ( 0 .. 3 ) {
    $c += $a{ substr , $d, 1 } * 4**$d;
}
  • в настоящее время четыре буквы кода. substr , $d, 1 возвращает каждую последующую букву из этой кодовой точки.
  • %a карты A до 00b (двоичный),T до 01b,C до 10b, и G до 11b.

    A   00
    T   01
    C   10
    G   11
    
  • умножить на 4**$d будет эквивалентно побитовому сдвигу влево 0, 2, 4 и 6.

так что эта забавная конструкция позволяет вам постройте любое 8-битное значение в системе base-four с помощью ATCG как цифры!

т. е. он выполняет следующие преобразования:

         A A A A
AAAA -> 00000000

         T A A T
TAAT -> 01000001 -> capital A in ascii

         T A A C
CAAT -> 01000010 -> capital B in ascii

CAATTCCTGGCTGTATTTCTTTCTGCCT -> BioGeek

эта часть:

next if $j++ % 96 >= 16;

выполняет приведенное выше преобразование только для первых 16 "кодовых точек", пропускает следующие 80, затем преобразует для следующих 16, пропускает следующие 80 и т. д. Он по существу просто пропускает части эллипса (система удаления нежелательной ДНК).


вот уродливый конвертер текста в ДНК, который вы могли бы использовать чтобы произвести что-либо, чтобы заменить спираль (не обрабатывает 80 пропустить вещь):

use strict;
use warnings;
my $in = shift;

my %conv = ( 0 => 'A', 1 => 'T', 2 => 'C', 3 => 'G');

for (my $i=0; $i<length($in); $i++) {
    my $chr = substr($in, $i, 1);
    my $chv = ord($chr);
    my $encoded ="";
    $encoded .= $conv{($chv >> 0) & 0x3};
    $encoded .= $conv{($chv >> 2) & 0x3};
    $encoded .= $conv{($chv >> 4) & 0x3};
    $encoded .= $conv{($chv >> 6) & 0x3};
    print $encoded;
}
print "\n";
$ perl q.pl 'print "BioGeek\n";'
AAGTCAGTTCCTCGCTATGTAACACACACAATTCCTGGCTGTATTTCTTTCTGCCTAGTTCGCTCACAGCGA

палкой в $d что вместо спирали (и удалить пропуская часть в декодере).