Как правильно деобфусактировать скрипт Perl? - PullRequest
55 голосов
/ 18 февраля 2012

Я пытаюсь деобфусцировать следующий код Perl ( source ):

#!/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($1,$d,1)}*(4**$d)}$perl.=chr $c}
             eval $perl;

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

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

( my $d =
"AA...GCTCACA\n" # 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 $1, $d, 1 } * 4**$d;
    }
    $perl .= chr $c;
}

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

( my $d =
"AA...GCTCACA\n" # 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 );

соединяет ключи хэша с $; разделителем индекса для эмуляции многомерного массива ,В документации сказано, что по умолчанию используется значение «\ 034», то же самое, что SUBSEP в awk, но когда я делаю:

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

, я получаю значение 28?Кроме того, мне не ясно, как это эмулирует многомерный массив.* * * * * * * * * * * * * * * * * * * * * * * * *

* * * * * * * * * * * * * * * * * * * * * * * *1043* Python * * * *1043* * * * * * * * *

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

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

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

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

Для $d в диапазоне от 0 до 3 извлекаем некоторую подстроку, но на этом этапе I 'Я полностью потерян.Последние несколько строк объединяют все и оценивают результат.

1 Ответ

50 голосов
/ 18 февраля 2012

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

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


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

* * * * * * $; вещь - просто запутывание, не может найти причину, чтобы использовать это в частности. $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 $1, $d, 1 } * 4**$d;
}
  • $1 содержит текущую четырехбуквенную кодовую точку. substr $1, $d, 1 возвращает каждое последующее письмо с этой кодовой точки.
  • %a отображает A в 00b (двоичный код), * ​​1056 * в 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 вместо спирали (и удалите пропускающую часть в декодере).

...