在軟件安全裏,有一種保護手段叫加密,通常狀況下都是爲代碼段加密,使本來的代碼沒法被靜態分析,只能動態調試。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的例子各位能夠在網上搜索或者本身想辦法用匯編轉換成機器碼輸入。
有疑惑或者不對的地方歡迎在評論指出,感謝