• 标 题:IDC Script实战
  • 作 者:softworm
  • 时 间:2003/08/03 08:01pm
  • 链 接:http://bbs.pediy.com

在研究一个Borland C++写的软件时,遇到以下问题:在主EXE文件和一个DLL中包含有大量的字符串资源,包括各种提示及错误信息。代码中使用这些资源的方式基本一致,即构造一个OWL的TStringIDS对象,把资源ID作为参数传入。在IDA中,为以下格式:
   
  push    nResourceID

  一开始,遇到这样的代码,我用ResHacker手工查找,把资源字符串作为相应代码的注释。这样做效率实在太低,转念一想,干嘛不试试IDC Script,要是能把所有的push nResourceID自动做上注释,无疑能大大增加代码的可读性。

  注意:这样做出的注释,可能有一些错误,把与资源访问无关的代码也进行解释。对于Resource ID在10以下的,最好不要用。比如 push 1 的意思可能是 push true。还有一些地方,是在调用new操作符分配内存,也会push一个立即数。不过这种注释错误一般能看出来,还是利大于弊。

  我的IDB文件为9MB多,在AMD 1700+上跑1次约5分钟。

  几句说明:

1. 用ResHacker打开该DLL,将字符串资源另存到单独的.RC文件中。用Notepad删除资源描
 述语句。得到的数据格式如下(test.rc):

  0, "test1"
  1, "test2"
  2, "test3"
   ...

2. 用FindBinary直接查找push指令的Opcode。当操作数为立即数时,对应的代码有
  0x6A,0x68两个。所以写成的Script在执行一次后,修改一下查找字符串再跑一次。

3.从RC文件中取出资源ID,转换为long进行比较,匹配即作注释。

代码如下:

#include <idc.idc>

static main()
{
auto nStartAddr; //起始地址=0x401000
auto nResult;    //找到的地址
auto szFile;     //
auto hFile;          

auto szData;          //RC文件的1行
auto nPos;   //  
auto szOperandInFile; //RC文件1行的ResourceID部分
auto szComment;       //RC文件1行的字符串部分
auto bFound;

auto nOperand;   //当前地址的第1个operand
auto nOperandInDataFile; //RC文件1行的ResourceID部分转换出的long值
auto nOperandType;   //当前operand类型,5为Immediate


//选择RC文件

szFile=AskFile(0,"*.rc","Select a data file");
 
hFile=fopen(szFile,"r");

if(0==hFile)
{
   Message("Failed to open the file");
   return;
}

nStartAddr=0x401000;

do //扫描IDB的CODE段
{
    nResult=FindBinary(nStartAddr,SEARCH_NEXT|SEARCH_DOWN,"6A");  //
                                                      //用"68"再做一遍
 
    if(nResult!=BADADDR)
    {
       nOperandType=GetOpType(nResult,0); //测试operand类型
 
       if(nOperandType==5) //Immediate
       {
          nOperand=GetOperandvalue(nResult,0);

          //在RC文件中搜索

          fseek(hFile,0,0);  
          bFound=0;

          do
          {
             szData=readstr(hFile);
             if(szData != -1) //文件尾
             {
               nPos=strstr(szData,",");  //分成2部分
               szOperandInFile=substr(szData,0,nPos);
               szComment=substr(szData,nPos+3,-1);

               nOperandInDataFile=atol(szOperandInFile);

               if(nOperand==nOperandInDataFile) //匹配?
               {
                    Message(form("\nFound at %X",nResult));
                    MakeComm(nResult,szComment); //注释
 
                    bFound=1; //找到则退出do-while
               }
            }
           }while((szData!= -1)&&(bFound==0));
        }
     }

     nStartAddr=NextAddr(nResult);  //更新地址

}while((nStartAddr<0x48D000)&&(nResult!=BADADDR));  //在DATA段前结束

fclose(hFile);

Message("\n");
Message(form("%s processed successfully!",szFile));
}