IDC:函数
IDC:函數(shù)
-
IDC腳本中的函數(shù)必須要有返回值。在IDC腳本中,支持兩類函數(shù):
-
內(nèi)建函數(shù)
-
用戶自定義函數(shù)
-
用戶自定義函數(shù)一般是像下面這樣的方式寫的:
static func(arg1,arg2,arg3) {statements ... }需要注意的一點(diǎn)是,聲明函數(shù)參數(shù)的時(shí)候,沒必要指定函數(shù)參數(shù)的類型了,因?yàn)镮DC會(huì)根據(jù)你傳入的參數(shù)自動(dòng)進(jìn)行參數(shù)類型轉(zhuǎn)換的。
-
默認(rèn)情況下,函數(shù)調(diào)用的時(shí)候參數(shù)傳遞是按值傳遞的,但是以下三種情況例外(引用傳遞):
-
對(duì)象類型的參數(shù)總是使用引用方式傳參
-
函數(shù)類型的參數(shù)總是使用應(yīng)用方式傳參
-
還可以強(qiáng)制使用 & 符號(hào)來讓參數(shù)使用引用方式傳參
-
如果IDC腳本中調(diào)用的函數(shù)不存在,IDA就會(huì)嘗試解析并使用當(dāng)前被調(diào)試的進(jìn)程中的符號(hào)或者標(biāo)簽,如果解析成功,那么就會(huì)執(zhí)行一次 AppCall(AppCall稍后會(huì)進(jìn)一步解釋)
IDC:AppCall
-
首先需要明確一點(diǎn),AppCall是IDC腳本中的一個(gè)內(nèi)建函數(shù)
-
先來看函數(shù)原型
anyvalue Appcall(ea, type, ...); -
-
功能:調(diào)用被調(diào)試進(jìn)程的函數(shù)
-
參數(shù):ea - 調(diào)用的函數(shù)地址
-
參數(shù):type - 調(diào)用的函數(shù)的類型或者說方式,支持三種調(diào)用形式
-
字符串形式,比如:“int func(void);”
-
類型對(duì)象形式,比如:GetTinfo(ea)
-
零:相當(dāng)于讓IDA自行決定,這種情況下,類型一般是從idb中進(jìn)行獲取的
-
-
參數(shù):..., 這個(gè)是可變參數(shù),用來傳遞你要調(diào)用的函數(shù)的參數(shù)
-
返回值:被調(diào)用函數(shù)的返回值
-
Remark:如果函數(shù)調(diào)用失敗,并且失敗的原因是內(nèi)存訪問異常或者其他異常,腳本會(huì)拋出一個(gè)runtime錯(cuò)誤信息,可以在腳本中使用 try/catch 進(jìn)行異常捕獲。在實(shí)際的使用過程中,很少使用AppCall這個(gè)函數(shù)調(diào)用,只是說IDA擁有這種在IDC腳本中存在未知函數(shù)的時(shí)候嘗試在被調(diào)試進(jìn)程中匹配符號(hào)的能力,舉個(gè)例子:_printf("hello\n") 這條語句會(huì)調(diào)用被分析程序的 _printf 函數(shù)
AppCall函數(shù)有2個(gè)選項(xiàng)可以使用,我們可以在IDC腳本中使用 SetAppcallOptions宏進(jìn)行設(shè)置:
#define APPCALL_MANUAL 0x0001
-
只設(shè)置AppCall, 不執(zhí)行,執(zhí)行完畢之后,需要調(diào)用一次 CleanupAppcall
#define APPCALL_DEBEV 0x0002
-
返回調(diào)試詳細(xì)信息, 如果設(shè)置了這個(gè)標(biāo)志位,當(dāng)AppCall執(zhí)行過程中發(fā)生異常的時(shí)候,會(huì)生成一個(gè)包含詳細(xì)異常信息的異常對(duì)象
#define APPCALL_TIMEOUT 0x0004
-
AppCall調(diào)用的超時(shí)時(shí)間, 超時(shí)時(shí)間是以毫秒為單位的,并且值是放在option的高2位字節(jié)中,如果AppCall調(diào)用超時(shí),錯(cuò)誤信息會(huì)放到 errbuf中,并且值是字符串 timeout
#define SET_APPCALL_TIMEOUT(x) ((x<<16)|0x0004)
-
指定AppCall超時(shí)時(shí)間的時(shí)候,需要拼裝option的值,這個(gè)就是一個(gè)輔助宏,用來生成option的值
使用AppCall這個(gè)功能,可以很隨意的調(diào)用被調(diào)試進(jìn)程內(nèi)的函數(shù)而不需要進(jìn)行任何的dll注入或者修改被調(diào)試進(jìn)程的內(nèi)存,如果被調(diào)用的函數(shù)名稱存在的話,AppCall還可以簡(jiǎn)化成 func(args)的形式,前提是func這個(gè)符號(hào)是存在的,舉個(gè)例子:
verinfo = object(); verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); GetVersionExA(&verinfo);上面這段代碼將會(huì)在被調(diào)試進(jìn)程內(nèi)創(chuàng)建一個(gè)OSVERSIONINFOA結(jié)構(gòu)體,并且將結(jié)構(gòu)體地址傳遞給GetVersionExA調(diào)用,調(diào)用完畢之后,verinfo 對(duì)象就被轉(zhuǎn)換成了IDC對(duì)象,內(nèi)存結(jié)構(gòu)如下:
object__at__: 18FEB0hdwBuildNumber: 7600.dwMajorVersion: 6.dwMinorVersion: 1.dwOSVersionInfoSize:dwPlatformId: 2.szCSDVersion: "\x00\x00\x00\x00..."其中_at_屬性表示這個(gè)結(jié)構(gòu)體的內(nèi)存地址,在這個(gè)例子中verinfo是一個(gè)臨時(shí)變量,所以_at_的值意義不大,大家在使用使用的過程中可能會(huì)遇到這個(gè)值很有用的情況。
AppCall會(huì)自動(dòng)在IDC對(duì)象和C對(duì)象之間進(jìn)行轉(zhuǎn)換,轉(zhuǎn)換的時(shí)候依據(jù)IDA中擁有的類型信息來進(jìn)行,但是還要遵循以下幾個(gè)轉(zhuǎn)換規(guī)則:
基本數(shù)據(jù)類型:
-
如果目標(biāo)數(shù)據(jù)類型也是一個(gè)基本數(shù)據(jù)類型(非指針),只需要執(zhí)行簡(jiǎn)單的轉(zhuǎn)換即可(附帶符號(hào)處理或者截?cái)嗵幚?#xff09;,比如: IDC中的值-1轉(zhuǎn)換成 _int32(0xFFFFFFFF),IDC中的0x555轉(zhuǎn)換成 _int8(0x55)
指針:
-
如果目標(biāo)類型是一個(gè)指針,并且IDC的值是一個(gè)字符串,這個(gè)字符串就轉(zhuǎn)換成一個(gè)指針對(duì)象,字符串的內(nèi)容直接拷貝到被調(diào)試進(jìn)程,后面追加一個(gè)結(jié)束符 \0
-
如果對(duì)應(yīng)的IDC的值是一個(gè)數(shù)字,轉(zhuǎn)換之后的結(jié)果是指針?biāo)赶虻膬?nèi)存的值是這個(gè)數(shù)值,如果你想得到一個(gè)數(shù)值的地址,可以直接使用 &符號(hào)
-
如果對(duì)應(yīng)的IDC值不是字符串,那這個(gè)值將會(huì)轉(zhuǎn)換成一個(gè)對(duì)象,指針指向的內(nèi)存使用這個(gè)對(duì)象進(jìn)行初始化
結(jié)構(gòu)體
-
如果目標(biāo)類型是一個(gè)結(jié)構(gòu)體,IDA會(huì)通過對(duì)應(yīng)的屬性來嘗試一個(gè)一個(gè)的初始化結(jié)構(gòu)體的成員。比如:在上面的例子中只有dwOSVersionInfoSize 屬性存在,那么這個(gè)結(jié)構(gòu)體字段就使用這個(gè)屬性類初始化,對(duì)于不存在的字段直接初始化成0
數(shù)組
-
數(shù)組的每個(gè)元素都是單獨(dú)初始化的,當(dāng)然如果對(duì)應(yīng)的IDC值是字符串除外,因?yàn)樽址旧砭褪强梢援?dāng)成一個(gè)完整的數(shù)組來使用的。
下面針對(duì)上述的幾種情況,我們來舉一些例子:
調(diào)用printf
auto n = 5;auto s = "short";_printf("Hello world, number is %d, string is %s\n", n, s);調(diào)用sscanf
auto x; auto nsuccess = _sscanf(s, "%d", &x);結(jié)構(gòu)體使用
verinfo = object();GetVersionExA(verinfo);另外,_userCall 這個(gè)內(nèi)建調(diào)用也是支持這些自動(dòng)轉(zhuǎn)換的
對(duì)于會(huì)發(fā)生異常的調(diào)用,配合APPCALL_MANUAL 標(biāo)志位,可以實(shí)現(xiàn)單步的效果,具體方式還需要大家仔細(xì)去研究一下.
總結(jié)
- 上一篇: linux 基础常用命令集
- 下一篇: uboot配置和编译过程详解