淺談代碼段加密原理(防止靜態分析)

在軟件安全裏,有一種保護手段叫加密,通常狀況下都是爲代碼段加密,使本來的代碼沒法被靜態分析,只能動態調試。ios

涉及到的知識有:PE文件結構,代碼重定位,shellcode。算法

代碼加密時可用各類算法組合起來使用,只要保證解密時用逆推的方法還原成源代碼便可,下面例子當中用的是最簡單的異或加密shell

因爲博主也是第一次接觸這個代碼段加密,有寫的不對或者不夠的地方,還麻煩大佬指正。感謝!!安全

思路:函數

1.獲取代碼段內容,進行加密後再覆蓋回去測試

2.把重定位去掉,目的使重定位發生的時機在解密以後,不然解密的數據是已經被重定位過的加密

3.新增一個節,在這個節中編寫解密步驟,而且要本身實現代碼節的重定位,理由同2。並將OEP改寫爲當前節的解密位置。  因爲TLS目錄運行的時機先於OEP,同理也能夠編寫TLS目錄進行解密。spa

主要步驟:指針

步驟:調試

1.經過讀取內容,找到代碼段位置(若是沒被修改過,用oep所在的節做爲代碼節來判斷比較科學,而不是單單靠.text),保存代碼段的偏移和長度,後續解密須要,而後進行異或加密。

2.經過可選PE頭的數據目錄成員,找到保存重定位表的數據  (直接聲明一個IMAGE_SECTION_HEADER來存放),再分別申請2個內存來存放屬於代碼節的重定位數據和非代碼節的數據,並記錄其長度。

3.刪除重定位相關的數據,刪除節表,文件內容,各頭裏面的相關數據

4.獲取到當前節表的末尾,建立一個新的節,以當前文件的映射大小(SizeOfImage)爲節內存起點,以當前文件大小爲節文件起點。節屬性爲可讀可學可執行已被初始化((0x20000000 | 0x40000000 | 0x80000000 | 0x40)  = E0000040)

5.根據2保存的代碼節的重定位數據長度+4(在該節找到一個4字節的位置(可緊接着重定位數據末尾)做爲標記位,存放4個0x00進去,以便後面shellcode用來獲取目標基址與當前基址的差值,以便重定位時使用))擴充內存,並把增長了標誌位的重定位數據賦值進去。

6.把原oep保存下來,並把新增節的RVA+代碼段的重定位數據長度+4(標誌位)做爲新的OEP。

7.編寫shellcode:先經過E8,00,00,00,00方法來獲取當前新增節所在的地址,再經過節地址得到當前進程的基址(1.當前指令地址-指令偏移;2.根據重定位後的數據),而後經過偏移找到代碼段進行解密(注意是內存偏移而不是文件偏移),解密後,獲取代碼節的重定位數據(該節開始數據就是重定位數據,長度爲須要重定位的代碼節數據長度+4),進行重定位,重定位完成後跳轉到原OEP進行文件正常運行流程(此處要本身進行代碼段的重定位是由於代碼段的數據已經本身加密過了,若是不本身實現解密後再重定位,那麼解密出來的數據是加密後且重定位的數據,沒法正常運行)

8.完善新增節後的文件數據(文件大小、文件映射大小、文件代碼大小(SizeOfCode,這個節將做爲解密使用,因此也是代碼類)、節表數量等),並將原先存放文件內容的空間進行擴容realloc,擴容大小爲原大小+這個節的文件大小。(擴容後可能返回一個新的地址,原地址被收回,因此要使用各類頭的數據的時候,要從新獲取)

注意新增節的長度爲代碼段重定位數據長度+4 +5(e8 00 00 00 00)+shellcode長度,且注意內存對齊和文件對齊。

