Подтвердить что ты не робот

Обратное проектирование Perl script на основе дампа ядра

Друг-сервер (да, действительно, не мой.) был взломан, и мы обнаружили двоичный файл perl, выполняющий некоторый код бота. Мы не смогли найти сам script (вероятно, он был получен по сети), но нам удалось создать основной дамп процесса perl.

Запуск строк в ядре дал нам некоторые подсказки (имена хостов, имена пользователей/пароли), но не исходный код script.

Мы хотели бы знать, что может сделать script, поэтому мы хотели бы перепроектировать код perl, который был запущен внутри этого интерпретатора perl.

Поиск, ближайшая вещь для де-компилятора perl, который я нашел, - это модуль B:: Deparse, который, кажется, идеально подходит для преобразования байт-кода деревьев синтаксического анализа обратно в читаемый код.

Теперь, как мне получить B:: Deparse для работы с дампом ядра? Или, в качестве альтернативы, как я могу перезапустить программу из ядра, загрузить B:: Deparse и выполнить ее?

Любые идеи приветствуются.

4b9b3361

Ответ 1

ysth попросил меня в IRC прокомментировать ваш вопрос. Я сделал целый куча вещей "разобрать" скомпилированные perl и прочее (просто посмотри мой Страница CPAN [http://search.cpan.org/~jjore]).

Perl компилирует ваш источник в дерево OP* structs, которое иногда имеют C-указатели на SV*, которые являются perl-значениями. Ваше основное Теперь у дампа есть куча этих OP* и SV*.

Самый лучший мир - это иметь модуль perl, например B:: Deparse выполняет работу по пониманию информации. Это работает с использованием легкого интерфейса для perl-памяти в B::OP и B::SV (задокументировано в B, perlguts и perlhack). Это нереально для вас, потому что объект B::* просто указатель на память с помощью аксессуаров для декодирования структуры для наших использовать. Рассмотрим:

require Data::Dumper;
require Scalar::Util;
require B;

my $value = 'this is a string';

my $sv      = B::svref_2object( \ $value );
my $address = Scalar::Util::refaddr( \ $value );

local $Data::Dumper::Sortkeys = 1;
local $Data::Dumper::Purity   = 1;
print Data::Dumper::Dumper(
  {
    address => $address,
    value   => \ $value,
    sv      => $sv,
    sv_attr => {
      CUR           => $sv->CUR,
      LEN           => $sv->LEN,
      PV            => $sv->PV,
      PVBM          => $sv->PVBM,
      PVX           => $sv->PVX,
      as_string     => $sv->as_string,
      FLAGS         => $sv->FLAGS,
      MAGICAL       => $sv->MAGICAL,
      POK           => $sv->POK,
      REFCNT        => $sv->REFCNT,
      ROK           => $sv->ROK,
      SvTYPE        => $sv->SvTYPE,
      object_2svref => $sv->object_2svref,
    },
  }
);

который при запуске показал, что объект B::PV (это ISA B::SV) является это просто интерфейс для представления памяти скомпилированная строка this is a string.

$VAR1 = {
          'address' => 438506984,
          'sv' => bless( do{\(my $o = 438506984)}, 'B::PV' ),
          'sv_attr' => {
                         'CUR' => 16,
                         'FLAGS' => 279557,
                         'LEN' => 24,
                         'MAGICAL' => 0,
                         'POK' => 1024,
                         'PV' => 'this is a string',
                         'PVBM' => 'this is a string',
                         'PVX' => 'this is a string',
                         'REFCNT' => 2,
                         'ROK' => 0,
                         'SvTYPE' => 5,
                         'as_string' => 'this is a string',
                         'object_2svref' => \'this is a string'
                       },
          'value' => do{my $o}
        };
$VAR1->{'value'} = $VAR1->{'sv_attr'}{'object_2svref'};

Это, однако, означает, что любой B::* с использованием кода должен фактически работать на живой памяти. Тай Маккуин думал, что он вспомнил отладчик С, который может полностью оживить рабочий процесс с учетом дампа ядра. Мой gdb не может. gdb может позволить вам сбросить содержимое вашего OP* и SV*. Вы, скорее всего, просто прочитали сбрасываемые структуры для интерпретировать вашу структуру программы. Вы могли бы, если хотите, использовать gdb, чтобы сбрасывать структуры, затем синтетически создавать объекты B::* которые вели себя в интерфейсе, как если бы они были обычными и использовали B::Deparse. У корня, наш депаратор и другое отладочное захоронение инструменты в основном ориентированы на объекты, поэтому вы можете просто "обмануть" их создавая кучу поддельных классов и объектов B::*.

Вы можете найти метод B:: Deparse class coderef2text поучительно. Он принимает ссылку на функцию, отбрасывает ее на B::CV объект и использует это для ввода метода deparse_sub:

require B;
require B::Deparse;
sub your_function { ... }

my $cv = B::svref_2object( \ &your_function );
my $deparser = B::Deparse->new;
print $deparser->deparse_sub( $cv );

Для более мягких представлений о OP* и связанных с ними идеях см. обновленный PerlGuts Illustrated и Оптимальные кишки.

Ответ 2

Я сомневаюсь, что там есть инструмент, который делает это из коробки, поэтому...

  • Найдите исходный код для версии perl, которую вы запускали. Это должно помочь вам понять расположение памяти интерпретатора perl. Это также поможет вам выяснить, есть ли способ сделать ярлык здесь (например, если байт-код предшествует легко найти заголовок в памяти или что-то еще).

  • Загрузите двоичный + основной дамп в отладчике, возможно, gdb

  • Используйте информацию в исходном коде perl, чтобы помочь вам убедить отладчика выплюнуть интересующий вас байт-код.

Как только у вас есть байт-код, B:: Deparse должен быть в состоянии заставить вас читать что-то более читаемое.

Ответ 3

Ну, undump превратит этот дамп ядра обратно в исполняемый файл (если вы можете найти рабочую версию). Затем вы можете загрузить его в perl и -MO=Deparse.