交互式反匯編器,簡稱為IDA。是目前最好的反匯編工具,常用於0day挖掘,逆向等領域,網上關於IDC腳本的說明少之又少,這里我就把我的一些常用使用技巧分享一下,在IDA中按下【shift + F2】可調出腳本編輯器,可以簡單的學習一下IDA IDC腳本的編寫與使用,IDC腳本借鑒的C語言的語法,所以其看起來很像。
簡單的IF語句
#include <idc.idc>
static main()
{
auto CurrAddress = ScreenEA();
if(CurrAddress == 0x401161)
{
Message("程序OEP => 0x%x \n",CurrAddress);
}
else
{
Message("沒有扎到OEP \n");
}
}
for語句
#include <idc.idc>
static main()
{
auto origEA,currEA,funcStart,funcEnd;
origEA = ScreenEA();
// origEA = OEP 如果origEA 不在函數內則返回-1
funcStart = GetFunctionAttr(origEA,FUNCATTR_START);
funcEnd = GetFunctionAttr(origEA,FUNCATTR_END);
//Message("OEP: %x 起始地址: %x --> 結束地址: %x \n",origEA,funcStart,funcEnd);
// NextHead 在currEA開始的位置尋找下一條指令的地址
for(currEA = funcStart; currEA != -1; currEA=NextHead(currEA,funcEnd))
{
Message("--> %8x \n",currEA);
}
}
while語句實現
#include <idc.idc>
static main()
{
auto origEA,currEA,funcStart,funcEnd;
origEA = ScreenEA();
// origEA = OEP 如果origEA 不在函數內則返回-1
funcStart = GetFunctionAttr(origEA,FUNCATTR_START);
funcEnd = GetFunctionAttr(origEA,FUNCATTR_END);
//Message("OEP: %x 起始地址: %x --> 結束地址: %x \n",origEA,funcStart,funcEnd);
while(currEA != BADADDR)
{
Message("--> %x \n",currEA);
currEA = NextHead(currEA,funcEnd);
}
}
idc 函數
#include <idc.idc>
// 定義一個函數
static OutPutAddress(MyString)
{
auto currAddress;
currAddress = ScreenEA();
Message("%d \n",MyString);
return currAddress;
}
static main()
{
auto ret = OutPutAddress(123);
Message("%x \n",ret);
}
idc 獲取函數名
#include <idc.idc>
static main()
{
auto origEA,currEA,funcStart,funcEnd;
origEA = ScreenEA();
// origEA = OEP 如果origEA 不在函數內則返回-1
funcStart = GetFunctionAttr(origEA,FUNCATTR_START);
funcEnd = GetFunctionAttr(origEA,FUNCATTR_END);
//Message("OEP: %x 起始地址: %x --> 結束地址: %x \n",origEA,funcStart,funcEnd);
while(currEA != BADADDR)
{
Message("--> %x name: %s \n",currEA,GetFunctionName(currEA));
currEA = NextHead(currEA,funcEnd);
}
}
idc 枚舉所有函數
#include <idc.idc>
static main()
{
auto currAddr,func,endSeg,funcName,counter;
currAddr = ScreenEA();
func = SegStart(currAddr);
endSeg = SegEnd(currAddr);
Message("%x --> %x \n",func,endSeg);
counter = 0;
while(func != BADADDR && func < endSeg)
{
funcName = GetFunctionName(func);
if(funcName != " ")
{
Message("%x --> %s \n",func,funcName);
counter++;
}
func = NextFunction(func);
}
}
枚舉指定函數並輸出
#include <idc.idc>
static main()
{
auto currAddr,func,endSeg,funcName,counter;
currAddr = ScreenEA();
func = SegStart(currAddr);
endSeg = SegEnd(currAddr);
Message("%x --> %x \n",func,endSeg);
counter = 0;
while(func != BADADDR && func < endSeg)
{
funcName = GetFunctionName(func);
if(funcName != " ")
{
if(funcName == "__lock")
{
Message("%x --> %s \n",func,funcName);
}
counter++;
}
func = NextFunction(func);
}
}
尋找特殊指令,並高亮顯示
#include <idc.idc>
static main(void)
{
auto head, op;
head = NextHead(0x00000000, 0xFFFFFFFF);
while ( head != BADADDR )
{
op = GetMnem(head);
Message("%x %s \n",head,op);
if ( op == "jmp" || op == "call" )
SetColor(head, CIC_ITEM, 0x010187);
if (op == "xor")
SetColor(head, CIC_ITEM, 0x010198);
head = NextHead(head, 0xFFFFFFFF);
}
}
ida dump 將函數dump到本地。
#include <idc.idc>
static getFuncName(ea)
{
auto funcName = get_func_name(ea);
auto dm = demangle_name(funcName, get_inf_attr(INF_LONG_DN));
if(dm != 0)
{
funcName = dm;
}
return funcName;
}
static functionDump(ea)
{
auto funcName = 0;
auto end = 0x0;
auto file_open = get_idb_path()[0:-4] + "_dump.log";
auto stream = fopen(file_open, "w");
auto peekAhead;
while( ea != BADADDR )
{
ea = NextFunction(ea);
peekAhead = NextFunction(ea);
end = FindFuncEnd(ea);
funcName = getFuncName(ea);
if(peekAhead == BADADDR)
{
fprintf(stream, "{ 0x%X, 0x%X, \"%s\" }\n", ea, end, funcName);
ea = peekAhead;
continue;
}
end = peekAhead - 1;
fprintf(stream, "{ 0x%X, 0x%X, \"%s\" }\n", ea, end,funcName);
}
fclose(stream);
}
static main()
{
functionDump(0x40000);
}
全量反匯編:
#include <idc.idc>
static main(void)
{
auto decode = 0x401000;
auto xref;
for(xref = RfirstB(decode); xref != BADADDR; xref = RnextB(decode,xref))
{
Message("xref: %x\n",xref);
auto i = 0;
auto inst = xref;
auto op;
while((i < 100) )
{
inst = FindCode(inst,0x00); // flag set to backwards
op = GetDisasm(inst); // get
Message("%x --> %s \n",inst,op);
i++;
}
}
}
查找特定指令片段
#include <idc.idc>
static main()
{
auto currAddr,startSeg,endSeg;
currAddr = ScreenEA();
startSeg = SegStart(currAddr);
endSeg = SegEnd(currAddr);
Message("OEP = %x 起始地址: %x 結束地址: %x \n",currAddr,startSeg,endSeg);
while(startSeg < endSeg)
{
auto op = GetDisasm(startSeg);
// 查找第一條指令
if(strstr(op,"push esi")==0)
{
startSeg++;
op = GetDisasm(startSeg);
if(strstr(op,"push edi"))
{
Message("特征: %x \n",startSeg-1);
}
}
startSeg++;
}
}
全局數組操作: 數組是全局的,並寫入數據庫,白嫖完了,一定得釋放。
#include <idc.idc>
static main()
{
// 創建數組元素
auto array_ptr = CreateArray("array");
// 獲取數組指針
auto ptr = GetArrayId("array");
Message("獲取到的操作指針: %x \n",ptr);
// 設置兩個字符串變量
SetArrayString(ptr,0,"hello");
SetArrayString(ptr,1,"lyshark");
// 設置兩個整數變量
SetArrayLong(ptr,2,100);
SetArrayLong(ptr,3,200);
// 如果提取字符串使用 AR_STR 標記 ,提取整數使用 AR_LONG
auto st = GetArrayElement(AR_STR,ptr,0);
auto st1 = GetArrayElement(AR_STR,ptr,1);
Message("提取字符串變量: %s %s !\n",st,st1);
auto lo = GetArrayElement(AR_LONG,ptr,2);
Message("提取整數變量: %d \n",lo);
// 刪除數組的0號元素
DelArrayElement(AR_STR,ptr,0);
// 注銷整個數組
DeleteArray(ptr);
}
字符串處理函數:
#include <idc.idc>
static main()
{
// 格式化字符串,類似於sprintf
auto name = form("hello %s","lyshark");
Message("格式化后的內容: %s \n",name);
Message("十六進制轉為整數: %d \n",xtol("0x41"));
Message("十進制100轉為八進制: %d \n",ltoa(100,8));
Message("十進制100轉換二進制: %d \n",ltoa(100,2));
Message("字符A的ASCII: %d \n",ord("A"));
Message("計算字符串長度: %d \n",strlen("hello lyshark"));
// 在著字符串中尋找子串
auto main = "hello lyshark";
auto sub = "lyshark";
Message("尋找子串: %d \n",strstr(main,sub));
}
反匯編函數:
#include <idc.idc>
static main()
{
// 索索特征碼
auto code = FindBinary(0x401020,1,"55 8B EC");
Message("%x \n",code);
// 反匯反匯編代碼
code = GetDisasm(0x401000);
Message("%s \n",code);
// 反匯 位於地址處的指令
code = GetMnem(0x401000);
Message("%s \n",code);
// 反匯opcode
code = GetOpnd(0x401070,0);
Message("%s \n",code);
}
枚舉函數(枚舉棧幀)
#include <idc.idc>
static main()
{
auto addr,args,end,locals,frame,firstArg,name,ret;
for(addr = NextFunction(addr); addr != BADADDR; addr = NextFunction(addr))
{
name = Name(addr);
end = GetFunctionAttr(addr,FUNCATTR_END);
locals = GetFunctionAttr(addr,FUNCATTR_FRSIZE);
// 得到棧幀大小
frame = GetFrame(addr);
// 棧中保存返回地址偏移量
ret = GetMemberOffset(frame," r");
if(ret == -1)continue;
firstArg = ret +4;
args = GetStrucSize(frame) - firstArg;
Message("函數: %s 開始: 0x%x 結束: 0x%x 大小: %d bytes 棧幀: %d bytes (%d args) \n",name,addr,end,locals,args,args/4);
}
}
檢索交叉引用(全部):
#include <idc.idc>
static main()
{
auto func,end,target,inst,name,flags,xref;
flags = SEARCH_DOWN | SEARCH_NEXT;
func = GetFunctionAttr(ScreenEA(),FUNCATTR_START);
if(func != -1)
{
name =Name(func);
end = GetFunctionAttr(func,FUNCATTR_END);
for(inst = func;inst < end; inst = FindCode(inst,flags))
{
for(target = Rfirst(inst);target != BADADDR; target = Rnext(inst,target))
{
xref = XrefType();
if(xref == fl_CN || xref == fl_CF)
{
Message("%s call -> %sfrom --> %x \n",name,Name(target),inst);
}
}
}
}
}
if
#include <idc.idc>
static main()
{
auto CurrAddress = ScreenEA();
if(CurrAddress == 0x401161)
{
Message("程序OEP => 0x%x \n",CurrAddress);
}
else
{
Message("沒有扎到OEP \n");
}
}
for
#include <idc.idc>
static main()
{
auto origEA,currEA,funcStart,funcEnd;
origEA = ScreenEA();
// origEA = OEP 如果origEA 不在函數內則返回-1
funcStart = GetFunctionAttr(origEA,FUNCATTR_START);
funcEnd = GetFunctionAttr(origEA,FUNCATTR_END);
//Message("OEP: %x 起始地址: %x --> 結束地址: %x \n",origEA,funcStart,funcEnd);
// NextHead 在currEA開始的位置尋找下一條指令的地址
for(currEA = funcStart; currEA != -1; currEA=NextHead(currEA,funcEnd))
{
Message("--> %8x \n",currEA);
}
}
while語句實現
#include <idc.idc>
static main()
{
auto origEA,currEA,funcStart,funcEnd;
origEA = ScreenEA();
// origEA = OEP 如果origEA 不在函數內則返回-1
funcStart = GetFunctionAttr(origEA,FUNCATTR_START);
funcEnd = GetFunctionAttr(origEA,FUNCATTR_END);
//Message("OEP: %x 起始地址: %x --> 結束地址: %x \n",origEA,funcStart,funcEnd);
while(currEA != BADADDR)
{
Message("--> %x \n",currEA);
currEA = NextHead(currEA,funcEnd);
}
}
idc 函數
#include <idc.idc>
// 定義一個函數
static OutPutAddress(MyString)
{
auto currAddress;
currAddress = ScreenEA();
Message("%d \n",MyString);
return currAddress;
}
static main()
{
auto ret = OutPutAddress(123);
Message("%x \n",ret);
}
idc 獲取函數名
#include <idc.idc>
static main()
{
auto origEA,currEA,funcStart,funcEnd;
origEA = ScreenEA();
// origEA = OEP 如果origEA 不在函數內則返回-1
funcStart = GetFunctionAttr(origEA,FUNCATTR_START);
funcEnd = GetFunctionAttr(origEA,FUNCATTR_END);
//Message("OEP: %x 起始地址: %x --> 結束地址: %x \n",origEA,funcStart,funcEnd);
while(currEA != BADADDR)
{
Message("--> %x name: %s \n",currEA,GetFunctionName(currEA));
currEA = NextHead(currEA,funcEnd);
}
}
idc 枚舉所有函數
#include <idc.idc>
static main()
{
auto currAddr,func,endSeg,funcName,counter;
currAddr = ScreenEA();
func = SegStart(currAddr);
endSeg = SegEnd(currAddr);
Message("%x --> %x \n",func,endSeg);
counter = 0;
while(func != BADADDR && func < endSeg)
{
funcName = GetFunctionName(func);
if(funcName != " ")
{
Message("%x --> %s \n",func,funcName);
counter++;
}
func = NextFunction(func);
}
}
#include <idc.idc>
static main()
{
auto currAddr,func,endSeg,funcName,counter;
currAddr = ScreenEA();
func = SegStart(currAddr);
endSeg = SegEnd(currAddr);
Message("%x --> %x \n",func,endSeg);
counter = 0;
while(func != BADADDR && func < endSeg)
{
funcName = GetFunctionName(func);
if(funcName != " ")
{
if(funcName == "__lock")
{
Message("%x --> %s \n",func,funcName);
}
counter++;
}
func = NextFunction(func);
}
}
尋找特殊指令,並高亮顯示
#include <idc.idc>
static main(void)
{
auto head, op;
head = NextHead(0x00000000, 0xFFFFFFFF);
while ( head != BADADDR )
{
op = GetMnem(head);
Message("%x %s \n",head,op);
if ( op == "jmp" || op == "call" )
SetColor(head, CIC_ITEM, 0x010187);
head = NextHead(head, 0xFFFFFFFF);
}
}
ida dump
#include <idc.idc>
static getFuncName(ea)
{
auto funcName = get_func_name(ea);
auto dm = demangle_name(funcName, get_inf_attr(INF_LONG_DN));
if(dm != 0)
{
funcName = dm;
}
return funcName;
}
static functionDump(ea)
{
auto funcName = 0;
auto end = 0x0;
auto file_open = get_idb_path()[0:-4] + "_dump.log";
auto stream = fopen(file_open, "w");
auto peekAhead;
while( ea != BADADDR )
{
ea = NextFunction(ea);
peekAhead = NextFunction(ea);
end = FindFuncEnd(ea);
funcName = getFuncName(ea);
if(peekAhead == BADADDR)
{
fprintf(stream, "{ 0x%X, 0x%X, \"%s\" }\n", ea, end, funcName);
ea = peekAhead;
continue;
}
end = peekAhead - 1;
fprintf(stream, "{ 0x%X, 0x%X, \"%s\" }\n", ea, end,funcName);
}
fclose(stream);
}
static main()
{
functionDump(0x40000);
}
查找特定指令片段
#include <idc.idc>
static main()
{
auto currAddr,startSeg,endSeg;
Jump(0x0401000); // 光標跳轉到起始位置
currAddr = ScreenEA(); // 反回當前光標所在地址
startSeg = SegStart(currAddr);
endSeg = SegEnd(currAddr);
Message("OEP = %x 起始地址: %x 結束地址: %x \n",currAddr,startSeg,endSeg);
while(startSeg < endSeg)
{
auto op = GetDisasm(startSeg);
// 查找第一條指令
if(strstr(op,"push esi")==0)
{
startSeg++;
op = GetDisasm(startSeg);
if(strstr(op,"push edi")==0)
{
Message("特征: %x \n",startSeg-1);
}
}
startSeg++;
}
}
關鍵字段定位:
#include <idc.idc>
static main()
{
auto currAddr,startSeg,endSeg;
auto array_ptr = CreateArray("array");
auto ptr = GetArrayId("array");
SetArrayString(ptr,0,"push ebp");
SetArrayString(ptr,1,"mov ebp, esp");
Jump(0x0401000); // 光標跳轉到起始位置
currAddr = ScreenEA(); // 反回當前光標所在地址
startSeg = SegStart(currAddr);
endSeg = SegEnd(currAddr);
Message("OEP = %x 起始地址: %x 結束地址: %x \n",currAddr,startSeg,endSeg);
while(startSeg < endSeg)
{
auto x = 0;
auto count=0;
for(x=0;x<2;x++)
{
auto op = GetDisasm(startSeg);
auto st = GetArrayElement(AR_STR,ptr,x);
if(strstr(op,st) == 0)
{
count = count +1;
if(count == 2)
{
msg("匹配地址: %x \n",startSeg--);
}
}
startSeg++;
}
}
DeleteArray(ptr);
}
全局數組操作: 數組是全局的,並寫入數據庫,白嫖完了,一定得釋放。
#include <idc.idc>
static main()
{
// 創建數組元素
auto array_ptr = CreateArray("array");
// 獲取數組指針
auto ptr = GetArrayId("array");
Message("獲取到的操作指針: %x \n",ptr);
// 設置兩個字符串變量
SetArrayString(ptr,0,"hello");
SetArrayString(ptr,1,"lyshark");
// 設置兩個整數變量
SetArrayLong(ptr,2,100);
SetArrayLong(ptr,3,200);
// 如果提取字符串使用 AR_STR 標記 ,提取整數使用 AR_LONG
auto st = GetArrayElement(AR_STR,ptr,0);
auto st1 = GetArrayElement(AR_STR,ptr,1);
Message("提取字符串變量: %s %s !\n",st,st1);
auto lo = GetArrayElement(AR_LONG,ptr,2);
Message("提取整數變量: %d \n",lo);
// 刪除數組的0號元素
DelArrayElement(AR_STR,ptr,0);
// 注銷整個數組
DeleteArray(ptr);
}
字符串處理函數:
#include <idc.idc>
static main()
{
// 格式化字符串,類似於sprintf
auto name = form("hello %s","lyshark");
Message("格式化后的內容: %s \n",name);
Message("十六進制轉為整數: %d \n",xtol("0x41"));
Message("十進制100轉為八進制: %d \n",ltoa(100,8));
Message("十進制100轉換二進制: %d \n",ltoa(100,2));
Message("字符A的ASCII: %d \n",ord("A"));
Message("計算字符串長度: %d \n",strlen("hello lyshark"));
// 在著字符串中尋找子串
auto main = "hello lyshark";
auto sub = "lyshark";
Message("尋找子串: %d \n",strstr(main,sub));
}
反匯編函數:
#include <idc.idc>
static main()
{
// 索索特征碼
auto code = FindBinary(0x401020,1,"55 8B EC");
Message("%x \n",code);
// 反匯反匯編代碼
code = GetDisasm(0x401000);
Message("%s \n",code);
// 反匯 位於地址處的指令
code = GetMnem(0x401000);
Message("%s \n",code);
// 反匯opcode
code = GetOpnd(0x401070,0);
Message("%s \n",code);
}
枚舉函數:
#include <idc.idc>
static main()
{
auto addr,args,end,locals,frame,firstArg,name,ret;
for(addr = NextFunction(addr); addr != BADADDR; addr = NextFunction(addr))
{
name = Name(addr);
end = GetFunctionAttr(addr,FUNCATTR_END);
locals = GetFunctionAttr(addr,FUNCATTR_FRSIZE);
// 得到棧幀大小
frame = GetFrame(addr);
// 棧中保存返回地址偏移量
ret = GetMemberOffset(frame," r");
if(ret == -1)continue;
firstArg = ret +4;
args = GetStrucSize(frame) - firstArg;
Message("函數: %s 開始: 0x%x 結束: 0x%x 大小: %d bytes 棧幀: %d bytes (%d args) \n",name,addr,end,locals,args,args/4);
}
}
枚舉指令: 測試
#include <idc.idc>
static main()
{
auto func,end,count,inst;
func = GetFunctionAttr(ScreenEA(),FUNCATTR_START);
if(func != -1)
{
end = GetFunctionAttr(func,FUNCATTR_END);
count =0;
inst = func;
while(inst < end)
{
count ++;
inst = FindCode(inst,SEARCH_DOWN | SEARCH_NEXT);
}
Message("%s --> %d \n",Name(func),count);
}
}
檢索交叉引用(全部):
#include <idc.idc>
static main()
{
auto func,end,target,inst,name,flags,xref;
flags = SEARCH_DOWN | SEARCH_NEXT;
func = GetFunctionAttr(ScreenEA(),FUNCATTR_START);
if(func != -1)
{
name =Name(func);
end = GetFunctionAttr(func,FUNCATTR_END);
for(inst = func;inst < end; inst = FindCode(inst,flags))
{
for(target = Rfirst(inst);target != BADADDR; target = Rnext(inst,target))
{
xref = XrefType();
if(xref == fl_CN || xref == fl_CF)
{
Message("%s call -> %sfrom --> %x \n",name,Name(target),inst);
}
}
}
}
}
枚舉指定交叉引用函數:
#include <idc.idc>
static FindFunction(bad_func)
{
auto func,addr,xref,source;
func = LocByName(bad_func);
if(func == BADADDR)
{
Message("error \n");
}
else
{
for(addr = RfirstB(func);addr != BADADDR; addr = RnextB(func,addr))
{
xref = XrefType();
if(xref == fl_CN || xref == fl_CF)
{
source = GetFunctionName(addr);
Message("%s call => %0x in %s \n",bad_func,addr,source);
}
}
}
}
static main()
{
FindFunction("LoadString");
}
#include <idc.idc>
static main()
{
auto inpt_count,i,ord,addr,name,purged,file,fd;
file = AskFile(1,"*.idt","select idt save file");
fd = fopen(file,"w");
inpt_count = GetEntryPointQty();
fprintf(fd,"Name = %s \n",GetInputFile());
fprintf(fd,"inpt_count = %x \n",inpt_count);
for(i=0;i<inpt_count;i++)
{
ord = GetEntryOrdinal(i);
if(ord == 0) continue;
addr = GetEntryPoint(ord);
if(ord == addr)
{
continue;
}
name = Name(addr);
fprintf(fd,"%d Name = %s \n",ord,name);
purged = GetFunctionAttr(addr,FUNCATTR_ARGSIZE);
if(purged > 0)
{
fprintf(fd,"pascal = %d ",purged);
}
fprintf(fd,"\n");
}
}