-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmorph.cpp
More file actions
120 lines (95 loc) · 3.47 KB
/
morph.cpp
File metadata and controls
120 lines (95 loc) · 3.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include "morph.h"
#include "macro.h"
#include "sig.h"
// Morph class
Morph* g_pMorph = new Morph();
// Morph functions
Morph::Morph()
{
}
Morph::Morph(uintptr_t moduleBase) : m_moduleBase(moduleBase)
{
}
Morph::~Morph()
{
}
size_t Morph::GetSizeOfImage(uintptr_t pImageBase)
{
if (!pImageBase)
return 0;
PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)pImageBase;
PIMAGE_NT_HEADERS Ntheaders = (PIMAGE_NT_HEADERS)((LPBYTE)pImageBase + DosHeader->e_lfanew);
return (size_t)Ntheaders->OptionalHeader.SizeOfImage;
}
int Morph::MorphModule(uintptr_t pImageBase)
{
// all the vars we need for the FindSignature() call
m_moduleBase = pImageBase;
m_imageSize = GetSizeOfImage(m_moduleBase);
if (!m_imageSize || m_imageSize > MAXDWORD)
return 0;
// the offset from the module base to pLastMatch -> used as: module size - sMatchOffset = range of bytes we still need to scan
PBYTE pLastMatch = { 0 };
size_t sMatchOffset = { 0 };
bool bMorphFinished = false;
size_t sMatchCount = { 0 };
while (!bMorphFinished)
{
Sig* AccessSig = new Sig();
// search for the marker we will place in our code later on
pLastMatch = AccessSig->FindSignature((LPVOID)(m_moduleBase + sMatchOffset), m_imageSize - sMatchOffset, (PCHAR)MARKER_BYTES, (PCHAR)MARKER_MASK);
// if marker found
if (pLastMatch != nullptr)
{
// call MorphMemory which generates the junk code and writes it to memory
MorphMemory(pLastMatch, MARKER_SIZE);
// increment the count and the last match address
sMatchCount++;
pLastMatch++;
// calculate the offset for next search
sMatchOffset = (size_t)(pLastMatch - m_moduleBase);
}
else
{
// we found all markers
bMorphFinished = true;
// here you can log how many regions got morphed by using sMatchCount
}
delete AccessSig;
}
return 1;
}
int Morph::MorphMemory(PBYTE pDst, BYTE length)
{
// get a place for our brand new random opcodes
PBYTE morphedOpcodes = new BYTE[length];
BYTE opcodeIt = 0;
// place the jmp instruction | EB is a short jump, and the following byte is the offset
morphedOpcodes[opcodeIt] = ASM_OP_JMP_EB;
opcodeIt++;
// JMP_Address + 2 + Second_Byte_value = Next_Instruction_Address | inx at address 0x100: (EB 08) = 100 + 2 (EB) + 08 = 0x110
morphedOpcodes[opcodeIt] = length - ASM_OP_JMP_EB_SIZE;
opcodeIt++;
// now fill the rest with random opcodes
for (; opcodeIt < length; opcodeIt++)
morphedOpcodes[opcodeIt] = GetRandomNumber(0, MAXBYTE); // 0xFF
// write the new opcodes to memory | .text is execute/read and .rdata is read-only so you have to use VirtualProtect
size_t dwOldProtect;
VirtualProtect(pDst, length, PAGE_EXECUTE_READWRITE, (PDWORD)&dwOldProtect);
memcpy(pDst, morphedOpcodes, length);
VirtualProtect(pDst, length, dwOldProtect, (PDWORD)&dwOldProtect);
// free the used memory again
delete morphedOpcodes;
return 1;
}
// Pseudo Random Number Generator
namespace MyRandom
{
// Initialize our mersenne twister with a random seed based on the clock (once at system startup)
std::mt19937 mersenne{ static_cast<std::mt19937::result_type>(std::time(nullptr)) };
}
int GetRandomNumber(int min, int max)
{
std::uniform_int_distribution<> die{ min, max }; // we can create a distribution in any function that needs it | in C++ 17: std::uniform_int_distribution die{ min, max };
return die(MyRandom::mersenne); // and then generate a random number from our global generator
}