明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

DLL文件脫殼

[摘要]DLL文件的脫殼與EXE文件步驟差不多, 所不同的是, DLL文件多了個基址重定位表等要考慮。 在2003年出版的《加密與解密》(第二版)中以UPX, PECompact為例講述了DLL...

DLL文件的脫殼與EXE文件步驟差不多, 所不同的是, DLL文件多了個基址重定位表等要考慮。

 

在2003年出版的《加密與解密》(第二版)中以UPX, PECompact為例講述了DLL重定位重建的方法, 由于本人的思路限制, 當時只是從UPX, PECompact自身特點找思路解決這問題, 即先分析UPX, PECompact對重定位表處理算法, 然后寫工具逆算法還原重定位表, 如UPXAngela.exe等工具。 這種思路的通用性不好, 針對不同的殼和版本, 要重寫工具, 并且逆算法可能不完美, 從而存在bug。

 

后來, askformore在“重建重定位表腳本”一文中, 提出了一種更通用性的解決辦法, 利用外殼重定位相關數(shù)據(jù)時, 會根據(jù)外殼轉(zhuǎn)儲的重定位表確定要重定位的RVA, 完成代碼重定位工作。 將這些要重定位的RVA提取出來, 再將這些RVA根據(jù)重定位表的定義重新生成一份新的重定位表。 shoooo也曾提到過這個思路。 于是, 在第三版重寫這部分時, 根據(jù)這個思路寫了一款工具來完成這個重建功能, 詳見附件的ReloREC。 另外, ReloREC重構(gòu)重定位表的算法代碼, 參考了ccfer在看雪論壇.珠海金山2007逆向分析挑戰(zhàn)賽 第二階段第三題 提交的代碼。 在此一并表示感謝!

 

 

聲明:本文以第三版“13.5 DLL文件脫殼”一文和其他章節(jié)臨時整理組織, 稍有簡化, 可能有部分地方用詞和描述不是太連貫。

加殼的DLL處理重定位表有以下幾種情況:

1)完整的保留了原重定位表;

2)對原重定位表進行了加密處理;

等等

 

像ASPack,ASProtect等殼屬于第1種情況, 沒有加密重定位表, 脫殼后, 只需找到重定位的地址和大小即可。

像UPX, PECompact等殼屬于第2種情況, 必須重建重定位表, 這也是本文所要討論的, 本文以UPX為例來講述一下重定位的重建。

用UPX v3.01將EdrLib.dll文件加殼, 用PE工具查看其PE信息。

EntryPoint:E640h

ImageBase:400000h

 

 

13.5.1 尋找OEP

 

當DLL被初次映射到進程的地址空間中時, 系統(tǒng)將調(diào)用DllMain函數(shù), 當卸載DLL時也會再次調(diào)用DllMain函數(shù)。 也就是說, DLL文件相比EXE文件運行有一些特殊性, EXE的入口點只在開始時執(zhí)行一次, 而DLL的入口點在整個執(zhí)行過程中至少要執(zhí)行兩次。 一次是在開始時, 用來對DLL做一些初始化。 至少還有一次是在退出時, 用來清理DLL再退出。 所以DLL找OEP也有兩條路可以走, 一是載入時找, 另一方法是在退出時找。 而且一般來說前一種方法外殼代碼較復雜, 建議用第二種方法。

UPX殼比較簡單, 往下翻翻, 就可看到跳到OEP的代碼:

 

代碼:

003DE7F5   .  58              pop     eax

003DE7F6   .  61              popad

003DE7F7   .  8D4424 80       lea     eax, dword ptr [esp-80]

003DE7FB   >  6A 00           push    0

003DE7FD   .  39C4            cmp     esp, eax

003DE7FF   .^ 75 FA           jnz     short 003DE7FB

003DE801   .  83EC 80         sub     esp, -80

003DE804   >- E9 372AFFFF     jmp     003D1240  //跳到OEP

13.5.2 Dump映像文件

 

停在OEP后, 運行LordPE, 在進程窗口選擇loaddll.exe進程, 在下方窗口中的EdrLib.dll模塊上單擊右鍵, 執(zhí)行“dump full”菜單命令, 將文件抓取并保存到文件里, 如圖13.43所示。

 

