文獻標識碼: A
文章編號: 0258-7998(2014)07-0130-04
自修改代碼SMC(Self-Modifying Code)是程序運行期間修改或產(chǎn)生代碼的一種機制[1]。自修改代碼以其具有在程序執(zhí)行過程中動態(tài)地修改和產(chǎn)生程序本身執(zhí)行的指令的特點,在增加代碼的理解難度阻止逆向工程和軟件保護方面有廣泛的應(yīng)用[2-3]。有文獻利用自修改代碼技術(shù)描述基于RSA算法的軟件加密保護方法[4],把自修改的特點和經(jīng)典的RSA加密算法結(jié)合起來保護軟件。為了能兼容原有的程序以及對現(xiàn)有程序進行完整支持,有的處理器實現(xiàn)了對自修改代碼的支持[5-6]。在二進制翻譯中,解決自修改代碼問題,首先是要能夠發(fā)現(xiàn)自修改代碼,由于自修改代碼的動態(tài)性,使得對一個純靜態(tài)翻譯器來說是不可能的,對動態(tài)翻譯器也比較困難。如果能夠提供一些手段監(jiān)視被修改的代碼[7],就可以在發(fā)現(xiàn)源機器代碼被修改后,置其對應(yīng)的目標機器代碼無效并進行重新翻譯,從而解決自修改代碼問題。DAISY[8]系統(tǒng)通過在頁設(shè)置寫保護標識,實現(xiàn)在發(fā)現(xiàn)自修改時銷毀頁中所有的翻譯信息。QEMU[9-10]系統(tǒng)把所有翻譯過的塊的目標代碼段存放在自己開辟的內(nèi)存空間Code cache中。被翻譯器翻譯的程序的執(zhí)行就是執(zhí)行Code cache中翻譯好的代碼塊。在自修改代碼發(fā)生時,QEMU通過系統(tǒng)信號判斷,然后清空Code cache中所有翻譯好的塊。參考文獻[11]也給出關(guān)于二進制翻譯中自修代碼的介紹。
1 自修改代碼
下面是一段匯編編寫的自修改代碼:
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
對于這段代碼,當(dāng)程序運行到MODIFY標識時,此處對應(yīng)的指令“movb $0x32, TARGET”向地址為TARGET的內(nèi)存單元寫數(shù)據(jù)0x32,對應(yīng)位置上的指令被修改,被修改位置上原來的指令“xor %eax, %eax”被自修改而變成了指令“inc %eax %eax”;程序繼續(xù)運行至jmp LOOP指令,跳轉(zhuǎn)到LOOP位置,當(dāng)再次運行到TARGET位置時,則運行修改后的指令“inc %eax %eax”而非原代碼段的指令“xor %eax, %eax”,這樣“test %eax, %eax”的結(jié)果是非零值,接著jnz END使得程序運行結(jié)束。如果該段程序沒有MODIFY這一自修改代碼指令,此程序段將陷入死循環(huán)中。
2 QEMU的自修改代碼機制
QEMU系統(tǒng)[9-10]是由法國人Farbic開發(fā)的一款多源多目標的二進制翻譯系統(tǒng)。它支持源平臺有PPC、ARM、X86、MIPS、SPARC和X86_64等,目標平臺可以是X86、PPC、ARM、MIPS等。
QEMU系統(tǒng)中的Code cache是其為了存儲翻譯后的塊而開辟的內(nèi)存空間,通過存儲基本塊對應(yīng)的翻譯后的塊到Code cache中,避免重復(fù)翻譯帶來的時間開銷,加速翻譯器翻譯的效率。QEMU系統(tǒng)開辟了16 MB的內(nèi)存空間作為系統(tǒng)的Code cache,并對每一個翻譯塊按照其生成的次序加入到Code cache中,直至Code cache被充滿。當(dāng)Code cache被充滿時,QEMU采用全清空策略清除Code cache中所有翻譯好的塊,實際上就是清除QEMU中維護的源與目標之間的Hash表。全清空策略就是Code cache 從低地址到高地址依次存放每個翻譯后的代碼塊,當(dāng)出現(xiàn)Code cache 空間不足或程序階段行為突變時,就將清除Code cache中所有翻譯好代碼塊。在發(fā)生自修改時,QEMU同樣采用全清空策略清除Code cache中翻譯好的塊,以防止因為自修改造成的Code cache不一致而使得翻譯的程序錯誤執(zhí)行。
3 自修改代碼對翻譯效率的影響分析
實驗采用的操作系統(tǒng)是CetOS-4.6, 翻譯器采用QEMU-0.9.0,針對的源和目標平臺都是Intel x86指令集。
為了敘述方便,這里用SmcPro表示一個自修該代碼實例。該實例把第1節(jié)中的自修改代碼進行了進一步修改,用COUNT控制代碼的循次數(shù)(即自修改代碼的次數(shù))。
為了描述方便,這里將用到的幾個符號作如下說明: 對于SmcPro,根據(jù)自修改次數(shù)COUNT不同的值,相對應(yīng)的程序為SMC_COUNT。如SMC_100表示SmcPro的COUNT為100,即自修改代碼執(zhí)行次數(shù)為100次。NSMC_COUNT表示與SMC_COUNT擁有相同代碼量但不包含自修代碼的程序段。
下面對SMC_COUNT和NSMC_COUNT程序在物理機和QEMU上進行測試和分析。
3.1 物理機上自修改代碼的影響
表1是對每一個SMC_COUNT和NSMC_COUNT在物理機上執(zhí)行10次得到的平均值對照表,行和列交匯的值為對應(yīng)程序的執(zhí)行時間效率。例如:表中行SMC和列50相交的位置的值是SMC_50在物理機上執(zhí)行10次的時間平均值。
分析表1中的數(shù)據(jù)可知, SMC_COUNT和NSMC_COUNT在物理機上的執(zhí)行時間相當(dāng)。事實上,這正是由于它們在執(zhí)行指令數(shù)量上是一致的,可以得出結(jié)論:物理機上自修改代碼對程序運行的性能沒有影響,程序的運行時間取決于程序運行過程中實際執(zhí)行的指令數(shù)量。
3.2 QEMU上自修改代碼的影響
下面對SMC_COUNT和NSMC_COUNT在QEMU用戶模式下的測試結(jié)果進行分析,其中每個數(shù)據(jù)都是經(jīng)過10次測試得到的平均值。有些數(shù)據(jù)是通過QEMU提供的日志信息得到, QEMU在用戶模式下,通過-d out_asm參數(shù)可以將翻譯的塊信息輸出到日志文件/tmp/qemu.log中。
3.2.1 時間對比
圖1給出了在QEMU上執(zhí)行的SMC和NSMC程序的執(zhí)行時間和COUNT關(guān)系圖,從表1和圖1可知,對于在物理機上執(zhí)行時間上基本沒有差別的SMC和NSMC程序,在QEMU上的執(zhí)行時間差別隨自修改同比次數(shù)的增加而越來越大。
從圖1可以清楚地看到,在QEMU上運行的測試程序隨著自修改同比次數(shù)的增加,自修改程序比非自修改程序在執(zhí)行時間上增加得更加明顯。
對圖1中的NSMC在自修改同比次數(shù)大于1 000后所表示的點進行線性擬合,可以得到式(1):
Tnsmc=0.000 026×C+0.000 291 (1)
其中,Tnsmc表示圖中的縱坐標,即程序執(zhí)行時間;C表示橫坐標,即COUNT。
由式(1)可知,對于非自修改程序,COUNT平均每增加1,對應(yīng)的時間增加0.000 026 s。
同樣得到:
Tsmc=0.000 151×C-0.010 899 (2)
其中,Tsmc表示圖中的縱坐標,即程序執(zhí)行時間;C表示橫坐標,即COUNT。
由式(2)可知,對于自修改程序,COUNT平均每增加1,對應(yīng)的時間增加0.000 151 s,而截距為負值說明隨著COUNT的增加,時間增加的速度也在增加。
由式(1)、式(2)可以得到,SMC程序執(zhí)行時間隨COUNT增大的增長率和NSMC程序的增長率的比值為:
由此可見,SMC程序的運行時間開銷隨COUNT的增長率是NSMC程序的約5.82倍。
圖2是NSMC程序在QEMU和物理機上的執(zhí)行時間對比圖。由圖可知,NSMC程序在QEMU和物理機上的執(zhí)行時間都隨COUNT的增加而增加,在QEMU上的執(zhí)行時間略大于在物理機上的執(zhí)行時間。為了對圖進行定量分析,這里給出降速因子的定義。
定義:一個程序Pro(SMC或NSMC程序)在QEMU上的執(zhí)行時間與其在物理機上的執(zhí)行時間的比值,稱為該程序在QEMU上執(zhí)行的降速因子,記作:SDF(Pro)。
對于圖2中所有描述出來的數(shù)據(jù)點,可以計算得出所有NSMC程序在QEMU上執(zhí)行的平均降速因子:SDF(NSMC)=1.033 421。
圖3是SMC在QEMU和物理機上的執(zhí)行時間對比,SMC程序在QEMU和物理機上的執(zhí)行時間隨COUNT的增加而增加,在QEMU上的執(zhí)行時間遠遠大于在物理機上的執(zhí)行時間,增長速度也較物理機上要快得多。對于自修改同比次數(shù)大于1 000的點,計算得出圖3中表示的所有SMC程序在QEMU上執(zhí)行的平均降速因子SDF(SMC)=5.925 423。
3.2.2 翻譯塊數(shù)量對比
圖4所示為翻譯的塊數(shù)與COUNT的關(guān)系圖,縱坐標表示翻譯的塊數(shù),用BLOCK表示,縮寫表示為BLK。從圖4可以看到,在QEMU翻譯器上,SMC程序隨著自修改同比次數(shù)的增加,翻譯塊的數(shù)量也在增加,而NSMC程序翻譯塊的個數(shù)基本不變。
對圖4中NSMC表示的折線進行線性擬合,可以得到:
BLK=-0.003 045×C+1 672 (4)
其中,BLK表示圖中的縱坐標,即翻譯的塊數(shù);C表示橫坐標,即COUNT。由式(4)可知,對于非自修改程序,隨著COUNT的增加,翻譯的塊數(shù)在少量地減少,平均COUNT每增加1,翻譯塊數(shù)減少0.003 045塊。
對圖4中的SMC表示量,通過對COUNT大于1 000的點進行線性擬合,可以得到:
BLK=10.508 430×C+1 712.533 333 (5)
其中,BLK表示圖中的縱坐標,即翻譯的塊數(shù)BLOCK;C表示橫坐標,即COUNT。由式(5)可知,對于自修改程序,COUNT平均每增加1,對應(yīng)的翻譯塊增加10.508 430個。
由式(2)和式(5)可知,對于自修改程序每增加一塊造成的時間開銷TPB(Time Per Block)為:
3.2.3 翻譯塊數(shù)對執(zhí)行時間影響
圖5和圖6描述了程序在QEMU上執(zhí)行的時間與翻譯塊數(shù)的關(guān)系。在翻譯塊的數(shù)量比較少時,程序在QEMU上的執(zhí)行時間很難發(fā)現(xiàn)規(guī)律,執(zhí)行時間具有很大的隨機性;隨著翻譯塊數(shù)的小幅增加,執(zhí)行時間時增時減,如圖5所示。但是當(dāng)翻譯塊的數(shù)量增加到一定程度后,執(zhí)行時間逐漸開始基本成線性增加,如圖6所示,當(dāng)翻譯塊數(shù)超過10 000后,程序的執(zhí)行時間與翻譯塊數(shù)量基本成線性關(guān)系,通過對10 000塊以后的數(shù)據(jù)點進行線性擬合得到的斜率為0.000 0144,這與式(6)的結(jié)論相當(dāng)。由此可知, 當(dāng)翻譯塊的數(shù)量達到一定程度后, 程序在QEMU上的執(zhí)行時間與翻譯塊的數(shù)量基本成線性關(guān)系。
由于自修改代碼是在程序執(zhí)行過程中修改程序本身的,在以塊為單位的二進制翻譯過程中,隨著自修次數(shù)的增加,造成的翻譯塊也急劇增加,從而使得程序在翻譯器上的執(zhí)行時間大大增加,究其根本原因是因為自修造成的Code cache中翻譯好的塊失效。在QEMU中,翻譯器每翻譯一個塊都會把翻譯后可以在目標機上執(zhí)行的代碼存放到Code cache中,但是由于自修代碼的出現(xiàn)使得在Code cache中的塊與源代碼塊在語義上不一致,因此必須清除掉Code cache中的翻譯好的塊,否則將執(zhí)行與原來語義不一致的代碼,造成翻譯的錯誤。QEMU在自修改代碼發(fā)生時對Code cache采用全清空策略[6],這樣導(dǎo)致在Code cache中的所有翻譯好的塊都失效,從而在程序再次執(zhí)行這些塊時,不得不重新翻譯,隨著自修改同比次數(shù)的增加,重復(fù)翻譯的塊數(shù)也在急劇增加,翻譯效率也就急劇下降。
通過測試用例對自修改代碼和非自修改代碼進行測試和分析,可以得出以下基本結(jié)論:(1)在物理機上,自修改代碼對程序的執(zhí)行時間沒有影響;(2)自修改代碼程序在QEMU上的執(zhí)行時間隨自修改同比次數(shù)增長的速度是非自修改程序的約5.82倍; (3)非自修改代碼在QEMU上執(zhí)行的平均降速因子約為1.033 421; (4)自修改代碼在QEMU上執(zhí)行的平均降速因子約為5.925 423;(5)自修改代碼平均每增加1次自修改,對應(yīng)在QEMU上的翻譯塊約增加10.51塊; (6)在QEMU上執(zhí)行的程序,翻譯塊數(shù)超過一定的值后,執(zhí)行時間與翻譯塊數(shù)基本成線性關(guān)系。
在以塊為基本單位的二進制翻譯器中,當(dāng)自修改代碼發(fā)生時,被修改的源代碼所在的塊對應(yīng)的Code cache中翻譯好的塊就必須被清除,否則將造成語義上的不一致,導(dǎo)致翻譯錯誤。本文量化分析了自修改代碼對QEMU翻譯效率的影響,得出了一些初步結(jié)論,下一步將繼續(xù)研究自修改代碼翻譯效率的提高問題。
參考文獻
[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] 莫翩晨, 林和, 蔡萬景,等. 基于RSA算法與自修改機制的軟件保護[J]. 計算機研究與發(fā)展, 2006,43(3):140-144.
[5] Intel.IA-32 Intel architecture software developer′s manu-als[Z]. 2005.
[6] 張浩,錢學(xué)海.自修改代碼在Godson-X上的處理實現(xiàn)[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.