在研究一個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));
}