dll.gif

圖13.45 抓取DLL內(nèi)存映像

 

對于DLL文件來說, Windows系統(tǒng)沒有辦法保證每一次運行時提供相同的基地址。 如果DLL基址所在內(nèi)存空間被占用或該區(qū)域不夠大, 系統(tǒng)會尋找另一個地址空間的區(qū)域來映射DLL, 此時外殼將對DLL執(zhí)行某些重定位操作。 從圖13.43得知, 此時DLL被映射到內(nèi)存的地址是03D000h, 與EdrLib.dll默認的基址400000h不同, 被重定位項所指向的地方是已經(jīng)重定位了的代碼數(shù)據(jù)。

例如這句:

 

代碼:

003D1266     A1 58B43D00        mov     eax, dword ptr [3DB458]

為了得到與加殼前一樣的文件, 必須找到重定位的代碼, 跳過它, 讓其不被重定位。 重新加載DLL, 對上句重定位的地址3D1267h下內(nèi)存寫斷點, 中斷幾下, 就可來到重定位的處理代碼。

 

 

代碼:

003DE79E  mov     al, byte ptr [edi]              ;指向UPX自己加密過的重定位表

003DE7A0  inc     edi                                  ;指針移向下一位

003DE7A1  or      eax, eax                            ;EAX=0?結(jié)束標志

003DE7A3  je      short 003DE7C7              

003DE7A5  cmp     al, 0EF

003DE7A7  ja      short 003DE7BA                  

003DE7A9  add     ebx, eax                          ;EBX的初值為(0xFFC+基址)

003DE7AB  mov     eax, dword ptr [ebx]             ;EBX指向需要重定位的數(shù)據(jù), 取出放到EAX

003DE7AD  xchg    ah, al

003DE7AF  rol     eax, 10

003DE7B2  xchg    ah, al

003DE7B4  add     eax, esi                          ; ESI指向UPX0區(qū)塊的VA, 本例=3D1000

003DE7B6  mov     dword ptr [ebx], eax           ;重定位

003DE7B8  jmp     short 003DE79C             

003DE7BA  and     al, 0F

003DE7BC  shl     eax, 10

003DE7BF  mov     ax, word ptr [edi]

003DE7C2  add     edi, 2

003DE7C5  jmp     short 003DE7A9           

003DE7C7  mov     ebp, dword ptr [esi+E044]        ;改好ESI為401000后, 按F4到這里

UPX殼己將原基址重定位表清零, 重定位操作時, 使用其自己的重定位表。 地址3DE7B4h處ESI指向UPX0區(qū)塊的VA, 本例為3D1000h, 為了讓代碼以默認ImageBase的值400000h重定位代碼, 可以在這句強制將ESI的值改為401000h。 來到這句后, 雙擊ESI寄存器, 改成401000h, 然后按F4來到3DE7C7h這時。 此時代碼段的數(shù)據(jù)沒被重定位, 可以Dump了。

 

代碼:

003D1253     833D 68AD4000 00     cmp     dword ptr [40AD68], 0

運行LordPE將DLL映像抓取, 并保存為upx_dumped.dll。

 

13.5.3 重建DLL的輸入表

 

ImportREC能很好地支持DLL的輸入表的重建, 首先, 在Options里將“Use PE Header From Disk”默認的選項去除。 這是因為ImportREC需要獲得基址計算RVA值, DLL如果重定位了, 從磁盤取默認基址計算會導致結(jié)果錯誤。

 

1)在ImportREC下拉列表框中選擇DLL裝載器的進程, 此處為loaddll.exe進程。

2)單擊“Pick DLL”按鈕, 在DLL進程列表中選擇EdrLib.dll進程(見圖13.47)。

 

dll2.gif

圖13.47 選擇DLL進程

3)在OEP處, 填上DLL入口的RVA值1240h, 單擊IAT AutoSearch按鈕獲取IAT地址。 如果失敗, 必須手工判斷DLL的IAT位置和大小, 其RVA為7000h, Size為E8h。

4)單擊“Get Import”按鈕, 讓其分析IAT結(jié)構(gòu)重建輸入表。

