日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

IDA Plugin 编写基础

發(fā)布時(shí)間:2024/4/11 编程问答 62 豆豆
生活随笔 收集整理的這篇文章主要介紹了 IDA Plugin 编写基础 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
IDA?Plugin?編寫(xiě)基礎(chǔ)

IDA是迄今為止最為強(qiáng)大的反匯編器,它有著眾多的功能。但是如果它不具備通過(guò)附加的模塊來(lái)對(duì)標(biāo)準(zhǔn)的函數(shù)進(jìn)行擴(kuò)展的功能(粗俗點(diǎn)說(shuō)就是plugin)的話,也就有負(fù)此盛名了。現(xiàn)在我們就來(lái)更為詳細(xì)地研究一下如何編寫(xiě)這些plugin。

喏,首要的就是要有這個(gè)叫做IDA的反匯編器,同時(shí)還要有與之匹配的IDA?SDK。SDK里主要的部分就是include目錄及其下的所有文件,這些文件里包含了編寫(xiě)plugin所用到的所有的宏定義和函數(shù)原型,同時(shí)用到它們的還有import?lib?——?ida.lib。我這里使用的編譯器是Intel?C++,與VC++結(jié)合起來(lái)用。我選擇它的原因就是,在SDK中沒(méi)有對(duì)它進(jìn)行內(nèi)嵌的支持(比如在SDK中就有Borland?C++和VC++編譯器的安裝文件),而這能使我們更好地理解。ida.lib文件是ida.wll(位于IDA目錄下)的import?library。其中所有的函數(shù)都是用ordinal導(dǎo)出的,而ordinal與函數(shù)名的比較是在ida.lib里進(jìn)行的。這就是需要使用與IDA版本相匹配的SDK的原因了,因?yàn)閷?dǎo)出函數(shù)的ordinal會(huì)因版本的不同而發(fā)生變化。喏,好了,萬(wàn)事具備了,我們開(kāi)始吧。

plugin到底是個(gè)什么東東呢?其實(shí)它也沒(méi)什么稀奇的,就像一個(gè)通常的DLL,只是導(dǎo)出了下面這個(gè)名為PLUGIN的結(jié)構(gòu)體:



?struct?plugin_t
?{int?version;????????//?IDA的版本,用于plugin的編寫(xiě),通常這個(gè)域的值為IDP_INTERFACE_VERSION?-?表示SDK版本的constant。
?????????????????????????如果這個(gè)域的值與所用IDA的版本不一致,就不會(huì)加載此plugin。
??int?flags???????????//?這個(gè)好理解,就是些標(biāo)志。嫌麻煩添0就行了。但這里要講一下所有可能的取值。
?????????????????????????
?????????????????????????PLUGIN_MOD?-?置位表示plugin會(huì)修改database(坦白講,沒(méi)有什么plugin會(huì)修改它)。如果此位置位,
?????????????????????????而進(jìn)程模塊卻禁止修改database,則plugin就不會(huì)被使用。這個(gè)標(biāo)志我們并不需要,另外的幾個(gè)也是一樣。

?????????????????????????PLUGIN_DRAW?-?置位表示IDA在調(diào)用plugin后需要重畫(huà)(即刷新)所有窗口。

?????????????????????????PLUGIN_SEG?-?plugin只在鼠標(biāo)所放之處的地址屬于某個(gè)segment時(shí)才能使用。這里也不需要。

?????????????????????????PLUGIN_UNL?-?若置位,則plugin在使用后會(huì)從內(nèi)存中卸載。這對(duì)于調(diào)試器來(lái)說(shuō)當(dāng)然是好了,但對(duì)我們來(lái)說(shuō)
?????????????????????????就不太合適了。?

?????????????????????????這些標(biāo)志可以用邏輯或(我們這里用or,C語(yǔ)言里用“|”)結(jié)合起來(lái)。但我說(shuō)過(guò),更為簡(jiǎn)單的是把所有這些
?????????????????????????域都填成紅色的NULL。

??void?(idaapi*?init)(void);????????//初始化函數(shù)加載plugin的時(shí)候調(diào)用,如果函數(shù)返回了什么不好的東西,則plugin就不會(huì)被加載。

??void?(idaapi*?term)(void);????????//卸載plugin時(shí)調(diào)用。一般不使用。

??void?(idaapi*?run)(int?arg);??????//也許這是最重要的域了?-?working?function,每次調(diào)用plugin都要運(yùn)行,包含著plugin的主要
??????????????????????????????????????代碼。
??char*?comment;????????????????????//注釋,作提示用的。
??char*?help;???????????????????????//help自然就是help了.
??char*?wanted_name;????????????????//首選的plugin名。
??char*?wanted_hotkey;??????????????//首選的熱鍵。一般來(lái)說(shuō)不依賴于plugin作者選用的鍵,實(shí)際的熱鍵值記錄在plugin.cfg,這個(gè)
??????????????????????????????????????文件后面會(huì)講到。
};

