文獻(xiàn)標(biāo)識(shí)碼: A
文章編號(hào): 0258-7998(2014)07-0130-04
自修改代碼SMC(Self-Modifying Code)是程序運(yùn)行期間修改或產(chǎn)生代碼的一種機(jī)制[1]。自修改代碼以其具有在程序執(zhí)行過(guò)程中動(dòng)態(tài)地修改和產(chǎn)生程序本身執(zhí)行的指令的特點(diǎn),在增加代碼的理解難度阻止逆向工程和軟件保護(hù)方面有廣泛的應(yīng)用[2-3]。有文獻(xiàn)利用自修改代碼技術(shù)描述基于RSA算法的軟件加密保護(hù)方法[4],把自修改的特點(diǎn)和經(jīng)典的RSA加密算法結(jié)合起來(lái)保護(hù)軟件。為了能兼容原有的程序以及對(duì)現(xiàn)有程序進(jìn)行完整支持,有的處理器實(shí)現(xiàn)了對(duì)自修改代碼的支持[5-6]。在二進(jìn)制翻譯中,解決自修改代碼問(wèn)題,首先是要能夠發(fā)現(xiàn)自修改代碼,由于自修改代碼的動(dòng)態(tài)性,使得對(duì)一個(gè)純靜態(tài)翻譯器來(lái)說(shuō)是不可能的,對(duì)動(dòng)態(tài)翻譯器也比較困難。如果能夠提供一些手段監(jiān)視被修改的代碼[7],就可以在發(fā)現(xiàn)源機(jī)器代碼被修改后,置其對(duì)應(yīng)的目標(biāo)機(jī)器代碼無(wú)效并進(jìn)行重新翻譯,從而解決自修改代碼問(wèn)題。DAISY[8]系統(tǒng)通過(guò)在頁(yè)設(shè)置寫(xiě)保護(hù)標(biāo)識(shí),實(shí)現(xiàn)在發(fā)現(xiàn)自修改時(shí)銷(xiāo)毀頁(yè)中所有的翻譯信息。QEMU[9-10]系統(tǒng)把所有翻譯過(guò)的塊的目標(biāo)代碼段存放在自己開(kāi)辟的內(nèi)存空間Code cache中。被翻譯器翻譯的程序的執(zhí)行就是執(zhí)行Code cache中翻譯好的代碼塊。在自修改代碼發(fā)生時(shí),QEMU通過(guò)系統(tǒng)信號(hào)判斷,然后清空Code cache中所有翻譯好的塊。參考文獻(xiàn)[11]也給出關(guān)于二進(jìn)制翻譯中自修代碼的介紹。
1 自修改代碼
下面是一段匯編編寫(xiě)的自修改代碼:
START: nop
mov $0x04, %eax
LOOP: inc %eax
TARGET: xor %eax, %eax
test %eax, %eax
jnz END
MODIFY: movb $0x32, TARGET
0x32 = “inc %eax”
jmp LOOP
END: nop
對(duì)于這段代碼,當(dāng)程序運(yùn)行到MODIFY標(biāo)識(shí)時(shí),此處對(duì)應(yīng)的指令“movb $0x32, TARGET”向地址為T(mén)ARGET的內(nèi)存單元寫(xiě)數(shù)據(jù)0x32,對(duì)應(yīng)位置上的指令被修改,被修改位置上原來(lái)的指令“xor %eax, %eax”被自修改而變成了指令“inc %eax %eax”;程序繼續(xù)運(yùn)行至jmp LOOP指令,跳轉(zhuǎn)到LOOP位置,當(dāng)再次運(yùn)行到TARGET位置時(shí),則運(yùn)行修改后的指令“inc %eax %eax”而非原代碼段的指令“xor %eax, %eax”,這樣“test %eax, %eax”的結(jié)果是非零值,接著jnz END使得程序運(yùn)行結(jié)束。如果該段程序沒(méi)有MODIFY這一自修改代碼指令,此程序段將陷入死循環(huán)中。
2 QEMU的自修改代碼機(jī)制
QEMU系統(tǒng)[9-10]是由法國(guó)人Farbic開(kāi)發(fā)的一款多源多目標(biāo)的二進(jìn)制翻譯系統(tǒng)。它支持源平臺(tái)有PPC、ARM、X86、MIPS、SPARC和X86_64等,目標(biāo)平臺(tái)可以是X86、PPC、ARM、MIPS等。
QEMU系統(tǒng)中的Code cache是其為了存儲(chǔ)翻譯后的塊而開(kāi)辟的內(nèi)存空間,通過(guò)存儲(chǔ)基本塊對(duì)應(yīng)的翻譯后的塊到Code cache中,避免重復(fù)翻譯帶來(lái)的時(shí)間開(kāi)銷(xiāo),加速翻譯器翻譯的效率。QEMU系統(tǒng)開(kāi)辟了16 MB的內(nèi)存空間作為系統(tǒng)的Code cache,并對(duì)每一個(gè)翻譯塊按照其生成的次序加入到Code cache中,直至Code cache被充滿(mǎn)。當(dāng)Code cache被充滿(mǎn)時(shí),QEMU采用全清空策略清除Code cache中所有翻譯好的塊,實(shí)際上就是清除QEMU中維護(hù)的源與目標(biāo)之間的Hash表。全清空策略就是Code cache 從低地址到高地址依次存放每個(gè)翻譯后的代碼塊,當(dāng)出現(xiàn)Code cache 空間不足或程序階段行為突變時(shí),就將清除Code cache中所有翻譯好代碼塊。在發(fā)生自修改時(shí),QEMU同樣采用全清空策略清除Code cache中翻譯好的塊,以防止因?yàn)樽孕薷脑斐傻腃ode cache不一致而使得翻譯的程序錯(cuò)誤執(zhí)行。
3 自修改代碼對(duì)翻譯效率的影響分析
實(shí)驗(yàn)采用的操作系統(tǒng)是CetOS-4.6, 翻譯器采用QEMU-0.9.0,針對(duì)的源和目標(biāo)平臺(tái)都是Intel x86指令集。
為了敘述方便,這里用SmcPro表示一個(gè)自修該代碼實(shí)例。該實(shí)例把第1節(jié)中的自修改代碼進(jìn)行了進(jìn)一步修改,用COUNT控制代碼的循次數(shù)(即自修改代碼的次數(shù))。
為了描述方便,這里將用到的幾個(gè)符號(hào)作如下說(shuō)明: 對(duì)于SmcPro,根據(jù)自修改次數(shù)COUNT不同的值,相對(duì)應(yīng)的程序?yàn)镾MC_COUNT。如SMC_100表示SmcPro的COUNT為100,即自修改代碼執(zhí)行次數(shù)為100次。NSMC_COUNT表示與SMC_COUNT擁有相同代碼量但不包含自修代碼的程序段。
下面對(duì)SMC_COUNT和NSMC_COUNT程序在物理機(jī)和QEMU上進(jìn)行測(cè)試和分析。
3.1 物理機(jī)上自修改代碼的影響
表1是對(duì)每一個(gè)SMC_COUNT和NSMC_COUNT在物理機(jī)上執(zhí)行10次得到的平均值對(duì)照表,行和列交匯的值為對(duì)應(yīng)程序的執(zhí)行時(shí)間效率。例如:表中行SMC和列50相交的位置的值是SMC_50在物理機(jī)上執(zhí)行10次的時(shí)間平均值。
分析表1中的數(shù)據(jù)可知, SMC_COUNT和NSMC_COUNT在物理機(jī)上的執(zhí)行時(shí)間相當(dāng)。事實(shí)上,這正是由于它們?cè)趫?zhí)行指令數(shù)量上是一致的,可以得出結(jié)論:物理機(jī)上自修改代碼對(duì)程序運(yùn)行的性能沒(méi)有影響,程序的運(yùn)行時(shí)間取決于程序運(yùn)行過(guò)程中實(shí)際執(zhí)行的指令數(shù)量。
3.2 QEMU上自修改代碼的影響
下面對(duì)SMC_COUNT和NSMC_COUNT在QEMU用戶(hù)模式下的測(cè)試結(jié)果進(jìn)行分析,其中每個(gè)數(shù)據(jù)都是經(jīng)過(guò)10次測(cè)試得到的平均值。有些數(shù)據(jù)是通過(guò)QEMU提供的日志信息得到, QEMU在用戶(hù)模式下,通過(guò)-d out_asm參數(shù)可以將翻譯的塊信息輸出到日志文件/tmp/qemu.log中。
3.2.1 時(shí)間對(duì)比
圖1給出了在QEMU上執(zhí)行的SMC和NSMC程序的執(zhí)行時(shí)間和COUNT關(guān)系圖,從表1和圖1可知,對(duì)于在物理機(jī)上執(zhí)行時(shí)間上基本沒(méi)有差別的SMC和NSMC程序,在QEMU上的執(zhí)行時(shí)間差別隨自修改同比次數(shù)的增加而越來(lái)越大。
從圖1可以清楚地看到,在QEMU上運(yùn)行的測(cè)試程序隨著自修改同比次數(shù)的增加,自修改程序比非自修改程序在執(zhí)行時(shí)間上增加得更加明顯。
對(duì)圖1中的NSMC在自修改同比次數(shù)大于1 000后所表示的點(diǎn)進(jìn)行線(xiàn)性擬合,可以得到式(1):
Tnsmc=0.000 026×C+0.000 291 (1)
其中,Tnsmc表示圖中的縱坐標(biāo),即程序執(zhí)行時(shí)間;C表示橫坐標(biāo),即COUNT。
由式(1)可知,對(duì)于非自修改程序,COUNT平均每增加1,對(duì)應(yīng)的時(shí)間增加0.000 026 s。
同樣得到:
Tsmc=0.000 151×C-0.010 899 (2)
其中,Tsmc表示圖中的縱坐標(biāo),即程序執(zhí)行時(shí)間;C表示橫坐標(biāo),即COUNT。
由式(2)可知,對(duì)于自修改程序,COUNT平均每增加1,對(duì)應(yīng)的時(shí)間增加0.000 151 s,而截距為負(fù)值說(shuō)明隨著COUNT的增加,時(shí)間增加的速度也在增加。
由式(1)、式(2)可以得到,SMC程序執(zhí)行時(shí)間隨COUNT增大的增長(zhǎng)率和NSMC程序的增長(zhǎng)率的比值為:
由此可見(jiàn),SMC程序的運(yùn)行時(shí)間開(kāi)銷(xiāo)隨COUNT的增長(zhǎng)率是NSMC程序的約5.82倍。
圖2是NSMC程序在QEMU和物理機(jī)上的執(zhí)行時(shí)間對(duì)比圖。由圖可知,NSMC程序在QEMU和物理機(jī)上的執(zhí)行時(shí)間都隨COUNT的增加而增加,在QEMU上的執(zhí)行時(shí)間略大于在物理機(jī)上的執(zhí)行時(shí)間。為了對(duì)圖進(jìn)行定量分析,這里給出降速因子的定義。
定義:一個(gè)程序Pro(SMC或NSMC程序)在QEMU上的執(zhí)行時(shí)間與其在物理機(jī)上的執(zhí)行時(shí)間的比值,稱(chēng)為該程序在QEMU上執(zhí)行的降速因子,記作:SDF(Pro)。
對(duì)于圖2中所有描述出來(lái)的數(shù)據(jù)點(diǎn),可以計(jì)算得出所有NSMC程序在QEMU上執(zhí)行的平均降速因子:SDF(NSMC)=1.033 421。
圖3是SMC在QEMU和物理機(jī)上的執(zhí)行時(shí)間對(duì)比,SMC程序在QEMU和物理機(jī)上的執(zhí)行時(shí)間隨COUNT的增加而增加,在QEMU上的執(zhí)行時(shí)間遠(yuǎn)遠(yuǎn)大于在物理機(jī)上的執(zhí)行時(shí)間,增長(zhǎng)速度也較物理機(jī)上要快得多。對(duì)于自修改同比次數(shù)大于1 000的點(diǎn),計(jì)算得出圖3中表示的所有SMC程序在QEMU上執(zhí)行的平均降速因子SDF(SMC)=5.925 423。
3.2.2 翻譯塊數(shù)量對(duì)比
圖4所示為翻譯的塊數(shù)與COUNT的關(guān)系圖,縱坐標(biāo)表示翻譯的塊數(shù),用BLOCK表示,縮寫(xiě)表示為BLK。從圖4可以看到,在QEMU翻譯器上,SMC程序隨著自修改同比次數(shù)的增加,翻譯塊的數(shù)量也在增加,而NSMC程序翻譯塊的個(gè)數(shù)基本不變。
對(duì)圖4中NSMC表示的折線(xiàn)進(jìn)行線(xiàn)性擬合,可以得到:
BLK=-0.003 045×C+1 672 (4)
其中,BLK表示圖中的縱坐標(biāo),即翻譯的塊數(shù);C表示橫坐標(biāo),即COUNT。由式(4)可知,對(duì)于非自修改程序,隨著COUNT的增加,翻譯的塊數(shù)在少量地減少,平均COUNT每增加1,翻譯塊數(shù)減少0.003 045塊。
對(duì)圖4中的SMC表示量,通過(guò)對(duì)COUNT大于1 000的點(diǎn)進(jìn)行線(xiàn)性擬合,可以得到:
BLK=10.508 430×C+1 712.533 333 (5)
其中,BLK表示圖中的縱坐標(biāo),即翻譯的塊數(shù)BLOCK;C表示橫坐標(biāo),即COUNT。由式(5)可知,對(duì)于自修改程序,COUNT平均每增加1,對(duì)應(yīng)的翻譯塊增加10.508 430個(gè)。
由式(2)和式(5)可知,對(duì)于自修改程序每增加一塊造成的時(shí)間開(kāi)銷(xiāo)TPB(Time Per Block)為:
3.2.3 翻譯塊數(shù)對(duì)執(zhí)行時(shí)間影響
圖5和圖6描述了程序在QEMU上執(zhí)行的時(shí)間與翻譯塊數(shù)的關(guān)系。在翻譯塊的數(shù)量比較少時(shí),程序在QEMU上的執(zhí)行時(shí)間很難發(fā)現(xiàn)規(guī)律,執(zhí)行時(shí)間具有很大的隨機(jī)性;隨著翻譯塊數(shù)的小幅增加,執(zhí)行時(shí)間時(shí)增時(shí)減,如圖5所示。但是當(dāng)翻譯塊的數(shù)量增加到一定程度后,執(zhí)行時(shí)間逐漸開(kāi)始基本成線(xiàn)性增加,如圖6所示,當(dāng)翻譯塊數(shù)超過(guò)10 000后,程序的執(zhí)行時(shí)間與翻譯塊數(shù)量基本成線(xiàn)性關(guān)系,通過(guò)對(duì)10 000塊以后的數(shù)據(jù)點(diǎn)進(jìn)行線(xiàn)性擬合得到的斜率為0.000 0144,這與式(6)的結(jié)論相當(dāng)。由此可知, 當(dāng)翻譯塊的數(shù)量達(dá)到一定程度后, 程序在QEMU上的執(zhí)行時(shí)間與翻譯塊的數(shù)量基本成線(xiàn)性關(guān)系。
由于自修改代碼是在程序執(zhí)行過(guò)程中修改程序本身的,在以塊為單位的二進(jìn)制翻譯過(guò)程中,隨著自修次數(shù)的增加,造成的翻譯塊也急劇增加,從而使得程序在翻譯器上的執(zhí)行時(shí)間大大增加,究其根本原因是因?yàn)樽孕拊斐傻腃ode cache中翻譯好的塊失效。在QEMU中,翻譯器每翻譯一個(gè)塊都會(huì)把翻譯后可以在目標(biāo)機(jī)上執(zhí)行的代碼存放到Code cache中,但是由于自修代碼的出現(xiàn)使得在Code cache中的塊與源代碼塊在語(yǔ)義上不一致,因此必須清除掉Code cache中的翻譯好的塊,否則將執(zhí)行與原來(lái)語(yǔ)義不一致的代碼,造成翻譯的錯(cuò)誤。QEMU在自修改代碼發(fā)生時(shí)對(duì)Code cache采用全清空策略[6],這樣導(dǎo)致在Code cache中的所有翻譯好的塊都失效,從而在程序再次執(zhí)行這些塊時(shí),不得不重新翻譯,隨著自修改同比次數(shù)的增加,重復(fù)翻譯的塊數(shù)也在急劇增加,翻譯效率也就急劇下降。
通過(guò)測(cè)試用例對(duì)自修改代碼和非自修改代碼進(jìn)行測(cè)試和分析,可以得出以下基本結(jié)論:(1)在物理機(jī)上,自修改代碼對(duì)程序的執(zhí)行時(shí)間沒(méi)有影響;(2)自修改代碼程序在QEMU上的執(zhí)行時(shí)間隨自修改同比次數(shù)增長(zhǎng)的速度是非自修改程序的約5.82倍; (3)非自修改代碼在QEMU上執(zhí)行的平均降速因子約為1.033 421; (4)自修改代碼在QEMU上執(zhí)行的平均降速因子約為5.925 423;(5)自修改代碼平均每增加1次自修改,對(duì)應(yīng)在QEMU上的翻譯塊約增加10.51塊; (6)在QEMU上執(zhí)行的程序,翻譯塊數(shù)超過(guò)一定的值后,執(zhí)行時(shí)間與翻譯塊數(shù)基本成線(xiàn)性關(guān)系。
在以塊為基本單位的二進(jìn)制翻譯器中,當(dāng)自修改代碼發(fā)生時(shí),被修改的源代碼所在的塊對(duì)應(yīng)的Code cache中翻譯好的塊就必須被清除,否則將造成語(yǔ)義上的不一致,導(dǎo)致翻譯錯(cuò)誤。本文量化分析了自修改代碼對(duì)QEMU翻譯效率的影響,得出了一些初步結(jié)論,下一步將繼續(xù)研究自修改代碼翻譯效率的提高問(wèn)題。
參考文獻(xiàn)
[1] Self-modifying code[EB/OL].(2009-04)[2014-01].http://en.wikipedia.org/wiki/Self-modifying code.
[2] KANZAKI Y, MONDEN A, NAKAMURA M, et al. Expl-oiting selfmodication mechanism for program protection[C].In:Proceedings of the 27th Annual International ComputerSoftware and Applications Conference, USA: IEEE Press,2003:170-181.
[3] MADOU M, ANCKAERT B, MOSELEY P, et al. Softwareprotection through dynamic code mutation[C]. In: Proceed-ings of Information Security Applications Conference, USA:ACM Press, 2005:194-206.
[4] 莫翩晨, 林和, 蔡萬(wàn)景,等. 基于RSA算法與自修改機(jī)制的軟件保護(hù)[J]. 計(jì)算機(jī)研究與發(fā)展, 2006,43(3):140-144.
[5] Intel.IA-32 Intel architecture software developer′s manu-als[Z]. 2005.
[6] 張浩,錢(qián)學(xué)海.自修改代碼在Godson-X上的處理實(shí)現(xiàn)[J].計(jì)算機(jī)工程, 2008,34(3):102-104.
[7] GSCHWIND M, ALTMAN E, SATHAYE S, et al. Dynamicand transparent binary translation[J]. IEEE Computer Soci-ety, 2000,33(3):54-59.
[8] EBCIOGLU K, ALTMAN E. DAISY: dynamic compilatonfor 100 percent architectural compatibility[C]. In: Proceed-ings of ISCA24, New York: ACM Press, 1997:26-37.
[9] QEMU: The open source processor emulator[EB/OL].(2010-03-31)[2014-01-26].http://fabrice.bellard.free.fr/qemu/about.html.
[10] BELLARD F. QEMU, a fast and portable dynamic trans-lator[C]. USENIX Annual Technical Conference, APR10-15, USENIX Association Proceedings of the Freenix/Open Source Track, 2005:41-46.
[11] SMITH J, NAIR R. Virtual machines: versatile platformsfor systems and processes[M]. Morgan Kaufmann, 2005.