9.完善完新節後,用一樣的方法,修復原重定位節,並增長5.中的標誌位的位置到重定位表數據中(重定位塊爲4字節塊RVA+4字節塊長度+2字節塊中偏移(0x3XXX開頭有效)組成,但重定位塊爲4字節對齊,因此最小的重定位塊爲12字節),根據2.中所求得的非代碼段的重定位的數據長度,再+12+8(8字節0,用來結尾)的長度進行非代碼節的重定位數據的擴容,並根據上一個節的大小,完善該節的相關數據。記得文件大小和內存大小的對齊。並更新可選PE頭當中的相關數據。

10.將8.的非代碼段的重定位數據,拼接到文件內容的末尾。拼接前記得先對文件內容大小進行擴容。

 

附上代碼:

  1 #include <Windows.h>
  2 #include <iostream>
  3 #include <stdio.h>
  4 #include <tlhelp32.h>
  5 #include <io.h>
  6 #include <string.h>
  7 #include "Asmjit\\asmjit.h"
  8 
  9 using namespace std;
 10 using namespace asmjit;
 11 using namespace asmjit::x86;
 12 
 13 char *g_pFileSrc = NULL;
 14 int g_iTextVirtualAddr = 0; //代碼節在內存中的地址
 15 int g_iTextVirtualLen = 0;     //代碼節在內存中的長度
 16 
 17 
 18 int main()
 19 {
 20     char szFileName[] = { "C:\\Users\\Admin\\Desktop\\彈窗.exe" };
 21     HANDLE hFile = CreateFileA(szFileName,
 22         GENERIC_READ | GENERIC_WRITE,
 23         FILE_SHARE_READ | FILE_SHARE_WRITE,
 24         NULL,
 25         OPEN_EXISTING,   //獲取文件內容
 26         FILE_ATTRIBUTE_ARCHIVE,
 27         NULL);
 28 
 29     if (hFile == INVALID_HANDLE_VALUE )
 30     {
 31         printf("文件打開失敗\n");
 32         return 1;
 33     }
 34 
 35     //獲取文件大小
 36     DWORD dwFileSize = GetFileSize(hFile, NULL);
 37 
 38     //申請空間將exe讀取到內存中
 39     g_pFileSrc = new char[dwFileSize];
 40     if (NULL == g_pFileSrc)
 41     {
 42         printf("空間申請失敗\n");
 43         return false;
 44     }
 45     ReadFile(hFile, g_pFileSrc, dwFileSize, NULL, NULL);
 46     CloseHandle(hFile);
 47 
 48     PIMAGE_DOS_HEADER pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc;
 49     PIMAGE_NT_HEADERS pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew);
 50     DWORD dwSectionCount = pNtHead->FileHeader.NumberOfSections;//節表數量
 51     //經過可選PE頭的地址+可選PE頭的長度,獲得節表位置
 52     PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((DWORD)(&pNtHead->OptionalHeader) + pNtHead->FileHeader.SizeOfOptionalHeader);
 53 
 54 
 55 
 56     /////////////////////////////////////
 57     /////////////加密代碼節//////////////
 58     /////////////////////////////////////
 59     for (int i = 0; i < dwSectionCount; i++)
 60     {
 61         //經過OEP的地址所在的節肯定代碼節位置
 62         if (pNtHead->OptionalHeader.AddressOfEntryPoint >= pSection->VirtualAddress
 63             && pNtHead->OptionalHeader.AddressOfEntryPoint < (pSection->VirtualAddress + pSection->Misc.VirtualSize))
 64             //if (!strcmp((char*)pSection->Name,".text"))  //找到代碼節  
 65         {
 66             g_iTextVirtualAddr = pSection->VirtualAddress;  //後續解密須要
 67             g_iTextVirtualLen = pSection->Misc.VirtualSize;
 68             cout << pSection->Name;
 69             for (int iCount = 0; iCount < pSection->Misc.VirtualSize; iCount++)
 70             {
 71                 *(char*)(g_pFileSrc + pSection->PointerToRawData + iCount) ^= 0x35;
 72             }
 73             pSection->Characteristics |= 0x80000000;  //讓代碼節可寫,以便後續解密
 74             break;
 75         }
 76         pSection++;
 77     }
 78 
 79 
 80 
 81     /////////////////////////////////////
 82     ///////////保存重定位表信息//////////
 83     /////////////////////////////////////
 84     DWORD dwRelocRVA = pNtHead->OptionalHeader.DataDirectory[5].VirtualAddress; //獲得重定位表的RVA
 85     pNtHead->OptionalHeader.DataDirectory[5].VirtualAddress = 0;
 86     DWORD dwRelocVirtualSize = 0;//重定位表的長度
 87     pNtHead->OptionalHeader.DataDirectory[5].Size = 0;
 88     DWORD dwRelocFileAddr = 0;//重定位表的文件位置
 89     DWORD dwRelocFileLen = 0;//重定位表的文件長度
 90     char szRelocName[8] = { 0 }; //重定位表名字(可能被更名混淆,作記錄)
 91     DWORD dwRelocTab = 0;        //重定位節屬性
 92 
 93 
 94     int iTextRelocSize = 0;  //代碼節塊的大小
 95     int iNotTextRelocSize = 0;//非代碼節塊的大小
 96     char *szNotTextRelocSrc = NULL;//重定位表非代碼段數據
 97     char *szTextRelocSrc = NULL;    //重定位表代碼段數據
 98     
 99     DWORD dwReloctOffset = 0; //當前遍歷的偏移
