So I started off working on this project this morning and I'm quite happy where I am right now with it. I just want to show people that creating a good polymorphic engine is not that hard and doesn't take a year to develop (unless really good or if you are going for metamorphic). This is far from a complete project but it's a start, and maybe will help someone to understand the concepts of polymorphic code better.
It dries out pretty quick and mostl likely after a few hundred runs won't find any code to patch (depending on the size of your executable) and most likely can jump over sections without finding anything to patch, but as said, I'm in early stages with it.
Anyways, here's the code.
I used my own modified version of z0mbie's ADE32 to calculate the opcode length
It dries out pretty quick and mostl likely after a few hundred runs won't find any code to patch (depending on the size of your executable) and most likely can jump over sections without finding anything to patch, but as said, I'm in early stages with it.
Anyways, here's the code.
C++:
#pragma once
#include <Windows.h>
#include <ctime>
#include <cstdlib>
#include "ADE32.h"
class CPolymorphic
{
private:
unsigned char regs32[8];
inline unsigned char Read (DWORD dwAddress)
{
return *(unsigned char*)dwAddress;
}
inline void Write (DWORD dwAddress, unsigned char val)
{
*(unsigned char*)dwAddress = val;
}
inline int randomize(int min, int max)
{
return (1 + int((max - min + 1)*rand()/(RAND_MAX + 1.0)));
}
bool PatchOpcode(DWORD dwAddress, BYTE bytes[], unsigned int bytecount);
void ObfuscateOpcode(DWORD dwAddress, int opcodeLen);
public:
CPolymorphic(void);
~CPolymorphic(void);
void Run(DWORD dwStart, DWORD dwLength);
};
C++:
#include "stdafx.h"
#include "Polymorphic.h"
#include <iostream>
using namespace std;
void CPolymorphic::ObfuscateOpcode(DWORD dwAddress, int opcodeLen)
{
if(opcodeLen == 1)
{
if ((this->randomize(1, 2) == 1) && (this->Read(dwAddress) == 0xC3 && this->Read(dwAddress + 1) == 0xCC && this->Read(dwAddress + 2) == 0xCC)) // retn -> retn 0
{
cout << hex << "retn -> retn 0" << dwAddress << endl;
this->Write(dwAddress, 0xC2);
this->Write(dwAddress + 1, 0x00);
this->Write(dwAddress + 2, 0x00);
}
else if (this->Read(dwAddress) == 0xCC) // int 3
{
if (this->Read(dwAddress + 1) == 0xCC)
{
if (this->randomize(1, 10) > 5)
{
cout << hex << "0xCC -> mov reg, reg" << dwAddress << endl;
this->Write(dwAddress, 0x8B); // mov
this->Write(dwAddress + 1, regs32[this->randomize(0, 7)]); // reg
}
else
{
cout << hex << "0xCC -> rand at 0x" << dwAddress << endl;
this->Write(dwAddress, this->randomize(0, 0xFF));
}
}
else
{
cout << hex << "0xCC -> rand at 0x" << dwAddress << endl;
this->Write(dwAddress, this->randomize(0, 0xFF));
}
}
else if (this->Read(dwAddress) == 0x90 && this->Read(dwAddress + 1) == 0x90) // nop
{
cout << hex << "0x90 0x90 -> mov reg, reg at 0x" << dwAddress << endl;
this->Write(dwAddress, 0x8B); // mov
this->Write(dwAddress + 1, regs32[this->randomize(0, 7)]); // reg
}
}
else if (opcodeLen == 2)
{
if (this->Read(dwAddress) == 0x8B) // mov
{
if (this->Read(dwAddress + 1) == 0xC0) // mov eax, eax
{
cout << "patched mov eax, eax" << endl;
if (this->randomize(1, 10) > 4)
{
this->Write(dwAddress, 0x8B); // mov
this->Write(dwAddress + 1, regs32[this->randomize(0, 7)]); // reg
}
else
{
this->Write(dwAddress, 0x90); // nop
this->Write(dwAddress + 1, 0x90); // nop
}
}
else if (this->Read(dwAddress + 1) == 0xDB) // mov ebx, ebx
{
cout << "patched mov ebx, ebx" << endl;
if (this->randomize(1, 10) > 4)
{
this->Write(dwAddress, 0x8B); // mov
this->Write(dwAddress + 1, regs32[this->randomize(0, 7)]); // reg
}
else
{
this->Write(dwAddress, 0x90); // nop
this->Write(dwAddress + 1, 0x90); // nop
}
}
else if (this->Read(dwAddress + 1) == 0xC9) // mov ecx, ecx
{
cout << "patched mov ecx, ecx" << endl;
if (this->randomize(1, 10) > 4)
{
this->Write(dwAddress, 0x8B); // mov
this->Write(dwAddress + 1, regs32[this->randomize(0, 7)]); // reg
}
else
{
this->Write(dwAddress, 0x90); // nop
this->Write(dwAddress + 1, 0x90); // nop
}
}
else if (this->Read(dwAddress + 1) == 0xD2) // mov edx, edx
{
cout << "patched mov edx, edx" << endl;
if (this->randomize(1, 10) > 4)
{
this->Write(dwAddress, 0x8B); // mov
this->Write(dwAddress + 1, regs32[this->randomize(0, 7)]); // reg
}
else
{
this->Write(dwAddress, 0x90); // nop
this->Write(dwAddress + 1, 0x90); // nop
}
}
else if (this->Read(dwAddress + 1) == 0xE4) // mov esp, esp
{
cout << "patched mov esp, esp" << endl;
if (this->randomize(1, 10) > 4)
{
this->Write(dwAddress, 0x8B); // mov
this->Write(dwAddress + 1, regs32[this->randomize(0, 7)]); // reg
}
else
{
this->Write(dwAddress, 0x90); // nop
this->Write(dwAddress + 1, 0x90); // nop
}
}
else if (this->Read(dwAddress + 1) == 0xED) // mov ebp, ebp
{
cout << "patched mov ebp, ebp" << endl;
if (this->randomize(1, 10) > 4)
{
this->Write(dwAddress, 0x8B); // mov
this->Write(dwAddress + 1, regs32[this->randomize(0, 7)]); // reg
}
else
{
this->Write(dwAddress, 0x90); // nop
this->Write(dwAddress + 1, 0x90); // nop
}
}
else if (this->Read(dwAddress + 1) == 0xF6) // mov esi, esi
{
cout << "patched mov esi, esi" << endl;
if (this->randomize(1, 10) > 4)
{
this->Write(dwAddress, 0x8B); // mov
this->Write(dwAddress + 1, regs32[this->randomize(0, 7)]); // reg
}
else
{
this->Write(dwAddress, 0x90); // nop
this->Write(dwAddress + 1, 0x90); // nop
}
}
else if (this->Read(dwAddress + 1) == 0xFF) // mov edi, edi
{
cout << "patched mov edi, edi" << endl;
if (this->randomize(1, 10) > 4)
{
this->Write(dwAddress, 0x8B); // mov
this->Write(dwAddress + 1, regs32[this->randomize(0, 7)]); // reg
}
else
{
this->Write(dwAddress, 0x90); // nop
this->Write(dwAddress + 1, 0x90); // nop
}
}
}
}
}
void CPolymorphic::Run(DWORD dwStart, DWORD dwLength)
{
DWORD dwCurrent = dwStart;
MEMORY_BASIC_INFORMATION mbi;
while (true)
{
VirtualQuery((void*)dwCurrent, &mbi, sizeof(mbi));
// Check if the memory page is mapped and accessible
if (mbi.State == MEM_COMMIT && mbi.Protect != 0x1)
{
DWORD prevAccess, newAccess, startAddress(dwCurrent);
// Enable writing access to the code
VirtualProtect((PBYTE)dwCurrent, ((DWORD)mbi.BaseAddress + mbi.RegionSize) - startAddress, PAGE_EXECUTE_READWRITE, &prevAccess);
while ((dwCurrent < (DWORD)mbi.BaseAddress + static_cast<DWORD>(mbi.RegionSize)) && (dwCurrent < dwStart + dwLength))
{
int nOpcodeLen = oplen((BYTE*)dwCurrent);
if (nOpcodeLen > 0)
{
this->ObfuscateOpcode(dwCurrent, nOpcodeLen);
dwCurrent += nOpcodeLen;
}
else
dwCurrent++;
}
// Apply old access to the code
VirtualProtect((PBYTE)startAddress, ((DWORD)mbi.BaseAddress + mbi.RegionSize) - startAddress, prevAccess, &newAccess);
}
else
dwCurrent = (DWORD)mbi.BaseAddress + mbi.RegionSize + 0x1; // Go to the next region
if (dwCurrent >= dwStart + dwLength)
break;
}
}
CPolymorphic::CPolymorphic(void)
{
srand((unsigned)time(0));
this->regs32[0] = 0xC0;
this->regs32[1] = 0xDB;
this->regs32[2] = 0xC9;
this->regs32[3] = 0xD2;
this->regs32[4] = 0xE4;
this->regs32[5] = 0xED;
this->regs32[6] = 0xF6;
this->regs32[7] = 0xFF;
}
CPolymorphic::~CPolymorphic(void)
{
}
I used my own modified version of z0mbie's ADE32 to calculate the opcode length