首页
社区
课程
招聘
[翻译]006使用含通用PE脱壳插件的IDA4.9专业版脱壳被压缩的可执行体
2006-11-5 16:13 8413

[翻译]006使用含通用PE脱壳插件的IDA4.9专业版脱壳被压缩的可执行体

2006-11-5 16:13
8413
标题:使用含通用PE脱壳插件的IDA4.9专业版脱壳被压缩的可执行体
     (原文自数据救援2005http://www.datarescue.com/idabase/unpack_pe/unpacking.pdf)

使用含通用PE脱壳插件的IDA4.9专业版脱壳被压缩的可执行体(C)数据拯救2005
从4.9 版开始,IDA专业版就带有通用PE脱壳插件,其源代码可在IDA专业版软件开发工具包内使用。这个指南将说明在实践中如何使用该插件,并将简要描述它在内部如何工作。

被压缩的应用程序
如果我们执行范例程序,这是出现在屏幕上的画面。



完全合法,但是不管怎样,如果我们在IDA专业版里打开这个可执行体,会出现下面的警告:



IDA探测到不寻常输入段,并告诉我们文件可能被加壳。
如果我们看了输入窗口就会观察到:



我们的程序仅仅从KERNEL32.DLL输入了三个函数。我们可以意识到GetProcAddress()动态链接库的一个常见函数LoadLibrary ()更多可能将是被脱壳引擎用来重建原始可执行体的输入。

使用通用PE脱壳插件
现在我们通过插件子菜单开始脱壳



出现插件选项对话框:



在这个对话框,我们可以调整地址范围,一旦到达,将导致调试器把程序执行挂起, 也有可能详细说明一个文件未加壳的资源存储在哪里。点击OK后,插件开始运行程序,在到达先前定义范围的内部地址前将会自我脱壳。接着出现下一个对话框指示脱壳结束,并提供结果的存储器快照。



注意在脱壳过程中到达的两个断点。后面我们要作更多说明。

为了重建程序的原始输入部,插件程序创建了新段。



一旦脱壳,我们就可以看到更为典型的start()函数结构



不管怎样,我们再试着改进以获得尽可能最好的反汇编。

申请签名
如果在程序脱壳后我们看到发现的串,就会明白程序是用Visual C++编译器编译的。 我们来申请关联FLIRT(Fast Library Identification and Recognition Technology)库签名



最终的反汇编列表如下:



更好一些,是不是?

幕后
我们现在来深入了解在实践中如何使用SDK 调试程序API函数以实现脱壳。
主要想法是开启一个进程针对于由调试程序引起的各种事件做出恰当的反应,直到我们能够确定程序被正确脱壳。所以首先我们设置一个句柄来接收调试程序事件,并启动一个进程直至其入口点:
              if ( !hook_to_notification_point(HT_DBG, callback, NULL) )
              {
                warning("Could not hook to notification point\n");
                return;
              }
              // Let's start the debugger 开始调试
              if ( !run_to(inf.beginEA) )
              {
                warning("Sorry, could not start the process");
                unhook_from_notification_point(HT_DBG, callback, NULL);
              }
事件将被送到我们的通知句柄,定义如下:
                    static int idaapi callback(void * /*user_data*/,
                                              int notification_code,
                                              va_list va)
                    {
                     switch ( notification_code )
                     {
                       case dbg_process_start:
                         ...
                       case dbg_library_load:
                         ...
                       case dbg_run_to:
                         ...
                       case dbg_bpt:
                         ...
                       case dbg_trace:
                         ...
                       case dbg_process_exit:
                         ...
                       ...
                     }
                     return 0;
                    }

当我们通过调用到run_to()开启进程,我们会收到相应的dbg_run_to事件,指示run_to()已被正确执行。我们现在在被压缩程序的入口点,并把断点设置在GetProcAddress()动态链接库函数上(假设脱壳引擎在重新创建原始应用程序的原始输入表前已终止工作。)
          case dbg_run_to:   // Parameters: thread_id_t tid
            dbg->stopped_at_debug_event(true);
            gpa = get_name_ea(BADADDR, "kernel32_GetProcAddress");
            ...
            else if( !add_bpt(gpa) )
            {
              bring_debugger_to_front();
              warning("Sorry, can not set bpt to kernel32.GetProcAddress");
              goto FORCE_STOP;
            }
            else
            {
              ++stage;
              set_wait_box("Waiting for a call to GetProcAddress()");
            }
            continue_process();
            break;

在到达我们设GetProcAddress()断点时,我们会收到一个dbg_bpt事件。我们可以从堆栈中提取返回地址,删除第一个断点,并在返回地址上设置第二个断点,以便一旦GetProcAddress()函数返回时可以被通知到。
             case dbg_bpt:      // A user defined breakpoint was reached.
                                // Parameters: thread_id_t tid
                                //             ea_t        breakpoint_ea
               {
                 /*tid_t tid =*/ va_arg(va, tid_t);
                 ea_t ea   = va_arg(va, ea_t);
                 ...
                 if ( ea == gpa )
                 {
                   regval_t rv;
                   if ( get_reg_val("esp", &rv) )
                   {
                     ea_t esp = rv.ival;
                     invalidate_dbgmem_contents(esp, 1024);
                     ea_t ret = get_long(esp);
                     ...
                     if ( !del_bpt(gpa) || !add_bpt(ret) )
                       error("Can not modify breakpoint");

你还记得在脱壳中我们看到的发生在地址0x7C80AC28 和0x00040C68D的两个断点信息吗?第一个是我们的GetProcAddress()断点,第二个是我们在返回地址下的断点。在接下来的反汇编里,你可以看到通向我们GetProcAddress()断点的调用。我们现在只需执行指令直到脱壳引擎重建程序的原始寄存器内容,然后跳转到脱壳程序的真实入口地址。



目前步进跟踪是在我们到达先前定义地址前的最简单的方法。所以我们只要到达第二个断点时就开启步进跟踪
del_bpt (ea);
if ( !is_library_entry(ea) )
{
   deb(IDA_DEBUG_PLUGIN, "%a: reached unpacker code, switching to trace mode\n",  
ea);
   enable_step_trace(true);
   ...
   set_wait_box("Waiting for the unpacker to finish");
}
else
{
   warning("%a: bpt in library code", ea); // how can it be?
   add_bpt(gpa);
}

对每一步指令我们要检查地址是否匹配先前定义的范围。如果到达界限,停止跟踪,从新分析脱壳后的代码,调整入口点,重新建立输入表,保存资源,然后-----最后拍摄快照。
case dbg_trace:    // A step occured (one instruction was executed). This event
                   // notification is only generated if step tracing is enabled.
                   // Parameter:  none
  ..
  /*tid_t tid =*/ va_arg(va, tid_t);
  ea_t ip   = va_arg(va, ea_t);
  if ( oep_area.contains(ip) )
  {
    // stop the trace mode
    enable_step_trace(false);
    // reanalyze the unpacked code
    set_wait_box("Reanalyzing the unpacked code");
    do_unknown_range(oep_area.startEA, oep_area.endEA, false);
    auto_make_code(ip);
    noUsed(oep_area.startEA, oep_area.endEA);
    auto_mark_range(oep_area.startEA, oep_area.endEA, AU_FINAL);
    // mark the program's entry point
    move_entry(ip);
    set_wait_box();
    ...
    set_wait_box("Recreating the import table");
    invalidate_dbgmem_config();
    ...
    create_impdir();
    set_wait_box("Storing resources to 'resource.res'");
    if ( resfile[0] != '\0' )
      extract_resource(resfile);
    set_wait_box();
    if ( take_memory_snapshot(true) )
      goto FORCE_STOP;
用户在他的IDA数据库获得存储器信息转储后,就可以像平常一样开始分析脱壳后的代码了。
不要犹豫,在SDK里面进一步看看源代码以获得所有执行的详细资料。

                                         
                                         IDA 4.9专业版脱壳教程      
  

阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!

收藏
点赞7
打赏
分享
最新回复 (4)
雪    币: 222
活跃值: (27)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
arthurchen 2 2006-11-5 17:17
2
0
标题:使用IDA Pro.图表化函数
        (文章来源数据拯救 2005 http://www.datarescue.com/idabase/graphs/graphs.pdf
    从IDA Pro4.17开始,可以使用VCG(可视化编译图表)图表库的一个局部端口――Wingraph32. IDA能够生成可转到Wingraph32的标准GDL 图表。在图表工具栏可以使用函数图表化命令。



让我们来详细看一看其更多的可能性。

流程图
通过图表观察一个函数代码的流程对一个函数的结构常常会提供比我们通过浏览得到的更好的全局概念。流程图命令绘制了这些图表。



如果你想要在同一时间图表化几个函数,或图表化一个较大函数的一部分,只要使用我们的标准选择键选择感兴趣的区域即可。



函数调用

通常分析函数之间的函数变量关系对于理解一个特定的应用程序如何工作是必要的。IDA提供给我们一个命令来图表化程序函数之间的所有存在的函数变量关系(交叉参考)



这个命令主要针对于小的程序,因为一旦一个程序包含大量的函数,图标会迅速变得极为复杂。注意:图标的颜色依据函数/地址的属性(外部函数,库函数,入口)。颜色配置和反汇编某一概念一致的。

函数交叉参考

Xref s to 和 Xref s from允许你专注于交叉参考至和自一个特定函数。

Xref s to控制导向一个指定函数的图表数据和代码的交叉参考。我们来看一看来自C标准库的toupper()函数调动特征至上一级情况(由某种特定程序采用的一个数据集)。
  


在图表顶部,我们注意到start()函数调用WinMain()函数。在左边,我们观察到一个指向回调函数()的函数指针。在底部右侧,我们可以观察到递归函数调用自身。我们也可以备注strtoul()(来自C标准库,将一个串转换为无符号长整型)间接依赖于toupper()函数。最后,要注意到被选择的函数始终由蓝色框架环绕。
                                    
  
Xref s from控制来自于一个指定函数的图表代码的交叉参考。从这个方向,在图表中仅使用代码交叉参考(而不是数据交叉代码)以避免使用所有来自每个函数的全局数据参考填充图表。 让我们在toupper()函数上使用这个命令。



这里,我们观察到toupper()函数广泛使用了其他C标准库函数,它们自身直接或间接地使用了一些Windows的应用程序接口,如WideCharToMultiByte()或VirtualAlloc()。和使用流程图命令一样,这些交叉参考命令也可以使用选择来图表化几个函数。

使用者定义过的交叉参考函数

IDA为熟练用户提供了高级图表化函数。我们来看看如何在实践中使用它们
来看一些需要使用这些选项的实例



数据交叉参考

要记住Xref s from命令仅能绘制代码交叉参考。不过有时,它会对跟踪数据交叉参考很有用。我们通过取消选择交叉参考至和从略数据选项应用它来观察一个指向函数指针阵列的指针。



  
更甚之的另一种可能性是显示全局数据的参考。我们可以通过一个函数或搜索涉及一组由参考函数引用的全局数据的函数来显示全局数据参考。这对于明确说明最大递归深度以避免一个几乎不可读的图表是个好意见。 



因为我们把打印递归点选项留为格纹状,所有在顶部出现一些点,标志着在特定递归深度确定的范围外至少有一个交叉参考存在

递归深度

正如我们先前提到的,函数调用命令如果用于通常的包含大量函数的程序没有作用。另外,通过指定递归深度,我们可以尝试得到同样类型的图表,不过要专注于某一特定函数。我们在fopen()函数试一试。



忽略特定函数

IDA的FLIRT(快速库辨认和识别技术)确定了来自很多库德标准函数。因为这些函数已有丰富备证,我们通常对其内部不再十分关注。为了隐藏所有这些内部交叉参考并得到简单的、可读性更强的图表, 我们可以简单地激活忽略来自库的函数的选项。



尽管如此,涉及像MessageBox()这种的外部Windows 应用程序接口的交叉参考总会呈现在我们的图表里。如果我们想要隐藏这些交叉参考,切实关注于一个函数与库函数的函数变量关系,我们也可以激活忽略外部选项。



相反地,我们也可以绘制涉及外部Windows应用程序接口的交叉参考,并且忽略涉及库函数的交叉参考。以此说明一个函数依赖于动态链接库的程度。



打印注释

让我们通过展示一种图表化Windows应用程序和某一特定动态链接库函数的变量关系的方式来结束有关IDA函数图表化功能部件的小指南。通过基于涉及这一独特动态链接库的所有外部声明的选择创建一个图表,这是可以达到的。我们也可以激活打印注释选项,它将打印和这些外部函数相关的注释。以下例子说明一个程序依赖于comdlg32.dll输出函数的程度。

这里如何结合使用IDA和WinGraph32为直观表示复杂可执行文件的大量信息提供了可能。

雪    币: 32401
活跃值: (18875)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 8 2006-11-8 15:33
3
0
辛苦了,我将两个主题合并了。
雪    币: 323
活跃值: (579)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
springkang[DFCG 11 2006-11-8 19:34
4
0
好文,学习了!
雪    币: 263
活跃值: (10)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
KAN 6 2007-1-13 22:55
5
0
这么好的文章能不顶一下
游客
登录 | 注册 方可回帖
返回