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.
001 | <pre>#pragma comment(linker, "/OPT:NOREF") // this tells the linker to keep the machine code of unreferenced source code |
002 | #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 :) |
004 | #include <windows.h> // familiar? |
005 | #include <stdio.h> // i wonder what this might be, hmm... |
007 | // gets the first sections header offset |
008 | #define SECHDROFFSET(a) ((LPVOID) ( (LPBYTE) a + \ |
009 | ((PIMAGE_DOS_HEADER)a)->e_lfanew + \ |
010 | sizeof(IMAGE_NT_HEADERS))) |
012 | // those are the offsets to the |
013 | #define OEP_o 21 // original entry point |
014 | #define SEG_o 11 // virtual address of section |
015 | #define BSZ_o 1 // block size, must be a multiple of 8 |
016 | #define SZ_o 6 // section size, must be a multiple of the chosen block size |
017 | // values in the stub |
020 | // every byte in the given block is XOR'ed with its index |
021 | void _xor_block(unsigned char *pblock, unsigned int blocksize) |
025 | for(i = 0; i < blocksize; i++) |
031 | // just a wrapper around the above function |
032 | int _xor_chunk(unsigned char* pchunk, unsigned long chunksize, unsigned int blocksize) |
034 | if(chunksize % blocksize || blocksize % 8) |
037 | unsigned long index = 0; |
039 | while(index < chunksize) |
041 | _xor_block(pchunk + index, blocksize); |
048 | // this is our stub and the new entry point for the encrypted PE |
049 | __declspec(naked) void __stdcall _stub(void) |
053 | push 0xFEFEFEFE //blocksize |
054 | push 0xFDFDFDFD //chunksize |
055 | push 0xFCFCFCFC //pchunk |
057 | call _xor_chunk //decrypt |
059 | mov eax, 0x7FFFFFFF //oep |
064 | // a placeholder, used for stub size calculation |
065 | __declspec(naked) int _end(void) |
070 | // so basicly the ASM code of the above 3 (w/o _end) functions will be added to the end of the ".text" section |
071 | // after updating the proper values in the stub, ofc |
072 | // then the PE header is updated along with the section header |
073 | // and with the entry point at _stub's code its all done! wow that was easy oO |
075 | // GO GO POWER RANGERS!!! |
078 | // im not going to lecture you about those, if you are not familiar with these structures, you should go read about PE format... |
079 | PIMAGE_DOS_HEADER pDosH; |
080 | PIMAGE_NT_HEADERS pNtH; |
081 | PIMAGE_SECTION_HEADER pSecH; |
086 | DWORD dwFileSize, dwSectionSize, dwStubSize, |
087 | dwVSize, dwOldProt, dwSpot, dwGap, bytes; |
089 | LPBYTE FileBuffer, SectionBuffer; |
090 | CHAR FileName[MAX_PATH]; |
092 | // get the filename to encrypt |
093 | printf("File to encrypt: "); |
094 | scanf("%s", &FileName); |
096 | // open it and get the size |
097 | hFile = CreateFile(FileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); |
098 | dwFileSize = GetFileSize(hFile, 0); |
101 | FileBuffer = (LPBYTE) malloc(dwFileSize); |
102 | ReadFile(hFile, FileBuffer, dwFileSize, &bytes, 0); |
104 | pDosH = (PIMAGE_DOS_HEADER) FileBuffer; |
106 | //
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 |
107 | if(pDosH->e_magic != IMAGE_DOS_SIGNATURE) |
110 | pNtH = (PIMAGE_NT_HEADERS) (FileBuffer + pDosH->e_lfanew); |
112 | if(pNtH->Signature != IMAGE_NT_SIGNATURE) |
115 | pSecH = (PIMAGE_SECTION_HEADER) SECHDROFFSET(FileBuffer); |
117 | while(memcmp(pSecH->Name, ".text", 5)) // get the ".text" section header |
120 | dwVSize
= pSecH->Misc.VirtualSize; // the virtual size of the section, later
this will be used as chunksize in our stub, after proper alignment |
121 | dwSectionSize = pSecH->SizeOfRawData; // speaks for itself |
122 | dwStubSize = (DWORD) _end - (DWORD) _xor_block; // the stubsize, in bytes |
124 | SectionBuffer = (LPBYTE) malloc(dwSectionSize); // allocate memory enough to hold our raw section data |
125 | memcpy(SectionBuffer, FileBuffer + pSecH->PointerToRawData, dwSectionSize); // ... copy the data |
127 | _xor_chunk(SectionBuffer,
dwSectionSize, 256); // aaand encrypt it! you can use different block
sizes here - 8, 16, 32, 64, 128, 256, 512... |
128 | memset(SectionBuffer
+ pSecH->Misc.VirtualSize, 0, (dwSectionSize -
pSecH->Misc.VirtualSize)); // fill with zeros after the end of actual
data |
130 | dwSpot
= pSecH->Misc.VirtualSize; // this will be the offset (relative to
the beginning of the section) where we will place our stub |
132 | while(dwSpot % 16) // align it to 16 byte boundary |
135 | 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 |
136 | dwGap = dwSpot - pSecH->Misc.VirtualSize; // the gap between our stub and the end of the data |
138 | DWORD
oep = pNtH->OptionalHeader.AddressOfEntryPoint +
pNtH->OptionalHeader.ImageBase; // the original entry point, this is a
linear address |
139 | DWORD
seg = pSecH->VirtualAddress + pNtH->OptionalHeader.ImageBase; //
the section address, you guessed right, this too is a linear one |
140 | DWORD bsz = 256; // you know what this is |
142 | while(dwVSize % bsz) // we need to align it to block size |
145 | VirtualProtect(_xor_block, dwStubSize, PAGE_EXECUTE_READWRITE, &dwOldProt); // to be able to update the stub... |
147 | // and update it, blah, blah, blah... |
148 | memcpy((void *)((unsigned long) _stub + OEP_o), &oep, 4); |
149 | memcpy((void *)((unsigned long) _stub + SEG_o), &seg, 4); |
150 | memcpy((void *)((unsigned long) _stub + BSZ_o), &bsz, 4); |
151 | memcpy((void *)((unsigned long) _stub + SZ_o), &dwVSize, 4); |
153 | memcpy(SectionBuffer + dwSpot, _xor_block, dwStubSize); // place the damn thing already! |
155 | pSecH->Characteristics
= 0xE0000060; // R/W/E, executable code, initialized data. although my
experience shows that you are just fine with R/W... |
156 | pSecH->Misc.VirtualSize += dwStubSize + dwGap; // update the virtual size of the section |
157 | pNtH->OptionalHeader.AddressOfEntryPoint = pSecH->VirtualAddress + dwSpot + ( (DWORD)_stub - (DWORD)_xor_block ) ; |
159 | // and finally update the file |
160 | SetFilePointer(hFile, pSecH->PointerToRawData, 0, FILE_BEGIN); //new section data |
161 | WriteFile(hFile, SectionBuffer, dwSectionSize, &bytes, 0); |
163 | SetFilePointer(hFile, pDosH->e_lfanew, 0, FILE_BEGIN); //new PE header |
164 | WriteFile(hFile, pNtH, sizeof(IMAGE_NT_HEADERS), &bytes, 0); |
166 | SetFilePointer(hFile, ((DWORD) pSecH - (DWORD) FileBuffer), 0, FILE_BEGIN); //new section header |
167 | WriteFile(hFile, pSecH, sizeof(IMAGE_SECTION_HEADER), &bytes, 0); |
169 | // some good habits :) |
Categories:
0 comments:
Post a Comment