├── .gitattributes ├── .gitignore ├── PeCrypter.cpp ├── PeCrypter.h ├── PeExplorer.cpp ├── PeExplorer.h ├── README.md ├── includes.h └── main.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /PeCrypter.cpp: -------------------------------------------------------------------------------- 1 | #include "includes.h" 2 | 3 | 4 | 5 | PeCrypter::~PeCrypter() 6 | { 7 | TextSection = nullptr; 8 | LastSection = nullptr; 9 | g_pPe = nullptr; 10 | Key = 0; 11 | } 12 | 13 | PeCrypter::PeCrypter(PeExplorer* Pe) 14 | { 15 | g_pPe = Pe; 16 | srand(time(NULL)); 17 | Key = rand() % 255; 18 | 19 | TextSection = g_pPe->GetSectionByCharacteristics(IMAGE_SCN_CNT_CODE); 20 | TextSection->Characteristics |= IMAGE_SCN_MEM_WRITE; 21 | 22 | LastSection = g_pPe->GetLastSection(); 23 | 24 | } 25 | 26 | template 27 | bool PeCrypter::PatchBytesByVal(DWORD DestAddress, DWORD SizeOfCode, LPVOID SrcAddress, T ValToLookFor) 28 | { 29 | for (int i = 0; i < SizeOfCode; ++i) 30 | { 31 | if (*(T*)(DestAddress + i) == ValToLookFor) 32 | { 33 | memcpy((PVOID)(DestAddress + i), SrcAddress, sizeof(T)); 34 | return true; 35 | } 36 | } 37 | return false; 38 | } 39 | 40 | void PeCrypter::EncryptBytes(DWORD Source, DWORD Size) 41 | { 42 | for (int i = 0; i < Size; ++i) 43 | *(BYTE*)(Source + i) ^= Key; 44 | } 45 | 46 | 47 | bool PeCrypter::Crypt(const char* ShellPtr, DWORD ShellSize) 48 | { 49 | printf("Crypting .text section...\n"); 50 | 51 | srand(time(NULL)); 52 | Key = rand() % 255; // Generate random key 53 | 54 | TextSection = g_pPe->GetSectionByCharacteristics(IMAGE_SCN_CNT_CODE); // Get code section, the name of it might variate. Therefore search for characteristics 55 | if (TextSection == nullptr) 56 | goto cleanup; 57 | TextSection->Characteristics |= IMAGE_SCN_MEM_WRITE; // Add write characteristics for encrypting the section 58 | 59 | LastSection = g_pPe->GetLastSection(); // Get last section for adding stub 60 | if (LastSection == nullptr) 61 | goto cleanup; 62 | 63 | EncryptBytes((DWORD)g_pPe->pMap + TextSection->PointerToRawData, TextSection->SizeOfRawData); // Encrypt section, keep in mind that the base of the PE mapped into memory is based at pMap not ImageBase 64 | // Encrypt the whole section, including alignment, not only VirtualSize 65 | 66 | LastSection->Characteristics |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; // Add characteristics for LastSection, preparing it for stub 67 | 68 | DWORD NewEIP = LastSection->VirtualAddress + LastSection->Misc.VirtualSize; // NewEIP should be the VirtualAddress + VirtualSize of the section before adding the stub size 69 | DWORD OldEIP = g_pPe->GetOptionalHeader()->AddressOfEntryPoint + g_pPe->GetOptionalHeader()->ImageBase; 70 | g_pPe->GetOptionalHeader()->AddressOfEntryPoint = NewEIP; 71 | 72 | LastSection->Misc.VirtualSize += ShellSize; // Add stub size 73 | 74 | DWORD OldRawSize = LastSection->SizeOfRawData; 75 | 76 | DWORD NewRawSize = AlignUp(LastSection->Misc.VirtualSize, g_pPe->GetOptionalHeader()->FileAlignment); // Align the section with FileAlignment. The RawDataSize should be dividable by the FileAlignment 77 | LastSection->SizeOfRawData = NewRawSize; // Thats why it should be the VirtualSize rounded up to be dividable by FileAlignment 78 | 79 | g_pPe->GetOptionalHeader()->SizeOfImage += (NewRawSize - OldRawSize); // Add the potentially added size of the section RawSize to SizeOfImage 80 | 81 | DWORD Dst = (DWORD)g_pPe->pMap + LastSection->Misc.VirtualSize - ShellSize + LastSection->PointerToRawData; // The destination to copy the stub to should be the base of the mapped PE + Pointer2RawData - StubSize 82 | // This will point to the end of the section VirtualSize and to the beginning of the stub 83 | 84 | DWORD size = TextSection->SizeOfRawData; // The size to be decrypted should be the RawSize of the code section 85 | 86 | DWORD start = TextSection->VirtualAddress + g_pPe->GetOptionalHeader()->ImageBase; // And the start address of the decryption should be the VirtualAddress of the code section + ImageBase, for it's loaded. 87 | 88 | 89 | memcpy((PVOID)Dst, ShellPtr, ShellSize); 90 | 91 | if (!PatchBytesByVal(Dst, ShellSize, &start, 0xAAAAAAAA)) // Replace the first DWORD of A's with the start address 92 | goto cleanup; 93 | if (!PatchBytesByVal(Dst, ShellSize, &size, 0xAAAAAAAA)) // Replace the second DWORD of A's with the size 94 | goto cleanup; 95 | if (!PatchBytesByVal(Dst, ShellSize, &Key, 0xAAAAAAAA)) // Replace the third DWORD of A's with the key 96 | goto cleanup; 97 | if (!PatchBytesByVal(Dst, ShellSize, &OldEIP, 0xAAAAAAAA)) // Replace the fourth DWORD of A's with the Old Entry Point to return to 98 | goto cleanup; 99 | 100 | return true; 101 | 102 | cleanup: 103 | PeCrypter::~PeCrypter(); 104 | return false; 105 | } 106 | -------------------------------------------------------------------------------- /PeCrypter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | class PeCrypter 3 | { 4 | public: 5 | ~PeCrypter(); 6 | PeCrypter(PeExplorer* g_pPe); 7 | bool Crypt(const char* ShellPtr, DWORD ShellSize); 8 | 9 | private: 10 | DWORD AlignDown(DWORD val, DWORD align) 11 | { 12 | return (val & ~(align - 1)); 13 | } 14 | 15 | DWORD AlignUp(DWORD val, DWORD align) 16 | { 17 | return ((val & (align - 1)) ? AlignDown(val, align) + align : val); 18 | } 19 | 20 | template 21 | bool PatchBytesByVal(DWORD DestAddress, DWORD SizeOfCode, LPVOID SrcAddress, T ValToLookFor); 22 | void EncryptBytes(DWORD Source, DWORD Size); 23 | 24 | DWORD Key = 0; 25 | PIMAGE_SECTION_HEADER LastSection = nullptr; 26 | PIMAGE_SECTION_HEADER TextSection = nullptr; 27 | PeExplorer* g_pPe = nullptr; 28 | }; 29 | 30 | -------------------------------------------------------------------------------- /PeExplorer.cpp: -------------------------------------------------------------------------------- 1 | #include "includes.h" 2 | 3 | 4 | 5 | PeExplorer::~PeExplorer() 6 | { 7 | 8 | if (pMap != nullptr) 9 | { 10 | UnmapViewOfFile(pMap); 11 | FileSize = -1; 12 | pMap = nullptr; 13 | } 14 | 15 | SectionHeaderList.clear(); 16 | pDosHeader = nullptr; 17 | pNtHeaders = nullptr; 18 | pFileHeader = nullptr; 19 | pOptionalHeader = nullptr; 20 | } 21 | 22 | // Overloaded Function to map a PE file to memory 23 | bool PeExplorer::Explore(const char* FileName, DWORD ExtraSize) 24 | { 25 | printf("Mapping PE File...\n"); 26 | 27 | int retries = 0; 28 | HANDLE FileHandle = INVALID_HANDLE_VALUE; 29 | 30 | do 31 | { 32 | FileHandle = CreateFile(FileName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 33 | if (FileHandle == INVALID_HANDLE_VALUE) 34 | { 35 | if (GetLastError() == ERROR_SHARING_VIOLATION) 36 | { 37 | ++retries; 38 | Sleep(250); 39 | continue; 40 | } 41 | else 42 | break; 43 | } 44 | else 45 | break; 46 | } while (retries < 10); 47 | 48 | if (FileHandle == INVALID_HANDLE_VALUE) 49 | { 50 | PeExplorer::~PeExplorer(); 51 | printf("File Could Not Be Read. Error: 0x%X\n", GetLastError()); 52 | return false; 53 | } 54 | 55 | FileSize = GetFileSize(FileHandle, NULL); 56 | FileSize += ExtraSize; 57 | 58 | HANDLE hMap = CreateFileMapping(FileHandle, NULL, PAGE_READWRITE, 0, FileSize, NULL); 59 | if (hMap == INVALID_HANDLE_VALUE) 60 | { 61 | CloseHandle(FileHandle); 62 | printf("Could not CreateFileMapping. Error: 0x%X\n", GetLastError()); 63 | std::cin.get(); 64 | return 0; 65 | } 66 | 67 | pMap = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, FileSize); 68 | if (pMap == nullptr) 69 | { 70 | CloseHandle(FileHandle); 71 | CloseHandle(hMap); 72 | printf("Could not Map File. Error: 0x%X\n", GetLastError()); 73 | std::cin.get(); 74 | return 0; 75 | } 76 | 77 | CloseHandle(FileHandle); 78 | CloseHandle(hMap); 79 | 80 | if (!Explore(pMap)) 81 | { 82 | PeExplorer::~PeExplorer(); 83 | return false; 84 | } 85 | 86 | return true; 87 | } 88 | 89 | // Overloaded Function to map a PE file to memory 90 | bool PeExplorer::Explore(PVOID pPe) 91 | { 92 | printf("Reading PE File...\n"); 93 | 94 | pMap = pPe; 95 | 96 | pDosHeader = static_cast(pPe); 97 | if (!VerifyDosHeader(pDosHeader->e_magic)) 98 | { 99 | PeExplorer::~PeExplorer(); 100 | printf("Could not verify DOS header\n"); 101 | return false; 102 | } 103 | 104 | pNtHeaders = reinterpret_cast((DWORD)pDosHeader + pDosHeader->e_lfanew); // pDosHeader + sizeof(DosHeader) + sizeof(DosStub) = pNtHeaders. Keep in mind that dos header + stub does not have constant size 105 | if (!VerifyPeHeader(pNtHeaders->Signature)) 106 | { 107 | PeExplorer::~PeExplorer(); 108 | printf("Could not verify PE header\n"); 109 | return false; 110 | } 111 | 112 | pFileHeader = static_cast(&pNtHeaders->FileHeader); // Get FileHeader pointer 113 | pOptionalHeader = static_cast(&pNtHeaders->OptionalHeader); // Get OptionalHeader pointer 114 | 115 | PIMAGE_SECTION_HEADER pFirstSection = reinterpret_cast((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader); // Address of first section header = pOptionalHeader + sizeof(OptionalHeader) 116 | // Keep in mind that OptionalHeader size is not constant use ->SizeOfOptionalHeader 117 | for (int i = 0; i < pFileHeader->NumberOfSections; ++i) 118 | SectionHeaderList.push_back(pFirstSection + i); // The section headers comes after each other in memory 119 | 120 | return true; 121 | } 122 | 123 | 124 | PIMAGE_SECTION_HEADER PeExplorer::GetSectionByName(const char* SectionName) 125 | { 126 | for (auto Section : SectionHeaderList) 127 | { 128 | if (!memcmp(Section->Name, SectionName, strlen(SectionName))) 129 | return Section; 130 | } 131 | return nullptr; 132 | } 133 | 134 | PIMAGE_SECTION_HEADER PeExplorer::GetSectionByCharacteristics(DWORD Characteristics) 135 | { 136 | for (auto Section : SectionHeaderList) 137 | { 138 | if (Section->Characteristics & Characteristics) 139 | return Section; 140 | } 141 | return nullptr; 142 | } 143 | 144 | PIMAGE_SECTION_HEADER PeExplorer::GetLastSection() 145 | { 146 | PIMAGE_SECTION_HEADER LastSection = new IMAGE_SECTION_HEADER(); 147 | for (auto Section : SectionHeaderList) 148 | { 149 | if (Section->PointerToRawData > LastSection->PointerToRawData) 150 | LastSection = Section; 151 | } 152 | return LastSection; 153 | } 154 | 155 | std::vector PeExplorer::GetSectionList() 156 | { 157 | return SectionHeaderList; 158 | } 159 | 160 | PIMAGE_DOS_HEADER PeExplorer::GetDosHeader() 161 | { 162 | return pDosHeader; 163 | } 164 | 165 | PIMAGE_NT_HEADERS PeExplorer::GetNtHeaders() 166 | { 167 | return pNtHeaders; 168 | } 169 | 170 | PIMAGE_FILE_HEADER PeExplorer::GetFileHeader() 171 | { 172 | return pFileHeader; 173 | } 174 | 175 | PIMAGE_OPTIONAL_HEADER PeExplorer::GetOptionalHeader() 176 | { 177 | return pOptionalHeader; 178 | } -------------------------------------------------------------------------------- /PeExplorer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define VerifyDosHeader(signature) (signature == (WORD)'ZM' ? true : false) 3 | #define VerifyPeHeader(signature) (signature == (WORD)'EP' ? true : false) 4 | 5 | class PeExplorer 6 | { 7 | public: 8 | 9 | bool Explore(PVOID pPe); 10 | bool Explore(const char* FileName, DWORD ExtraSize); 11 | PIMAGE_SECTION_HEADER GetSectionByName(const char* SectionName); 12 | PIMAGE_SECTION_HEADER GetSectionByCharacteristics(DWORD Characteristics); 13 | PIMAGE_SECTION_HEADER GetLastSection(); 14 | ~PeExplorer(); 15 | 16 | std::vector GetSectionList(); 17 | PIMAGE_DOS_HEADER GetDosHeader(); 18 | PIMAGE_NT_HEADERS GetNtHeaders(); 19 | PIMAGE_FILE_HEADER GetFileHeader(); 20 | PIMAGE_OPTIONAL_HEADER GetOptionalHeader(); 21 | 22 | LPVOID pMap = nullptr; 23 | 24 | private: 25 | 26 | DWORD FileSize = -1; 27 | 28 | PIMAGE_DOS_HEADER pDosHeader = nullptr; 29 | PIMAGE_NT_HEADERS pNtHeaders = nullptr; 30 | PIMAGE_FILE_HEADER pFileHeader = nullptr; 31 | PIMAGE_OPTIONAL_HEADER pOptionalHeader = nullptr; 32 | std::vector SectionHeaderList; 33 | }; 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PePacker 2 | Simple PE Packer Which Encrypts .text Section 3 | I release a simple PE file packer which encrypts the .text section and adds a decryption stub to the end of the last section. The encryption is a simple xor encryption which can easily be developed to something more stronger. 4 | -------------------------------------------------------------------------------- /includes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "PeExplorer.h" 9 | #include "PeCrypter.h" -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "includes.h" 2 | 3 | 4 | const char shell[] = { 0xB8, 0xAA, 0xAA, 0xAA, 0xAA, // mov eax, 0xAAAAAAAA 5 | 0x89, 0xC1, // mov ecx, eax 6 | 0x81, 0xC1, 0xAA, 0xAA, 0xAA, 0xAA, // add ecx, 0xAAAAAAAA 7 | 0xBA, 0xAA, 0xAA, 0xAA, 0xAA, // mov edx, 0xAAAAAAAA 8 | // l1: 9 | 0x30, 0x10, // xor byte[eax], edx 10 | 0x40, // inc eax 11 | 0x39, 0xC8, // cmp eax, ecx 12 | 0x75, 0xF9, // jne l1 13 | 0x68, 0xAA, 0xAA, 0xAA, 0xAA, // push 0xAAAAAAAA 14 | 0xC3 }; // ret 15 | 16 | DWORD Size = sizeof(shell); 17 | 18 | 19 | int main(int argc, char *argv[]) 20 | { 21 | if (argc < 2) 22 | { 23 | printf("usage: filename.exe"); 24 | return 0; 25 | } 26 | 27 | PeExplorer* g_pPe = new PeExplorer(); 28 | 29 | if (!g_pPe->Explore(argv[1], Size)) 30 | { 31 | std::cin.get(); 32 | return 0; 33 | } 34 | 35 | PeCrypter* g_pCrypt = new PeCrypter(g_pPe); 36 | if (!g_pCrypt->Crypt(shell, Size)) 37 | { 38 | std::cin.get(); 39 | return 0; 40 | } 41 | 42 | 43 | g_pPe->~PeExplorer(); 44 | g_pCrypt->~PeCrypter(); 45 | 46 | 47 | 48 | std::cin.get(); 49 | return 0; 50 | } 51 | --------------------------------------------------------------------------------