一般來(lái)說(shuō),include里的loader.hpp文件里這個(gè)結(jié)構(gòu)體是作為類(lèi)來(lái)聲明的,我想對(duì)那些不了解類(lèi)的讀者說(shuō),其實(shí)在C++里類(lèi)和結(jié)構(gòu)體在本質(zhì)上都是一樣的。喏,好像到了該給出源代碼的時(shí)候了。我這里給出一個(gè)最簡(jiǎn)單的plugin,這個(gè)plugin會(huì)將database中的無(wú)用指令:
бесполезные?группы?инструкций:

pusha
popa

push?eax
push?edx
rdtsc
pop?edx
pop?eax

push?edx
push?eax
rdtsc
pop?eax
pop?edx

替換為“更為明了”的nop指令。下面是代碼:

#pragma?comment(linker,"/NODEFAULTLIB")
#pragma?comment(linker,"/Entry:Dllmain")????//Runtime庫(kù)占了40kb字節(jié),卻沒(méi)什么有用的東西,特別是對(duì)plugin。
??????????????????????????????????????????????然而,如果切斷它,則需要重新標(biāo)記入口點(diǎn)。

#define?__NT__
#define?__IDP__????//這個(gè)一定要有,否則plugin就罷工。

typedef?unsigned?char?BYTE;????//這里沒(méi)有包含標(biāo)準(zhǔn)的include文件需要額外定義BYTE類(lèi)型

#i?nclude?<ida.hpp>
#i?nclude?<idp.hpp>
#i?nclude?<bytes.hpp>
#i?nclude?<loader.hpp>
#i?nclude?<kernwin.hpp>????//"紳士的選擇"?IDA中的頭文件

??//重新標(biāo)記入口點(diǎn)
bool?Dllmain(void*?hInstDLL,?int?reason,?int?reserved)
{return?true;}

char?comment[]?=?"Experimental?plugin";
char?help[]?=?"Experimental?plugin";
char?wanted_name[]?=?"ExpPlugin";
char?wanted_hotkey[]?=?"F11";

BYTE?rdtsc1[]={0x52,?0x0F,?0x31,?0x5A,?0x58};
BYTE?rdtsc2[]={0x50,?0x0F,?0x31,?0x58,?0x5A};????//就是些opcodes

??//plugin的initialization?procedure

根據(jù)不同的返回值,IDA可以加載或者不加載plugin。可能返回的值有:

????PLUGIN_SKIP?-?不加載返回值。

????PLUGIN_OK?-?喏,一個(gè)OK自然要加載plugin啦。

????PLUGIN_KEEP?-?不但要加載,還要常駐內(nèi)存。

比如說(shuō),要想讓plugin只處理PE格式的文件,需要這樣寫(xiě)initialization?procedure:

if?(inf.filetype?!=?f_PE)?return?PLUGIN_SKIP;
return?PLUGIN_OK;

這里就不研究那個(gè)inf結(jié)構(gòu)體了,詳情請(qǐng)見(jiàn)SDK。我們這里總是要加載plugin的,所以代碼如下:

int?init(void)
{return?PLUGIN_OK;}

????//在unload?procedure里也是什么也不用干,空著它。

void?term(void)
{return;}

????//最后就是主要的run函數(shù)了
在研究主函數(shù)之前有興趣可以研究一下database的讀寫(xiě)函數(shù),還有獲取當(dāng)前地址的函數(shù),也即IDA中鼠標(biāo)所放之處的地址:

?get_byte
?get_word
?get_long?-?從database中讀取各種長(zhǎng)度字節(jié)。接受一個(gè)參數(shù)——listing中的地址。

?patch_byte
?patch_word
?patch_long?-?向database中寫(xiě)入各種長(zhǎng)度字節(jié)。兩個(gè)參數(shù),第一個(gè)——地址,第二個(gè)——值。

可以猜到,名字里有byte的函數(shù)是用于(即接受或返回)字節(jié)的,word——字,而long——雙字。

?get_screen_ea?-?獲取當(dāng)前地址的函數(shù),當(dāng)前地址就是它的返回值。

