程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> .net加殼軟件CLISecure調試筆記(二)

.net加殼軟件CLISecure調試筆記(二)

編輯:關於.NET

CLI內核隨記(2)

今天有空,繼續調試上次的殼。該殼下載地址http://www.secureteam.net。上一次並沒有深入殼的解密流程,而是看了下虛方法的定位。今天的重點是殼解密流程。殼安裝後有一個GUI主程序,一個本地dll。調試的重點就是這個本地dll。

這次仍然下斷點在它掛鉤JIT的地方。怎樣激活這個斷點?只要運行一個還沒有JIT的方法既可。便於重復,這裡固定為顯示關於窗口。F9運行後,我們中斷在hook方法的入口處:

再看一下椎棧,椎頂的值0x79E9776F指向了mscorwks.dll中調用JIT的地方,而第二個0x790AF170則指向了JIT中調用compileMethod的地方,自然,一調用compileMethod就跳轉到hook的代碼中來了。

下面的一段代碼是調用CEEInfo::getMethodModule判斷是否是當前Module需要JIT。如果是,繼續執行解密過程,如果不是,自然不需要解密了。

012B2A4C  |.  8B45 0C    mov eax,dword ptr ss:[ebp+C]
012B2A4F  |.  8B48 04    mov ecx,dword ptr ds:[eax+4]
012B2A52  |.  8B51 04    mov edx,dword ptr ds:[ecx+4]
012B2A55  |.  8B45 0C    mov eax,dword ptr ss:[ebp+C]
012B2A58  |.  8B48 04    mov ecx,dword ptr ds:[eax+4]
012B2A5B  |.  8B41 04    mov eax,dword ptr ds:[ecx+4]
012B2A5E  |.  8B4D 0C    mov ecx,dword ptr ss:[ebp+C]
012B2A61  |.  8D4401 04  lea eax,dword ptr ds:[ecx+eax+>
012B2A65  |.  8B4D 0C    mov ecx,dword ptr ss:[ebp+C]
012B2A68  |.  8B5411 04  mov edx,dword ptr ds:[ecx+edx+>
012B2A6C  |.  50         push eax
012B2A6D  |.  8B42 30    mov eax,dword ptr ds:[edx+30]
012B2A70  |.  FFD0       call eax;調用getMethodModule
012B2A72  |.  8945 F0    mov dword ptr ss:[ebp-10],eax
012B2A75  |.  8D4D F0    lea ecx,dword ptr ss:[ebp-10]
012B2A78  |.  51         push ecx
012B2A79  |.  8D55 F8    lea edx,dword ptr ss:[ebp-8]
012B2A7C  |.  52         push edx
012B2A7D  |.  8B8D 7CFFF>mov ecx,dword ptr ss:[ebp-84]
012B2A83  |.  E8 88FEFFF>call CliSec_1.012B2910
012B2A88  |.  8D45 98    lea eax,dword ptr ss:[ebp-68]
012B2A8B  |.  50         push eax
012B2A8C  |.  8B8D 7CFFF>mov ecx,dword ptr ss:[ebp-84]
012B2A92  |.  E8 89FAFFF>call CliSec_1.012B2520
012B2A97  |.  50         push eax
012B2A98  |.  8D4D F8    lea ecx,dword ptr ss:[ebp-8]
012B2A9B  |.  E8 80F7FFF>call CliSec_1.012B2220
012B2AA0  |.  0FB6C8     movzx ecx,al
012B2AA3  |.  85C9       test ecx,ecx
012B2AA5  |.  0F84 35020>je CliSec_1.012B2CE0;正常(需要解密)時這裡不會跳

緊接著代碼取方法的名稱:

012B2AAB  |.  8D55 B4    lea edx,dword ptr ss:[ebp-4C]
012B2AAE  |.  52         push edx
012B2AAF  |.  8B45 10    mov eax,dword ptr ss:[ebp+10]
012B2AB2  |.  8B08       mov ecx,dword ptr ds:[eax]
012B2AB4  |.  51         push ecx
012B2AB5  |.  8B55 0C    mov edx,dword ptr ss:[ebp+C]
012B2AB8  |.  8B42 04    mov eax,dword ptr ds:[edx+4]
012B2ABB  |.  8B48 04    mov ecx,dword ptr ds:[eax+4]
012B2ABE  |.  8B55 0C    mov edx,dword ptr ss:[ebp+C]
012B2AC1  |.  8B42 04    mov eax,dword ptr ds:[edx+4]
012B2AC4  |.  8B50 04    mov edx,dword ptr ds:[eax+4]
012B2AC7  |.  8B45 0C    mov eax,dword ptr ss:[ebp+C]
012B2ACA  |.  8D5410 04  lea edx,dword ptr ds:[eax+edx+>
012B2ACE  |.  8B45 0C    mov eax,dword ptr ss:[ebp+C]
012B2AD1  |.  8B4C08 04  mov ecx,dword ptr ds:[eax+ecx+>
012B2AD5  |.  52         push edx
012B2AD6  |.  8B11       mov edx,dword ptr ds:[ecx]
012B2AD8  |.  FFD2       call edx    ;這裡調用.text:7A0A2503 CEEInfo::getMethodName

這兩大段代碼其實就是我在上一篇調試隨記中講的取vtable的過程,這裡略過。最後一句call edx後,看一下eax的值:EAX 11095453 ASCII "UxQ="。這說明了顯示關於窗口的方法名稱是”UxQ=”,顯示,這是混淆過的。下面的代碼調用getMethodDefFormMethod:

012B2ADA  |.  8945 B0    mov dword ptr ss:[ebp-50],eax
012B2ADD  |.  8B45 10    mov eax,dword ptr ss:[ebp+10]
012B2AE0  |.  8B08       mov ecx,dword ptr ds:[eax]
012B2AE2  |.  51         push ecx
012B2AE3  |.  8B55 0C    mov edx,dword ptr ss:[ebp+C]
012B2AE6  |.  8B42 04    mov eax,dword ptr ds:[edx+4]
012B2AE9  |.  8B48 0C    mov ecx,dword ptr ds:[eax+C]
012B2AEC  |.  8B55 0C    mov edx,dword ptr ss:[ebp+C]
012B2AEF  |.  8B42 04    mov eax,dword ptr ds:[edx+4]
012B2AF2  |.  8B50 0C    mov edx,dword ptr ds:[eax+C]
012B2AF5  |.  8B45 0C    mov eax,dword ptr ss:[ebp+C]
012B2AF8  |.  8D5410 04  lea edx,dword ptr ds:[eax+edx+>
012B2AFC  |.  8B45 0C    mov eax,dword ptr ss:[ebp+C]
012B2AFF  |.  8B4C08 04  mov ecx,dword ptr ds:[eax+ecx+>
012B2B03  |.  52         push edx
012B2B04  |.  8B51 38    mov edx,dword ptr ds:[ecx+38]
012B2B07  |.  FFD2       call edx;調用.text:7A0A27FB CEEInfo::getMethodDefFromMethod

CEEInfo::getMethodDefFromMethod是沒有見過的函數,在遇到這種情況時,對於.net 2.0我們可以參考sscli的源代碼或直接看反匯編代碼。這裡直接看返回值,答案就明了了。EAX 060000B0,這個函數返回的就是方法的token。

緊接著的代碼比較是否是有效的token值,如果是,則繼續運行。代碼如下:

012B2B09  |.  8945 B8    mov dword ptr ss:[ebp-48],eax
012B2B0C  |.  8B45 B8    mov eax,dword ptr ss:[ebp-48]
012B2B0F  |.  25 FFFFFF0>and eax,0FFFFFF
012B2B14  |.  0F84 C6010>je CliSec_1.012B2CE0

緊接著代碼如下:

012B2B1A  |.  8B4D B8    mov ecx,dword ptr ss:[ebp-48]
012B2B1D  |.  81E1 FFFFF>and ecx,0FFFFFF
012B2B23  |.  894D A4    mov dword ptr ss:[ebp-5C],ecx
012B2B26  |.  8D4D F8    lea ecx,dword ptr ss:[ebp-8]
012B2B29  |.  E8 72F9FFF>call CliSec_1.012B24A0

這裡012B2B26處的ecx=0013E890,指向了椎棧。調試到現在,我們並沒有跟蹤這個椎棧值的變化,更不可能知道它的作用。因此,重新調試(這就是選擇一個固定方法的好處,可重復性),並觀察該處值的改變。

首先記下此時的椎棧值:

0013E890   012D45AC  CliSec_1.012D45AC

0013E894   012F2178

重新運行後再次中斷在hook方法的入口處,注意這時觀察椎棧的值,特別是0013E890處的變化。

入口處的值與剛才第一次調試過程中的值不一樣,因此直接在0013E890及0013E894兩處下硬件寫中斷。從中斷後返回地址可以知道,改變這兩處值的是我們忽略的一個函數:

012B2A83  |.  E8 88FEFFF>call CliSec_1.012B2910

這個調用的具體過程,是下一篇的內容,呵呵。這裡,我們先放過它。接著向下走:

012B2B2E  |.  8B50 04    mov edx,dword ptr ds:[eax+4]
012B2B31  |.  8955 AC    mov dword ptr ss:[ebp-54],edx
012B2B34  |.  8B45 AC    mov eax,dword ptr ss:[ebp-54]
012B2B37  |.  8B48 04    mov ecx,dword ptr ds:[eax+4]
012B2B3A  |.  8B55 A4    mov edx,dword ptr ss:[ebp-5C]
012B2B3D  |.  8B4491 FC  mov eax,dword ptr ds:[ecx+edx*4>
012B2B41  |.  8945 A8    mov dword ptr ss:[ebp-58],eax
012B2B44  |.  8B4D F0    mov ecx,dword ptr ss:[ebp-10]
012B2B47  |.  51         push ecx                        ; /Arg1
012B2B48  |.  8B8D 7CFFF>mov ecx,dword ptr ss:[ebp-84]   ; |
012B2B4E  |.  E8 8DF4FFF>call CliSec_1.012B1FE0          ; \CliSec_1.012B1FE0

如果跟進012B2B4E處的調用,你會發現這裡取得了主程序的基址0x11000000。再向下走,就是分配空間,填充解密過的方法體:

012B2B60  |.  8B55 A0    mov edx,dword ptr ss:[ebp-60]
012B2B63  |.  0355 A8    add edx,dword ptr ss:[ebp-58]
012B2B66  |.  8B85 7CFFF>mov eax,dword ptr ss:[ebp-84]
012B2B6C  |.  8950 38    mov dword ptr ds:[eax+38],edx
012B2B6F  |.  6A 1C      push 1C
012B2B71  |.  E8 F950000>call CliSec_1.012B7C6F          ;  new
012B2B76  |.  83C4 04    add esp,4
012B2B79  |.  8945 90    mov dword ptr ss:[ebp-70],eax
012B2B7C  |.  837D 90 00 cmp dword ptr ss:[ebp-70],0
012B2B80  |.  74 1A      je short CliSec_1.012B2B9C
012B2B82  |.  8B8D 7CFFF>mov ecx,dword ptr ss:[ebp-84]
012B2B88  |.  8B51 38    mov edx,dword ptr ds:[ecx+38]
012B2B8B  |.  52         push edx
012B2B8C  |.  8B4D 90    mov ecx,dword ptr ss:[ebp-70]
012B2B8F  |.  E8 2CF4FFF>call CliSec_1.012B1FC0
012B2B94  |.  8985 78FFF>mov dword ptr ss:[ebp-88],eax

因此,012B2B8F也是一處關鍵代碼,可以跟進去看是怎麼解密代碼的。(真正有沒有解密呢,跟進去就知道了 )不過在跟進去之前,先看一下椎棧。

注意棧頂的第一個值110A477C,細心的話會發現這個數值指向了哪裡:

Yes,它指向了.text節。而所有的IL方法都是存在.text節中的。不妨看一下該處的數據:

經常調試.net程序的可以一眼看出,圖中高亮的數據,不正是一個方法體嗎。接下來不用說了,改變參數後,調用真正的JIT的compileMethod:

012B2CD6  |.  8B55 10    mov edx,dword ptr ss:[ebp+10]
012B2CD9  |.  C742 14 10>mov dword ptr ds:[edx+14],10
012B2CE0  |>  8B45 1C    mov eax,dword ptr ss:[ebp+1C]
012B2CE3  |.  50         push eax                        ; /Arg6
012B2CE4  |.  8B4D 18    mov ecx,dword ptr ss:[ebp+18]   ; |
012B2CE7  |.  51         push ecx                        ; |Arg5
012B2CE8  |.  8B55 14    mov edx,dword ptr ss:[ebp+14]   ; |
012B2CEB  |.  52         push edx                        ; |Arg4
012B2CEC  |.  8B45 10    mov eax,dword ptr ss:[ebp+10]   ; |
012B2CEF  |.  50         push eax                        ; |Arg3
012B2CF0  |.  8B4D 0C    mov ecx,dword ptr ss:[ebp+C]    ; |
012B2CF3  |.  51         push ecx                        ; |Arg2
012B2CF4  |.  8B55 08    mov edx,dword ptr ss:[ebp+8]    ; |
012B2CF7  |.  52         push edx                        ; |Arg1
012B2CF8  |.  FF15 E4452>call dword ptr ds:[12D45E4]     ; \mscorjit.7906E7F4

中斷在最後012B2CF8處,看一下傳給真正的JIT的參數:

要注意Arg3,因為它指向了修改後的IL體。跟進去看一下:

0013EA6C  B8 65 A5 00 14 2C A5 00 88 47 0A 11 0E 00 00 00

IL方法體為110A4788,代碼大小0x0E,這正是剛才我們說的110A477C處的方法,指向啊原文件的.text節。這裡,又有一個想法:這段代碼倒底有沒有被解密呢?

我們用UltraEdit直接打開原文件,搜索字符串133001000E00000027000011731D0100060A066F0E01000A,可以找到兩處。根據110A477C對應的文件偏移,我們可以確定如下:

到這裡,可以下初步結論了:該殼並沒有加密原代碼,只是新建了方法體。在JIT時,將原代碼的正確偏移傳給JIT。

很懶的一個殼啊,如果要寫脫殼機,只需要直接在原文件中改偏移就行了。(沒有實踐,也許還需要更多工作。)小組誰有空來寫一個?

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved