Windows PE变形练手2-开发一套自己的PE嵌入模板
PE嵌入模板
? ? 編寫一段代碼,生成一個(gè)已經(jīng)處理過(guò)重定位信息,同時(shí)所有的內(nèi)容都在代碼段里,并且沒(méi)有導(dǎo)入表的PE程序,把這個(gè)程序嵌入到其他PE的相關(guān)位置,能夠獨(dú)立的運(yùn)行,接下來(lái)是整理了2個(gè)模板,一個(gè)是HelloWorld的,另一個(gè)是通用模板LoadLibrary的模板。
? ? 開發(fā)環(huán)境masm32和vs2012,相關(guān)環(huán)境搭建我之前整理過(guò)[?http://blog.csdn.net/u013761036/article/details/52186683?];
直接C++的話貌似不行,我用vs2015本地創(chuàng)建了一個(gè)空的項(xiàng)目,默認(rèn)優(yōu)化全開:
還是會(huì)有kernel32.dll。
?
接下來(lái)是模板1,功能是所有的東西都在一個(gè)獨(dú)立的模塊,彈出對(duì)話框,同時(shí)處理了全局變量的重定位問(wèn)題。模板如下[代碼是仿照Windows?PE?權(quán)威指南,但是有些地方已經(jīng)改過(guò)了,書上代碼在我本地跑有問(wèn)題,再獲取Kernel32.dll地址的時(shí)候并不能成功得到地址。那個(gè)函數(shù)我已經(jīng)重寫了]:
;---------------------------------------- ;補(bǔ)丁代碼 ;本段代碼使用了API函數(shù)地址動(dòng)態(tài)獲取以及重定位技術(shù) ;程序功能:彈出對(duì)話框 ;作者:Thinker ;開發(fā)日期:2017.4.30 ;開發(fā)測(cè)試環(huán)境:vs2012+masm32、Win7 X64 ;----------------------------------------.386 .model flat,stdcall option casemap:noneinclude windows.inc;注意,此處不靜態(tài)包含引入任何其他動(dòng)態(tài)鏈接庫(kù),包括Kernell32.dll_ProtoGetProcAddress typedef proto :dword,:dword _ProtoLoadLibrary typedef proto :dword _ApiGetProcAddress typedef ptr _ProtoGetProcAddress _ApiLoadLibrary typedef ptr _ProtoLoadLibrary;---------------------------------------- ;補(bǔ)丁代碼中引入的其他動(dòng)態(tài)鏈接庫(kù)函數(shù)的聲明 ;----------------------------------------_ProtoMessageBox typedef proto :dword,:dword,:dword,:dword _ApiMessageBox typedef ptr _ProtoMessageBox;被添加到目標(biāo)文件的代碼從這里開始,到APPEND_CODE_END處結(jié)束 .code jmp _NewEntry;以下內(nèi)容為兩個(gè)重要函數(shù)名 ;幾乎所有補(bǔ)丁都必須使用 szGetProcAddr db 'GetProcAddress',0 szLoadLib db 'LoadLibraryA',0;---------------------------------------- ;補(bǔ)丁代碼中其他全局變量的定義 ;----------------------------------------szUser32Dll db 'user32.dll',0 szMessageBox db 'MessageBoxA',0 szHello db 'HelloWorldPE',0 ;---------------------------------------- ;獲取kernel32.dll 的基地址 ;----------------------------------------_getKernelBase proc;下面是Windows PE權(quán)威指南上的代碼,獲取Kernel32.dll地址失敗,無(wú)奈我用自己之前的C++代碼改了下,測(cè)試幾次發(fā)現(xiàn)可以;local @dwRet ;pushad ;assume fs:nothing ;mov eax,fs:[30h] ;PEB ;mov eax,[eax+0ch] ;PEB_LDE_DATA ;mov esi,[eax+1ch] ;InInitializationOrderModuleList ;lodsd ;mov eax,[eax+8] ;Kernel32.dll的基地址 ;mov @dwRet ,eax ;popad ;mov eax,@dwRet ;ret;之前寫的C++代碼改的[http://blog.csdn.net/u013761036/article/details/71006302]local @dwRet pushad assume fs:nothing mov ebx, fs:[30h] ;得到peb結(jié)構(gòu)體的地址 mov ebx, [ebx + 0ch] ;得到Ldr結(jié)構(gòu)體的地址 mov ebx, [ebx + 0ch] ;得到ldr.InLoadOrderModuleList.Flink 第一個(gè)模塊,當(dāng)前進(jìn)程 mov ebx, [ebx] ;得到第二個(gè)模塊地址 ntdll.dll mov ebx, [ebx] ;得到第三個(gè)模塊地址 kernel32.dll mov ebx, [ebx + 18h] ;得到第三個(gè)模塊地址(kernel32模塊的dllbase) mov @dwRet, ebx popad mov eax,@dwRet ret _getKernelBase endp;---------------------------------------- ;獲取制定字符串的API函數(shù)的調(diào)用地址 ;入口參數(shù):_hModule 為動(dòng)態(tài)鏈接庫(kù)的基地址 ; _lpApi為API函數(shù)名稱首指 ;出口參數(shù):eax 位函數(shù)在虛擬地址空間中的真實(shí)地址 ;---------------------------------------- _getApi proc _hModule,_lpApi local @ret local @dwLen pushad mov @ret,0 ;計(jì)算API字符串的長(zhǎng)度,含最后的0 mov edi,_lpApi mov ecx,-1 xor al,al cld repnz scasb mov ecx,edi sub ecx,_lpApi mov @dwLen,ecx;從PE文件頭的數(shù)據(jù)目錄獲取導(dǎo)出表地址 mov esi,_hModule add esi,[esi+3ch] assume esi:ptr IMAGE_NT_HEADERS mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress add esi,_hModule assume esi:ptr IMAGE_EXPORT_DIRECTORY;查找符合名稱的導(dǎo)出函數(shù)名 mov ebx,[esi].AddressOfNames add ebx,_hModule xor edx,edx .repeat push esi mov edi,[ebx] add edi,_hModule mov esi,_lpApi mov ecx,@dwLen repz cmpsb .if ZERO? pop esi jmp @F .endif pop esi add ebx,4 inc edx .until edx >= [esi].NumberOfNames jmp _ret @@:;通過(guò)API名稱索引獲取序號(hào)索引,再獲取地址索引 sub ebx,[esi].AddressOfNames sub ebx,_hModule shr ebx,1 add ebx,[esi].AddressOfNameOrdinals add ebx,_hModule movzx eax,word ptr [ebx] shl eax,2 add eax,[esi].AddressOfFunctions add eax,_hModule;從地址表得到導(dǎo)出函數(shù)地址 mov eax,[eax] add eax,_hModule mov @ret,eax_ret:assume esi:nothing popad mov eax,@ret ret _getApi endp;---------------------------------------- ;補(bǔ)丁功能部分 ;傳入3個(gè)參數(shù) ; _kernel :kernel32.dll的基地址 ; _getAddr:函數(shù)GetProcAddress地址 ; _LoadLib:函數(shù)LoadLibraryA地址 ;---------------------------------------- _patchFun proc _kernel,_getAddr,_loadLib;---------------------------------------- ;補(bǔ)丁代碼局部變量定義 ;----------------------------------------local hUser32Base:dword local _messageBox:_ApiMessageBoxpushad;---------------------------------------- ;補(bǔ)丁功能代碼,下面例子彈出對(duì)話框 ;---------------------------------------- ;獲取user32.dll的基地址 mov eax,offset szUser32Dll add eax,ebxmov edx,_loadLib push eax call edx mov hUser32Base,eax;使用GetProcAddress函數(shù)的首地址 ;傳入兩個(gè)參數(shù)調(diào)用GetProcAddress函數(shù) ;獲得MessageBoxA的首地址 mov eax,offset szMessageBox add eax,ebxmov edx,_getAddr mov ecx,hUser32Base push eax push ecx call edx mov _messageBox,eax;調(diào)用函數(shù)MessageBox mov eax,offset szHello add eax,ebx mov edx,_messageBoxpush MB_OK push NULL push eax push NULL call edxpopad ret_patchFun endp_start proclocal hKernel32Base:dword ;存放kernel32.dll基地址local _getProcAddress:_ApiGetProcAddress local _loadLibrary :_ApiLoadLibrary pushad ;獲取kernel32.dll的基地址 lea edx,_getKernelBase add eax,ebx call edx mov hKernel32Base,eax;從基地址出發(fā)搜索GetProcAddress函數(shù)的首地址 mov eax,offset szGetProcAddr add eax,ebxmov edi,hKernel32Base mov ecx,edi lea edx,_getApi add edx,ebxpush eax push ecx call edx mov _getProcAddress,eax;從基地址出發(fā)搜索LoadLibraryA函數(shù)的首地址 mov eax,offset szLoadLib add eax,ebxmov edi,hKernel32Base mov ecx,edi lea edx,_getApi add edx,ebxpush eax push ecx call edx mov _loadLibrary,eax;調(diào)用補(bǔ)丁代碼 lea edx,_patchFun add edx,ebxpush _loadLibrary push _getProcAddress push hKernel32Base call edxpopad ret _start endp;EXE文件新的入口地址_NewEntry: call @F ;免去重定位 @@:pop ebx sub ebx,offset @Binvoke _startjmpToStart db 0E9h,0F0h,0FFh,0FFh,0FFh ret end _NewEntry? ? 最后的黑體是跳轉(zhuǎn)用的。如果單獨(dú)跑這個(gè)地方可以去掉,不然一條轉(zhuǎn)都崩潰了,通常留著是為了嵌入到別的程序里之后,執(zhí)行完之后跳轉(zhuǎn)到原來(lái)程序入口地址等。
模板1的執(zhí)行結(jié)果如下:
并沒(méi)有導(dǎo)入表,同時(shí)相關(guān)字符串也沒(méi)有存在數(shù)據(jù)段里:
代碼段部分就是全部了,可以拷貝來(lái)獨(dú)立的用。
模板2:和1類似,就是做了一個(gè)loadlibrary的模板,這樣就和其他注入姿勢(shì)一樣了,只是加載一個(gè)dll,然后所有的東西在dll里面寫就行了。Dllmain函數(shù)被調(diào)用的時(shí)候記得觸發(fā)下自己就OK了。模板代碼如下[一樣書上的獲取kernel32.dll代碼無(wú)效,此處已經(jīng)修正]。
;---------------------------------------- ;補(bǔ)丁代碼 ;本段代碼使用了API函數(shù)地址動(dòng)態(tài)獲取以及重定位技術(shù) ;程序功能:loadlibrary實(shí)現(xiàn)通用補(bǔ)丁代碼 ;作者:Thinker ;開發(fā)日期:2017.4.30 ;開發(fā)測(cè)試環(huán)境:vs2012+masm32、Win7 X64 ;----------------------------------------.386 .model flat,stdcall option casemap:noneinclude windows.inc_ProtoLoadLibrary typedef proto :dword _ApiLoadLibrary typedef ptr _ProtoLoadLibrary;被添加到目標(biāo)文件的代碼從這里開始,到APPEND_CODE_END處結(jié)束 .code jmp _NewEntryszLoadLib db 'LoadLibraryA',0 szDllName db 'I.dll',0;---------------------------------------- ;獲取kernel32.dll 的基地址 ;---------------------------------------- _getKernelBase proclocal @dwRet pushad assume fs:nothing mov ebx, fs:[30h] ;得到peb結(jié)構(gòu)體的地址 mov ebx, [ebx + 0ch] ;得到Ldr結(jié)構(gòu)體的地址 mov ebx, [ebx + 0ch] ;得到ldr.InLoadOrderModuleList.Flink 第一個(gè)模塊,當(dāng)前進(jìn)程 mov ebx, [ebx] ;得到第二個(gè)模塊地址 ntdll.dll mov ebx, [ebx] ;得到第三個(gè)模塊地址 kernel32.dll mov ebx, [ebx + 18h] ;得到第三個(gè)模塊地址(kernel32模塊的dllbase) mov @dwRet, ebx popad mov eax,@dwRet ret _getKernelBase endp;---------------------------------------- ;獲取制定字符串的API函數(shù)的調(diào)用地址 ;入口參數(shù):_hModule 為動(dòng)態(tài)鏈接庫(kù)的基地址 ; _lpApi為API函數(shù)名稱首指 ;出口參數(shù):eax 位函數(shù)在虛擬地址空間中的真實(shí)地址 ;---------------------------------------- _getApi proc _hModule,_lpApi local @ret local @dwLen pushad mov @ret,0 ;計(jì)算API字符串的長(zhǎng)度,含最后的0 mov edi,_lpApi mov ecx,-1 xor al,al cld repnz scasb mov ecx,edi sub ecx,_lpApi mov @dwLen,ecx;從PE文件頭的數(shù)據(jù)目錄獲取導(dǎo)出表地址 mov esi,_hModule add esi,[esi+3ch] assume esi:ptr IMAGE_NT_HEADERS mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress add esi,_hModule assume esi:ptr IMAGE_EXPORT_DIRECTORY;查找符合名稱的導(dǎo)出函數(shù)名 mov ebx,[esi].AddressOfNames add ebx,_hModule xor edx,edx .repeat push esi mov edi,[ebx] add edi,_hModule mov esi,_lpApi mov ecx,@dwLen repz cmpsb .if ZERO? pop esi jmp @F .endif pop esi add ebx,4 inc edx .until edx >= [esi].NumberOfNames jmp _ret @@:;通過(guò)API名稱索引獲取序號(hào)索引,再獲取地址索引 sub ebx,[esi].AddressOfNames sub ebx,_hModule shr ebx,1 add ebx,[esi].AddressOfNameOrdinals add ebx,_hModule movzx eax,word ptr [ebx] shl eax,2 add eax,[esi].AddressOfFunctions add eax,_hModule;從地址表得到導(dǎo)出函數(shù)地址 mov eax,[eax] add eax,_hModule mov @ret,eax_ret:assume esi:nothing popad mov eax,@ret ret _getApi endp_start proclocal hKernel32Base:dword ;存放kernel32.dll基地址 local _loadLibrary :_ApiLoadLibrary pushad ;獲取kernel32.dll的基地址 lea edx,_getKernelBase add eax,ebx call edx mov hKernel32Base,eax;從基地址出發(fā)搜索LoadLibraryA函數(shù)的首地址 mov eax,offset szLoadLib add eax,ebxmov edi,hKernel32Base mov ecx,edi lea edx,_getApi add edx,ebxpush eax push ecx call edx mov _loadLibrary,eax;調(diào)用補(bǔ)丁代碼mov eax,offset szDllName push eax call _loadLibrarypopad ret _start endp;EXE文件新的入口地址_NewEntry: call @F ;免去重定位 @@:pop ebx sub ebx,offset @Binvoke _start;jmpToStart db 0E9h,0F0h,0FFh,0FFh,0FFh ret end _NewEntry運(yùn)行結(jié)果:
????代碼段大小0x109,學(xué)習(xí)資料上的是優(yōu)化到0x80,然而我照著寫完MD各種運(yùn)行不了,而且他里面定義了一堆變量最后根本沒(méi)用上。獲取Kernel32.dll部分的代碼也是錯(cuò)的。FK浪費(fèi)我太多時(shí)間調(diào)那個(gè)匯編代碼,后來(lái)直接自己改了一個(gè)。上面的那個(gè)沒(méi)有采取優(yōu)化的姿勢(shì),需要用的,如果感覺(jué)大的話可以進(jìn)行下匯編代碼調(diào)整,優(yōu)化下體積。
????以后的PE嵌入通常用的也是這個(gè)通用的模板,因?yàn)橹灰ǔ?/span>Loadlibrary就OK了。當(dāng)然如果想做反彈或者別的,對(duì)應(yīng)的用這個(gè)姿勢(shì)改就行了。目標(biāo)就是不要有導(dǎo)入表,記得處理重定位,函數(shù)用到的數(shù)據(jù)記得是在代碼段,不是放在數(shù)據(jù)段里面。
總結(jié)
以上是生活随笔為你收集整理的Windows PE变形练手2-开发一套自己的PE嵌入模板的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: R3抹掉加载的DLL
- 下一篇: Windows PE变形练手3-把通用模