void?run(int?arg)
{BYTE?cb1;
??int?i,?tmp0;

?ea_t?CA?=?get_screen_ea();
?cb1=get_byte(CA);

????//pusha
????//popa
?if?(cb1==0x60?&&?get_byte(CA+1)==0x61)????//?pusha的opcode?-?60h,而popa?-?61h
???{patch_word(CA,?0x9090);
?????return;}

????//rdtsc
?if?(cb1==0x50)????//序列的第一個(gè)字節(jié)?-?push?eax的opcode
???{tmp0=1;
????for?(i=0;?i<5;?i++)????//數(shù)組中的其它字節(jié),使用循環(huán)檢驗(yàn)
????if?(get_byte(CA+i+1)!=rdtsc1[i])?{tmp0=0;?break;}

????if?(tmp0==1)
??????{patch_long(CA,?0x90909090);
????????patch_word(CA+4,?0x9090);
????????return;}}

?if?(cb1==0x52)
???{tmp0=1;
?????for?(i=0;?i<4;?i++)
?????if?(get_byte(CA+i+1)!=rdtsc2[i])?{tmp0=0;?break;}

?????if?(tmp0==1)
???????{patch_long(CA,?0x90909090);
?????????patch_word(CA+4,?0x9090);
?????????return;}}
};

????//現(xiàn)在放入前面講過(guò)的導(dǎo)出結(jié)構(gòu)體。
????//一定要寫(xiě)上extern?"C",使得linker能正確找到導(dǎo)出結(jié)構(gòu)體的名字

extern?"C"?plugin_t?PLUGIN?=?{
IDP_INTERFACE_VERSION,
0,
init,
term,
run,
comment,
help,
wanted_name,
wanted_hotkey
};

????????現(xiàn)在我們來(lái)看如何將它編譯。以下是bat文件:

icl?-Gz?/I?<SDK的include目錄的路徑>?plugin.cpp?ida.lib?/link?/subsystem:windows?/DLL?/def:plugin.def?/out:exp.plw
del?"<IDA目錄路徑>\plugins\exp.plw"
copy?exp.plw?"<IDA目錄路徑>\plugins\"
PAUSE

我已經(jīng)說(shuō)過(guò),此處是以Intel?C++為例的,如果用VC++的話,源代碼不用改,而編譯用的命令行則需要修改(不過(guò)就是把icl換成cl)。現(xiàn)在來(lái)詳細(xì)講一下。

-Gz告訴intel?complier,默認(rèn)使用stdcall規(guī)則向函數(shù)傳遞參數(shù)。
/I?-?IDA?SDK的include目錄的路徑
plugin.cpp?-?plungin源代碼。
ida.lib?-?SDK的import?library,應(yīng)該和源代碼放入一個(gè)目錄。
/link參數(shù)的后面是liner?options,就不用多說(shuō)了。除了def文件。因?yàn)檫@里已經(jīng)有源代碼和bat文件了,就需要生成def文件。

LIBRARY?exp
EXPORTS?PLUGIN

def文件指明需要導(dǎo)出PLUGIN結(jié)構(gòu)體。一般來(lái)說(shuō),到這里就都完成了,plugin已經(jīng)可以使用了,剩下的只是把它加到IDA里了。可以把它拷貝到IDA的plugins目錄里。但這還不夠,還需要配置一下。所有plugins的配置都保存在plugins目錄下plugins.cfg文件里。通常文件的起始處是注釋,后面就是plugin的配置了。為了將我們的exp.plw(Windows下的plugin的擴(kuò)展名都是plw)加入進(jìn)去,需要在文件末尾加入四個(gè)參數(shù),順序?如下:

????plugin名??文件名??熱鍵??參數(shù)。

這里的參數(shù)就是傳給run函數(shù)的,我個(gè)人覺(jué)得沒(méi)什么用,所以就設(shè)為0。熱鍵嘛,可以設(shè)為F11,好像IDA用不到這個(gè)鍵。這樣,我們所添加的這一行就是下面這個(gè)樣子的:

????????expplugin????exp????F11????0

不主張?jiān)谇懊鎸?xiě)一個(gè)句點(diǎn)加一個(gè)逗號(hào),因?yàn)槟菢泳统闪俗⑨尅_?#xff0c;一般來(lái)說(shuō)可以認(rèn)為,mission?accomplished。剩下的就是啟動(dòng)IDA,打開(kāi)某個(gè)文件,那個(gè)文件里要有我們前面給出的指令(比如,可以自己立馬用ASM寫(xiě)一個(gè)),然后進(jìn)行檢查。如果沒(méi)有問(wèn)題,就按下F11鍵或從菜單里選擇我們的plugin,這時(shí)那些指令就應(yīng)該都被替換成nop了。當(dāng)然,鼠標(biāo)應(yīng)該放在這些scrambled的指令(如果可以這樣說(shuō)的話)的前面,當(dāng)然這些都是些垃圾指令了。到這里就真的都完成了。
????????
[C]?dragon
www.wasm.ru/article.php?article=idaplugin

鄙人拙譯
http://greatdong.blog.edu.cn

總結(jié)

以上是生活随笔為你收集整理的IDA Plugin 编写基础的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。