逆向工程基于核心转储的Perl脚本

时间:2010-08-26 15:33:58

标签: perl reverse-engineering

朋友的服务器(是的,真的。不是我的。)被打破了,我们发现了一个运行一些机器人代码的perl二进制文件。我们找不到脚本本身(可能是通过网络收到的eval'),但我们设法创建了perl进程的核心转储。

在核心上运行字符串给了我们一些提示(主机名,用户名/密码),但不是脚本的源代码。

我们想知道脚本能够做什么,所以我们想对perl解释器中运行的perl代码进行反向工程。

搜索周围,我发现的最接近perl解编译器的是B :: Deparse模块,它似乎非常适合将解析树的字节码转换回可读代码。

现在,我如何让B :: Deparse在核心转储上运行?或者,或者,如何从核心重新启动程序,加载B :: Deparse并执行它?

欢迎任何想法。

3 个答案:

答案 0 :(得分:7)

是的,我告诉IRC对你的问题发表评论。我做了一整个 一堆东​​西“拆解”编译的perl和东西(只看我的 CPAN页面[http://search.cpan.org/~jjore])。

Perl将您的源代码编译为OP*结构树 偶尔会有SV*的C指针,它们是perl值。你的核心 dump现在有一堆OP*SV*被隐藏。

最好的世界就是拥有一个perl模块 B::Deparse为您完成信息理解工作。它 通过在B::OPB::SV中使用光接口来实现内存 B::*个类(记录在Bperlgutsperlhack)。这对你来说是不现实的,因为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
运行时显示B::SV对象(它是ISA 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使用代码必须实际运行 在现场记忆中。 Tye McQueen认为他记得一个C调试器 在核心转储的情况下,可以完全恢复工作流程。我的gdb 不能。 OP*可以允许您转储SV*gdb的内容 B::*结构。你很可能只是阅读转储的结构 解释你的程序的结构。如果你愿意,你可以使用 B::Deparse转储结构,然后合成创建B::*个对象 在界面中表现得好像是普通的并且使用它们 coderef2text就此而言。在root,我们的deparser和其他调试转储 工具大多是面向对象的,所以你可以“愚弄”它们 创建一堆伪造的B::CV类和对象。

您可能会发现阅读B :: Deparse类的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*方法:

{{1}}

有关{{1}}及相关提示的更温和的介绍,请参阅更新 PerlGuts IllustratedOptree guts

答案 1 :(得分:2)

我怀疑有一个开箱即用的工具,所以......

  1. 找到您运行的perl版本的源代码。这应该有助于您了解perl解释器的内存布局。它还可以帮助你弄清楚是否有办法在这里采用一个快捷方式(例如,如果字节码前面有一个易于查找的内存或其他东西)。

  2. 在调试器中加载二进制+核心转储,可能是gdb

  3. 使用perl源代码中的信息来指导您说服调试器吐出您感兴趣的字节码。

  4. 一旦你有字节码,B :: Deparse应该能够让你更具可读性。

答案 2 :(得分:0)

好吧,undump会将核心转储重新转换为二进制可执行文件(如果可以找到工作版本)。然后,您应该可以将其加载到perl-MO=Deparse