100 
101 
102 
103 
104     /////////////////////////////////////
105     ////////拷貝並刪除重定位表數據///////
106     /////////////////////////////////////
107     pSection = (PIMAGE_SECTION_HEADER)((DWORD)(&pNtHead->OptionalHeader) + pNtHead->FileHeader.SizeOfOptionalHeader);//從新找到表頭
108     for (int i = 0; i < dwSectionCount; i++)
109     {
110         if (pSection->VirtualAddress == dwRelocRVA) //找到重定位節表,保留重定位表相關數據到內存中,隨後刪除重定位表
111         {
112             //保存重定位表數據
113             dwRelocVirtualSize = pSection->Misc.VirtualSize;
114             dwRelocFileAddr = pSection->PointerToRawData;
115             dwRelocFileLen = pSection->SizeOfRawData;
116             dwRelocTab = pSection->Characteristics;
117             strcpy(szRelocName, (char *)pSection->Name);
118 
119             PIMAGE_BASE_RELOCATION pBaseRelocation = (PIMAGE_BASE_RELOCATION)(g_pFileSrc + dwRelocFileAddr);//重定位表當前塊
120             while ((pBaseRelocation->VirtualAddress != 0) && (pBaseRelocation->SizeOfBlock != 0))  //遍歷到重定位表末尾爲止
121             {
122                 //若是當前重定位範圍在代碼段內  則記錄起來
123                 if (pBaseRelocation->VirtualAddress >= g_iTextVirtualAddr & pBaseRelocation->VirtualAddress < g_iTextVirtualAddr + g_iTextVirtualLen)
124                 {
125                     while (pBaseRelocation->VirtualAddress < g_iTextVirtualAddr + g_iTextVirtualLen) //因爲代碼段是連續的,一直遍歷到非代碼段
126                     {
127                         iTextRelocSize += pBaseRelocation->SizeOfBlock; //記錄長度
128                         pBaseRelocation = (PIMAGE_BASE_RELOCATION)((DWORD)pBaseRelocation + pBaseRelocation->SizeOfBlock);
129                     }
130                     szTextRelocSrc = (char *)realloc(szTextRelocSrc, iTextRelocSize);
131                     //從末尾-重定位長度=重定位數據  再+遍歷的偏移  獲得須要複製的數據的地址  複製長度爲因此代碼節範圍的重定位數據長度
132                     memcpy(szTextRelocSrc, g_pFileSrc + dwFileSize - dwRelocFileLen + dwReloctOffset, iTextRelocSize);
133                     dwReloctOffset += iTextRelocSize;//複製完以後  更新偏移(因爲這個這段數據連續的  所有複製完再更新)
134                 }
135                 else
136                 {
137                     szNotTextRelocSrc = (char*)realloc(szNotTextRelocSrc, iNotTextRelocSize + pBaseRelocation->SizeOfBlock); //將本來的存放重定位的空間擴容
138                     /*非代碼塊的複製源起點=重定位表位置(起始位置+末尾-重定位長度)+偏移
139                     目標位置爲剛申請出來的空間的空閒起點(起點+已賦值的長度)*/
140                     memcpy(szNotTextRelocSrc + iNotTextRelocSize ,
141                         g_pFileSrc + dwFileSize - dwRelocFileLen + dwReloctOffset, 
142                         pBaseRelocation->SizeOfBlock);
143                     dwReloctOffset += pBaseRelocation->SizeOfBlock;//此時文件偏移增長
144                     iNotTextRelocSize += pBaseRelocation->SizeOfBlock;//記錄非代碼段的長度
145                     pBaseRelocation = (PIMAGE_BASE_RELOCATION)((DWORD)pBaseRelocation + pBaseRelocation->SizeOfBlock);                    
146                 }
147                 
148             }
149             /*此時,原重定位的數據已經分紅了非代碼段(szNotTextRelocSrc)和代碼段(szTextRelocSrc)兩部分
150             還原時,還原非代碼段的數據便可*/
151 
152             //文件內容+文件長度 = 取到文件末尾  再-當前重定位表的長度,取到重定位表的起始位置
153             memset(g_pFileSrc + dwFileSize - dwRelocFileLen, 0, dwRelocFileLen);//把重定位表數據用0覆蓋
154             memset(pSection, 0, sizeof(IMAGE_SECTION_HEADER));
155             pNtHead->FileHeader.NumberOfSections--;
156             //調整文件內存大小
157             int iAlignmentSize = dwRelocVirtualSize % pNtHead->OptionalHeader.SectionAlignment;
158             if (!iAlignmentSize)
159             {
160                 pNtHead->OptionalHeader.SizeOfImage -= dwRelocVirtualSize;        //調整文件內存大小
161             }
162             else
163             {
164                 pNtHead->OptionalHeader.SizeOfImage =
165                     pNtHead->OptionalHeader.SizeOfImage
166                     - (dwRelocVirtualSize - iAlignmentSize + pNtHead->OptionalHeader.SectionAlignment);
167             }
168             dwFileSize -= dwRelocFileLen;
169             break;
170         }
171         pSection++;
172     }
173 
174 
175 
176     //找到最後一個節表,獲得新增節的文件起點和映射到內存中的起點
177     pSection = (PIMAGE_SECTION_HEADER)((DWORD)(&pNtHead->OptionalHeader) + pNtHead->FileHeader.SizeOfOptionalHeader);
178     pSection += (pNtHead->FileHeader.NumberOfSections - 1);
179     //文件起點   //文件長度本來就已經對齊  無需再對齊
180     int iNewSectionFileAddr = pSection->PointerToRawData + pSection->SizeOfRawData;
181 
182     //文件映射起點
183     int iNewSectionFileMapAddr = 0;
184     int iMemoryAlignment = pSection->Misc.VirtualSize % pNtHead->OptionalHeader.SectionAlignment;
185     if (!iMemoryAlignment)
186     {
187         iNewSectionFileMapAddr = pSection->VirtualAddress + pSection->Misc.VirtualSize;
188     }
189     else
190     {
191         iNewSectionFileMapAddr = pSection->VirtualAddress
192             + pSection->Misc.VirtualSize
193             + (pNtHead->OptionalHeader.SectionAlignment - iMemoryAlignment);
194     }
195 
196 
197     /////////////////////////////////////
198     ////////////開始新增節///////////////
199     /////////////////////////////////////
200     pSection++;
201     /*記錄當前屬性 方便調試*/
202     memset(pSection, 0, sizeof(IMAGE_SECTION_HEADER));    //初始化當前節屬性
203     memcpy(pSection->Name, ".kd", 3);                        //節名字
204     pSection->VirtualAddress = iNewSectionFileMapAddr;                //節的內存起始地址
205     pSection->PointerToRawData = iNewSectionFileAddr;                //節的文件起始地址
206     
207     pSection->Characteristics = (0x20000000 | 0x40000000 | 0x80000000 | 0x40); //節屬性 可讀可寫可執行已被初始化
208     pNtHead->FileHeader.NumberOfSections += 1;            //節表數量+1
209     
210     
211     //做爲標誌位  後面獲取內存基址使用
212     int iTabOffset = iTextRelocSize;            //標誌位偏移
213     int iTabRva = pSection->VirtualAddress;//標誌位所在的RVA起點
214     int iTextAlignment = iTextRelocSize + 4 ; //站位後的代碼節重定位數據長度
215     
216     szTextRelocSrc = (char*)realloc(szTextRelocSrc,iTextAlignment);  
217     memset(szTextRelocSrc + iTextRelocSize, 0, 4);//重定位標記
218     //g_pFileSrc = (char*)realloc(g_pFileSrc, dwFileSize + iTextAlignment);
219     //memcpy(g_pFileSrc + dwFileSize , szTextRelocSrc, iTextAlignment);//添加代碼節的重定位數據
220     //dwFileSize += iTextAlignment;
221 
222     int iOldOEP = pNtHead->OptionalHeader.AddressOfEntryPoint;//原來的oep
223     //將OEP改成新增節偏移   (原始的內存長度(映射末尾)-當前映射基址)  
224     pNtHead->OptionalHeader.AddressOfEntryPoint = pSection->VirtualAddress + iTextAlignment;
225     int iNewOEP = pNtHead->OptionalHeader.AddressOfEntryPoint;
226     /////////////////////////////////////
227     ////////////編寫shellcode///////////
228     /////////////////////////////////////
229     JitRuntime        _x86RunTimeObject;
230     X86Assembler    a(&_x86RunTimeObject); //重定位
231 
232 
233     // 動態編譯過程
234     // 也就是組織shellcode的過程
235     //獲得實際加載基址:1.利用重定位 (還能夠直接利用shellcode自定位得到)
236     int ioldIB = pNtHead->OptionalHeader.ImageBase;//目標基址
237     extern int g_iTextVirtualAddr;//解密須要
238     extern int g_iTextVirtualLen;
239 
240     //獲取進程基址
241     char szGetOEP[] = { 0xE8,0x00,0x00,0x00,0x00 }; //同理jit.call(0x00000000);
242     a.pop(eax);
243     a.sub(eax, 5);//此時獲得oep所在的地址 oep距離基址隔着
244     a.mov(ebx, eax);//備份一個OEP所在進程地址
245     a.sub(eax, iNewOEP);//OEP所在的基址-偏移  獲得基址
246     a.mov(ebp, eax);    //保存進程基址到ebp
247 
248     a.sub(ebx, iTextAlignment - iTabOffset);//獲得標誌塊的位置
249     a.mov(edx, dword_ptr(ebx));//獲得重定位後該地址的值  該值爲目標基址與實際基址的差值(因爲之前是0,重定位後的值=0-目標+實際)
250     
251      
252     //解密代碼段
253     Label begin = a.newLabel();
254     Label over = a.newLabel();
255     //此時ebp爲實際加載基址
256     a.mov(esi, ebp);
257     a.add(esi, g_iTextVirtualAddr);//esi爲代碼段的起點
258     a.mov(edi, 0);//edi爲循環偏移
259     a.bind(begin);
260     a.cmp(edi, g_iTextVirtualLen);
261     a.jnl(over);
262     a.mov(ecx, esi);
263     a.add(ecx, edi); //開始解密
264     a.movsx(al, byte_ptr(ecx));
265     a.xor_(al, 0x35);
266     a.mov(byte_ptr(ecx), al);
267     a.inc(edi);
268     a.jmp(begin);
269     a.bind(over);//解密完畢
270     
271 
272     //代碼節重定位
273     /*基址爲代碼節的重定位數據、iTextRelocSize代碼節的長度、ebp程序基址、edi遍歷偏移*/
274     Label TextBegin = a.newLabel(); //代碼節遍歷起點
275     Label TextOver = a.newLabel();  //代碼節遍歷終點    
276     Label LumpBegin =a.newLabel(); //代碼節的塊遍歷起點
277     Label LumpOver = a.newLabel();  //代碼節的塊的遍歷終點
278 
279     /*重定位數據:基址+iTextbAddr、數據長度:iTextRelocSize
280     edi程序基址、esi重定位數據基址(基址+iTextbAddr)*/
281     int iTextOffset = pSection->VirtualAddress; //重定位所在的偏移
282     
283     
284     a.push(ebp);
285     a.mov(ebp, esp);
286     a.sub(esp, 16);//-16塊RVA -12塊長度 -8塊循環下標 -4塊內偏移(0x3XXX) ebp即程序基址
287     a.mov(dword_ptr(ebp, -4), edx);//把差值保留在edx中
288 
289     a.cmp(dword_ptr(ebp), ioldIB);
290     a.je(TextOver);//當前進程基址=預計基址 則無需重定位
291     a.mov(edi, 0); //edi遍歷偏移
292     a.bind(TextBegin);//節循環起點
293     a.cmp(edi, iTextRelocSize);//遍歷下標大於等於重定位長度  則遍歷完成
294     a.jnl(TextOver);
295     a.mov(esi, dword_ptr(ebp));//獲得進程基址
296     a.add(esi, iTextOffset);//esi爲重定位數據的基址
297     a.mov(eax, dword_ptr(esi, edi));
298     a.cmp(eax, 0);  //若是爲0 則遍歷完畢
299     a.je(TextOver);
300     a.mov(dword_ptr(ebp, -16), eax);//塊RVA
301     a.mov(edx, 4);
302     a.add(edx, edi);
303     a.mov(eax, dword_ptr(esi, edx));
304     a.mov(dword_ptr(ebp, -12), eax);//塊長度
305     a.mov(dword_ptr(ebp,-8), 8); //塊內循環偏移   從第8位開始 4RVA+4SIZE
306 
307     a.bind(LumpBegin);//節循環起點
308     a.mov(ebx, dword_ptr(ebp, -8)); //ebx塊內偏移
309     a.cmp(ebx, dword_ptr(ebp, -12));
310     a.jnl(LumpOver);
311     a.mov(ecx, esi);//重定位數據基址
312     a.add(ecx, edi);//當前遍歷偏移
313     a.movzx(eax, word_ptr(ecx, ebx));
314     a.add(dword_ptr(ebp, -8), 2);//塊內偏移+2
315     a.cmp(eax, 0); //爲0 則遍歷完畢當前塊
316     a.je(LumpOver);
317     a.xor_(eax, 0x3000);
318     a.add(eax, dword_ptr(ebp, -16));//+塊RVA
319     a.add(eax, dword_ptr(ebp));//獲得重定位地址
320     a.mov(edx, dword_ptr(eax));//得到裏面的數據
321     a.add(edx, dword_ptr(ebp, -4));
322     /*a.sub(edx, ioldIB);
323     a.add(edx, dword_ptr(ebp));*/
324     a.mov(dword_ptr(eax), edx);//重定位成功
325     a.jmp(LumpBegin);
326     a.bind(LumpOver);//節循環終點
327     a.add(edi, dword_ptr(ebp, -12));
328     a.jmp(TextBegin);
329     a.bind(TextOver);//節循環終點
330     
331     a.add(esp, 16);//-16
332     a.pop(ebp);
333     //回到原OEP  此時ebp爲程序基址
334     a.mov(ebx, ebp);
335     a.add(ebx, iOldOEP);//當前進程基址+原OEP
336     a.jmp(ebx);
337 
338     // 生成機器碼
339     // 也叫生成shellcode
340     // 使用一個函數指針指向
341     PVOID pCode = a.make();
342     int iJitSize = a.getCodeSize() + sizeof(szGetOEP);
343     iTextAlignment += iJitSize;
344 
345     if (!(iTextAlignment % pNtHead->OptionalHeader.FileAlignment))  //節文件長度   根據代碼段重定位數據長度
346     {
347         pSection->SizeOfRawData = iTextAlignment;
348     }
349     else
350     {
351         pSection->SizeOfRawData = iTextAlignment
352             + pNtHead->OptionalHeader.FileAlignment
353             - (iTextAlignment % pNtHead->OptionalHeader.FileAlignment);
354     }
355     if (!(iTextAlignment % pNtHead->OptionalHeader.SectionAlignment))  //節內存長度
356     {
357         pSection->Misc.VirtualSize = iTextAlignment;
358     }
359     else
360     {
361         pSection->Misc.VirtualSize = iTextAlignment
362             + pNtHead->OptionalHeader.SectionAlignment
363             - (iTextAlignment % pNtHead->OptionalHeader.SectionAlignment);
364     }
365     pNtHead->OptionalHeader.SizeOfCode += pSection->SizeOfRawData;        //新增節的內容一樣爲代碼  
366     pNtHead->OptionalHeader.SizeOfImage += pSection->Misc.VirtualSize;
367 
368     int iNewSecionFileSize = pSection->SizeOfRawData;
369     g_pFileSrc = (char*)realloc(g_pFileSrc, dwFileSize + iNewSecionFileSize);
370     memcpy(g_pFileSrc + dwFileSize, szTextRelocSrc, iTextRelocSize + 4);//添加代碼節的重定位數據
371     memcpy(g_pFileSrc + dwFileSize + iTextRelocSize + 4, szGetOEP, sizeof(szGetOEP));//壓入求基址指令
372     memcpy(g_pFileSrc + dwFileSize + iTextRelocSize + 4 + sizeof(szGetOEP), pCode, a.getCodeSize()); //壓入shellcode
373     dwFileSize += iNewSecionFileSize;
374 
375 
376 
377     /////////////////////////////////////
378     //////////修復重定位表//////////////
379     /////////////////////////////////////
380     pDosHead = (PIMAGE_DOS_HEADER)g_pFileSrc;
381     pNtHead = (PIMAGE_NT_HEADERS)((DWORD)pDosHead + pDosHead->e_lfanew);
382     dwSectionCount = pNtHead->FileHeader.NumberOfSections;//節表數量
383     //經過可選PE頭的地址+可選PE頭的長度,獲得節表位置
384     pSection = (PIMAGE_SECTION_HEADER)((DWORD)(&pNtHead->OptionalHeader) + pNtHead->FileHeader.SizeOfOptionalHeader);
385     pSection += dwSectionCount;  //pSection的首地址+(節表數量*40)
386     memset(pSection, 0, sizeof(IMAGE_SECTION_HEADER));            //初始化
387 
388     //重定位表屬性
389     strcpy((char*)pSection->Name, szRelocName);                    //節名
390     /*若是原有的重定位表的虛擬空間大小比實際存放數據的空間大10字節(用於新增新的重定位塊),則無需擴大,不然則要按節對齊尺寸擴大
391     前12字節爲數據,後40爲一個重定位塊的長度 (以全爲0的重定位塊爲結尾)  */
392     pSection->PointerToRawData = dwFileSize;
393     int iRelocSize = iNotTextRelocSize + 20;
394     if (!(iRelocSize % pNtHead->OptionalHeader.FileAlignment))
395     {
396         pSection->SizeOfRawData = iRelocSize;
397     }
398     else
399     {
400         pSection->SizeOfRawData = iRelocSize
401             + pNtHead->OptionalHeader.FileAlignment
402             - (iRelocSize % pNtHead->OptionalHeader.FileAlignment);
403     }
404     int iAddrSize = pSection->SizeOfRawData; //這個節的文件長度
405     pSection->VirtualAddress = pNtHead->OptionalHeader.SizeOfImage;//節RVA起始位置
406     if (!(iRelocSize % pNtHead->OptionalHeader.SectionAlignment))
407     {
408         pSection->Misc.VirtualSize = iRelocSize;
409     }
410     else
411     {
412         pSection->Misc.VirtualSize = iRelocSize
413             + pNtHead->OptionalHeader.SectionAlignment
414             - (iRelocSize % pNtHead->OptionalHeader.SectionAlignment);
415     }
416     pSection->Characteristics = dwRelocTab | 0x80000000;
417     pNtHead->OptionalHeader.DataDirectory[5].VirtualAddress = pSection->VirtualAddress;
418     pNtHead->OptionalHeader.DataDirectory[5].Size = iNotTextRelocSize + 12 + 8;
419     pNtHead->FileHeader.NumberOfSections++; 
420     pNtHead->OptionalHeader.SizeOfImage += pSection->Misc.VirtualSize;
421     
422     
423     //重定位的塊以4字節對齊 
424     char szAddReloc[12] = { 0 };
425     int iTabLen = sizeof(szAddReloc);
426     int iTabAddr = iTabRva + iTabOffset;
427     iTabRva = iTabAddr & 0xfff000;
428     iTabOffset = (iTabAddr & 0xfff) | 0x3000;
429     memcpy(szAddReloc, &iTabRva, 12);//RVA
430     memcpy(szAddReloc + 4, &iTabLen, 4);//size
431     memcpy(szAddReloc + 8, &iTabOffset, 4);//偏移  位於第8個字節後面
432 
433     szNotTextRelocSrc = (char *)realloc(szNotTextRelocSrc, iAddrSize);//增長重定位數據
434     memcpy(szNotTextRelocSrc + iNotTextRelocSize, szAddReloc, sizeof(szAddReloc));//把新的重定位塊數據加到原重定位塊數據上
435     memset(szNotTextRelocSrc + iNotTextRelocSize + sizeof(szAddReloc), 0, 8);
436 
437     g_pFileSrc = (char*)realloc(g_pFileSrc, dwFileSize + iAddrSize);//把空間大小增長重定位節所佔文件大小
438     
439     memcpy(g_pFileSrc + dwFileSize, szNotTextRelocSrc, iAddrSize);
440     dwFileSize += iAddrSize;//更新文件大小
441 
442 
443     HANDLE hNewFile = CreateFileA("C:\\Users\\Admin\\Desktop\\彈窗測試.exe",
444         GENERIC_READ | GENERIC_WRITE,
445         FILE_SHARE_READ | FILE_SHARE_WRITE,
446         NULL,
447         CREATE_ALWAYS,   //建立並覆蓋上一個文件
448         FILE_ATTRIBUTE_ARCHIVE,
449         NULL);
450     
451     if (hNewFile == INVALID_HANDLE_VALUE)
452     {
453         printf("文件保存失敗\n");
454         return 1;
455     }
456     int iError = GetLastError();
457     LPDWORD iNum = NULL;
458     WriteFile(hNewFile, g_pFileSrc, dwFileSize, iNum, NULL); //寫入文件
459     CloseHandle(hNewFile);
460 
461     MessageBoxA(0, "by:阿怪\n          2020.8.25", "加密成功", 0);
462     system("pause");
463 }

運行效果:

 

 

shellcode的例子各位能夠在網上搜索或者本身想辦法用匯編轉換成機器碼輸入。

有疑惑或者不對的地方歡迎在評論指出,感謝

相關文章
相關標籤/搜索