打造XP下可運(yùn)行的微型PE(292字節(jié)).doc_第1頁(yè)
打造XP下可運(yùn)行的微型PE(292字節(jié)).doc_第2頁(yè)
打造XP下可運(yùn)行的微型PE(292字節(jié)).doc_第3頁(yè)
打造XP下可運(yùn)行的微型PE(292字節(jié)).doc_第4頁(yè)
打造XP下可運(yùn)行的微型PE(292字節(jié)).doc_第5頁(yè)
已閱讀5頁(yè),還剩8頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

前幾天和朋友交流技術(shù),提到手工打造微型PE文件,他說(shuō)現(xiàn)在網(wǎng)上流傳的大部分版本在XP SP3下都不能運(yùn)行,于是心血來(lái)潮,拍著胸脯說(shuō):“你放心,忙完了幫你做一個(gè)?!焙髞?lái)花了半天時(shí)間,終于打造出一個(gè)XP下可運(yùn)行的微型PE,彈出一個(gè)對(duì)話框,292字節(jié),當(dāng)然這離極限也許還差得遠(yuǎn),不過(guò)自己做了一次,還是有些心得,貼出來(lái)和大家分享一下。本文介紹的這個(gè)MiniPE可以在下載:/source/774041第一步 準(zhǔn)備PE文件先創(chuàng)建一個(gè)PE文件,為了盡可能地小,我們用匯編語(yǔ)言來(lái)編寫。代碼如下:.386.model flat,stdcalloption casemap:none.databyData db 90h.codestart:end代碼什么也沒(méi)做,運(yùn)行就報(bào)錯(cuò)(因?yàn)镻E文件的EntryPoint實(shí)際上指向了不存在的區(qū)域),代碼我們到后面再來(lái)填充它,這個(gè)PE文件只包含一個(gè)數(shù)據(jù)節(jié)。在Windows XP下,PE文件必須包含至少一個(gè)節(jié),否則無(wú)法運(yùn)行,這正是我們?yōu)槭裁匆xbyData這個(gè)數(shù)據(jù)的原因。為了讓生成出的PE文件盡可能小,在鏈接的時(shí)候,我們使用/align:4這個(gè)選項(xiàng),指定文件和節(jié)為4字節(jié)對(duì)齊(高版本的Microsoft增量鏈接器可能不支持4字節(jié)對(duì)齊,比如我測(cè)試的8.0版本,要求至少16字節(jié)對(duì)齊。所以使用這個(gè)選項(xiàng),應(yīng)該用低版本的鏈接器,我用的是MASM32V9自帶的鏈接器,版本是5.12。)這樣生成出來(lái)的PE文件只有460字節(jié),這是一個(gè)很好的開始,因?yàn)榇蟛糠謽O其簡(jiǎn)單的匯編程序生成出來(lái)都會(huì)在1.5K左右,如果是高級(jí)語(yǔ)言編寫的,將會(huì)更高。文件的內(nèi)容如下:00000000h: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 ; MZ?. .00000010h: B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ; ?.00000020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000030h: 00 00 00 00 00 00 00 00 00 00 00 00 A8 00 00 00 ; .?.00000040h: 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 ; .?.?L?Th00000050h: 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F ; is program canno00000060h: 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 ; t be run in DOS00000070h: 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 ; mode.$.00000080h: 5D 17 1D DB 19 76 73 88 19 76 73 88 19 76 73 88 ; .?vs?vs?vs?00000090h: E5 56 61 88 18 76 73 88 52 69 63 68 19 76 73 88 ; 錠a?vs圧ich.vs?000000a0h: 00 00 00 00 00 00 00 00 50 45 00 00 4C 01 01 00 ; .PE.L.000000b0h: 77 B8 1A 49 00 00 00 00 00 00 00 00 E0 00 0F 01 ; w?I.?.000000c0h: 0B 01 05 0C 00 00 00 00 04 00 00 00 00 00 00 00 ; .000000d0h: C8 01 00 00 C8 01 00 00 C8 01 00 00 00 00 40 00 ; ?.?.?.000000e0h: 04 00 00 00 04 00 00 00 04 00 00 00 00 00 00 00 ; .000000f0h: 04 00 00 00 00 00 00 00 CC 01 00 00 C8 01 00 00 ; .?.?.00000100h: 00 00 00 00 02 00 00 00 00 00 10 00 00 10 00 00 ; .00000110h: 00 00 10 00 00 10 00 00 00 00 00 00 10 00 00 00 ; .00000120h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000130h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000140h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000150h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000160h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000170h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000180h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000190h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .000001a0h: 2E 64 61 74 61 00 00 00 01 00 00 00 C8 01 00 00 ; .data.?.000001b0h: 04 00 00 00 C8 01 00 00 00 00 00 00 00 00 00 00 ; .?.000001c0h: 00 00 00 00 40 00 00 C0 90 00 00 00 ; .缾.第二步 去掉數(shù)據(jù)節(jié)內(nèi)容看到文件的最后4字節(jié),90 00 00 00,這正是我們定義的byData(鏈接器使用4字節(jié)對(duì)起,后面3字節(jié)填0),這當(dāng)然不是我們需要的東西,我們定義byData,只是為了讓鏈接器生成PE文件時(shí)能至少有一個(gè)節(jié)。所以我們先把它拿掉,在UltraEdit中直接刪除最后4個(gè)字節(jié),把000001a8處Section的Virtual Size改為0,這樣,文件又少了4個(gè)字節(jié)。第三步 去掉DOS Stub我們的目標(biāo)是在Windows XP下運(yùn)行,DOS Stub自然是多余的,可是鏈接器并沒(méi)有選項(xiàng)來(lái)去掉DOS Stub,只好手工來(lái)做這個(gè)工作,文件偏移0x3C處(IMAGE_DOS_HEADER的e_lfanew)指定了PE文件頭位置,這里是0x000000A8,直接將文件偏移0x3C到0xA8間的數(shù)據(jù)刪除,把后面的數(shù)據(jù)往前移,再將一些數(shù)據(jù)適當(dāng)修正,比如e_lfanew修正為0x40。這里DOS Stub的大小為0xA8-0x40=0x68,拿掉它,我們的文件又小了104字節(jié),內(nèi)容如下:00000000h: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 ; MZ?. .00000010h: B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ; ?.00000020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000030h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 ; .00000040h: 50 45 00 00 4C 01 01 00 77 B8 1A 49 00 00 00 00 ; PE.L.w?I.00000050h: 00 00 00 00 E0 00 0F 01 0B 01 05 0C 00 00 00 00 ; .?.00000060h: 09 00 00 00 00 00 00 00 60 01 00 00 60 01 00 00 ; .00000070h: 60 01 00 00 00 00 40 00 04 00 00 00 04 00 00 00 ; .00000080h: 04 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 ; .00000090h: 64 01 00 00 60 01 00 00 00 00 00 00 02 00 00 00 ; d.000000a0h: 00 00 10 00 00 10 00 00 00 00 10 00 00 10 00 00 ; .000000b0h: 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 ; .000000c0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .000000d0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .000000e0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .000000f0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000100h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000110h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000120h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000130h: 00 00 00 00 00 00 00 00 2E 64 61 74 61 00 00 00 ; .data.00000140h: 00 00 00 00 60 01 00 00 00 00 00 00 60 01 00 00 ; .00000150h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 C0 ; .第四步 重疊DOS文件頭和PE文件頭在Windows下,PE裝載器只關(guān)心DOS文件頭的e_magic和e_lfanew,有這么多無(wú)用的項(xiàng)目,何不把PE文件頭往前挪挪,大家擠一擠,再謄點(diǎn)空間出來(lái)。當(dāng)然,PE文件頭的長(zhǎng)度超過(guò)了DOS文件頭,往前移動(dòng),肯定是會(huì)覆蓋到e_lfanew的。e_lfanew是不能隨便亂填的,怎么辦?我們把PE文件頭移動(dòng)到文件偏移0x04的位置,再把e_lfanew修改為0x04,現(xiàn)在PE裝載器可以正確從e_lfanew找到PE文件頭的位置了,我們?cè)趤?lái)看看PE文件頭,在PE文件頭偏移0x3C-0x4=0x38的位置,剛好是IMAGE_OPETION_HEADER的SectionAlignment節(jié)對(duì)齊值,剛剛好,我們的節(jié)對(duì)齊也是4,講到這里,如果你鏈接PE文件時(shí),用的對(duì)齊值不是4那么就得修改為4咯。這一步也很簡(jiǎn)單,直接把剛才文件偏移0x40的數(shù)據(jù)拷貝到0x04處,這時(shí)候,我們的PE文件總大小為292字節(jié):sizeof(IMAGE_NT_HEADERS)+sizeof(IMAGE_SECTION_HEADER)+4。文件內(nèi)容如下:00000000h: 4D 5A 90 00 50 45 00 00 4C 01 01 00 77 B8 1A 49 ; MZ?PE.L.w?I00000010h: 00 00 00 00 00 00 00 00 E0 00 0F 01 0B 01 05 0C ; .?.00000020h: 00 00 00 00 09 00 00 00 00 00 00 00 60 01 00 00 ; .00000030h: 60 01 00 00 60 01 00 00 00 00 40 00 04 00 00 00 ; .00000040h: 04 00 00 00 04 00 00 00 00 00 00 00 04 00 00 00 ; .00000050h: 00 00 00 00 64 01 00 00 60 01 00 00 00 00 00 00 ; .d.00000060h: 02 00 00 00 00 00 10 00 00 10 00 00 00 00 10 00 ; .00000070h: 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00 00 ; .00000080h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000090h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .000000a0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .000000b0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .000000c0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .000000d0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .000000e0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .000000f0h: 00 00 00 00 00 00 00 00 00 00 00 00 2E 64 61 74 ; .dat00000100h: 61 00 00 00 00 00 00 00 60 01 00 00 00 00 00 00 ; a.00000110h: 60 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .00000120h: 40 00 00 C0 ; .第五步 添加代碼這一步很有意思,我們的PE文件沒(méi)有代碼節(jié),也沒(méi)有導(dǎo)入表,怎么讓他調(diào)用MessageBoxA呢?第一個(gè)問(wèn)題很好解決,PE文件頭的EntryPoint不一定要指向代碼節(jié),例如很多加殼軟件都會(huì)修改EntryPoint,讓它指向自己的地址。極端一點(diǎn),EntryPoint甚至可以指向PE文件的任意位置。我們來(lái)看一下,實(shí)際上對(duì)于PE文件頭,PE裝載器有很多字段也不會(huì)解釋,這里把這些字段列出來(lái),其中帶“*”的字段表示值不能隨便填,能隨便填的值后面是其相對(duì)于我們這個(gè)PE文件的文件偏移:IMAGE_FILE_HEADER STRUCTMachine *NumberOfSections *TimeDateStampPointerToSymbolTable 0x0CNumberOfSymbols 0x10SizeOfOptionalHeader *Characteristics *IMAGE_FILE_HEADER ENDSIMAGE_FILE_HEADER ENDSIMAGE_OPTIONAL_HEADER32 STRUCTMagic *MajorLinkerVersion 0x1EMinorLinkerVersion 0x1FSizeOfCode 0x20SizeOfInitializedData 0x24SizeOfUninitializedData 0x28AddressOfEntryPoint *BaseOfCode 0x30BaseOfData 0x34ImageBase *SectionAlignment *FileAlignment *MajorOperatingSystemVersion *MinorOperatingSystemVersion *MajorImageVersion *MinorImageVersion *MajorSubsystemVersion *MinorSubsystemVersion *Win32VersionValue *SizeOfImage *SizeOfHeaders *CheckSum 0x5CSubsystem *DllCharacteristics *SizeOfStackReserve *SizeOfStackCommit *SizeOfHeapReserve *SizeOfHeapCommit *LoaderFlags 0x74NumberOfRvaAndSizes *DataDirectory *IMAGE_OPTIONAL_HEADER32 ENDS另外對(duì)于DataDirectories,都指定了Virtual Address和Size,一個(gè)結(jié)構(gòu)16字節(jié),實(shí)際上只要我們把它的任意一個(gè)字段填0,另外一個(gè)字段就可以挪作它用了(TLS除外,兩個(gè)字段必須都為0),有些DataDirectories甚至可以兩個(gè)字段都任意填寫,比如Exception Table,Seccrity Table,Base Relocation Table,Copyright Data Table,Global Ptr,再加上后面那個(gè)數(shù)據(jù)節(jié)的節(jié)表,除了VirtualSize,RAV/Offset和Pointer To Raw Data外,其他的都能隨意填充。這樣算下來(lái),只要我們的代碼足夠小,還是有足夠的空間容納的?,F(xiàn)在讓我們來(lái)寫代碼。一個(gè)沒(méi)有導(dǎo)入表的程序,如何才能動(dòng)態(tài)裝載User32.dll并調(diào)用其中的MessageBoxA呢?我們來(lái)看看下面的代碼:.386.model flat,stdcalloption casemap:noneinclude windows.inc.dataszUser32 db user32.dll,0szMsg db Hello World!,0szTitle db MiniPE,0.codeGetApi proc hModule,nIndexmov esi,hModulemov edx,nIndexadd esi,(IMAGE_DOS_HEADER ptr esi).e_lfanewassume esi:ptr IMAGE_NT_HEADERSmov esi,esi.OptionalHeader.DataDirectory.VirtualAddressadd esi,eaxassume esi:ptr IMAGE_EXPORT_DIRECTORYsub edx,esi.nBaserol edx,2mov edi,esi.AddressOfFunctionsadd edi,eaxadd edi,edxmov edx,dword ptr ediadd eax,edxretGetApi endpWinMain proclocal hModuleassume fs:nothingmov eax,fs:30hmov eax,eax+0Chmov eax,eax+0Chmov eax,eaxmov eax,eaxmov eax,eax+18hmov hModule,eaxinvoke GetApi,hModule,245h.if eaxpush offset szUser32call eax.if eaxmov hModule,eaxinvoke GetApi,hModule,1DDh.if eaxpush MB_OKpush offset szTitlepush offset szMsgpush 0call eax.endif.endif.endifretWinMain endpend WinMain上面的代碼并沒(méi)有顯示調(diào)用任何API,但是在Windows XP下,你嘗試編譯并運(yùn)行它,你會(huì)發(fā)現(xiàn)他竟然能彈出一個(gè)對(duì)話框來(lái)??纯创a的入口:首先加載fs:30h到eax,如果你研究過(guò)SHE的,一定對(duì)fs段寄存器很熟悉。在基于NT的操作系統(tǒng)中,fs寄存器用于訪問(wèn)線程本地信息(TEB)。我們來(lái)看看TEB到0x30處的定義:0x00 NtTib :_NT_TIB0x1C EnvironmentPointer :Ptr32 Void0x20 ClientId :_CLIENT_ID0x28 ActiveRpcHandle :Ptr32 Void0x2C ThreadLocalStoragePointer :Ptr32 Void0x30 ProcessEnvironmentBlock :Ptr32 _PEB很顯然,這里是通過(guò)TEB來(lái)訪問(wèn)進(jìn)程環(huán)境塊(PEB),后面的代碼又將PEB的0x0C的數(shù)據(jù)加載到eax,我們來(lái)看PEB到0x0C的定義:0x00 InheritedAddressSpace :UChar0x01 ReadImageFileExecOptions :UChar0x02 BeginDebugged :UChar0x03 SpareBool :UChar0x04 Mutant :Ptr32 Void0x08 ImageBaseAddress :Ptr32 Void0x0C Ldr :Ptr _PEB_LDR_DATA可見(jiàn),偏移0x0C出是_PEB_LDR_DATA,加載程序信息,后面的代碼又訪問(wèn)了這個(gè)結(jié)構(gòu)0x0C處的數(shù)據(jù),我們?cè)賮?lái)看看_PEB_LDR_DATA到0x0C的定義:0x00 Length :Uint4B0x04 Initialized :UChar0x08 SsHandle :Ptr32 Void0x0C InLoadOrderModuleList :_LIST_ENTRY實(shí)際上_PEB_LDR_DATA+0x0C處的InLoadOrderModuleList正是LDR_DATA_TABLE_ENTRY結(jié)構(gòu),讓我們來(lái)看看它:0x00 InLoadOrderLinks :_LIST_ENTRY0x08 InMemoryOrderLinks :_LIST_ENTRY0x10 InInitializationOrderLinks :_LIST_ENTRY0x18 DllBase :Ptr32 Void0x1C EntryPoint :Ptr32 Voi我們的程序首先讀取了其偏移0處的數(shù)據(jù),它正是_LIST_ENTRY的Flink字段前向鏈接,mov eax,eax這段代碼直接跳過(guò)這個(gè)結(jié)構(gòu),把下一個(gè)_PEB_LDR_DATA結(jié)構(gòu)加載到eax,重復(fù)兩次,在讀0x18處的內(nèi)容模塊基地址。這是為什么呢?因?yàn)樵赪indows XP下,任何進(jìn)程都必須含有至少3個(gè)模塊:自身、ntdll.dll、kernel32.dll,其加載順序也是自身、ntdll.dll、kernel32.dll。我們跳過(guò)前兩個(gè)模塊,把第三個(gè)模塊kernel32.dll的基地址加載到eax寄存器。上面的結(jié)構(gòu)看上去很復(fù)雜,要得到這些結(jié)構(gòu)的詳細(xì)信息,可以在WindDbg中使用“DT ModuleName!*”命令來(lái)列出模塊所有名字列表,然后再用“DT ModuleName!StructName”來(lái)列出結(jié)構(gòu)的詳細(xì)定義。得到了kernel32.dll的基地址,后面的代碼就很容易理解了,通過(guò)導(dǎo)出序號(hào)0x245從kernel32.dll的導(dǎo)出表中查找導(dǎo)出函數(shù)(0x245對(duì)應(yīng)的正是LoadLibraryA),得到LoadLibraryA的地址再通過(guò)調(diào)用它來(lái)加載user32.dll,再用同樣的方法用序號(hào)0x1DD從user32.dll導(dǎo)出表中查找MessageBoxA的地址。當(dāng)然,這里我們也可以使用函數(shù)名從模塊中查找導(dǎo)出函數(shù),不過(guò)為了盡量把代碼寫得短小,這里用了序號(hào)。羅云彬的Windows環(huán)境下32位匯編語(yǔ)言程序設(shè)計(jì)中對(duì)這兩種方法都作了說(shuō)明,有興趣可以參考一下。解決了無(wú)導(dǎo)入表調(diào)用MessageBoxA的問(wèn)題,我們還要想辦法把我們的代碼優(yōu)化得盡可能短,再回憶我們前面講的,我們要利用PE文件頭的空余字段,這些字段看上去沒(méi)有一塊足夠大的連續(xù)空間可以容納我們的整個(gè)代碼,所以我們還希望我們的代碼每條指令的機(jī)器碼盡量短,以便我們可以通過(guò)插入JZ/JNZ這樣的指令來(lái)靈活地利用空余的空間。在高級(jí)語(yǔ)言中,有_falstcall這樣的調(diào)用約定,我們借鑒一下,通過(guò)寄存器來(lái)傳遞調(diào)用函數(shù)的參數(shù),最終優(yōu)化出來(lái),我的代碼如下:.386.model flat,stdcalloption casemap:noneinclude windows.inc.codeWinMain procassume fs:nothingmov ebx,offset GetApimov eax,fs:30hmov eax,eax+0Chmov eax,eax+0Chmov eax,eaxmov eax,eaxmov eax,eax+18hmov edx,245hcall ebxpush 00400000hcall eaxmov edx,1DDhcall ebxpush MB_OKpush 00400000hpush 00400000hpush 0call eaxretWinMain endpGetApi procmov esi,eaxadd esi,(IMAGE_DOS_HEADER ptr esi).e_lfanewassume esi:ptr IMAGE_NT_HEADERSmov esi,esi.OptionalHeader.DataDirectory.VirtualAddressadd esi,eaxassume esi:ptr IMAGE_EXPORT_DIRECTORYsub edx,esi.nBaserol edx,2mov edi,esi.AddressOfFunctionsadd edi,eaxadd edi,edxmov edx,dword ptr ediadd eax,edxretGetApi endpend WinMain在上面的代碼中,對(duì)于GetApi的調(diào)用,我們使用eax來(lái)傳遞hModule,因?yàn)闊o(wú)論是通過(guò)訪問(wèn)TEB還是LoadLibraryA,模塊地址都已經(jīng)在eax中了,無(wú)須再用其他指令調(diào)整,edx來(lái)傳遞導(dǎo)出序號(hào)。上面的被調(diào)函數(shù)并沒(méi)有保護(hù)寄存器,是因?yàn)槲覀兊拇a可以完全掌握所有的寄存器,確保關(guān)鍵寄存器不會(huì)被被調(diào)用函數(shù)覆蓋。代碼中有三個(gè)push 00400000h將字符串地址壓棧,可以肯定,我們最終會(huì)把user32.dll,Hello!,MiniPE這些字符串找個(gè)合適的空隙存放起來(lái),地址暫時(shí)不能確定,先空起來(lái),最后再填。代碼編譯出來(lái):004001E0 /$ BB 1E024000 MOV EBX,ASMTest.0040021E004001E5 |. 64:A1 3000000MOV EAX,DWORD PTR FS:30004001EB |. 8B40 0C MOV EAX,DWORD PTR DS:EAX+C004001EE |. 8B40 0C MOV EAX,DWORD PTR DS:EAX+C004001F1 |. 8B00 MOV EAX,DWORD PTR DS:EAX004001F3 |. 8B00 MOV EAX,DWORD PTR DS:EAX004001F5 |. 8B40 18 MOV EAX,DWORD PTR DS:EAX+18004001F8 |. BA 45020000 MOV EDX,245004001FD |. FFD3 CALL EBX004001FF |. 68 02004000 PUSH ASMTest.0040000200400204 |. FFD0 CALL EAX00400206 |. BA DD010000 MOV EDX,1DD0040020B |. FFD3 CALL EBX0040020D |. 6A 00 PUSH 00040020F |. 68 1A004000 PUSH ASMTest.0040001A00400214 |. 68 0D004000 PUSH ASMTest.0040000D00400219 |. 6A 00 PUSH 00040021B |. FFD0 CALL EAX0040021D . C3 RETN0040021E . 8BF0 MOV ESI,EAX00400220 . 0376 3C ADD ESI,DWORD PTR DS:ESI+3C00400223 . 8B76 78 MOV ESI,DWORD PTR DS:ESI+7800400226 . 03F0 ADD ESI,EAX00400228 . 2B56 10 SUB EDX,DWORD PTR DS:ESI+100040022B . C1C2 02 ROL EDX,20040022E . 8B7E 1C MOV EDI,DWORD PTR DS:ESI+1C00400231 . 03F8 ADD EDI,EAX00400233 . 03FA ADD EDI,EDX00400235 . 8B17 MOV EDX,DWORD PTR DS:EDI00400237 . 03C2 ADD EAX,EDX00400239 . C3 RETN有90字節(jié),看樣子空隙足矣。主函數(shù)的代碼規(guī)模比較大,盡量找個(gè)連續(xù)的位置,看一下,文件偏移0x94這個(gè)位置比較合適(DataDirectories的Exception Table Address處),把剛才編譯好的Shellcode拷貝進(jìn)去。到文件偏移0xB0這個(gè)位置,注意,不能填了,那么在偏移0xAC這個(gè)位置我們安排兩條指令來(lái)跳過(guò)它,直接跳到0xB4,JE 004000B4 JNE 004000B4,Shellcode剛好4字節(jié)。這樣按順序往下填寫,遇到需要跳過(guò)的地方就在它前面四字節(jié)位置用JE/JNE,到最后,從0x11E還空了些字段出來(lái)。然后是GetApi這個(gè)函數(shù),雖然才28字節(jié)??墒请y阿,連連續(xù)28字節(jié)的位置都找不出來(lái)了。起始地址我們放在文件偏移0x0C處(PE文件頭的Time/Date Stamp字段),和前面一樣,遇到不能覆蓋的位置就在它前面四字節(jié)用JE/JNE跳過(guò)。但是代碼填到文件偏移0x25處為難了,0x2A是不能覆蓋的,那是PE文件頭的EntryPoint阿,看看這里的指令,ADD ESI,EAX SUB EDX,DWORD PTR ESI+10h,兩條算術(shù)指令,那么我們就用JNZ來(lái)跳過(guò)。我們可以肯定地知道,這兩條算術(shù)指令的運(yùn)算結(jié)果不可能是0,否則,我們的程序也就出錯(cuò)了。依次類推,后面遇到為難的而剛好又是算術(shù)指令的地方就用JNZ來(lái)跳過(guò),才兩字節(jié)阿,又節(jié)省了寶貴的資源。這樣跳來(lái)跳去,到文件偏移0x8C的地方,GetApi的代碼也填完了。再回頭來(lái)看看主函數(shù)的第一條代碼,將GetApi的地址存入ebx,現(xiàn)在我們確定了GetApi的位置,那么就把0040000C填進(jìn)去吧。然后是三個(gè)字符串,分別是“user32”(全名應(yīng)該是“user32.dll”,但實(shí)在找不出位置了,就用“user32”吧),“Hello!”,“MiniPE”。剛才說(shuō)了,在文件偏移0x11E處還有空位呢,“user32”就填這里吧?!癏ello!”放在文件偏移0xD8處,“MiniPE”放在文件偏移0xE0處。最后別忘了修正004001FF |. 68 02004000 PUSH ASMTest.004000020040020F |. 68 1A004000 PUSH ASMTest.0040001A00400214 |. 68 0D004000 PUSH ASMTest.0040000D這三條指令后面字符串和PE文件頭EntryPoint的地址,EntryPoint修正為0x00000094。到此為止,292字節(jié)的微型PE打造成功了,最終的文件內(nèi)容如下:00000000h: 4D 5A 90 00 50 45 00 00 4C 01 01 00 8B F0 03 76 ; MZ?PE.L.嬸.v00000010h: 3C 8B 76 78 74 0D 75 0B E0 00 0F 01 0B 01 03 F0 ; 媣xt.u.?.?00000020h: 2B 56 10 03 F0 2B 56 10 75 06 00 00 94

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論