flash漏洞調試技巧
本周中心抓到一個在野的flash 0day(相關信息見此鏈接),於是又撿起了一年多的flash 漏洞的相關知識,遂總結一下。
普通的trace
調試flasher樣本一般建議使用調試版的flash player,在調試版本下可以輸出swf文件運行時的相關日誌,便於進行相關的分析,安裝之後會在家目錄(C:\User\<your name>mm.cfg)生成該文件(早期的flash調試版本不會生成該文件,需要手動生成)。
文件中包含以下配置選項,手動生成的話紅色框中的選項為必選項,用於告訴flash生成錯誤日誌及trace日誌(對應的日誌文件保存在C:\Users\<your name>\AppData\Roaming\Macromedia\Flash Player\Logs目錄下)。
通過FFdec,可以直接往flash中打trace補丁,用於輸出對應的參數,變量。
findpropstrict Qname(PackageNamespace(""),"trace") pushstring "Hello World!" callpropvoid Qname(PackageNamespace(""),"trace") 1 |
Jit函數監控
但是大多數漏洞調試中,trace不夠強大,這就需要通過調試器了,因為flash裏的腳本在執行的時候會轉為jit,因此調試非常不便,這也是早期flash很難搞的一個問題,但是可以通過以下斷點解決。
29.r0.140 flash.ocx .dvalloc /b 0x79990000 30;eb 0x79990000 5e;ew 0x79990001 c3 bp Flash32_29_0_0_140 + 0x8D03D2 ".printf \"the method_name is: %ma\\n\",poi(eax+8);.if(poi(esi+20)=0xFFFFFFFF){bp poi(esi+4}.else{gc}" bp Flash32_29_0_0_140 + 0x8BA425 ".printf \"the method_index is:%p the method_info_pointer is:%p the jit code is:%p the method_body is:%p\\n\",poi(esi+20),esi,poi(esi+4),poi(esi+24);r ecx = esi;r $t0 = poi(esp);ed esp eip+1;r esp = esp - 4;ed esp @$t0;r esp = esp -4;ed esp 0x79990000;r eip = Flash32_29_0_0_140 + 0x8D03AF;g" |
原理
fun_verifyMethod,該函數是flash引擎中用於對jit函數校驗的地方,該函數返回的esi其實是一個jit method的對象,裏面包含了具體生成的jit函數的index,method ,jit code等屬性,其中index是引擎內部用於識別jit函數的標記(就一數字),jit code標記了生成的對應地址,但是對應正常人而言index這種數字明顯沒有意義,我們需要具體的函數名,這就引出之後的fun_getMethodName函數。
fun_getMethodName,其ecx接受一個method的對象(即fun_verifyMethod返回的對象),結果會返回一個具體函數的函數名,但是該函數默認在flash運行時不會調用,因此需要在fun_verifyMethod調用後手動調用一下fun_getMethodName,既可以獲得對應的函數名,此時結合fun_verifyMethod返回的地址,就能實現正常的調試。
使用
腳本中一共三條命令,第一條用於生成一段內存,主要用於在fun_verifyMethod後,改變程序流程去執行fun_getMethodName(你可以理解為hook),之後分別是這兩個函數的斷點。
.dvalloc /b 0x79990000 30;eb 0x79990000 5e;ew 0x79990001 c3 bp Flash32_29_0_0_140 + 0x8D03D2 ".printf \"the method_name is: %ma\\n\",poi(eax+8);.if(poi(esi+20)=0xFFFFFFFF){bp poi(esi+4}.else{gc}" bp Flash32_29_0_0_140 + 0x8BA425 ".printf \"the method_index is:%p the method_info_pointer is:%p the jit code is:%p the method_body is:%p\\n\",poi(esi+20),esi,poi(esi+4),poi(esi+24);r ecx = esi;r $t0 = poi(esp);ed esp eip+1;r esp = esp - 4;ed esp @$t0;r esp = esp -4;ed esp 0x79990000;r eip = Flash32_29_0_0_140 + 0x8D03AF;g" |
調試的時候,下這兩個斷點,運行之後生成整個jit函數的信息,記下來,每個函數index很重要。
運行第二遍就可以正常調試了,此時只要將紅字換成對應的函數index即可(對同一個swf,index是固定的),此時運行,即可在指定jit函數生成的時候斷下。
bp Flash32_29_0_0_140 + 0x8D03D2 ".printf \"the method_name is: %ma\\n\",poi(eax+8);.if(poi(esi+20)=0xFFFFFFFF){bp poi(esi+4}.else{gc}" |
此時針對replace的jit code地址下斷點,及可以斷下。
通用性
替換,該腳本是針對29.r0.140 flash.ocx,之後需要使用其他版本的時候需要改對應的地址,這就涉及到如何快速獲取對應的fun_getMethodName和fun_verifyMethod函數。
fun_getMethodName,ida裏找cinit字符,對應引用的函數。
引用函數如下。
再向上一層就是了。
fun_verifyMethod函數,搜JIT failed字符。
對應的引用。
對該函數的引用,第一個就是,不是就找找反正不多。
需要修改以下三個值(藍色部分根據你要跟的函數index自己替換),
第一個紅色地址為fun_getMethodName返回的ret地址。
第二個紅色地址為fun_verifyMethod返回前的pop esi的地址。
第三個紅色地址為fun_getMethodName的起始地址減一(為啥減一是為了windbg中斷點hook的需要)。
.dvalloc /b 0x79990000 30;eb 0x79990000 5e;ew 0x79990001 c3 bp Flash32_29_0_0_140 + 0x8D03D2 ".printf \"the method_name is: %ma\\n\",poi(eax+8);.if(poi(esi+20)=0xFFFFFFFF){bp poi(esi+4}.else{gc}" bp Flash32_29_0_0_140 + 0x8BA425 ".printf \"the method_index is:%p the method_info_pointer is:%p the jit code is:%p the method_body is:%p\\n\",poi(esi+20),esi,poi(esi+4),poi(esi+24);r ecx = esi;r $t0 = poi(esp);ed esp eip+1;r esp = esp - 4;ed esp @$t0;r esp = esp -4;ed esp 0x79990000;r eip = Flash32_29_0_0_140 + 0x8D03AF;g" |
轉載請註明出處
flash漏洞調試技巧