5)勾選Add new section, 單擊“Fix Dump”按鈕, 并選擇剛抓取的映像文件dumped.dll, 它將創(chuàng)建一個dumped_.dll文件。

 

13.5.4 構(gòu)造重定位表

 

原理請參考本文開始處的說明。

先來回顧一個重定位表的結(jié)構(gòu):

 

代碼:

IMAGE_BASE_RELOCATION STRUCT

    VirtualAddress    dd    0

    SizeOfBlock        dd    0

    Type1            dw    0; 其中:Bit15—Bit12為類型 type, Bit11--Bit0 為ItemOffset

IMAGE_RELOCATION ENDS

重定位表以1000h大小為一個段, 因為ItemOffset最長為12位, 即剛好為1000h。 如果還有更多段, 將重復上面數(shù)據(jù)結(jié)構(gòu), 直到VirtualAddress為NULL, 表示結(jié)束。

ReloREC工具可以根據(jù)一組重定位的RVA, 重新構(gòu)造一個新的重定位表。 首先要做的工作是將UPX外殼這些要重定位的RVA提取出來。

 在處理重定位代碼語句中, 下面這句就是對代碼重定位, 其中EBX保存的就是要重定位的地址。

 

代碼:

003DE7B6     mov     dword ptr [ebx], eax      ;EBX指向要重定位的RVA

補丁的思路是找塊代碼空間, 跳過去執(zhí)行補丁代碼, 將重定位的地址轉(zhuǎn)成RVA, 并保存下來。 如下語句跳到補丁代碼處:

 

代碼:

003DE7B8   jmp     short 003DE80A

我們鍵入的補丁代碼:

003DE80A   pushad

003DE80B   mov     edx, dword ptr [3E0000]    ;從全局變量3E0000h取一地址指針

003DE811   sub     ebx, 3D0000                  ;減外殼基址, 將ebx中的地址轉(zhuǎn)成RVA

003DE817   mov     dword ptr [edx], ebx       ;將獲得的RVA保存下來

003DE819   add     edx, 4                        ;指向下一個DWRD地址

003DE81C   mov     dword ptr [3E0000], edx  ;將指針保存到全局變量中

003DE822   popad

003DE823   jmp     003DE79C                       ;跳回外殼代碼

3E0000h這個地址是OllyDbg的插件HideOD臨時分配的, 其初始值設為3E0010h, 如圖13.71。

dll3.gif

 

 補丁代碼鍵入完成后, 外殼在處理重定位相關代碼時, 這段補丁代碼將需要重定位的RVA全部提取出來。 執(zhí)行完補丁代碼, 數(shù)據(jù)窗口將保存需要重定位的RVA,

 將需要重定位的RVA復制出來(選取數(shù)據(jù)時, 最后一個DWORD數(shù)據(jù)是0), 操作時單擊鼠標右鍵, 執(zhí)行菜單Binary/Binary copy(二進制復制)功能, 再運行WinHex, 新建一文檔, 將這段二進制數(shù)據(jù)粘貼進去, 粘貼時, 選擇ASCII Hex模式(圖13.52), 然后將提取的數(shù)據(jù)保存為Relo.bin。

Relo.bin中保存的就是需要重定位的地址, 以RVA表示。 部分數(shù)據(jù)如下:

代碼:

0000101D

00001031

0000106E

0000108D

000010A1

000010DE

000010FB

00001109

0000110F

……

ReloREC這款工具, 就是根據(jù)這些RVA重新生成一份新的重定位表

 準備工作完成, 運行ReloREC, 將Relo.bin拖放到ReloREC主界面上可打開此文件, 如圖13.53。 然后在dumped_.dll里找一塊空白代碼處保存重定位表(一般在UPX1或UPX2區(qū)塊里找), 在這選擇C000h處。 在Relocation's RVA域里填上原始重定位表的RVA地址, 本例為C000h, 最后單擊“Fix Dump”按鈕, 打開上節(jié)剛修復輸入表的dumped_.dll文件, 即可完成重定位表的修復。


上面是電腦上網(wǎng)安全的一些基礎常識,學習了安全知識,幾乎可以讓你免費電腦中毒的煩擾。




標簽:DLL文件脫殼