• 标 题:IDA Pro插件试刀
  • 作 者:softworm
  • 时 间:2003年9月03日 09:19
  • 链 接:http://bbs.pediy.com

在研究一个采用Flexlm进行保护的软件时,当使用了相应版本Flexlm SDK的Sig文件后,IDA Pro顺利地识别出了若干符号。美中不足的是,大部分符号(函数名)被做成了repeatable comment。函数名字仍然是类似sub_45A7F8或unknown_libname_15的东西。要是能用对应的注释为函数命名,就可以使用相应的插件,实现在SoftIce中进行符号化调试。

  这样的注释太多,手工完成是不明智的。第一想法是用IDC Script来做这件事。但尝试了几次,结果总是不如人意。用IDC的几个内置函数(如NextFunction,FindFuncEnd等等)遍历IDB文件中的函数时,不知什么原因,总是有不少函数会被漏掉。另外,在我的IDA Pro 4.3.0.740a上,无论是用IDC Script的Message函数还是插件的msg函数在状态窗口中输出信息时,经常出错,象是越界访问数组。代码看起来没什么错,不知道是否有bug。

  以下用插件来实现,查找所有具有library属性的函数(从Sig文件中得到的符号,都有此属性?)。检查函数名,若为sub_XXXX或unknown_libname_XX形式,则取其repeatable注释。若存在,将函数改为此名。注意有的注释不止一行,如该vendor daemon中42C41B处的注释为:

  _reg
    _l_timer_signal

      在命名函数时,不允许存在回车换行符。对这种情况,只用最后一行。对于重名函数,后续命名时使用递增的函数名,如_l_timer_signal_1,_l_timer_signal_2。在调试代码时发现,若要使用存储在由IDA分配的内存中的数据时,必须及时保存,否则该数据可能会损坏。

  我不知道IDA的Script和Plugin有什么区别?请高手指教。好象Plugin功能更强,可以完成Script的功能,提供了更多的函数。因为可在VC中编程,还可使用IDA SDK以外的函数。

  以下的代码针对具体的应用,并不具有通用性,只是探讨Plugin的应用。所有的代码都在run函数中。直接从SDK的sample修改而来。经过以下处理,该vendor daemon中没有明确命名的函数已所剩无几。

  
#include <ida.hpp>
#include <idp.hpp>
#include <bytes.hpp>
#include <loader.hpp>
#include <kernwin.hpp>
#include <name.hpp>

...

int init(void)
{
    return PLUGIN_OK;
}


void run(int arg)
{
     func_t * pFunc_t;
     ea_t nStart;          //函数地址
   char szAnswer[256];   //原来的函数名
   char szOrigCmt[256];  //函数的repeatable注释
   char szTemp[256];
    char szNewCmt[256];   //调整后的注释(重名函数用)
    char szAsc[10];

    int nCounter=0;  //累加
   char * lpszCmt=0;    //指向函数注释的指针
   char * lpszDelimiter=0;  //分隔符(换行=0xA)
    bool bRet;

  
    int nNumOfFuncs=get_func_qty();  //取函数总数

   for(int i=0;i<nNumOfFuncs;i++)
   {
       pFunc_t=getn_func(i);
       if(pFunc_t->flags & FUNC_LIB)  //只处理库函数
     {
               nStart=pFunc_t->startEA;

               get_func_name(nStart,szAnswer,sizeof(szAnswer));

               if((0==strncmp(szAnswer,"sub_",4))||
   (0==strncmp(szAnswer,"unkn",4)))  //函数名以"sub_"或"unkn"打头吗    
         {
        szOrigCmt[0]=0;   //清当前内容
        
      lpszCmt=get_func_comment(pFunc_t,true);  //取注释

      if(!lpszCmt) continue;   //无注释
        
      strcpy(szOrigCmt,lpszCmt);  //保存当前注释
  
      //检查注释是否不止1行

      lpszDelimiter=0;
       szTemp[0]=0;

                     if(lpszDelimiter=strrchr(szOrigCmt,0xA)) //查找换行符
     {
            strcpy(szTemp,lpszDelimiter+1);
        
                          szOrigCmt[0]=0;
            strcpy(szOrigCmt,szTemp);   //用最后1行
      }

      bRet=set_name(nStart,szOrigCmt);
    
      nCounter=0;
          while(0==bRet) //命名失败(函数名已被使用)
      {
    szAsc[0]=0;
    _itoa(++nCounter,szAsc,10);
            
    szNewCmt[0]=0;
    strcpy(szNewCmt,szOrigCmt);
    strcat(szNewCmt,"_");
    strcat(szNewCmt,szAsc);  //创建递增的函数名
            
    bRet=set_name(nStart,szNewCmt);
                     }
                }
          }
     }
}

char comment[] = "My first plugin";

char help[] =
        "A sample plugin module
"
        "
"
        "This module shows you how to create plugin modules.
"
        "
"
        "It does nothing useful - just prints a message that is was called
"
        "and shows the current address.
";

char wanted_name[] = "My first plugin";

char wanted_hotkey[] = "Alt-0";

extern "C" plugin_t PLUGIN = {
  IDP_INTERFACE_VERSION,
  0,                    // plugin flags
  init,                 // initialize

  term,              // terminate. this pointer may be NULL.

  run,                // invoke plugin

  comment,       // long comment about the plugin
                        // it could appear in the status line
                        // or as a hint

  help,                 // multiline help about the plugin

  wanted_name,          // the preferred short name of the plugin
  wanted_hotkey         // the preferred hotkey to run the plugin
};