易格式可執行檔案脫殼方法一則
易格式可執行檔案脫殼方法一則
前言:
易格式殼執行檔案就是用易語言編譯生成的可執行檔案。由於易語言的全中文化和簡單易用,現在有不少軟體都是用它寫的。我們今天就來研究一下關於這種檔案的脫殼問題。有人說:脫殼的方法還用你說!是的,我脫殼的水平的確很爛,不過易格式可執行檔案和標準的PE檔案有所不同(植於不同在何處下面還要詳細敘述),所以平常我們用的脫殼的辦法就顯得不是很方便了,於是就有了這篇文章。其實關於易格式可執行檔案脫殼的方法我以前在《易格式初步分析》一文中作過說明,不過那個說明實在是太簡單了,而且當時還沒有稱手的工具,所以現在準備詳細的說一下那個方法。
起因:
前幾天有人在罈子裡放出一個程式請求。據帖子裡面留言,是用“軟體保護神”加的殼。下載回來開啟一看,是一個示例程式,估計是想檢驗加殼強度吧?
要脫殼的軟體:
由於要脫殼的不是什麼正式的軟體,也就沒有必要把地址放上來了,自己用易語言寫一個程式再加上殼就可以了。
原理及分析:
易格式可執行檔案是一種特殊的可執行檔案。它由PE骨骼和易格式原體兩部分組成。PE部分用來釋放、尋找、載入易格式裝載器。易格式原體部分包含了程式執行所需要的程式碼、資料和資源。易格式可執行檔案在被PE裝載器裝載後,首先PE部分尋找並載入易格式裝載器(易格式裝載器在krnln.fne這個檔案裡,這個檔案實質上是一個DLL檔案),然後把執行權轉交給易格式裝載器。易格式裝載器得到控制權後,載入易格式原體,載入介面地址,並對需要的部分進行重定位。接著又把執行權轉交給了易格式的程式碼部分。到這個時候,程式才開始正式的運作,你在易語言中寫的程式碼才開始被執行。有人認為易語言編譯出來的程式碼不是全編譯,是解釋執行的。其實透過載入器和支援庫的做法只是為了可移植性考慮的做法。至於程式碼是否是全編譯的,自己跟蹤一下就知道了:)不好意思,有點跑題了,我們接著剛才的說。說到這兒,不知道有沒有人發現問題:因為易格式最終是要被易格式裝載器裝載的,所以在被裝載的時候,易格式的原體部分應該是完整且正確的,否則裝載過程將發生錯誤。這也就是說為什麼在用ASProtect對易格式殼執行檔案加殼時要選擇“保留附加資料”的原因了。根據前面的分析,只要能獲得易格式原體,然後我們再給它加上一副PE骨骼,一切就完成了。這樣就給了我們可乘之機。在裝載器裝載完成後,我們就可以從記憶體中把易格式提取出來。
但是事情不會這麼簡單的,經過試驗(過程下面會詳細描述,這裡就不多說了),最終合成出了一個可執行檔案,執行的時候卻出現了非法操作。難道上面的分析有誤?調出OD跟蹤:
00401000 >/$ E8 06000000 CALL foo24.0040100B
00401005 |. 50 PUSH EAX ; /ExitCode
00401006 \. E8 BB010000 CALL <JMP.&KERNEL32.ExitProcess> ; \ExitProcess
0040100B /$ 55 PUSH EBP
0040100C |. 8BEC MOV EBP,ESP
0040100E |. 81C4 F0FEFFFF ADD ESP,-110
00401014 |. E9 83000000 JMP foo24.0040109C
00401019 |. 6B 72 6E 6C 6E>ASCII "krnln.fnr",0
00401023 |. 6B 72 6E 6C 6E>ASCII "krnln.fne",0
0040102D |. 47 65 74 4E 65>ASCII "GetNewSock",0
00401038 |. 53 6F 66 74 77>ASCII "Software\FlySky\"
00401048 |. 45 5C 49 6E 73>ASCII "E\Install",0
00401052 |. 50 61 74 68 00>ASCII "Path",0
00401057 |. 4E 6F 74 20 66>ASCII "Not found the ke"
00401067 |. 72 6E 65 6C 20>ASCII "rnel library or "
00401077 |. 74 68 65 20 6B>ASCII "the kernel libra"
00401087 |. 72 79 20 69 73>ASCII "ry is invalid!",0
00401096 |. 45 72 72 6F 72>ASCII "Error",0
0040109C |> 8D85 FCFEFFFF LEA EAX,DWORD PTR SS:[EBP-104]
004010A2 |. 50 PUSH EAX
004010A3 |. E8 44010000 CALL foo24.004011EC
004010A8 |. 68 19104000 PUSH foo24.00401019 ; /StringToAdd = "krnln.fnr"
004010AD |. 8D85 FCFEFFFF LEA EAX,DWORD PTR SS:[EBP-104] ; |
004010B3 |. 50 PUSH EAX ; |ConcatString
004010B4 |. E8 25010000 CALL <JMP.&KERNEL32.lstrcatA> ; \lstrcatA
004010B9 |. 50 PUSH EAX ; /FileName
004010BA |. E8 19010000 CALL <JMP.&KERNEL32.LoadLibraryA> ; \LoadLibraryA 載入核心支援庫
004010BF |. 85C0 TEST EAX,EAX
004010C1 |. 0F85 9E000000 JNZ foo24.00401165
004010C7 |. 8D85 F4FEFFFF LEA EAX,DWORD PTR SS:[EBP-10C]
004010CD |. 50 PUSH EAX ; /pHandle
004010CE |. 68 19000200 PUSH 20019 ; |Access = KEY_READ
004010D3 |. 6A 00 PUSH 0 ; |Reserved = 0
004010D5 |. 68 38104000 PUSH foo24.00401038 ; |Subkey = "Software\FlySky\E\Install"
004010DA |. 68 01000080 PUSH 80000001 ; |hKey = HKEY_CURRENT_USER
004010DF |. E8 36010000 CALL <JMP.&ADVAPI32.RegOpenKeyExA> ; \RegOpenKeyExA 從登錄檔中查詢核心支援庫的位置
004010E4 |. 83F8 00 CMP EAX,0
004010E7 |. 0F85 B8000000 JNZ foo24.004011A5
004010ED |. C785 F0FEFFFF >MOV DWORD PTR SS:[EBP-110],103
004010F7 |. 8D85 F0FEFFFF LEA EAX,DWORD PTR SS:[EBP-110]
004010FD |. 50 PUSH EAX ; /pBufSize
004010FE |. 8D85 FCFEFFFF LEA EAX,DWORD PTR SS:[EBP-104] ; |
00401104 |. 50 PUSH EAX ; |Buffer
00401105 |. 6A 00 PUSH 0 ; |pValueType = NULL
00401107 |. 6A 00 PUSH 0 ; |Reserved = NULL
00401109 |. 68 52104000 PUSH foo24.00401052 ; |ValueName = "Path"
0040110E |. FFB5 F4FEFFFF PUSH DWORD PTR SS:[EBP-10C] ; |hKey
00401114 |. E8 07010000 CALL <JMP.&ADVAPI32.RegQueryValueExA> ; \RegQueryValueExA
00401119 |. 50 PUSH EAX
0040111A |. FFB5 F4FEFFFF PUSH DWORD PTR SS:[EBP-10C] ; /hKey
00401120 |. E8 EF000000 CALL <JMP.&ADVAPI32.RegCloseKey> ; \RegCloseKey
00401125 |. 58 POP EAX
00401126 |. 83F8 00 CMP EAX,0
00401129 |. 75 7A JNZ SHORT foo24.004011A5
0040112B |. 8D85 FCFEFFFF LEA EAX,DWORD PTR SS:[EBP-104]
00401131 |. 50 PUSH EAX ; /String
00401132 |. E8 AD000000 CALL <JMP.&KERNEL32.lstrlenA> ; \lstrlenA
00401137 |. 8D9D FCFEFFFF LEA EBX,DWORD PTR SS:[EBP-104]
0040113D |. 03D8 ADD EBX,EAX
0040113F |. 4B DEC EBX
00401140 |. 803B 5C CMP BYTE PTR DS:[EBX],5C
00401143 |. 74 05 JE SHORT foo24.0040114A
00401145 |. 66:C703 5C00 MOV WORD PTR DS:[EBX],5C
0040114A |> 68 23104000 PUSH foo24.00401023 ; /StringToAdd = "krnln.fne"
0040114F |. 8D85 FCFEFFFF LEA EAX,DWORD PTR SS:[EBP-104] ; |
00401155 |. 50 PUSH EAX ; |ConcatString
00401156 |. E8 83000000 CALL <JMP.&KERNEL32.lstrcatA> ; \lstrcatA
0040115B |. 50 PUSH EAX ; /FileName
0040115C |. E8 77000000 CALL <JMP.&KERNEL32.LoadLibraryA> ; \LoadLibraryA
00401161 |. 85C0 TEST EAX,EAX
00401163 |. 74 40 JE SHORT foo24.004011A5
00401165 |> 8985 F8FEFFFF MOV DWORD PTR SS:[EBP-108],EAX
0040116B |. 68 2D104000 PUSH foo24.0040102D ; /ProcNameOrOrdinal = "GetNewSock"
00401170 |. 50 PUSH EAX ; |hModule
00401171 |. E8 5C000000 CALL <JMP.&KERNEL32.GetProcAddress> ; \GetProcAddress
00401176 |. 85C0 TEST EAX,EAX
00401178 |. 74 20 JE SHORT foo24.0040119A
0040117A |. 68 E8030000 PUSH 3E8
0040117F |. FFD0 CALL EAX
00401181 |. 85C0 TEST EAX,EAX
00401183 |. 74 15 JE SHORT foo24.0040119A
00401185 |. E8 00000000 CALL foo24.0040118A
0040118A |$ 810424 761E000>ADD DWORD PTR SS:[ESP],1E76
00401191 |. FFD0 CALL EAX ;裝跳到核心支援庫領空
10029E72 55 PUSH EBP
10029E73 8BEC MOV EBP,ESP
10029E75 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
10029E78 50 PUSH EAX
10029E79 B9 F8E81210 MOV ECX,krnln.1012E8F8
10029E7E E8 ACF5FFFF CALL krnln.1002942F ;繼續跟進
10029E83 5D POP EBP
10029E84 C2 0400 RETN 4
1002942F 55 PUSH EBP
10029430 8BEC MOV EBP,ESP
10029432 83EC 08 SUB ESP,8
10029435 53 PUSH EBX
10029436 56 PUSH ESI
10029437 57 PUSH EDI
10029438 894D F8 MOV DWORD PTR SS:[EBP-8],ECX
1002943B FF15 C8230D10 CALL DWORD PTR DS:[<&KERNEL32.GetProcess>; KERNEL32.GetProcessHeap
10029441 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
10029444 8981 EC030000 MOV DWORD PTR DS:[ECX+3EC],EAX
1002944A 8B55 08 MOV EDX,DWORD PTR SS:[EBP+8]
1002944D 8B42 30 MOV EAX,DWORD PTR DS:[EDX+30]
10029450 83E0 01 AND EAX,1
10029453 85C0 TEST EAX,EAX
10029455 75 10 JNZ SHORT krnln.10029467
10029457 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+8]
1002945A 51 PUSH ECX
1002945B 8B4D F8 MOV ECX,DWORD PTR SS:[EBP-8]
1002945E E8 FD400300 CALL krnln.1005D560
10029463 FFE0 JMP EAX ;易格式已經裝載完成了,轉交指揮權
00404207 FC CLD ;易格式程式碼的起始位置
00404208 DBE3 FINIT
0040420A 68 027F8000 PUSH 807F02
0040420F B8 03000000 MOV EAX,3
00404214 E8 31000000 CALL foo24.0040424A
00404219 83C4 04 ADD ESP,4
0040421C 68 01000152 PUSH 52010001
00404221 E8 1E000000 CALL foo24.00404244
00404226 83C4 04 ADD ESP,4
00404229 6A 00 PUSH 0
0040422B E8 0E000000 CALL foo24.0040423E
00404230 E8 03000000 CALL foo24.00404238
00404235 83C4 04 ADD ESP,4
00404238 FF25 94788000 JMP DWORD PTR DS:[807894]
0040423E FF25 98788000 JMP DWORD PTR DS:[807898]
00404244 FF25 9C788000 JMP DWORD PTR DS:[80789C]
0040424A FF25 A0788000 JMP DWORD PTR DS:[8078A0] ;最後在這個地方程式當掉了
00404250 FF25 90788000 JMP DWORD PTR DS:[807890]
00404256 FF25 78788000 JMP DWORD PTR DS:[807878]
0040425C FF25 7C788000 JMP DWORD PTR DS:[80787C]
00404262 FF25 80788000 JMP DWORD PTR DS:[807880]
轉跳指向了一個莫名其妙的地址,程式不當掉才怪。
啟動W32Dasm載入程式,進行靜態分析。在相同位置得到了這樣的反彙編程式碼:
:00404207 FC cld
:00404208 DBE3 finit
:0040420A 6806424000 push 00404206
:0040420F B803000000 mov eax, 00000003
:00404214 E831000000 call 0040424A
:00404219 83C404 add esp, 00000004
:0040421C 6801000152 push 52010001
:00404221 E81E000000 call 00404244
:00404226 83C404 add esp, 00000004
:00404229 6A00 push 00000000
:0040422B E80E000000 call 0040423E
:00404230 E803000000 call 00404238
:00404235 83C404 add esp, 00000004
* Referenced by a CALL at Address:
|:00404230
|
:00404238 FF255C3C4000 jmp dword ptr [00403C5C]
* Referenced by a CALL at Address:
|:0040422B
|
:0040423E FF25603C4000 jmp dword ptr [00403C60]
* Referenced by a CALL at Address:
|:00404221
|
:00404244 FF25643C4000 jmp dword ptr [00403C64]
* Referenced by a CALL at Address:
|:00404214
|
:0040424A FF25683C4000 jmp dword ptr [00403C68]
* Referenced by a CALL at Addresses:
|:00403E10 , :00403EE0 , :00403F67 , :00403F77 , :004040A1
|:00404107 , :00404194 , :004041FA
|
:00404250 FF25583C4000 jmp dword ptr [00403C58]
* Referenced by a CALL at Addresses:
|:00403E75 , :00403F37 , :00404014 , :0040403A , :004040F7
|:0040412D , :004041EA
|
:00404256 FF25403C4000 jmp dword ptr [00403C40]
* Referenced by a CALL at Addresses:
|:00403E4A , :00403ECD , :00403FB1 , :0040408E , :00404181
|
:0040425C FF25443C4000 jmp dword ptr [00403C44]
:00404262 FF25483C4000 jmp dword ptr [00403C48]
經過對比很明顯就能發現,轉跳的地址不同。原因呢?很簡單:重定位。
用EcE載入程式,檢視@code段的重定位資訊,得到如下結果:
0:RT_HELP_FUNC 0000053E
0:RT_HELP_FUNC 00000544
0:RT_HELP_FUNC 0000054A
0:RT_HELP_FUNC 00000550
0:RT_HELP_FUNC 00000556
0:RT_HELP_FUNC 0000055C
0:RT_HELP_FUNC 00000562
0:RT_HELP_FUNC 00000568
在“重要裝載資訊”裡顯示,易格式所在節的RVA在0x00003000處。@code段的偏移為0x00000CFC。然後計算0x004000000+0x00003000+0x00000cfc+0x0000053E = 0x0040423A,正是那個錯誤的地址。
也就是說,我們從記憶體中提取出來的易格式原體是經過裝載器重定位後的,所以當我們以重定位後的易格式原體被裝載器載入,然後再次進行重定位,自然會指向錯誤的地址。所以只要我們修復了從記憶體中提取到易格式原體的重定位資訊即可。
總結一下,脫殼的思路如下:
載入要脫殼的程式,等待裝載器把易格式裝入記憶體 -〉從記憶體中獲取易格式原體並儲存下來 -〉修復易格式原體的重定位資訊 -〉將修復後的原體植入PE骨骼。
實施步驟:
1。雙擊執行加了殼的程式,這裡是2-2.exe。(廢話:))
2。啟動WinHex,在“工具”-〉“RAM編輯器”中選擇2-2.exe程式,開啟其主要記憶體。
3。查詢字串“WTNE”,這是易格式的驗證字串。在0x00403000處找到了。
4。然後向下找,找到“@reloc”(如果沒有,就找“@var”),結果在0x004042AC處找到了。
5。一般易格式是按照FileAlignment對齊的,也就是說,易格式原體應該是從0x00403000――0x00403400的部分。
6。把這一部分的資料“複製塊”-〉“進入正常檔案”,我們把它命名為yt.dat。
7。用EcE載入yt.dat,在載入之前,必須要在“綜合功能中心”-〉“綜合設定”-〉“分析設定”中,設定“分析物件型別”為“易格式原體檔案”。如果可以正常載入的話,說明我們的第一步提取成功了。
8。下面我們要進行的是修復重定位的工作。在以前這可是個極度痛苦的工作。試想一下吧,計算修復成千上萬個重定位資料後,人會變成什麼樣子……不過現在情況好多了,可以利用EcE裡面帶的“易格式重定位資訊修復”工具來代替我們完成這個工作,不過你必須要有0.60版本以上的EcE,在罈子裡有最新的下載(算是廣告吧:))。
9。選擇EcE左邊工具欄中“綜合功能中心”-〉“工具箱”,啟動“易格式重定位資訊修復”。在一個警告提示之後,會出現一個輸入框,讓你輸入“重定位基址”。這個基址也就是易格式原體實際上的RVA了。由於我們是從程式記憶體0x00403000處體取得易格式原體,這個地方就輸入00403000。確定後稍等片刻,會提示“重定位資訊修復完成”。
10。接下來改把易格式重新封裝起來了。PE骨骼要求能完成找到易語言核心支援庫,裝載易格式裝載器等一系列工作。到哪兒去製作一個符合要求的PE骨骼呢?EcE的工具箱也提供了這樣的功能(好像工具箱是專門為脫殼設計的:))。
11。關閉剛才開啟的原體。在“工具箱”中選擇“易格式原體植入PE骨骼”。首先會讓你選擇易格式原體檔案,我們選擇“yt.dat”。然後在輸入要儲存到的檔名,這裡用new.exe。稍等片刻會提示已經完成。
12。現在基本上大功告成了。執行一下new.exe試試看能否正常執行:)
後記:
之所以沒有提供加殼後的軟體下載,前面我也說過了,是因為我感覺這種方法適用於大部分殼(當然了,只是針對易格式殼執行程式)。至少我試過的UPX,ASProtect,軟體保護神,比泰加密等均殼易用這種方法脫殼或解密,所以也沒有很強的針對性了。不過對於某些殼也是無效的,這樣就需要變通變通了。
也許有會說這樣看來易格式可執行檔案的安全性不高啊。其實並非如此。易格式很特殊,而大部分加殼軟體的作者並非都熟悉易格式,而且那些軟體也沒有針對性的保護措施,所以才會很容易的被脫掉。我相信隨著人們對易格式的認識加深,用不了多長時間就會有專門的加殼軟體 for 易格式的版本或者保護選項了。
另外,加殼不是保護軟體的最終手段,不要太依靠那個東西,畢竟,鎖是防君子不防小人的。
monkeycz
2004年11月16日
相關文章
- UNIX/LINUX平臺可執行檔案格式分析2012-07-24Linux
- Linux可執行檔案格式-ELF結構詳解2021-11-19Linux
- Linux核心研究系列之可執行檔案格式(轉)2007-08-11Linux
- Linux/Unix平臺可執行檔案格式分析(轉)2007-08-15Linux
- 脫ASPack2.12加殼的DLL檔案簡便方法2004-12-18
- ExeStealth 常用脫殼方法 + ExeStealth V2.72主程式脫殼2015-11-15
- 對Crunch v1.1主程式檔案的脫殼方法 ---ljtt2000-11-30
- Armadillo3.60
加殼的EXE檔案脫殼全過程2004-09-08
- Java執行exe,bat等可執行檔案2008-07-27JavaBAT
- 從C檔案到可執行elf檔案2013-09-24
- drools執行String規則或執行某個規則檔案2022-06-02
- Mach-O 可執行檔案2018-02-27Mac
- maven 打包可執行 jar 檔案2016-09-29MavenJAR
- MATLAB生成可執行檔案2013-08-19Matlab
- 一個可執行檔案是怎麼來的2015-11-02
- 先分析,再脫殼(一)2003-09-04
- ubuntu 把檔案設定為可執行檔案2017-03-15Ubuntu
- 脫殼----對用Petite2.2加殼的程式進行手動脫殼的一點分析
(5千字)2000-07-27
- 脫殼----對用pecompact加殼的程式進行手動脫殼
(1千字)2000-07-30
- Python程式碼打包成可執行檔案的常用方法!2023-02-02Python
- Windows2000可執行檔案一覽(一) (轉)2007-12-12Windows
- 寫給新手
- 淺談脫殼方法2004-12-18
- 建立可執行檔案build.sh2018-06-29UI
- Linux可執行的檔案(轉)2007-08-11Linux
- matlab (.m)檔案生成 windows 可執行(.exe)檔案2017-05-10MatlabWindows
- Windows2000可執行檔案一覽(轉)2007-08-11Windows
- 殼的工作原理脫殼2013-04-10
- 股市風暴4.0的外殼分析與脫殼方法(一) (7千字)2001-06-10
- 檔案格式引起的指令碼執行錯誤2023-02-15指令碼
- 壹次脫殼法――Armadillo 雙程式標準殼 快速脫殼2015-11-15
- C語言判斷檔案是否存在,判斷檔案可讀可寫可執行2018-09-15C語言
- 把可執行jar打包成exe檔案2018-10-10JAR
- 怎麼生成可執行的.jar檔案???????????2003-12-01JAR
- 0171-建立核心可執行檔案2024-07-13
- Windows2000可執行檔案一覽(二) (轉)2007-12-12Windows
- 從Android執行時出發,打造我們的脫殼神器2020-08-19Android
- VBExplorer.exe脫殼教程
附脫殼指令碼2015-11-15指令碼
- 【原創】將Java程式變成可執行檔案的簡單方法2009-04-15Java