在研究一个采用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
};