├── LICENSE
├── README.md
├── screenshots
├── after.png
└── before.png
└── src
├── function.cpp
├── function.h
├── instruction.cpp
├── instruction.h
├── main.cpp
├── pe.cpp
├── pe.h
├── util.cpp
├── util.h
├── virtual_instruction.cpp
├── virtual_instruction.h
├── vm.cpp
├── vm.h
├── vm_handler.cpp
├── vm_handler.h
├── vm_section.cpp
└── vm_section.h
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Connor-Jay Dunn
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BinaryShield
2 |
3 | **BinaryShield** is an open-source, bin-to-bin x86-64 code virtualizer designed to offer strong protection against reverse engineering efforts. It translates commonly used x86-64 instructions into a custom bytecode, which is executed by a secure, purpose-built virtual machine. For more information on virtualization and the technical details of how the BinaryShield VM works, click [here](https://connorjaydunn.github.io/blog/posts/binaryshield-a-bin2bin-x86-64-code-virtualizer/).
4 |
5 | Features
6 | ----
7 | * _Bytecode encryption (soon)_
8 | * Multi-Thread safe VM
9 | * _VM handler mutation (soon)_
10 | * Stack-Based, RISC VM
11 | * Multiple VM handler instances
12 | * Wide range of supported opcodes
13 | * Trivial to implement support for new opcodes
14 | * _VM handler integrity checks (soon)_
15 | * Over 60+ VM handlers
16 |
17 | Screenshots
18 | ---
19 |
20 |
21 |
22 |
23 | before virtualization
24 |
25 |
26 |
27 |
28 |
29 | after virtualization
30 |
31 |
32 | Dependencies
33 | ---
34 | * C++14 or higher,
35 | * [Zydis](https://github.com/zyantific/zydis)
36 |
37 | Usage
38 | ----
39 | ```bash
40 | binaryshield.exe
41 | ```
42 |
43 | Example:
44 |
45 | ```bash
46 | binaryshield.exe calc.exe 0x16D0 0x16E6
47 | ```
48 |
49 | TODO
50 | ----
51 |
52 | * Bytecode encryption
53 | * ~~VM context collision check~~
54 | * VM handler mutation
55 | * VM handler integrity checks
56 | * ~~Multiple VM handler instances~~
57 | * Anti-Debugger checks
58 | * Add function by code markers
59 | * Randomised VM context
60 | * Ability to virtualize areas of code, not just functions
61 |
62 | Disclaimer
63 | ---
64 | **BinaryShield** is currently in a very early stage of development and is **not suitable for commercial use** at this time. While the core functionality is in place, there may still be bugs, incomplete features, and potential security vulnerabilities.
65 |
66 | I am actively working on improving and expanding the tool, and will continue to release updates regularly. Feedback and contributions are welcome.
--------------------------------------------------------------------------------
/screenshots/after.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorjaydunn/BinaryShield/f745963e0970f93f98f256e7032b71d9812c4777/screenshots/after.png
--------------------------------------------------------------------------------
/screenshots/before.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorjaydunn/BinaryShield/f745963e0970f93f98f256e7032b71d9812c4777/screenshots/before.png
--------------------------------------------------------------------------------
/src/function.cpp:
--------------------------------------------------------------------------------
1 | #include "function.h"
2 |
3 | Function::Function(DWORD startRva, DWORD endRva, std::vector bytes) : startRva(startRva), endRva(endRva), bytes(bytes) {};
4 |
5 | bool Function::disassemble()
6 | {
7 | // initialise zydis decoder
8 | ZydisDecoder decoder;
9 | if (ZYAN_FAILED(ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64)))
10 | {
11 | std::cerr << "error initializing ZydisDecoder" << std::endl;
12 | return 0;
13 | }
14 |
15 | ZydisDecodedInstruction instructionInfo;
16 | ZydisDecodedOperand operandInfo[ZYDIS_MAX_OPERAND_COUNT];
17 |
18 | // first pass: disassemble each instruction
19 | DWORD offset = 0;
20 | while (offset < bytes.size())
21 | {
22 | if (ZYAN_FAILED(ZydisDecoderDecodeFull(&decoder, bytes.data() + offset, bytes.size(), &instructionInfo, operandInfo)))
23 | {
24 | std::cerr << "error decoding instruction" << std::endl;
25 | return 0;
26 | }
27 |
28 | instructions.push_back(Instruction(instructionInfo, operandInfo, offset + startRva));
29 |
30 | offset += instructionInfo.length;
31 | }
32 |
33 | // second pass: find branch destinations
34 | for (int i = 0; i < instructions.size(); i++)
35 | {
36 | if (instructions[i].isBranchInstruction())
37 | {
38 | for (int j = 0; j < instructions.size(); j++)
39 | {
40 | // check if instruction is destination of our branch
41 | if (instructions[i].getRva() +
42 | instructions[i].getOperandInfo()[0].imm.value.s +
43 | instructions[i].getInstructionInfo().length == instructions[j].getRva())
44 | {
45 | instructions[i].setDestInstructionIndex(j);
46 | }
47 | }
48 | }
49 | }
50 |
51 | return 1;
52 | }
53 |
54 | bool Function::compileInstructionsToVirtualInstructions()
55 | {
56 | // push context onto virtual stack
57 | VM::popVmContext(&instructions[0]);
58 | instructions[0].compileToVirtualInstructions();
59 |
60 | // compile each instruction to a set of virtual instructions
61 | for (int i = 1; i < instructions.size(); i++)
62 | {
63 | if (!instructions[i].compileToVirtualInstructions())
64 | // unable to virtualise instruciton, likely no support implemented
65 | return 0;
66 | }
67 |
68 | return 1;
69 | }
70 |
71 | void Function::resolveBranchInstructions(DWORD bytecodeRva)
72 | {
73 | for (int i = 0; i < instructions.size(); i++)
74 | {
75 | if (instructions[i].isBranchInstruction())
76 | {
77 | // get bytecode rva of the destination instruction
78 | DWORD targetBytecodeRva = getBytecodeIndex(instructions[i].getDestInstructionIndex()) + bytecodeRva;
79 |
80 | // set branch instructions operand to rva of destination instruction's bytecode rva
81 | if (instructions[i].isConditionalBranchInstruction())
82 | {
83 | // if conditional branch, second virtual instruction is the "push target.rva"
84 | instructions[i].getVirtualInstructions()[1].setOperand(targetBytecodeRva);
85 | }
86 | else
87 | {
88 | // if non-conditional branch, first virtual instruction is the "push target.rva"
89 | instructions[i].getVirtualInstructions()[0].setOperand(targetBytecodeRva);
90 | }
91 | }
92 | }
93 | }
94 |
95 | DWORD Function::getBytecodeIndex(int instructionIndex)
96 | {
97 | DWORD bytecodeIndex = 0;
98 |
99 | /*
100 | the following is a hacky solution to the fact instruction[0] will have "non-real" instructions
101 | to deal with the vm context. A better solution will be required in order to support x86 call.
102 | Perhaps we should implement a second vector of type VirtualInstruction that will store these
103 | "injected" instructions.
104 | */
105 | if (instructionIndex == 0)
106 | {
107 | // length of "injected" virtual instructions (VM::popVmContext())
108 | bytecodeIndex = 0x55;
109 | }
110 |
111 | // calculate the bytecode index of instructionIndex via summing all previous instruction bytecode sizes
112 | for (int i = 0; i < instructionIndex; i++)
113 | bytecodeIndex += instructions[i].getVirtualInstructionBytes().size();
114 |
115 | return bytecodeIndex;
116 | }
117 |
118 | std::vector Function::getVirtualInstructionBytes()
119 | {
120 | std::vector bytes;
121 |
122 | for (int i = 0; i < instructions.size(); i++)
123 | {
124 | std::vector virtualInstructionBytes = instructions[i].getVirtualInstructionBytes();
125 | bytes.insert(bytes.end(), virtualInstructionBytes.begin(), virtualInstructionBytes.end());
126 | }
127 |
128 | return bytes;
129 | }
130 |
131 | DWORD Function::getStartRva() { return startRva; }
132 |
133 | DWORD Function::getEndRva() { return endRva; }
--------------------------------------------------------------------------------
/src/function.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include "instruction.h"
8 | #include "virtual_instruction.h"
9 |
10 | class Function
11 | {
12 | public:
13 | Function(DWORD startRva, DWORD endRva, std::vector bytes);
14 |
15 | bool disassemble();
16 | bool compileInstructionsToVirtualInstructions();
17 | void resolveBranchInstructions(DWORD bytecodeRva);
18 | DWORD getBytecodeIndex(int instructionIndex);
19 |
20 | std::vector getVirtualInstructionBytes();
21 | DWORD getStartRva();
22 | DWORD getEndRva();
23 | private:
24 | DWORD startRva;
25 | DWORD endRva;
26 | std::vector bytes;
27 | std::vector instructions;
28 | };
--------------------------------------------------------------------------------
/src/instruction.cpp:
--------------------------------------------------------------------------------
1 | #include "instruction.h"
2 |
3 | Instruction::Instruction(ZydisDecodedInstruction instructionInfo, ZydisDecodedOperand* operandInfo, DWORD rva) : instructionInfo(instructionInfo), rva(rva)
4 | {
5 | this->operandInfo = std::vector(operandInfo, operandInfo + instructionInfo.operand_count);
6 | }
7 |
8 | bool Instruction::compileToVirtualInstructions()
9 | {
10 | // generate the corrosponding virtual instructions
11 | if (!VM::compileInstructionToVirtualInstructions(this))
12 | {
13 | std::cerr << "error compiling instruction" << std::endl;
14 | return 0;
15 | }
16 |
17 | return 1;
18 | }
19 |
20 | void Instruction::addVirtualInstruction(VirtualInstruction virtualInstruction) { virtualInstructions.push_back(virtualInstruction); }
21 |
22 | bool Instruction::isBranchInstruction()
23 | {
24 | switch (instructionInfo.mnemonic)
25 | {
26 | case ZYDIS_MNEMONIC_JNBE:
27 | case ZYDIS_MNEMONIC_JB:
28 | case ZYDIS_MNEMONIC_JBE:
29 | case ZYDIS_MNEMONIC_JCXZ:
30 | case ZYDIS_MNEMONIC_JECXZ:
31 | case ZYDIS_MNEMONIC_JKNZD:
32 | case ZYDIS_MNEMONIC_JKZD:
33 | case ZYDIS_MNEMONIC_JL:
34 | case ZYDIS_MNEMONIC_JLE:
35 | case ZYDIS_MNEMONIC_JNB:
36 | case ZYDIS_MNEMONIC_JNL:
37 | case ZYDIS_MNEMONIC_JNLE:
38 | case ZYDIS_MNEMONIC_JNO:
39 | case ZYDIS_MNEMONIC_JNP:
40 | case ZYDIS_MNEMONIC_JNS:
41 | case ZYDIS_MNEMONIC_JNZ:
42 | case ZYDIS_MNEMONIC_JO:
43 | case ZYDIS_MNEMONIC_JP:
44 | case ZYDIS_MNEMONIC_JRCXZ:
45 | case ZYDIS_MNEMONIC_JS:
46 | case ZYDIS_MNEMONIC_JZ:
47 | case ZYDIS_MNEMONIC_JMP:
48 | return 1;
49 | }
50 | return 0;
51 | }
52 |
53 | // if instruction is a branch instruction, but not JMP, then it must be a conditional branch
54 | bool Instruction::isConditionalBranchInstruction() { return (isBranchInstruction() && instructionInfo.mnemonic != ZYDIS_MNEMONIC_JMP); }
55 |
56 | void Instruction::setDestInstructionIndex(int destInstructionIndex) { this->destInstructionIndex = destInstructionIndex; }
57 |
58 | DWORD Instruction::getRva() { return rva; }
59 |
60 | ZydisDecodedInstruction Instruction::getInstructionInfo() { return instructionInfo; }
61 |
62 | std::vector Instruction::getOperandInfo() { return operandInfo; }
63 |
64 | int Instruction::getDestInstructionIndex() { return destInstructionIndex; }
65 |
66 | std::vector Instruction::getVirtualInstructionBytes()
67 | {
68 | std::vector bytes;
69 |
70 | // iterate over each virtual instruction and get its raw bytes
71 | for (int i = 0; i < virtualInstructions.size(); i++)
72 | {
73 | std::vector virtualInstructionBytes = virtualInstructions[i].getBytes();
74 | bytes.insert(bytes.end(), virtualInstructionBytes.begin(), virtualInstructionBytes.end());
75 | }
76 |
77 | return bytes;
78 | }
79 |
80 | std::vector& Instruction::getVirtualInstructions() { return virtualInstructions; }
--------------------------------------------------------------------------------
/src/instruction.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "vm.h"
9 | #include "virtual_instruction.h"
10 |
11 | class Instruction
12 | {
13 | public:
14 | Instruction(ZydisDecodedInstruction instructionInfo, ZydisDecodedOperand* operandInfo, DWORD rva);
15 |
16 | bool compileToVirtualInstructions();
17 | void addVirtualInstruction(VirtualInstruction virtualInstruction);
18 | bool isBranchInstruction();
19 | bool isConditionalBranchInstruction();
20 | void setDestInstructionIndex(int destInstructionIndex);
21 | DWORD getRva();
22 | ZydisDecodedInstruction getInstructionInfo();
23 | std::vector getOperandInfo();
24 | int getDestInstructionIndex();
25 | std::vector getVirtualInstructionBytes();
26 | std::vector& getVirtualInstructions();
27 | private:
28 | DWORD rva;
29 | int destInstructionIndex; // index of instruction the current instruction will jump or call
30 | ZydisDecodedInstruction instructionInfo;
31 | std::vector operandInfo;
32 | std::vector virtualInstructions;
33 | };
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "pe.h"
6 |
7 | int main(int argc, char* argv[])
8 | {
9 | if (argc != 4)
10 | {
11 | std::cerr << "usage: binaryshield.exe " << std::endl;
12 | return 1;
13 | }
14 |
15 | std::cout << "starting..." << std::endl;
16 |
17 | PE pe(argv[1]);
18 |
19 | if (!pe.load())
20 | return 1;
21 |
22 | pe.addFunctionByRva(std::stoi(argv[2], nullptr, 16), std::stoi(argv[3], nullptr, 16));
23 |
24 | std::cout << "virtualizing function(s)..." << std::endl;
25 |
26 | if (!pe.virtualizeFunctions())
27 | return 1;
28 |
29 | std::cout << "success" << std::endl;
30 |
31 | if (!pe.addVmSection())
32 | return 1;
33 |
34 | if (!pe.save("protected.exe"))
35 | return 1;
36 |
37 | std::cout << "exiting..." << std::endl;
38 |
39 | return 0;
40 | }
--------------------------------------------------------------------------------
/src/pe.cpp:
--------------------------------------------------------------------------------
1 | #include "pe.h"
2 |
3 | PE::PE(std::string path) : path(path) {};
4 |
5 | PE::~PE() { close(); }
6 |
7 | bool PE::load()
8 | {
9 | if (!open())
10 | return 0;
11 |
12 | if (!emitRead())
13 | return 0;
14 |
15 | close();
16 |
17 | if (!parseHeaders())
18 | return 0;
19 |
20 | return 1;
21 | }
22 |
23 | bool PE::save(std::string path)
24 | {
25 | // create a new file for writing our protected.exe to
26 | HANDLE hOutputFile = CreateFileA(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
27 |
28 | if (hOutputFile == INVALID_HANDLE_VALUE)
29 | {
30 | std::cerr << "error while creating output file: " << std::endl;
31 | return 0;
32 | }
33 |
34 | // write our protected.exe bytes to new file
35 | DWORD bytesWritten = 0;
36 | if (!WriteFile(hOutputFile, bytes.data(), bytes.size(), &bytesWritten, NULL))
37 | {
38 | std::cerr << "error while writing to output file: " << std::endl;
39 | CloseHandle(hOutputFile);
40 | return 0;
41 | }
42 |
43 | CloseHandle(hOutputFile);
44 | return 1;
45 | }
46 |
47 | void PE::addFunctionByRva(DWORD startRva, DWORD endRva)
48 | {
49 | functions.push_back(Function
50 | (
51 | startRva,
52 | endRva,
53 | std::vector(bytes.begin() + rvaToFileOffset(startRva), bytes.begin() + rvaToFileOffset(endRva))
54 | ));
55 | }
56 |
57 | bool PE::virtualizeFunction(Function function)
58 | {
59 | // todo: check if function can be vm'd (i.e. is sizeof(function->bytes) >= 5)
60 |
61 | if (!vmSection.isInitialised())
62 | vmSection.initialise(getNewSectionVirtualAddress(), getNewSectionFileOffset());
63 |
64 | if (!function.disassemble())
65 | return 0;
66 |
67 | if (!function.compileInstructionsToVirtualInstructions())
68 | return 0;
69 |
70 | removeOriginalFunctionBytes(function);
71 |
72 | DWORD bytecodeRva = vmSection.getWritePointerRva();
73 |
74 | // resolve branch instructions now we know bytecode rva
75 | function.resolveBranchInstructions(bytecodeRva);
76 |
77 | vmSection.addBytes(function.getVirtualInstructionBytes());
78 |
79 | // redirect function to a vm trampoline
80 | redirectFunctionToVmTramp(function, vmSection.getWritePointerRva());
81 | vmSection.addVmTramp(bytecodeRva);
82 |
83 | return 1;
84 | }
85 |
86 | bool PE::virtualizeFunctions()
87 | {
88 | // iterate over each function and virtulize it
89 | for (int i = 0; i < functions.size(); i++)
90 | {
91 | if (!virtualizeFunction(functions[i]))
92 | return 0;
93 | }
94 |
95 | return 1;
96 | }
97 |
98 | bool PE::addVmSection() { return addSection(".binshld", 0xE0000000, vmSection.getBytes()); }
99 |
100 | DWORD PE::rvaToFileOffset(DWORD rva)
101 | {
102 | // find section rva lies within and calculate file offset
103 | for (int i = 0; i < pNtHeader->FileHeader.NumberOfSections; i++)
104 | {
105 | if (rva >= pSectionHeader[i].VirtualAddress &&
106 | rva < pSectionHeader[i].VirtualAddress + (pSectionHeader[i].Misc.VirtualSize))
107 | {
108 | return (rva - pSectionHeader[i].VirtualAddress) + pSectionHeader[i].PointerToRawData;
109 | }
110 | }
111 |
112 | return 0x0; // this should never happen, throw exception here
113 | }
114 |
115 | DWORD PE::fileOffsetToRva(DWORD offset)
116 | {
117 | // find section rva lies within and calculate rva
118 | for (int i = 0; i < pNtHeader->FileHeader.NumberOfSections; i++)
119 | {
120 | if (offset >= pSectionHeader[i].PointerToRawData &&
121 | offset < pSectionHeader[i].PointerToRawData + (pSectionHeader[i].SizeOfRawData))
122 | {
123 | return (offset - pSectionHeader[i].PointerToRawData) + pSectionHeader[i].PointerToRawData;
124 | }
125 | }
126 |
127 | // this should never happen
128 | return 0x0;
129 | }
130 |
131 | bool PE::parseHeaders()
132 | {
133 | // verify we have a pe via the dos header
134 | pDosHeader = (PIMAGE_DOS_HEADER)bytes.data();
135 | if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
136 | {
137 | std::cerr << "invalid dos header" << std::endl;
138 | return 0;
139 | }
140 |
141 | // verify we havea valid pe via the nt header
142 | pNtHeader = (PIMAGE_NT_HEADERS)(bytes.data() + pDosHeader->e_lfanew);
143 | if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
144 | {
145 | std::cerr << "invalid nt header" << std::endl;
146 | return 0;
147 | }
148 |
149 | // pSectionHeader is a pointer to the start of an array of type IMAGE_SECTION_HEADER
150 | pSectionHeader = (PIMAGE_SECTION_HEADER)(bytes.data() + pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS));
151 |
152 | return 1;
153 | }
154 |
155 | bool PE::open()
156 | {
157 | hFile = CreateFileA(path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
158 |
159 | if (hFile == INVALID_HANDLE_VALUE)
160 | {
161 | std::cerr << "error while oppening input file: " << std::endl;
162 | return 0;
163 | }
164 |
165 | return 1;
166 | }
167 |
168 | void PE::close()
169 | {
170 | // if already closed, ignore, else close handle to file and set hFile to nullptr
171 | if (hFile != nullptr)
172 | {
173 | CloseHandle(hFile);
174 | hFile = nullptr;
175 | }
176 | }
177 |
178 | bool PE::emitRead()
179 | {
180 | // get file size
181 | DWORD size = GetFileSize(hFile, NULL);
182 | if (size == INVALID_FILE_SIZE)
183 | {
184 | std::cerr << "error while getting input file size: " << std::endl;
185 | return 0;
186 | }
187 |
188 | // resize our bytes vector to size of binary
189 | bytes.resize(size);
190 |
191 | // read raw file bytes into our bytes vector
192 | DWORD bytesRead;
193 | if (!ReadFile(hFile, bytes.data(), size, &bytesRead, NULL))
194 | {
195 | std::cerr << "error while reading input file: " << std::endl;
196 | return 0;
197 | }
198 |
199 | return 1;
200 | }
201 |
202 | bool PE::addSection(std::string name, DWORD flags, std::vector bytes)
203 | {
204 | // get next section's file offset
205 | DWORD newSectionFO = getNewSectionFileOffset();
206 |
207 | // create IMAGE_SECTION_HEADER for new section
208 | PIMAGE_SECTION_HEADER pNewSectionHeader = &pSectionHeader[pNtHeader->FileHeader.NumberOfSections];
209 | pNewSectionHeader->Characteristics = flags;
210 | pNewSectionHeader->Misc.VirtualSize = align(bytes.size(), pNtHeader->OptionalHeader.SectionAlignment);
211 | pNewSectionHeader->SizeOfRawData = align(bytes.size(), pNtHeader->OptionalHeader.FileAlignment);
212 | pNewSectionHeader->VirtualAddress = getNewSectionVirtualAddress();
213 | pNewSectionHeader->PointerToRawData = newSectionFO;
214 | CopyMemory(pNewSectionHeader->Name, name.c_str(), min(name.size(), IMAGE_SIZEOF_SHORT_NAME));
215 |
216 | // increase section count in the file header, and update size of image
217 | pNtHeader->FileHeader.NumberOfSections += 1;
218 | pNtHeader->OptionalHeader.SizeOfImage += pNewSectionHeader->Misc.VirtualSize;
219 |
220 | // resize our bytes vector to fit our new section bytes in
221 | this->bytes.resize(newSectionFO + pNewSectionHeader->SizeOfRawData);
222 |
223 | // actually copy the section bytes into our bytes vector
224 | std::copy(bytes.begin(), bytes.end(), this->bytes.begin() + newSectionFO);
225 |
226 | // parse section headers again (likely not required as we only store pointers to headers)
227 | if (!parseHeaders())
228 | return 0;
229 |
230 | return 1;
231 | }
232 |
233 | DWORD PE::getNewSectionVirtualAddress()
234 | {
235 | // return the next section's "virtual address", which is actually its relative virtual address
236 | return align
237 | (
238 | pSectionHeader[pNtHeader->FileHeader.NumberOfSections - 1].VirtualAddress + pSectionHeader[pNtHeader->FileHeader.NumberOfSections - 1].Misc.VirtualSize,
239 | pNtHeader->OptionalHeader.SectionAlignment
240 | );
241 | }
242 |
243 | DWORD PE::getNewSectionFileOffset()
244 | {
245 | // return the next section's file offset
246 | return align
247 | (
248 | pSectionHeader[pNtHeader->FileHeader.NumberOfSections - 1].PointerToRawData + pSectionHeader[pNtHeader->FileHeader.NumberOfSections - 1].SizeOfRawData,
249 | pNtHeader->OptionalHeader.FileAlignment
250 | );
251 | }
252 |
253 | void PE::redirectFunctionToVmTramp(Function function, DWORD vmTrampRva)
254 | {
255 | std::vector relToVmTrapBytes = convertToByteVector(vmTrampRva - (function.getStartRva() + 5));
256 |
257 | // replace first bytes of instruction with a redirection to the vm trampoline jump
258 | bytes[rvaToFileOffset(function.getStartRva())] = 0xE9;
259 | std::copy(relToVmTrapBytes.begin(), relToVmTrapBytes.end(), bytes.begin() + rvaToFileOffset(function.getStartRva() + 1));
260 | }
261 |
262 | void PE::removeOriginalFunctionBytes(Function function)
263 | {
264 | // replace all the original function bytes with 0xCC
265 | std::fill
266 | (
267 | bytes.begin() + rvaToFileOffset(function.getStartRva()),
268 | bytes.begin() + rvaToFileOffset(function.getEndRva()),
269 | 0xCC
270 | );
271 | }
--------------------------------------------------------------------------------
/src/pe.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "vm_section.h"
9 | #include "function.h"
10 | #include "util.h"
11 |
12 | class PE
13 | {
14 | public:
15 | PE(std::string path);
16 | ~PE();
17 |
18 | bool load();
19 | bool save(std::string path);
20 |
21 | void addFunctionByRva(DWORD startRva, DWORD endRva);
22 | bool virtualizeFunctions();
23 | bool addVmSection();
24 |
25 | DWORD rvaToFileOffset(DWORD rva);
26 | DWORD fileOffsetToRva(DWORD offset);
27 | private:
28 | std::string path;
29 | HANDLE hFile = nullptr;
30 | std::vector bytes;
31 | PIMAGE_DOS_HEADER pDosHeader;
32 | PIMAGE_NT_HEADERS pNtHeader;
33 | PIMAGE_SECTION_HEADER pSectionHeader;
34 | bool parseHeaders();
35 | bool open();
36 | void close();
37 | bool emitRead();
38 | bool addSection(std::string name, DWORD flags, std::vector bytes);
39 | DWORD getNewSectionVirtualAddress();
40 | DWORD getNewSectionFileOffset();
41 |
42 | std::vector functions;
43 | bool virtualizeFunction(Function function);
44 | void redirectFunctionToVmTramp(Function function, DWORD vmTrampRva);
45 | void removeOriginalFunctionBytes(Function function);
46 |
47 | VMSection vmSection;
48 | };
--------------------------------------------------------------------------------
/src/util.cpp:
--------------------------------------------------------------------------------
1 | #include "util.h"
2 |
3 | int getRandomInt(int min, int max)
4 | {
5 | std::random_device rd;
6 | std::mt19937 generator(rd());
7 | std::uniform_int_distribution distribution(min, max);
8 |
9 | return distribution(generator);
10 | }
11 |
12 | DWORD align(DWORD x, DWORD alignment) { return (x + alignment - 1) & ~(alignment - 1); }
13 |
14 | DWORD rvaToFileOffset(DWORD rva, DWORD virtualAddress, DWORD pointerToRawData) { return (rva - virtualAddress) + pointerToRawData; }
15 |
16 | DWORD fileOffsetToRva(DWORD fileOffset, DWORD virtualAddress, DWORD pointerToRawData) { return (fileOffset - pointerToRawData) + virtualAddress; }
--------------------------------------------------------------------------------
/src/util.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | template
8 | std::vector convertToByteVector(T x)
9 | {
10 | std::vector bytes;
11 | size_t byteCount = sizeof(T);
12 |
13 | for (size_t i = 0; i < byteCount; ++i)
14 | bytes.push_back((BYTE)((x >> (i * 8)) & 0xFF));
15 |
16 | return bytes;
17 | }
18 |
19 | int getRandomInt(int min, int max);
20 |
21 | DWORD align(DWORD x, DWORD alignment);
22 |
23 | DWORD rvaToFileOffset(DWORD rva, DWORD virtualAddress, DWORD pointerToRawData);
24 |
25 | DWORD fileOffsetToRva(DWORD fileOffset, DWORD virtualAddress, DWORD pointerToRawData);
--------------------------------------------------------------------------------
/src/virtual_instruction.cpp:
--------------------------------------------------------------------------------
1 | #include "virtual_instruction.h"
2 |
3 | VirtualInstruction::VirtualInstruction(DWORD vmHandlerRva, long long operand, BYTE operandSize)
4 | : vmHandlerRva(vmHandlerRva),
5 | operand(operand),
6 | operandSize(operandSize/8),
7 | hasOperand(true)
8 | {};
9 |
10 | VirtualInstruction::VirtualInstruction(DWORD vmHandlerRva) : vmHandlerRva(vmHandlerRva) {};
11 |
12 | std::vector VirtualInstruction::getBytes()
13 | {
14 | std::vector bytes;
15 |
16 | // convert vmHandlerRva into a BYTE vector
17 | std::vector vmHandlerRvaBytes = convertToByteVector(vmHandlerRva);
18 | bytes.insert(bytes.end(), vmHandlerRvaBytes.begin(), vmHandlerRvaBytes.end());
19 |
20 | // if operand exists, convert it into a BYTE vector
21 | if (hasOperand)
22 | {
23 | std::vector operandBytes;
24 |
25 | switch (operandSize)
26 | {
27 | case 8: operandBytes = convertToByteVector(operand); break;
28 | case 4: operandBytes = convertToByteVector(operand); break;
29 | case 2: operandBytes = convertToByteVector(operand); break;
30 | case 1: operandBytes = convertToByteVector(operand); break;
31 | }
32 |
33 | bytes.insert(bytes.end(), operandBytes.begin(), operandBytes.end());
34 | }
35 |
36 | return bytes;
37 | }
38 |
39 | void VirtualInstruction::setOperand(long long operand) { this->operand = operand; }
--------------------------------------------------------------------------------
/src/virtual_instruction.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #include "util.h"
7 |
8 | class VirtualInstruction
9 | {
10 | public:
11 | VirtualInstruction(DWORD vmHandlerRva, long long operand, BYTE operandSize);
12 | VirtualInstruction(DWORD vmHandlerRva);
13 |
14 | std::vector getBytes();
15 |
16 | void setOperand(long long operand);
17 | private:
18 | DWORD vmHandlerRva;
19 | long long operand;
20 | bool hasOperand = false;
21 | BYTE operandSize;
22 | };
--------------------------------------------------------------------------------
/src/vm.cpp:
--------------------------------------------------------------------------------
1 | #include "instruction.h"
2 | #include "vm.h"
3 |
4 | namespace VM
5 | {
6 | std::vector vmHandlers;
7 |
8 | bool compileInstructionToVirtualInstructions(Instruction* instruction)
9 | {
10 | switch (instruction->getInstructionInfo().mnemonic)
11 | {
12 | case ZYDIS_MNEMONIC_PUSH: return x86PushHandler(instruction);
13 | case ZYDIS_MNEMONIC_POP: return x86PopHandler(instruction);
14 | case ZYDIS_MNEMONIC_MOV: return x86MovHandler(instruction);
15 | case ZYDIS_MNEMONIC_LEA: return x86LeaHandler(instruction);
16 | case ZYDIS_MNEMONIC_RET: return x86RetHandler(instruction);
17 | case ZYDIS_MNEMONIC_CMP: return x86CmpHandler(instruction);
18 | case ZYDIS_MNEMONIC_TEST: return x86TestHandler(instruction);
19 | case ZYDIS_MNEMONIC_JMP: return x86JmpHandler(instruction);
20 | case ZYDIS_MNEMONIC_JNZ: return x86JneHandler(instruction);
21 | case ZYDIS_MNEMONIC_NOP: return 1;
22 |
23 | case ZYDIS_MNEMONIC_ADD:
24 | case ZYDIS_MNEMONIC_SUB:
25 | case ZYDIS_MNEMONIC_XOR:
26 | case ZYDIS_MNEMONIC_AND:
27 | case ZYDIS_MNEMONIC_OR:
28 | case ZYDIS_MNEMONIC_SHL:
29 | return x86ArithmeticHandler(instruction, instruction->getInstructionInfo().mnemonic, true);
30 | }
31 | return 0;
32 | }
33 |
34 | bool x86PushHandler(Instruction* instruction)
35 | {
36 | std::vector operandInfo = instruction->getOperandInfo();
37 |
38 | switch (operandInfo[0].type)
39 | {
40 | case ZYDIS_OPERAND_TYPE_REGISTER:
41 | {
42 | emitPushRegister(instruction, operandInfo[0].reg.value, operandInfo[0].size);
43 | return 1;
44 | }
45 | case ZYDIS_OPERAND_TYPE_IMMEDIATE:
46 | {
47 | emitPushImmediate(instruction, operandInfo[0].imm.value.s, operandInfo[0].size);
48 | return 1;
49 | }
50 | case ZYDIS_OPERAND_TYPE_MEMORY:
51 | {
52 | calculateEffectiveAddress(instruction, operandInfo[0].mem);
53 | emitRead(instruction, operandInfo[0].size);
54 | return 1;
55 | }
56 | case ZYDIS_OPERAND_TYPE_POINTER: return 0;
57 | case ZYDIS_OPERAND_TYPE_UNUSED: return 0;
58 | }
59 |
60 | return 0;
61 | }
62 |
63 | bool x86PopHandler(Instruction* instruction)
64 | {
65 | std::vector operandInfo = instruction->getOperandInfo();
66 |
67 | switch (operandInfo[0].type)
68 | {
69 | case ZYDIS_OPERAND_TYPE_REGISTER:
70 | {
71 | emitPopRegister(instruction, operandInfo[0].reg.value, operandInfo[0].size);
72 | return 1;
73 | }
74 | case ZYDIS_OPERAND_TYPE_IMMEDIATE: return 0;
75 | case ZYDIS_OPERAND_TYPE_MEMORY: return 0;
76 | case ZYDIS_OPERAND_TYPE_POINTER: return 0;
77 | case ZYDIS_OPERAND_TYPE_UNUSED: return 0;
78 | }
79 |
80 | return 0;
81 | }
82 |
83 | bool x86MovHandler(Instruction* instruction)
84 | {
85 | std::vector operandInfo = instruction->getOperandInfo();
86 |
87 | switch (operandInfo[0].type)
88 | {
89 | case ZYDIS_OPERAND_TYPE_REGISTER:
90 | {
91 | switch (operandInfo[1].type)
92 | {
93 | case ZYDIS_OPERAND_TYPE_REGISTER:
94 | {
95 | if (operandInfo[0].size == 32)
96 | zeroRegister(instruction, operandInfo[0].reg.value);
97 | emitPushRegister(instruction, operandInfo[1].reg.value, operandInfo[0].size);
98 | emitPopRegister(instruction, operandInfo[0].reg.value, operandInfo[0].size);
99 | return 1;
100 | }
101 | case ZYDIS_OPERAND_TYPE_IMMEDIATE:
102 | {
103 | if (operandInfo[0].size == 32)
104 | zeroRegister(instruction, operandInfo[0].reg.value);
105 | emitPushImmediate(instruction, operandInfo[1].imm.value.s, operandInfo[0].size);
106 | emitPopRegister(instruction, operandInfo[0].reg.value, operandInfo[0].size);
107 | return 1;
108 | }
109 | case ZYDIS_OPERAND_TYPE_MEMORY:
110 | {
111 | calculateEffectiveAddress(instruction, operandInfo[1].mem);
112 | if (operandInfo[0].size == 32)
113 | zeroRegister(instruction, operandInfo[0].reg.value);
114 | emitRead(instruction, operandInfo[0].size);
115 | emitPopRegister(instruction, operandInfo[0].reg.value, operandInfo[0].size);
116 | return 1;
117 | }
118 | case ZYDIS_OPERAND_TYPE_POINTER: return 0;
119 | case ZYDIS_OPERAND_TYPE_UNUSED: return 0;
120 | }
121 | }
122 | case ZYDIS_OPERAND_TYPE_IMMEDIATE: return 0;
123 | case ZYDIS_OPERAND_TYPE_MEMORY:
124 | {
125 | calculateEffectiveAddress(instruction, operandInfo[0].mem);
126 | emitPopRegister(instruction, R0, 64);
127 |
128 | switch (operandInfo[1].type)
129 | {
130 | case ZYDIS_OPERAND_TYPE_REGISTER:
131 | {
132 | emitPushRegister(instruction, operandInfo[1].reg.value, operandInfo[0].size);
133 | emitPushRegister(instruction, R0, 64);
134 | emitWrite(instruction, operandInfo[0].size);
135 | return 1;
136 | }
137 | case ZYDIS_OPERAND_TYPE_IMMEDIATE:
138 | {
139 | emitPushImmediate(instruction, operandInfo[1].imm.value.s, operandInfo[0].size);
140 | emitPushRegister(instruction, R0, 64);
141 | emitWrite(instruction, operandInfo[0].size);
142 | return 1;
143 | }
144 | case ZYDIS_OPERAND_TYPE_MEMORY: return 0;
145 | case ZYDIS_OPERAND_TYPE_POINTER: return 0;
146 | case ZYDIS_OPERAND_TYPE_UNUSED: return 0;
147 | }
148 | }
149 | case ZYDIS_OPERAND_TYPE_POINTER: return 0;
150 | case ZYDIS_OPERAND_TYPE_UNUSED: return 0;
151 | }
152 |
153 | return 0;
154 | }
155 |
156 | bool x86LeaHandler(Instruction* instruction)
157 | {
158 | std::vector operandInfo = instruction->getOperandInfo();
159 |
160 | calculateEffectiveAddress(instruction, operandInfo[1].mem);
161 | emitPopRegister(instruction, R0, 64);
162 | emitPushRegister(instruction, R0, operandInfo[0].size);
163 | if (operandInfo[0].size == 32)
164 | zeroRegister(instruction, operandInfo[0].reg.value);
165 | emitPopRegister(instruction, operandInfo[0].reg.value, operandInfo[0].size);
166 |
167 | return 1;
168 | }
169 |
170 | bool x86RetHandler(Instruction* instruction)
171 | {
172 | // add check for operand (i.e. ret 0xC)
173 | pushVmContext(instruction);
174 | emitExit(instruction);
175 | return 1;
176 | }
177 |
178 | bool x86CmpHandler(Instruction* instruction) { return x86ArithmeticHandler(instruction, ZYDIS_MNEMONIC_SUB, false); }
179 |
180 | bool x86TestHandler(Instruction* instruction) { return x86ArithmeticHandler(instruction, ZYDIS_MNEMONIC_AND, false); }
181 |
182 | bool x86JmpHandler(Instruction* instruction)
183 | {
184 | if (instruction->getOperandInfo()[0].type != ZYDIS_OPERAND_TYPE_IMMEDIATE)
185 | return 0;
186 | emitJmp(instruction);
187 | return 1;
188 | }
189 |
190 | bool x86JneHandler(Instruction* instruction)
191 | {
192 | if (instruction->getOperandInfo()[0].type != ZYDIS_OPERAND_TYPE_IMMEDIATE)
193 | return 0;
194 | emitPushRegister(instruction, ZYDIS_REGISTER_RFLAGS, 64);
195 | emitJne(instruction);
196 | return 1;
197 | }
198 |
199 | bool x86ArithmeticHandler(Instruction* instruction, ZydisMnemonic operation, bool storeOutput)
200 | {
201 | std::vector operandInfo = instruction->getOperandInfo();
202 |
203 | switch (operandInfo[0].type)
204 | {
205 | case ZYDIS_OPERAND_TYPE_REGISTER:
206 | {
207 | switch (operandInfo[1].type)
208 | {
209 | case ZYDIS_OPERAND_TYPE_REGISTER:
210 | {
211 | emitPushRegister(instruction, operandInfo[0].reg.value, operandInfo[0].size);
212 | emitPushRegister(instruction, operandInfo[1].reg.value, operandInfo[0].size);
213 | emitArithmetic(instruction, operation, operandInfo[0].size);
214 | emitPopRegister(instruction, ZYDIS_REGISTER_RFLAGS, 64);
215 | if (storeOutput)
216 | {
217 | if (operandInfo[0].size == 32)
218 | zeroRegister(instruction, operandInfo[0].reg.value);
219 | emitPopRegister(instruction, operandInfo[0].reg.value, operandInfo[0].size);
220 | }
221 | else
222 | {
223 | emitPopRegister(instruction, R0, operandInfo[0].size);
224 | }
225 | return 1;
226 | }
227 | case ZYDIS_OPERAND_TYPE_IMMEDIATE:
228 | emitPushRegister(instruction, operandInfo[0].reg.value, operandInfo[0].size);
229 | emitPushImmediate(instruction, operandInfo[1].imm.value.s, operandInfo[0].size);
230 | emitArithmetic(instruction, operation, operandInfo[0].size);
231 | emitPopRegister(instruction, ZYDIS_REGISTER_RFLAGS, 64);
232 | if (storeOutput)
233 | {
234 | if (operandInfo[0].size == 32)
235 | zeroRegister(instruction, operandInfo[0].reg.value);
236 | emitPopRegister(instruction, operandInfo[0].reg.value, operandInfo[0].size);
237 | }
238 | else
239 | {
240 | emitPopRegister(instruction, R0, operandInfo[0].size);
241 | }
242 | return 1;
243 | case ZYDIS_OPERAND_TYPE_MEMORY:
244 | {
245 | calculateEffectiveAddress(instruction, operandInfo[1].mem);
246 | emitRead(instruction, operandInfo[0].size);
247 | emitPushRegister(instruction, operandInfo[0].reg.value, operandInfo[0].size);
248 | emitArithmetic(instruction, operation, operandInfo[0].size);
249 | emitPopRegister(instruction, ZYDIS_REGISTER_RFLAGS, 64);
250 |
251 | if (storeOutput)
252 | {
253 | if (operandInfo[0].size == 32)
254 | zeroRegister(instruction, operandInfo[0].reg.value);
255 | emitPopRegister(instruction, operandInfo[0].reg.value, operandInfo[0].size);
256 | }
257 | else
258 | {
259 | emitPopRegister(instruction, R0, operandInfo[0].size);
260 | }
261 | return 1;
262 | }
263 | case ZYDIS_OPERAND_TYPE_POINTER: return 0;
264 | case ZYDIS_OPERAND_TYPE_UNUSED: return 0;
265 | }
266 | }
267 | case ZYDIS_OPERAND_TYPE_IMMEDIATE:
268 | return 0;
269 | case ZYDIS_OPERAND_TYPE_MEMORY:
270 | {
271 | calculateEffectiveAddress(instruction, operandInfo[0].mem);
272 | emitPushRegister(instruction, ZYDIS_REGISTER_RSP, 64);
273 | emitRead(instruction, 64);
274 | emitPopRegister(instruction, R0, 64);
275 |
276 | switch (operandInfo[1].type)
277 | {
278 | case ZYDIS_OPERAND_TYPE_REGISTER:
279 | {
280 | emitRead(instruction, operandInfo[0].size);
281 | emitPushRegister(instruction, operandInfo[1].reg.value, operandInfo[0].size);
282 | emitArithmetic(instruction, operation, operandInfo[0].size);
283 | emitPopRegister(instruction, ZYDIS_REGISTER_RFLAGS, 64);
284 | if (storeOutput)
285 | {
286 | emitPushRegister(instruction, R0, 64);
287 | emitWrite(instruction, operandInfo[0].size);
288 | }
289 | else
290 | {
291 | emitPopRegister(instruction, R0, operandInfo[0].size);
292 | }
293 | return 1;
294 | }
295 | case ZYDIS_OPERAND_TYPE_IMMEDIATE:
296 | {
297 | emitRead(instruction, operandInfo[0].size);
298 | emitPushImmediate(instruction, operandInfo[1].imm.value.s, operandInfo[0].size);
299 | emitArithmetic(instruction, operation, operandInfo[0].size);
300 | emitPopRegister(instruction, ZYDIS_REGISTER_RFLAGS, 64);
301 | if (storeOutput)
302 | {
303 | emitPushRegister(instruction, R0, 64);
304 | emitWrite(instruction, operandInfo[0].size);
305 | }
306 | else
307 | {
308 | emitPopRegister(instruction, R0, operandInfo[0].size);
309 | }
310 | return 1;
311 | }
312 | case ZYDIS_OPERAND_TYPE_MEMORY: return 0;
313 | case ZYDIS_OPERAND_TYPE_POINTER: return 0;
314 | case ZYDIS_OPERAND_TYPE_UNUSED: return 0;
315 | }
316 | }
317 | case ZYDIS_OPERAND_TYPE_POINTER: return 0;
318 | case ZYDIS_OPERAND_TYPE_UNUSED: return 0;
319 | }
320 |
321 | return 0;
322 | }
323 |
324 | BYTE getVirtualRegisterIndex(ZydisRegister reg)
325 | {
326 | switch (reg)
327 | {
328 | case ZYDIS_REGISTER_RFLAGS:
329 | return 0;
330 |
331 | case ZYDIS_REGISTER_RAX:
332 | case ZYDIS_REGISTER_EAX:
333 | case ZYDIS_REGISTER_AX:
334 | case ZYDIS_REGISTER_AL:
335 | return 1;
336 |
337 | case ZYDIS_REGISTER_RBX:
338 | case ZYDIS_REGISTER_EBX:
339 | case ZYDIS_REGISTER_BX:
340 | case ZYDIS_REGISTER_BL:
341 | return 2;
342 |
343 | case ZYDIS_REGISTER_RCX:
344 | case ZYDIS_REGISTER_ECX:
345 | case ZYDIS_REGISTER_CX:
346 | case ZYDIS_REGISTER_CL:
347 | return 3;
348 |
349 | case ZYDIS_REGISTER_RDX:
350 | case ZYDIS_REGISTER_EDX:
351 | case ZYDIS_REGISTER_DX:
352 | case ZYDIS_REGISTER_DL:
353 | return 4;
354 |
355 | case ZYDIS_REGISTER_RSI:
356 | case ZYDIS_REGISTER_ESI:
357 | case ZYDIS_REGISTER_SI:
358 | case ZYDIS_REGISTER_SIL:
359 | return 5;
360 |
361 | case ZYDIS_REGISTER_RDI:
362 | case ZYDIS_REGISTER_EDI:
363 | case ZYDIS_REGISTER_DI:
364 | case ZYDIS_REGISTER_DIL:
365 | return 6;
366 |
367 | case ZYDIS_REGISTER_RBP:
368 | case ZYDIS_REGISTER_EBP:
369 | case ZYDIS_REGISTER_BP:
370 | case ZYDIS_REGISTER_BPL:
371 | return 7;
372 |
373 | case ZYDIS_REGISTER_R8:
374 | case ZYDIS_REGISTER_R8D:
375 | case ZYDIS_REGISTER_R8W:
376 | case ZYDIS_REGISTER_R8B:
377 | return 8;
378 |
379 | case ZYDIS_REGISTER_R9:
380 | case ZYDIS_REGISTER_R9D:
381 | case ZYDIS_REGISTER_R9W:
382 | case ZYDIS_REGISTER_R9B:
383 | return 9;
384 |
385 | case ZYDIS_REGISTER_R10:
386 | case ZYDIS_REGISTER_R10D:
387 | case ZYDIS_REGISTER_R10W:
388 | case ZYDIS_REGISTER_R10B:
389 | return 10;
390 |
391 | case ZYDIS_REGISTER_R11:
392 | case ZYDIS_REGISTER_R11D:
393 | case ZYDIS_REGISTER_R11W:
394 | case ZYDIS_REGISTER_R11B:
395 | return 11;
396 |
397 | case ZYDIS_REGISTER_R12:
398 | case ZYDIS_REGISTER_R12D:
399 | case ZYDIS_REGISTER_R12W:
400 | case ZYDIS_REGISTER_R12B:
401 | return 12;
402 |
403 | case ZYDIS_REGISTER_R13:
404 | case ZYDIS_REGISTER_R13D:
405 | case ZYDIS_REGISTER_R13W:
406 | case ZYDIS_REGISTER_R13B:
407 | return 13;
408 |
409 | case ZYDIS_REGISTER_R14:
410 | case ZYDIS_REGISTER_R14D:
411 | case ZYDIS_REGISTER_R14W:
412 | case ZYDIS_REGISTER_R14B:
413 | return 14;
414 |
415 | case ZYDIS_REGISTER_R15:
416 | case ZYDIS_REGISTER_R15D:
417 | case ZYDIS_REGISTER_R15W:
418 | case ZYDIS_REGISTER_R15B:
419 | return 15;
420 |
421 | default:
422 | return -1; // something went wrong
423 | }
424 | }
425 |
426 | BYTE getVirtualRegisterIndex(VIRTUAL_REGISTERS reg)
427 | {
428 | switch (reg)
429 | {
430 | case R0: return 16;
431 | case R1: return 17;
432 |
433 | default: return -1; // something went wrong
434 | }
435 | }
436 |
437 | DWORD getVmHandlerRva(VMHandlerTypes type)
438 | {
439 | // array of possible rvas we can return
440 | std::vector targetHandlersRva;
441 |
442 | for (int i = 0; i < vmHandlers.size(); i++)
443 | {
444 | if (vmHandlers[i].getType() == type)
445 | {
446 | targetHandlersRva.push_back(vmHandlers[i].getRva());
447 | }
448 | }
449 |
450 | // select a random handler from our array of target handlers
451 | return targetHandlersRva[getRandomInt(0, targetHandlersRva.size() - 1)];
452 | }
453 |
454 | void popVmContext(Instruction* instruction)
455 | {
456 | emitPopRegister(instruction, ZYDIS_REGISTER_RFLAGS, 64);
457 | emitPopRegister(instruction, ZYDIS_REGISTER_RAX, 64);
458 | emitPopRegister(instruction, ZYDIS_REGISTER_RBX, 64);
459 | emitPopRegister(instruction, ZYDIS_REGISTER_RCX, 64);
460 | emitPopRegister(instruction, ZYDIS_REGISTER_RDX, 64);
461 | emitPopRegister(instruction, ZYDIS_REGISTER_RSI, 64);
462 | emitPopRegister(instruction, ZYDIS_REGISTER_RDI, 64);
463 | emitPopRegister(instruction, ZYDIS_REGISTER_RBP, 64);
464 | emitPopRegister(instruction, ZYDIS_REGISTER_R8, 64);
465 | emitPopRegister(instruction, ZYDIS_REGISTER_R9, 64);
466 | emitPopRegister(instruction, ZYDIS_REGISTER_R10, 64);
467 | emitPopRegister(instruction, ZYDIS_REGISTER_R11, 64);
468 | emitPopRegister(instruction, ZYDIS_REGISTER_R12, 64);
469 | emitPopRegister(instruction, ZYDIS_REGISTER_R13, 64);
470 | emitPopRegister(instruction, ZYDIS_REGISTER_R14, 64);
471 | emitPopRegister(instruction, ZYDIS_REGISTER_R15, 64);
472 | emitPopRegister(instruction, R0, 64);
473 | }
474 |
475 | void pushVmContext(Instruction* instruction)
476 | {
477 | emitPushRegister(instruction, ZYDIS_REGISTER_R15, 64);
478 | emitPushRegister(instruction, ZYDIS_REGISTER_R14, 64);
479 | emitPushRegister(instruction, ZYDIS_REGISTER_R13, 64);
480 | emitPushRegister(instruction, ZYDIS_REGISTER_R12, 64);
481 | emitPushRegister(instruction, ZYDIS_REGISTER_R11, 64);
482 | emitPushRegister(instruction, ZYDIS_REGISTER_R10, 64);
483 | emitPushRegister(instruction, ZYDIS_REGISTER_R9, 64);
484 | emitPushRegister(instruction, ZYDIS_REGISTER_R8, 64);
485 | emitPushRegister(instruction, ZYDIS_REGISTER_RBP, 64);
486 | emitPushRegister(instruction, ZYDIS_REGISTER_RDI, 64);
487 | emitPushRegister(instruction, ZYDIS_REGISTER_RSI, 64);
488 | emitPushRegister(instruction, ZYDIS_REGISTER_RDX, 64);
489 | emitPushRegister(instruction, ZYDIS_REGISTER_RCX, 64);
490 | emitPushRegister(instruction, ZYDIS_REGISTER_RBX, 64);
491 | emitPushRegister(instruction, ZYDIS_REGISTER_RAX, 64);
492 | emitPushRegister(instruction, ZYDIS_REGISTER_RFLAGS, 64);
493 | }
494 |
495 | template
496 | void emitPushRegister(Instruction* instruction, T reg, BYTE size)
497 | {
498 | switch (reg)
499 | {
500 | case ZYDIS_REGISTER_RSP: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(PUSHRSP64))); return;
501 | case ZYDIS_REGISTER_ESP: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(PUSHRSP32))); return;
502 | case ZYDIS_REGISTER_SP: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(PUSHRSP16))); return;
503 | case ZYDIS_REGISTER_SPL: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(PUSHRSP8))); return;
504 | }
505 |
506 | switch (size)
507 | {
508 | case 64: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(PUSHR64), getVirtualRegisterIndex(reg), 8)); return;
509 | case 32: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(PUSHR32), getVirtualRegisterIndex(reg), 8)); return;
510 | case 16: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(PUSHR16), getVirtualRegisterIndex(reg), 8)); return;
511 | case 8: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(PUSHR8), getVirtualRegisterIndex(reg), 8)); return;
512 | }
513 | }
514 |
515 | template
516 | void emitPopRegister(Instruction* instruction, T reg, BYTE size)
517 | {
518 | switch (reg)
519 | {
520 | case ZYDIS_REGISTER_RSP: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(POPRSP64))); return;
521 | case ZYDIS_REGISTER_ESP: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(POPRSP32))); return;
522 | case ZYDIS_REGISTER_SP: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(POPRSP16))); return;
523 | case ZYDIS_REGISTER_SPL: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(POPRSP8))); return;
524 | }
525 |
526 | switch (size)
527 | {
528 | case 64: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(POPR64), getVirtualRegisterIndex(reg), 8)); return;
529 | case 32: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(POPR32), getVirtualRegisterIndex(reg), 8)); return;
530 | case 16: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(POPR16), getVirtualRegisterIndex(reg), 8)); return;
531 | case 8: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(POPR8), getVirtualRegisterIndex(reg), 8)); return;
532 | }
533 | }
534 |
535 | void emitPushImmediate(Instruction* instruction, long long immediate, BYTE size)
536 | {
537 | switch (size)
538 | {
539 | case 64: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(PUSHI64), immediate, 64)); return;
540 | case 32: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(PUSHI32), immediate, 32)); return;
541 | case 16: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(PUSHI16), immediate, 16)); return;
542 | case 8: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(PUSHI8), immediate, 8)); return;
543 | }
544 | }
545 |
546 | void emitRead(Instruction* instruction, BYTE size)
547 | {
548 | switch (size)
549 | {
550 | case 64: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(READ64))); return;
551 | case 32: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(READ32))); return;
552 | case 16: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(READ16))); return;
553 | case 8: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(READ8))); return;
554 | }
555 | }
556 |
557 | void emitWrite(Instruction* instruction, BYTE size)
558 | {
559 | switch (size)
560 | {
561 | case 64: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(WRITE64))); return;
562 | case 32: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(WRITE32))); return;
563 | case 16: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(WRITE16))); return;
564 | case 8: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(WRITE8))); return;
565 | }
566 | }
567 |
568 | void emitJmp(Instruction* instruction) { instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(JMP), 0x0, 32)); }
569 |
570 | void emitJne(Instruction* instruction) { instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(JNE), 0x0, 32)); }
571 |
572 | void emitExit(Instruction* instruction) { instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(EXIT))); }
573 |
574 | void emitAdd(Instruction* instruction, BYTE size)
575 | {
576 | switch (size)
577 | {
578 | case 64: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(ADD64))); return;
579 | case 32: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(ADD32))); return;
580 | case 16: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(ADD16))); return;
581 | case 8: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(ADD8))); return;
582 | }
583 | }
584 |
585 | void emitSub(Instruction* instruction, BYTE size)
586 | {
587 | switch (size)
588 | {
589 | case 64: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(SUB64))); return;
590 | case 32: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(SUB32))); return;
591 | case 16: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(SUB16))); return;
592 | case 8: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(SUB8))); return;
593 | }
594 | }
595 |
596 | void emitXor(Instruction* instruction, BYTE size)
597 | {
598 | switch (size)
599 | {
600 | case 64: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(XOR64))); return;
601 | case 32: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(XOR32))); return;
602 | case 16: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(XOR16))); return;
603 | case 8: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(XOR8))); return;
604 | }
605 | }
606 |
607 | void emitAnd(Instruction* instruction, BYTE size)
608 | {
609 | switch (size)
610 | {
611 | case 64: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(AND64))); return;
612 | case 32: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(AND32))); return;
613 | case 16: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(AND16))); return;
614 | case 8: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(AND8))); return;
615 | }
616 | }
617 |
618 | void emitOr(Instruction* instruction, BYTE size)
619 | {
620 | switch (size)
621 | {
622 | case 64: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(OR64))); return;
623 | case 32: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(OR32))); return;
624 | case 16: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(OR16))); return;
625 | case 8: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(OR8))); return;
626 | }
627 | }
628 |
629 | void emitShl(Instruction* instruction, BYTE size)
630 | {
631 | switch (size)
632 | {
633 | case 64: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(SHL64))); return;
634 | case 32: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(SHL32))); return;
635 | case 16: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(SHL16))); return;
636 | case 8: instruction->addVirtualInstruction(VirtualInstruction(getVmHandlerRva(SHL8))); return;
637 | }
638 | }
639 |
640 | void emitArithmetic(Instruction* instruction, ZydisMnemonic operation, BYTE size)
641 | {
642 | switch (operation)
643 | {
644 | case ZYDIS_MNEMONIC_ADD: emitAdd(instruction, size); return;
645 | case ZYDIS_MNEMONIC_SUB: emitSub(instruction, size); return;
646 | case ZYDIS_MNEMONIC_XOR: emitXor(instruction, size); return;
647 | case ZYDIS_MNEMONIC_AND: emitAnd(instruction, size); return;
648 | case ZYDIS_MNEMONIC_OR: emitOr(instruction, size); return;
649 | case ZYDIS_MNEMONIC_SHL: emitShl(instruction, size); return;
650 | }
651 | }
652 |
653 | void zeroRegister(Instruction* instruction, ZydisRegister reg)
654 | {
655 | emitPushImmediate(instruction, 0x0, 64);
656 | emitPopRegister(instruction, reg, 64);
657 | }
658 |
659 | void calculateEffectiveAddress(Instruction* instruction, ZydisDecodedOperandMem mem)
660 | {
661 | ZydisRegister base = mem.base;
662 | ZydisRegister index = mem.index;
663 | BYTE scale = mem.scale;
664 | bool hasDisplacement = mem.disp.has_displacement;
665 | long long displacement = mem.disp.value;
666 |
667 | bool is64Bits = (base != ZYDIS_REGISTER_NONE && ZydisRegisterGetWidth(ZYDIS_MACHINE_MODE_LONG_64, base) == 64) ||
668 | (index != ZYDIS_REGISTER_NONE && ZydisRegisterGetWidth(ZYDIS_MACHINE_MODE_LONG_64, index) == 64);
669 |
670 | if (base == ZYDIS_REGISTER_RIP)
671 | {
672 | emitPushImmediate(instruction, instruction->getRva() + instruction->getInstructionInfo().length + displacement, 64);
673 | emitPushRegister(instruction, R1, 64);
674 | emitArithmetic(instruction, ZYDIS_MNEMONIC_ADD, 64);
675 | emitPopRegister(instruction, R0, 64);
676 | return;
677 | }
678 |
679 | if (base != ZYDIS_REGISTER_NONE)
680 | {
681 | if (base == ZYDIS_REGISTER_RSP)
682 | {
683 | emitPushRegister(instruction, ZYDIS_REGISTER_RSP, 64);
684 | }
685 | else
686 | {
687 | if (is64Bits)
688 | {
689 | emitPushRegister(instruction, base, 64);
690 | }
691 | else
692 | {
693 | emitPushRegister(instruction, base, 32);
694 | }
695 | }
696 | }
697 | else
698 | {
699 | if (is64Bits)
700 | {
701 | emitPushImmediate(instruction, 0x0, 64);
702 | }
703 | else
704 | {
705 | emitPushImmediate(instruction, 0x0, 32);
706 | }
707 | }
708 |
709 | if (index != ZYDIS_REGISTER_NONE)
710 | {
711 | if (is64Bits)
712 | {
713 | emitPushRegister(instruction, index, 64);
714 | }
715 | else
716 | {
717 | emitPushRegister(instruction, index, 32);
718 | }
719 |
720 | if (scale > 1)
721 | {
722 | emitPushImmediate(instruction, std::log2(scale), 64);
723 | if (is64Bits)
724 | {
725 | emitArithmetic(instruction, ZYDIS_MNEMONIC_SHL, 64);
726 | }
727 | else
728 | {
729 | emitArithmetic(instruction, ZYDIS_MNEMONIC_SHL, 32);
730 | }
731 | emitPopRegister(instruction, R0, 64);
732 | }
733 | }
734 | else
735 | {
736 | if (is64Bits)
737 | {
738 | emitPushImmediate(instruction, 0x0, 64);
739 | }
740 | else
741 | {
742 | emitPushImmediate(instruction, 0x0, 32);
743 | }
744 | }
745 |
746 | if (hasDisplacement)
747 | {
748 | if (is64Bits)
749 | {
750 | emitPushImmediate(instruction, displacement, 64);
751 | }
752 | else
753 | {
754 | emitPushImmediate(instruction, displacement, 32);
755 | }
756 | }
757 | else
758 | {
759 | if (is64Bits)
760 | {
761 | emitPushImmediate(instruction, 0x0, 64);
762 | }
763 | else
764 | {
765 | emitPushImmediate(instruction, 0x0, 32);
766 | }
767 | }
768 |
769 | if (is64Bits)
770 | {
771 | emitArithmetic(instruction, ZYDIS_MNEMONIC_ADD, 64);
772 | emitPopRegister(instruction, R0, 64);
773 | emitArithmetic(instruction, ZYDIS_MNEMONIC_ADD, 64);
774 | emitPopRegister(instruction, R0, 64);
775 | }
776 | else
777 | {
778 | emitArithmetic(instruction, ZYDIS_MNEMONIC_ADD, 32);
779 | emitPopRegister(instruction, R0, 32);
780 | emitArithmetic(instruction, ZYDIS_MNEMONIC_ADD, 32);
781 | emitPopRegister(instruction, R0, 32);
782 | }
783 | }
784 | }
--------------------------------------------------------------------------------
/src/vm.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include "vm_handler.h"
8 | #include "virtual_instruction.h"
9 | #include "util.h"
10 |
11 | class Instruction;
12 |
13 | namespace VM
14 | {
15 | enum VIRTUAL_REGISTERS
16 | {
17 | R0, // general purpose register
18 | R1, // module base
19 | };
20 |
21 | extern std::vector vmHandlers;
22 |
23 | bool compileInstructionToVirtualInstructions(Instruction* instruction);
24 |
25 | bool x86PushHandler(Instruction* instruction);
26 | bool x86PopHandler(Instruction* instruction);
27 | bool x86MovHandler(Instruction* instruction);
28 | bool x86LeaHandler(Instruction* instruction);
29 | bool x86RetHandler(Instruction* instruction);
30 | bool x86CmpHandler(Instruction* instruction);
31 | bool x86TestHandler(Instruction* instruction);
32 | bool x86JmpHandler(Instruction* instruction);
33 | bool x86JneHandler(Instruction* instruction);
34 | bool x86ArithmeticHandler(Instruction* instruction, ZydisMnemonic operation, bool storeOutput);
35 |
36 | BYTE getVirtualRegisterIndex(ZydisRegister reg);
37 | BYTE getVirtualRegisterIndex(VIRTUAL_REGISTERS reg);
38 | DWORD getVmHandlerRva(VMHandlerTypes type);
39 |
40 | void popVmContext(Instruction* instruction);
41 | void pushVmContext(Instruction* instruction);
42 |
43 | template
44 | void emitPushRegister(Instruction* instruction, T reg, BYTE size);
45 | template
46 | void emitPopRegister(Instruction* instruction, T reg, BYTE size);
47 | void emitPushImmediate(Instruction* instruction, long long immediate, BYTE size);
48 | void emitRead(Instruction* instruction, BYTE size);
49 | void emitWrite(Instruction* instruction, BYTE size);
50 | void emitJmp(Instruction* instruction);
51 | void emitJne(Instruction* instruction);
52 | void emitExit(Instruction* instruction);
53 | void emitAdd(Instruction* instruction, BYTE size);
54 | void emitSub(Instruction* instruction, BYTE size);
55 | void emitXor(Instruction* instruction, BYTE size);
56 | void emitAnd(Instruction* instruction, BYTE size);
57 | void emitOr(Instruction* instruction, BYTE size);
58 | void emitShl(Instruction* instruction, BYTE size);
59 | void emitArithmetic(Instruction* instruction, ZydisMnemonic operation, BYTE size);
60 | void zeroRegister(Instruction* instruction, ZydisRegister reg);
61 | void calculateEffectiveAddress(Instruction* instruction, ZydisDecodedOperandMem mem);
62 | }
--------------------------------------------------------------------------------
/src/vm_handler.cpp:
--------------------------------------------------------------------------------
1 | #include "vm_handler.h"
2 |
3 | VMHandlerTypes VMHandler::getType() { return type; }
4 |
5 | DWORD VMHandler::getRva() { return rva; }
6 |
7 | DWORD VMHandler::getFileOffset() { return fileOffset; }
8 |
9 | std::vector VMHandler::getBytes() { return bytes; }
10 |
11 | void VMHandler::setRva(DWORD rva) { this->rva = rva; }
12 |
13 | void VMHandler::setFileOffset(DWORD fileOffset) { this->fileOffset = fileOffset; }
--------------------------------------------------------------------------------
/src/vm_handler.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | /*
7 |
8 | afaik, stack collision check is only required for
9 | handlers that push values onto stack, or modify the vsp. They
10 | shouldn't be required on other handlers since they operate
11 | within a safe range (I think).
12 |
13 | Reason we require the check after the main part of PopRSP64, ..., PopRSP8 has executed
14 | is due to the fact this could result in a collision depending on how rsp was
15 | affected. Similarly, inside CONTEXT_COLLISION_CHECK we select the smallest
16 | value between rsp & r15 to determine where we will base our vmctx relocation.
17 |
18 | */
19 |
20 | #define CONTEXT_COLLISION_CHECK \
21 | 0x48, 0x8D, 0xB4, 0x24, 0x97, 0x00, 0x00, 0x00, /* lea rsi, qword ptr [rsp+0x97] */ \
22 | 0x49, 0x39, 0xF7, /* cmp r15, rsi */ \
23 | 0x7F, 0x22, /* jg NO_COLLISION */ \
24 | 0x48, 0x89, 0xE7, /* mov rdi, rsp */ \
25 | 0x49, 0x39, 0xFF, /* cmp r15, rdi */ \
26 | 0x49, 0x0F, 0x42, 0xFF, /* cmovb rdi, r15 */ \
27 | 0x48, 0x83, 0xEF, 0x40, /* sub rdi, 0x40 */ \
28 | 0x48, 0x83, 0xEE, 0x08, /* sub rsi, 0x08 */ \
29 | 0x48, 0xC7, 0xC1, 0x90, 0x00, 0x00, 0x00, /* mov rcx, 0x90 */ \
30 | 0xFD, /* std */ \
31 | 0xF3, 0xA4, /* rep movsb */ \
32 | 0x48, 0xFF, 0xC7, /* inc rdi */ \
33 | 0x48, 0x89, 0xFC, /* mov rsp, rdi */ \
34 | /* NO_COLLISION: */
35 |
36 | #define JMP_TO_NEXT_HANDLER \
37 | 0x41, 0x8B, 0x45, 0x00, /* mov eax, dword ptr [r13] */ \
38 | 0x49, 0x83, 0xC5, 0x04, /* add r13, 0x04 */ \
39 | 0x4C, 0x01, 0xF0, /* add rax, r14 */ \
40 | 0xFF, 0xE0, /* jmp rax */
41 |
42 | enum VMHandlerTypes
43 | {
44 | ENTER, EXIT,
45 |
46 | PUSHI64, PUSHI32, PUSHI16, PUSHI8,
47 |
48 | PUSHR64, PUSHR32, PUSHR16, PUSHR8,
49 |
50 | PUSHRSP64, PUSHRSP32, PUSHRSP16, PUSHRSP8,
51 |
52 | POPRSP64, POPRSP32, POPRSP16, POPRSP8,
53 |
54 | POPR64, POPR32, POPR16, POPR8,
55 |
56 | READ64, READ32, READ16, READ8,
57 |
58 | WRITE64, WRITE32, WRITE16, WRITE8,
59 |
60 | ADD64, ADD32, ADD16, ADD8,
61 |
62 | SUB64, SUB32, SUB16, SUB8,
63 |
64 | XOR64, XOR32, XOR16, XOR8,
65 |
66 | AND64, AND32, AND16, AND8,
67 |
68 | OR64, OR32, OR16, OR8,
69 |
70 | NAND64, NAND32, NAND16, NAND8,
71 |
72 | NOR64, NOR32, NOR16, NOR8,
73 |
74 | SHL64, SHL32, SHL16, SHL8,
75 |
76 | JMP,
77 |
78 | JNE,
79 | };
80 |
81 | class VMHandler
82 | {
83 | public:
84 | VMHandlerTypes getType();
85 | DWORD getRva();
86 | DWORD getFileOffset();
87 | std::vector getBytes();
88 |
89 | void setRva(DWORD rva);
90 | void setFileOffset(DWORD fileOffset);
91 | protected:
92 | VMHandlerTypes type;
93 | DWORD rva;
94 | DWORD fileOffset;
95 | std::vector bytes;
96 | };
97 |
98 | class Enter : public VMHandler
99 | {
100 | public:
101 | Enter()
102 | {
103 | type = ENTER;
104 | bytes =
105 | {
106 | 0x41, 0x57, // push r15
107 | 0x41, 0x56, // push r14
108 | 0x41, 0x55, // push r13
109 | 0x41, 0x54, // push r12
110 | 0x41, 0x53, // push r11
111 | 0x41, 0x52, // push r10
112 | 0x41, 0x51, // push r9
113 | 0x41, 0x50, // push r8
114 | 0x55, // push rbp
115 | 0x57, // push rdi
116 | 0x56, // push rsi
117 | 0x52, // push rdx
118 | 0x51, // push rcx
119 | 0x53, // push rbx
120 | 0x50, // push rax
121 | 0x9C, // pushfq
122 | 0x49, 0x89, 0xE7, // mov r15, rsp
123 | 0x48, 0x81, 0xEC, 0x0, 0x1, 0x0, 0x0, // sub rsp, 0x100
124 | 0x65, 0x4C, 0x8B, 0x34, 0x25, 0x60, 0x0, 0x0, 0x0, // mov r14, qword ptr gs:[0x60]
125 | 0x4D, 0x8B, 0x76, 0x10, // mov r14, qword ptr [r13+0x10]
126 | 0x4C, 0x89, 0xB4, 0x24, 0x88, 0x00, 0x00, 0x00, // mov qword ptr [rsp+0x88], r14
127 | 0x45, 0x8B, 0xAF, 0x80, 0x0, 0x0, 0x0, // mov r13d, dword ptr [r15+0x80]
128 | 0x4D, 0x01, 0xF5, // add r13, r14
129 | JMP_TO_NEXT_HANDLER
130 | };
131 | };
132 | private:
133 |
134 | };
135 | class Exit : public VMHandler
136 | {
137 | public:
138 | Exit()
139 | {
140 | type = EXIT;
141 | bytes =
142 | {
143 | 0x4C, 0x89, 0xFC, // mov rsp, r15
144 | 0x9D, // popfq
145 | 0x58, // pop rax
146 | 0x5B, // pop rbx
147 | 0x59, // pop rcx
148 | 0x5A, // pop rdx
149 | 0x5E, // pop rsi
150 | 0x5F, // pop rdi
151 | 0x5D, // pop rbp
152 | 0x41, 0x58, // pop r8
153 | 0x41, 0x59, // pop r9
154 | 0x41, 0x5A, // pop r10
155 | 0x41, 0x5B, // pop r11
156 | 0x41, 0x5C, // pop r12
157 | 0x41, 0x5D, // pop r13
158 | 0x41, 0x5E, // pop r14
159 | 0x41, 0x5F, // pop r15
160 | 0xC3, // ret
161 | };
162 | };
163 | private:
164 |
165 | };
166 |
167 | class PushR64 : public VMHandler
168 | {
169 | public:
170 | PushR64()
171 | {
172 | type = PUSHR64;
173 | bytes =
174 | {
175 | CONTEXT_COLLISION_CHECK
176 | 0x49, 0x8B, 0x45, 0x00, // mov rax, qword ptr [r13]
177 | 0x48, 0x25, 0xFF, 0x00, 0x00, 0x00, // and rax, 0xFF
178 | 0x49, 0xFF, 0xC5, // inc r13
179 | 0x48, 0x8B, 0x04, 0xC4, // mov rax, qword ptr [rsp+rax*0x08]
180 | 0x49, 0x83, 0xEF, 0x08, // sub r15, 0x08
181 | 0x49, 0x89, 0x07, // mov qword ptr [r15], rax
182 | JMP_TO_NEXT_HANDLER
183 | };
184 | }
185 | };
186 | class PushR32 : public VMHandler
187 | {
188 | public:
189 | PushR32()
190 | {
191 | type = PUSHR32;
192 | bytes =
193 | {
194 | CONTEXT_COLLISION_CHECK
195 | 0x49, 0x8B, 0x45, 0x00, // mov rax, qword ptr [r13]
196 | 0x48, 0x25, 0xFF, 0x00, 0x00, 0x00, // and rax, 0xFF
197 | 0x49, 0xFF, 0xC5, // inc r13
198 | 0x8B, 0x04, 0xC4, // mov eax, dword ptr [rsp+rax*0x08]
199 | 0x49, 0x83, 0xEF, 0x04, // sub r15, 0x04
200 | 0x41, 0x89, 0x07, // mov dword ptr [r15], eax
201 | JMP_TO_NEXT_HANDLER
202 | };
203 | }
204 | };
205 | class PushR16 : public VMHandler
206 | {
207 | public:
208 | PushR16()
209 | {
210 | type = PUSHR16;
211 | bytes =
212 | {
213 | CONTEXT_COLLISION_CHECK
214 | 0x49, 0x8B, 0x45, 0x00, // mov rax, qword ptr [r13]
215 | 0x48, 0x25, 0xFF, 0x00, 0x00, 0x00, // and rax, 0xFF
216 | 0x49, 0xFF, 0xC5, // inc r13
217 | 0x66, 0x8B, 0x04, 0xC4, // mov ax, word ptr [rsp+rax*0x08]
218 | 0x49, 0x83, 0xEF, 0x02, // sub r15, 0x02
219 | 0x66, 0x41, 0x89, 0x07, // mov word ptr [r15], ax
220 | JMP_TO_NEXT_HANDLER
221 | };
222 | }
223 | };
224 | class PushR8 : public VMHandler
225 | {
226 | public:
227 | PushR8()
228 | {
229 | type = PUSHR8;
230 | bytes =
231 | {
232 | CONTEXT_COLLISION_CHECK
233 | 0x49, 0x8B, 0x45, 0x00, // mov rax, qword ptr [r13]
234 | 0x48, 0x25, 0xFF, 0x00, 0x00, 0x00, // and rax, 0xFF
235 | 0x49, 0xFF, 0xC5, // inc r13
236 | 0x8A, 0x04, 0xC4, // mov al, byte ptr [rsp+rax*0x08]
237 | 0x49, 0x83, 0xEF, 0x01, // sub r15, 0x01
238 | 0x41, 0x88, 0x07, // mov byte ptr [r15], al
239 | JMP_TO_NEXT_HANDLER
240 | };
241 | }
242 | };
243 |
244 | class PushRSP64 : public VMHandler
245 | {
246 | public:
247 | PushRSP64()
248 | {
249 | type = PUSHRSP64;
250 | bytes =
251 | {
252 | CONTEXT_COLLISION_CHECK
253 | 0x4C, 0x89, 0xF8, // mov rax, r15
254 | 0x49, 0x83, 0xEF, 0x08, // sub r15, 0x08
255 | 0x49, 0x89, 0x07, // mov qword ptr [r15], rax
256 | JMP_TO_NEXT_HANDLER
257 | };
258 | }
259 | };
260 | class PushRSP32 : public VMHandler
261 | {
262 | public:
263 | PushRSP32()
264 | {
265 | type = PUSHRSP32;
266 | bytes =
267 | {
268 | CONTEXT_COLLISION_CHECK
269 | 0x44, 0x89, 0xF8, // mov eax, r15d
270 | 0x49, 0x83, 0xEF, 0x04, // sub r15, 0x04
271 | 0x41, 0x89, 0x07, // mov dword ptr [r15], eax
272 | JMP_TO_NEXT_HANDLER
273 | };
274 | }
275 | };
276 | class PushRSP16 : public VMHandler
277 | {
278 | public:
279 | PushRSP16()
280 | {
281 | type = PUSHRSP16;
282 | bytes =
283 | {
284 | CONTEXT_COLLISION_CHECK
285 | 0x66, 0x44, 0x89, 0xF8, // mov ax, r15w
286 | 0x49, 0x83, 0xEF, 0x02, // sub r15, 0x02
287 | 0x66, 0x41, 0x89, 0x07, // mov word ptr [r15], ax
288 | JMP_TO_NEXT_HANDLER
289 | };
290 | }
291 | };
292 | class PushRSP8 : public VMHandler
293 | {
294 | public:
295 | PushRSP8()
296 | {
297 | type = PUSHRSP8;
298 | bytes =
299 | {
300 | CONTEXT_COLLISION_CHECK
301 | 0x44, 0x88, 0xF8, // mov al, r15b
302 | 0x49, 0x83, 0xEF, 0x01, // sub r15, 0x01
303 | 0x41, 0x88, 0x07, // mov byte ptr [r15], al
304 | JMP_TO_NEXT_HANDLER
305 | };
306 | }
307 | };
308 |
309 | class PopRSP64 : public VMHandler
310 | {
311 | public:
312 | PopRSP64()
313 | {
314 | type = POPRSP64;
315 | bytes =
316 | {
317 | 0x4D, 0x8B, 0x3F, // mov r15, qword ptr [r15]
318 | CONTEXT_COLLISION_CHECK
319 | JMP_TO_NEXT_HANDLER
320 | };
321 | }
322 | };
323 | class PopRSP32 : public VMHandler
324 | {
325 | public:
326 | PopRSP32()
327 | {
328 | type = POPRSP32;
329 | bytes =
330 | {
331 | 0x45, 0x8B, 0x3F, // mov r15d, dword ptr [r15]
332 | CONTEXT_COLLISION_CHECK
333 | JMP_TO_NEXT_HANDLER
334 | };
335 | }
336 | };
337 | class PopRSP16 : public VMHandler
338 | {
339 | public:
340 | PopRSP16()
341 | {
342 | type = POPRSP16;
343 | bytes =
344 | {
345 | 0x66, 0x45, 0x8B, 0x3F, // mov r15w, word ptr [r15]
346 | CONTEXT_COLLISION_CHECK
347 | JMP_TO_NEXT_HANDLER
348 | };
349 | }
350 | };
351 | class PopRSP8 : public VMHandler
352 | {
353 | public:
354 | PopRSP8()
355 | {
356 | type = POPRSP8;
357 | bytes =
358 | {
359 | 0x45, 0x8A, 0x3F, // mov r15b, byte ptr [r15]
360 | CONTEXT_COLLISION_CHECK
361 | JMP_TO_NEXT_HANDLER
362 | };
363 | }
364 | };
365 |
366 | class PopR64 : public VMHandler
367 | {
368 | public:
369 | PopR64()
370 | {
371 | type = POPR64;
372 | bytes =
373 | {
374 | 0x49, 0x8B, 0x45, 0x00, // mov rax, qword ptr [r13]
375 | 0x48, 0x25, 0xFF, 0x00, 0x00, 0x00, // and rax, 0xFF
376 | 0x49, 0xFF, 0xC5, // inc r13
377 | 0x49, 0x8B, 0x1F, // mov rbx, qword ptr [r15]
378 | 0x49, 0x83, 0xC7, 0x08, // add r15, 0x08
379 | 0x48, 0x89, 0x1C, 0xC4, // mov qword ptr [rsp+rax*8], rbx
380 | JMP_TO_NEXT_HANDLER
381 | };
382 | }
383 | };
384 | class PopR32 : public VMHandler
385 | {
386 | public:
387 | PopR32()
388 | {
389 | type = POPR32;
390 | bytes =
391 | {
392 | 0x49, 0x8B, 0x45, 0x00, // mov rax, qword ptr [r13]
393 | 0x48, 0x25, 0xFF, 0x00, 0x00, 0x00, // and rax, 0xFF
394 | 0x49, 0xFF, 0xC5, // inc r13
395 | 0x41, 0x8B, 0x1F, // mov ebx, dword ptr [r15]
396 | 0x49, 0x83, 0xC7, 0x04, // add r15, 0x04
397 | 0x89, 0x1C, 0xC4, // mov dword ptr [rsp+rax*8], ebx
398 | JMP_TO_NEXT_HANDLER
399 | };
400 | }
401 | };
402 | class PopR16 : public VMHandler
403 | {
404 | public:
405 | PopR16()
406 | {
407 | type = POPR16;
408 | bytes =
409 | {
410 | 0x49, 0x8B, 0x45, 0x00, // mov rax, qword ptr [r13]
411 | 0x48, 0x25, 0xFF, 0x00, 0x00, 0x00, // and rax, 0xFF
412 | 0x49, 0xFF, 0xC5, // inc r13
413 | 0x66, 0x41, 0x8B, 0x1F, // mov bx, word ptr [r15]
414 | 0x49, 0x83, 0xC7, 0x02, // add r15, 0x02
415 | 0x66, 0x89, 0x1C, 0xC4, // mov word ptr [rsp+rax*8], bx
416 | JMP_TO_NEXT_HANDLER
417 | };
418 | }
419 | };
420 | class PopR8 : public VMHandler
421 | {
422 | public:
423 | PopR8()
424 | {
425 | type = POPR8;
426 | bytes =
427 | {
428 | 0x49, 0x8B, 0x45, 0x00, // mov rax, qword ptr [r13]
429 | 0x48, 0x25, 0xFF, 0x00, 0x00, 0x00, // and rax, 0xFF
430 | 0x49, 0xFF, 0xC5, // inc r13
431 | 0x41, 0x8A, 0x1F, // mov bl, byte ptr [r15]
432 | 0x49, 0x83, 0xC7, 0x01, // add r15, 0x01
433 | 0x88, 0x1C, 0xC4, // mov byte ptr [rsp+rax*8], bl
434 | JMP_TO_NEXT_HANDLER
435 | };
436 | }
437 | };
438 |
439 | class PushI64 : public VMHandler
440 | {
441 | public:
442 | PushI64()
443 | {
444 | type = PUSHI64;
445 | bytes =
446 | {
447 | CONTEXT_COLLISION_CHECK
448 | 0x49, 0x8B, 0x45, 0x00, // mov rax, qword ptr [r13]
449 | 0x49, 0x83, 0xC5, 0x08, // add r13, 0x08
450 | 0x49, 0x83, 0xEF, 0x08, // sub r15, 0x08
451 | 0x49, 0x89, 0x07, // mov qword ptr [r15], rax
452 | JMP_TO_NEXT_HANDLER
453 | };
454 | }
455 | };
456 | class PushI32 : public VMHandler
457 | {
458 | public:
459 | PushI32()
460 | {
461 | type = PUSHI32;
462 | bytes =
463 | {
464 | CONTEXT_COLLISION_CHECK
465 | 0x41, 0x8B, 0x45, 0x00, // mov eax, dword ptr [r13]
466 | 0x49, 0x83, 0xC5, 0x04, // add r13, 0x04
467 | 0x49, 0x83, 0xEF, 0x04, // sub r15, 0x04
468 | 0x41, 0x89, 0x07, // mov dword ptr [r15], eax
469 | JMP_TO_NEXT_HANDLER
470 | };
471 | }
472 | };
473 | class PushI16 : public VMHandler
474 | {
475 | public:
476 | PushI16()
477 | {
478 | type = PUSHI16;
479 | bytes =
480 | {
481 | CONTEXT_COLLISION_CHECK
482 | 0x66, 0x41, 0x8B, 0x45, 0x00, // mov ax, word ptr [r13]
483 | 0x49, 0x83, 0xC5, 0x02, // add r13, 0x02
484 | 0x49, 0x83, 0xEF, 0x02, // sub r15, 0x02
485 | 0x66, 0x41, 0x89, 0x07, // mov word ptr [r15], ax
486 | JMP_TO_NEXT_HANDLER
487 | };
488 | }
489 | };
490 | class PushI8 : public VMHandler
491 | {
492 | public:
493 | PushI8()
494 | {
495 | type = PUSHI8;
496 | bytes =
497 | {
498 | CONTEXT_COLLISION_CHECK
499 | 0x41, 0x8A, 0x45, 0x00, // mov al, byte ptr [r13]
500 | 0x49, 0x83, 0xC5, 0x01, // add r13, 0x01
501 | 0x49, 0x83, 0xEF, 0x01, // sub r15, 0x01
502 | 0x41, 0x88, 0x07, // mov byte ptr [r15], al
503 | JMP_TO_NEXT_HANDLER
504 | };
505 | }
506 | };
507 |
508 | class Read64 : public VMHandler
509 | {
510 | public:
511 | Read64()
512 | {
513 | type = READ64;
514 | bytes =
515 | {
516 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
517 | 0x48, 0x8B, 0x00, // mov rax, qword ptr [rax]
518 | 0x49, 0x89, 0x07, // mov qword ptr [r15], rax
519 | JMP_TO_NEXT_HANDLER
520 | };
521 | }
522 | };
523 | class Read32 : public VMHandler
524 | {
525 | public:
526 | Read32()
527 | {
528 | type = READ32;
529 | bytes =
530 | {
531 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
532 | 0x8B, 0x00, // mov eax, dword ptr [rax]
533 | 0x49, 0x83, 0xC7, 0x04, // add r15, 0x04
534 | 0x41, 0x89, 0x07, // mov dword ptr [r15], eax
535 | JMP_TO_NEXT_HANDLER
536 | };
537 | }
538 | };
539 | class Read16 : public VMHandler
540 | {
541 | public:
542 | Read16()
543 | {
544 | type = READ16;
545 | bytes =
546 | {
547 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
548 | 0x66, 0x8B, 0x00, // mov ax, word ptr [rax]
549 | 0x49, 0x83, 0xC7, 0x06, // add r15, 0x06
550 | 0x66, 0x41, 0x89, 0x07, // mov word ptr [r15], ax
551 | JMP_TO_NEXT_HANDLER
552 | };
553 | }
554 | };
555 | class Read8 : public VMHandler
556 | {
557 | public:
558 | Read8()
559 | {
560 | type = READ8;
561 | bytes =
562 | {
563 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
564 | 0x8A, 0x00, // mov al, byte ptr [rax]
565 | 0x49, 0x83, 0xC7, 0x07, // add r15, 0x07
566 | 0x41, 0x88, 0x07, // mov byte ptr [r15], al
567 | JMP_TO_NEXT_HANDLER
568 | };
569 | }
570 | };
571 |
572 | class Write64 : public VMHandler
573 | {
574 | public:
575 | Write64()
576 | {
577 | type = WRITE64;
578 | bytes =
579 | {
580 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
581 | 0x49, 0x8B, 0x5F, 0x08, // mov rbx, qword ptr [r15+0x08]
582 | 0x49, 0x83, 0xC7, 0x10, // add r15, 0x10
583 | 0x48, 0x89, 0x18, // mov qword ptr [rax], rbx
584 | JMP_TO_NEXT_HANDLER
585 | };
586 | }
587 | };
588 | class Write32 : public VMHandler
589 | {
590 | public:
591 | Write32()
592 | {
593 | type = WRITE32;
594 | bytes =
595 | {
596 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
597 | 0x41, 0x8B, 0x5F, 0x08, // mov ebx, dword ptr [r15+0x08]
598 | 0x49, 0x83, 0xC7, 0x0C, // add r15, 0x0C
599 | 0x89, 0x18, // mov dword ptr [rax], ebx
600 | JMP_TO_NEXT_HANDLER
601 | };
602 | }
603 | };
604 | class Write16 : public VMHandler
605 | {
606 | public:
607 | Write16()
608 | {
609 | type = WRITE16;
610 | bytes =
611 | {
612 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
613 | 0x66, 0x41, 0x8B, 0x5F, 0x08, // mov bx, word ptr [r15+0x08]
614 | 0x49, 0x83, 0xC7, 0x0A, // add r15, 0x0A
615 | 0x66, 0x89, 0x18, // mov word ptr [rax], bx
616 | JMP_TO_NEXT_HANDLER
617 | };
618 | }
619 | };
620 | class Write8 : public VMHandler
621 | {
622 | public:
623 | Write8()
624 | {
625 | type = WRITE8;
626 | bytes =
627 | {
628 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
629 | 0x41, 0x8A, 0x5F, 0x08, // mov bl, byte ptr [r15+0x08]
630 | 0x49, 0x83, 0xC7, 0x09, // add r15, 0x9
631 | 0x88, 0x18, // mov byte ptr [rax], bl
632 | JMP_TO_NEXT_HANDLER
633 | };
634 | }
635 | };
636 |
637 | class Add64 : public VMHandler
638 | {
639 | public:
640 | Add64()
641 | {
642 | type = ADD64;
643 | bytes =
644 | {
645 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
646 | 0x49, 0x01, 0x47, 0x08, // add qword ptr [r15+0x08], rax
647 | 0x9C, // pushfq
648 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
649 | JMP_TO_NEXT_HANDLER
650 | };
651 | }
652 | };
653 | class Add32 : public VMHandler
654 | {
655 | public:
656 | Add32()
657 | {
658 | type = ADD32;
659 | bytes =
660 | {
661 | 0x41, 0x8B, 0x07, // mov eax, dword ptr [r15]
662 | 0x49, 0x83, 0xEF, 0x04, // sub r15, 0x04
663 | 0x41, 0x01, 0x47, 0x08, // add dword ptr [r15+0x08], eax
664 | 0x9C, // pushfq
665 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
666 | JMP_TO_NEXT_HANDLER
667 | };
668 | }
669 | };
670 | class Add16 : public VMHandler
671 | {
672 | public:
673 | Add16()
674 | {
675 | type = ADD16;
676 | bytes =
677 | {
678 | 0x66, 0x41, 0x8B, 0x07, // mov ax, word ptr [r15]
679 | 0x49, 0x83, 0xEF, 0x06, // sub r15, 0x06
680 | 0x66, 0x41, 0x01, 0x47, 0x08, // add word ptr [r15+0x08], ax
681 | 0x9C, // pushfq
682 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
683 | JMP_TO_NEXT_HANDLER
684 | };
685 | }
686 | };
687 | class Add8 : public VMHandler
688 | {
689 | public:
690 | Add8()
691 | {
692 | type = ADD8;
693 | bytes =
694 | {
695 | 0x41, 0x8A, 0x07, // mov al, byte ptr [r15]
696 | 0x49, 0x83, 0xEF, 0x07, // sub r15, 0x07
697 | 0x41, 0x00, 0x47, 0x08, // add byte ptr [r15+0x08], al
698 | 0x9C, // pushfq
699 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
700 | JMP_TO_NEXT_HANDLER
701 | };
702 | }
703 | };
704 |
705 | class Sub64 : public VMHandler
706 | {
707 | public:
708 | Sub64()
709 | {
710 | type = SUB64;
711 | bytes =
712 | {
713 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
714 | 0x49, 0x29, 0x47, 0x08, // sub qword ptr [r15+0x08], rax
715 | 0x9C, // pushfq
716 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
717 | JMP_TO_NEXT_HANDLER
718 | };
719 | }
720 | };
721 | class Sub32 : public VMHandler
722 | {
723 | public:
724 | Sub32()
725 | {
726 | type = SUB32;
727 | bytes =
728 | {
729 | 0x41, 0x8B, 0x07, // mov eax, dword ptr [r15]
730 | 0x49, 0x83, 0xEF, 0x04, // sub r15, 0x04
731 | 0x41, 0x29, 0x47, 0x08, // sub dword ptr [r15+0x08], eax
732 | 0x9C, // pushfq
733 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
734 | JMP_TO_NEXT_HANDLER
735 | };
736 | }
737 | };
738 | class Sub16 : public VMHandler
739 | {
740 | public:
741 | Sub16()
742 | {
743 | type = SUB16;
744 | bytes =
745 | {
746 | 0x66, 0x41, 0x8B, 0x07, // mov ax, word ptr [r15]
747 | 0x49, 0x83, 0xEF, 0x06, // sub r15, 0x06
748 | 0x66, 0x41, 0x29, 0x47, 0x08, // sub word ptr [r15+0x08], ax
749 | 0x9C, // pushfq
750 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
751 | JMP_TO_NEXT_HANDLER
752 | };
753 | }
754 | };
755 | class Sub8 : public VMHandler
756 | {
757 | public:
758 | Sub8()
759 | {
760 | type = SUB8;
761 | bytes =
762 | {
763 | 0x41, 0x8A, 0x07, // mov al, byte ptr [r15]
764 | 0x49, 0x83, 0xEF, 0x07, // sub r15, 0x07
765 | 0x41, 0x28, 0x47, 0x08, // sub byte ptr [r15+0x08], al
766 | 0x9C, // pushfq
767 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
768 | JMP_TO_NEXT_HANDLER
769 | };
770 | }
771 | };
772 |
773 | class Xor64 : public VMHandler
774 | {
775 | public:
776 | Xor64()
777 | {
778 | type = XOR64;
779 | bytes =
780 | {
781 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
782 | 0x49, 0x31, 0x47, 0x08, // xor qword ptr [r15+0x08], rax
783 | 0x9C, // pushfq
784 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
785 | JMP_TO_NEXT_HANDLER
786 | };
787 | }
788 | };
789 | class Xor32 : public VMHandler
790 | {
791 | public:
792 | Xor32()
793 | {
794 | type = XOR32;
795 | bytes =
796 | {
797 | 0x41, 0x8B, 0x07, // mov eax, dword ptr [r15]
798 | 0x49, 0x83, 0xEF, 0x04, // sub r15, 0x04
799 | 0x41, 0x31, 0x47, 0x08, // xor dword ptr [r15+0x08], eax
800 | 0x9C, // pushfq
801 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
802 | JMP_TO_NEXT_HANDLER
803 | };
804 | }
805 | };
806 | class Xor16 : public VMHandler
807 | {
808 | public:
809 | Xor16()
810 | {
811 | type = XOR16;
812 | bytes =
813 | {
814 | 0x66, 0x41, 0x8B, 0x07, // mov ax, word ptr [r15]
815 | 0x49, 0x83, 0xEF, 0x06, // sub r15, 0x06
816 | 0x66, 0x41, 0x31, 0x47, 0x08, // xor word ptr [r15+0x08], ax
817 | 0x9C, // pushfq
818 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
819 | JMP_TO_NEXT_HANDLER
820 | };
821 | }
822 | };
823 | class Xor8 : public VMHandler
824 | {
825 | public:
826 | Xor8()
827 | {
828 | type = XOR8;
829 | bytes =
830 | {
831 | 0x41, 0x8A, 0x07, // mov al, byte ptr [r15]
832 | 0x49, 0x83, 0xEF, 0x07, // sub r15, 0x07
833 | 0x41, 0x30, 0x47, 0x08, // xor byte ptr [r15+0x08], al
834 | 0x9C, // pushfq
835 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
836 | JMP_TO_NEXT_HANDLER
837 | };
838 | }
839 | };
840 |
841 | class And64 : public VMHandler
842 | {
843 | public:
844 | And64()
845 | {
846 | type = AND64;
847 | bytes =
848 | {
849 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
850 | 0x49, 0x21, 0x47, 0x08, // and qword ptr [r15+0x08], rax
851 | 0x9C, // pushfq
852 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
853 | JMP_TO_NEXT_HANDLER
854 | };
855 | }
856 | };
857 | class And32 : public VMHandler
858 | {
859 | public:
860 | And32()
861 | {
862 | type = AND32;
863 | bytes =
864 | {
865 | 0x41, 0x8B, 0x07, // mov eax, dword ptr [r15]
866 | 0x49, 0x83, 0xEF, 0x04, // sub r15, 0x04
867 | 0x41, 0x21, 0x47, 0x08, // and dword ptr [r15+0x08], eax
868 | 0x9C, // pushfq
869 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
870 | JMP_TO_NEXT_HANDLER
871 | };
872 | }
873 | };
874 | class And16 : public VMHandler
875 | {
876 | public:
877 | And16()
878 | {
879 | type = AND16;
880 | bytes =
881 | {
882 | 0x66, 0x41, 0x8B, 0x07, // mov ax, word ptr [r15]
883 | 0x49, 0x83, 0xEF, 0x06, // sub r15, 0x06
884 | 0x66, 0x41, 0x21, 0x47, 0x08, // and word ptr [r15+0x08], ax
885 | 0x9C, // pushfq
886 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
887 | JMP_TO_NEXT_HANDLER
888 | };
889 | }
890 | };
891 | class And8 : public VMHandler
892 | {
893 | public:
894 | And8()
895 | {
896 | type = AND8;
897 | bytes =
898 | {
899 | 0x41, 0x8A, 0x07, // mov al, byte ptr [r15]
900 | 0x49, 0x83, 0xEF, 0x07, // sub r15, 0x07
901 | 0x41, 0x20, 0x47, 0x08, // and byte ptr [r15+0x08], al
902 | 0x9C, // pushfq
903 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
904 | JMP_TO_NEXT_HANDLER
905 | };
906 | }
907 | };
908 |
909 | class Or64 : public VMHandler
910 | {
911 | public:
912 | Or64()
913 | {
914 | type = OR64;
915 | bytes =
916 | {
917 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
918 | 0x49, 0x09, 0x47, 0x08, // or qword ptr [r15+0x08], rax
919 | 0x9C, // pushfq
920 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
921 | JMP_TO_NEXT_HANDLER
922 | };
923 | }
924 | };
925 | class Or32 : public VMHandler
926 | {
927 | public:
928 | Or32()
929 | {
930 | type = OR32;
931 | bytes =
932 | {
933 | 0x41, 0x8B, 0x07, // mov eax, dword ptr [r15]
934 | 0x49, 0x83, 0xEF, 0x04, // sub r15, 0x04
935 | 0x41, 0x09, 0x47, 0x08, // or dword ptr [r15+0x08], eax
936 | 0x9C, // pushfq
937 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
938 | JMP_TO_NEXT_HANDLER
939 | };
940 | }
941 | };
942 | class Or16 : public VMHandler
943 | {
944 | public:
945 | Or16()
946 | {
947 | type = OR16;
948 | bytes =
949 | {
950 | 0x66, 0x41, 0x8B, 0x07, // mov ax, word ptr [r15]
951 | 0x49, 0x83, 0xEF, 0x06, // sub r15, 0x06
952 | 0x66, 0x41, 0x09, 0x47, 0x08, // or word ptr [r15+0x08], ax
953 | 0x9C, // pushfq
954 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
955 | JMP_TO_NEXT_HANDLER
956 | };
957 | }
958 | };
959 | class Or8 : public VMHandler
960 | {
961 | public:
962 | Or8()
963 | {
964 | type = OR8;
965 | bytes =
966 | {
967 | 0x41, 0x8A, 0x07, // mov al, byte ptr [r15]
968 | 0x49, 0x83, 0xEF, 0x07, // sub r15, 0x07
969 | 0x41, 0x08, 0x47, 0x08, // or byte ptr [r15+0x08], al
970 | 0x9C, // pushfq
971 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
972 | JMP_TO_NEXT_HANDLER
973 | };
974 | }
975 | };
976 |
977 | class Nand64 : public VMHandler
978 | {
979 | public:
980 | Nand64()
981 | {
982 | type = NAND64;
983 | bytes =
984 | {
985 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
986 | 0x49, 0x8B, 0x5F, 0x08, // mov rbx, qword ptr [r15+0x08]
987 | 0x48, 0x21, 0xD8, // not rax, rbx
988 | 0x48, 0xF7, 0xD0, // not rax
989 | 0x49, 0x89, 0x47, 0x08, // mov qword ptr [r15+0x08], rax
990 | 0x9C, // pushfq
991 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
992 | JMP_TO_NEXT_HANDLER
993 | };
994 | }
995 | };
996 | class Nand32 : public VMHandler
997 | {
998 | public:
999 | Nand32()
1000 | {
1001 | type = NAND32;
1002 | bytes =
1003 | {
1004 | 0x41, 0x8B, 0x07, // mov eax, dword ptr [r15]
1005 | 0x41, 0x8B, 0x5F, 0x04, // mov ebx, dword ptr [r15+0x04]
1006 | 0x49, 0x83, 0xEF, 0x04, // sub r15, 0x04
1007 | 0x21, 0xD8, // and eax, ebx
1008 | 0xF7, 0xD0, // not eax
1009 | 0x41, 0x89, 0x47, 0x08, // mov qword ptr [r15+0x08], eax
1010 | 0x9C, // pushfq
1011 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
1012 | JMP_TO_NEXT_HANDLER
1013 | };
1014 | }
1015 | };
1016 | class Nand16 : public VMHandler
1017 | {
1018 | public:
1019 | Nand16()
1020 | {
1021 | type = NAND16;
1022 | bytes =
1023 | {
1024 | 0x66, 0x41, 0x8B, 0x07, // mov ax, word ptr [r15]
1025 | 0x66, 0x41, 0x8B, 0x5F, 0x02, // mov bx, word ptr [r15+0x02]
1026 | 0x49, 0x83, 0xEF, 0x06, // sub r15, 0x06
1027 | 0x66, 0x21, 0xD8, // and ax, bx
1028 | 0x66, 0xF7, 0xD0, // not ax
1029 | 0x66, 0x41, 0x89, 0x47, 0x08, // mov qword ptr [r15+0x08], ax
1030 | 0x9C, // pushfq
1031 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
1032 | JMP_TO_NEXT_HANDLER
1033 | };
1034 | }
1035 | };
1036 | class Nand8 : public VMHandler
1037 | {
1038 | public:
1039 | Nand8()
1040 | {
1041 | type = NAND8;
1042 | bytes =
1043 | {
1044 | 0x41, 0x8A, 0x07, // mov al, word ptr [r15]
1045 | 0x41, 0x8A, 0x5F, 0x01, // mov bl, word ptr [r15+0x01]
1046 | 0x49, 0x83, 0xEF, 0x07, // sub r15, 0x07
1047 | 0x20, 0xD8, // and al, bl
1048 | 0xF6, 0xD0, // not al
1049 | 0x41, 0x88, 0x47, 0x08, // mov qword ptr [r15+0x08], al
1050 | 0x9C, // pushfq
1051 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
1052 | JMP_TO_NEXT_HANDLER
1053 | };
1054 | }
1055 | };
1056 |
1057 | class Nor64 : public VMHandler
1058 | {
1059 | public:
1060 | Nor64()
1061 | {
1062 | type = NOR64;
1063 | bytes =
1064 | {
1065 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
1066 | 0x49, 0x8B, 0x5F, 0x08, // mov rbx, qword ptr [r15+0x08]
1067 | 0x48, 0x09, 0xD8, // or rax, rbx
1068 | 0x48, 0xF7, 0xD0, // not rax
1069 | 0x49, 0x89, 0x47, 0x08, // mov qword ptr [r15+0x08], rax
1070 | 0x9C, // pushfq
1071 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
1072 | JMP_TO_NEXT_HANDLER
1073 | };
1074 | }
1075 | };
1076 | class Nor32 : public VMHandler
1077 | {
1078 | public:
1079 | Nor32()
1080 | {
1081 | type = NOR32;
1082 | bytes =
1083 | {
1084 | 0x41, 0x8B, 0x07, // mov eax, dword ptr [r15]
1085 | 0x41, 0x8B, 0x5F, 0x04, // mov ebx, dword ptr [r15+0x04]
1086 | 0x49, 0x83, 0xEF, 0x04, // sub r15, 0x04
1087 | 0x09, 0xD8, // or eax, ebx
1088 | 0xF7, 0xD0, // not eax
1089 | 0x41, 0x89, 0x47, 0x08, // mov qword ptr [r15+0x08], eax
1090 | 0x9C, // pushfq
1091 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
1092 | JMP_TO_NEXT_HANDLER
1093 | };
1094 | }
1095 | };
1096 | class Nor16 : public VMHandler
1097 | {
1098 | public:
1099 | Nor16()
1100 | {
1101 | type = NOR16;
1102 | bytes =
1103 | {
1104 | 0x66, 0x41, 0x8B, 0x07, // mov ax, word ptr [r15]
1105 | 0x66, 0x41, 0x8B, 0x5F, 0x02, // mov bx, word ptr [r15+0x02]
1106 | 0x49, 0x83, 0xEF, 0x06, // sub r15, 0x06
1107 | 0x66, 0x09, 0xD8, // or ax, bx
1108 | 0x66, 0xF7, 0xD0, // not ax
1109 | 0x66, 0x41, 0x89, 0x47, 0x08, // mov qword ptr [r15+0x08], ax
1110 | 0x9C, // pushfq
1111 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
1112 | JMP_TO_NEXT_HANDLER
1113 | };
1114 | }
1115 | };
1116 | class Nor8 : public VMHandler
1117 | {
1118 | public:
1119 | Nor8()
1120 | {
1121 | type = NOR8;
1122 | bytes =
1123 | {
1124 | 0x41, 0x8A, 0x07, // mov al, word ptr [r15]
1125 | 0x41, 0x8A, 0x5F, 0x01, // mov bl, word ptr [r15+0x01]
1126 | 0x49, 0x83, 0xEF, 0x07, // sub r15, 0x07
1127 | 0x08, 0xD8, // or al, bl
1128 | 0xF6, 0xD0, // not al
1129 | 0x41, 0x88, 0x47, 0x08, // mov qword ptr [r15+0x08], al
1130 | 0x9C, // pushfq
1131 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
1132 | JMP_TO_NEXT_HANDLER
1133 | };
1134 | }
1135 | };
1136 |
1137 | class Shl64 : public VMHandler
1138 | {
1139 | public:
1140 | Shl64()
1141 | {
1142 | type = SHL64;
1143 | bytes =
1144 | {
1145 | 0x49, 0x8B, 0x07, // mov rax, qword ptr [r15]
1146 | 0x41, 0x8A, 0x4F, 0x08, // mov cl, byte ptr [r15+0x08]
1147 | 0x49, 0x83, 0xEF, 0x07, // sub r15, 0x07
1148 | 0x48, 0xD3, 0xE0, // shl rax, cl
1149 | 0x49, 0x89, 0x47, 0x08, // mov qword ptr [r15+0x08], rax
1150 | 0x9C, // pushfq
1151 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
1152 | JMP_TO_NEXT_HANDLER
1153 | };
1154 | }
1155 | };
1156 | class Shl32 : public VMHandler
1157 | {
1158 | public:
1159 | Shl32()
1160 | {
1161 | type = SHL32;
1162 | bytes =
1163 | {
1164 | 0x41, 0x8B, 0x07, // mov eax, dword ptr [r15]
1165 | 0x41, 0x8A, 0x4F, 0x04, // mov cl, byte ptr [r15+0x04]
1166 | 0x49, 0x83, 0xEF, 0x07, // sub r15, 0x07
1167 | 0xD3, 0xE0, // shl eax, cl
1168 | 0x41, 0x89, 0x47, 0x08, // mov dword ptr [r15+0x08], eax
1169 | 0x9C, // pushfq
1170 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
1171 | JMP_TO_NEXT_HANDLER
1172 | };
1173 | }
1174 | };
1175 | class Shl16 : public VMHandler
1176 | {
1177 | public:
1178 | Shl16()
1179 | {
1180 | type = SHL16;
1181 | bytes =
1182 | {
1183 | 0x66, 0x41, 0x8B, 0x07, // mov ax, word ptr [r15]
1184 | 0x41, 0x8A, 0x4F, 0x02, // mov cl, byte ptr [r15+0x02]
1185 | 0x49, 0x83, 0xEF, 0x07, // sub r15, 0x07
1186 | 0x66, 0xD3, 0xE0, // shl ax, cl
1187 | 0x66, 0x41, 0x89, 0x47, 0x08, // mov word ptr [r15+0x08], ax
1188 | 0x9C, // pushfq
1189 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
1190 | JMP_TO_NEXT_HANDLER
1191 | };
1192 | }
1193 | };
1194 | class Shl8 : public VMHandler
1195 | {
1196 | public:
1197 | Shl8()
1198 | {
1199 | type = SHL8;
1200 | bytes =
1201 | {
1202 | 0x41, 0x8A, 0x07, // mov al, byte ptr [r15]
1203 | 0x41, 0x8A, 0x4F, 0x01, // mov cl, byte ptr [r15+0x01]
1204 | 0x49, 0x83, 0xEF, 0x07, // sub r15, 0x07
1205 | 0xD2, 0xE0, // shl al, cl
1206 | 0x41, 0x88, 0x47, 0x08, // mov byte ptr [r15+0x08], al
1207 | 0x9C, // pushfq
1208 | 0x41, 0x8F, 0x07, // pop qword ptr [r15]
1209 | JMP_TO_NEXT_HANDLER
1210 | };
1211 | }
1212 | };
1213 |
1214 | class Jmp : public VMHandler
1215 | {
1216 | public:
1217 | Jmp()
1218 | {
1219 | type = JMP;
1220 | bytes =
1221 | {
1222 | 0x45, 0x8B, 0x6D, 0x00, // mov r13d, dword ptr [r13]
1223 | 0x4D, 0x01, 0xF5, // add r13, r14
1224 | JMP_TO_NEXT_HANDLER
1225 | };
1226 | }
1227 | };
1228 |
1229 | class Jne : public VMHandler
1230 | {
1231 | public:
1232 | Jne()
1233 | {
1234 | type = JNE;
1235 | bytes =
1236 | {
1237 | 0x41, 0x8B, 0x45, 0x00, // mov eax, dword ptr [r13]
1238 | 0x49, 0x83, 0xC5, 0x04, // add r13, 0x4
1239 | 0x4C, 0x01, 0xF0, // add rax, r14
1240 | 0x41, 0xFF, 0x37, // push qword ptr [r15]
1241 | 0x9D, // popfq
1242 | 0x4D, 0x8D, 0x7F, 0x08, // lea r15, qword ptr [r15+0x08]
1243 | 0x4C, 0x0F, 0x45, 0xE8, // cmovne r13, rax
1244 | JMP_TO_NEXT_HANDLER
1245 | };
1246 | }
1247 | };
--------------------------------------------------------------------------------
/src/vm_section.cpp:
--------------------------------------------------------------------------------
1 | #include "vm_section.h"
2 |
3 | void VMSection::initialise(DWORD virtualAddress, DWORD pointerToRawData)
4 | {
5 | this->virtualAddress = virtualAddress;
6 | this->pointerToRawData = pointerToRawData;
7 | addVmHandlers();
8 | initialised = true;
9 | }
10 |
11 | bool VMSection::isInitialised() { return initialised; }
12 |
13 | DWORD VMSection::getWritePointer() { return writePointer; }
14 |
15 | DWORD VMSection::getWritePointerFileOffset() { return writePointer + pointerToRawData; }
16 |
17 | DWORD VMSection::getWritePointerRva() { return fileOffsetToRva(getWritePointerFileOffset(), virtualAddress, pointerToRawData); }
18 |
19 | std::vector VMSection::getBytes() { return bytes; }
20 |
21 | void VMSection::addVmTramp(DWORD bytecodeRva)
22 | {
23 | addBytes({ 0x68 }); addBytes(convertToByteVector(bytecodeRva)); // push bytecodeRva
24 |
25 | DWORD relToEnterHandler = VM::getVmHandlerRva(ENTER) - fileOffsetToRva(writePointer + pointerToRawData + 5, virtualAddress, pointerToRawData);
26 |
27 | if (relToEnterHandler <= 127 && relToEnterHandler >= -128)
28 | {
29 | addBytes({ 0xEB, (BYTE)(relToEnterHandler & 0xFF) }); // jmp short vmenter
30 | }
31 | else
32 | {
33 | addBytes({ 0xE9 }); addBytes(convertToByteVector(relToEnterHandler)); // jmp far vmenter
34 | }
35 | }
36 |
37 | void VMSection::addBytes(std::vector bytes)
38 | {
39 | this->bytes.insert(this->bytes.begin() + writePointer, bytes.begin(), bytes.end());
40 | writePointer += bytes.size();
41 | }
42 |
43 | void VMSection::addVmHandlers()
44 | {
45 | // there is likely an elegant way of doing this
46 |
47 | VMHandler* vmHandlers[] =
48 | {
49 | new Enter(), new Exit(),
50 | new PushR64(), new PushR32(), new PushR16(), new PushR8(),
51 | new PopR64(), new PopR32(), new PopR16(), new PopR8(),
52 | new PushI64(), new PushI32(), new PushI16(), new PushI8(),
53 | new PushRSP64(), new PushRSP32(), new PushRSP16(), new PushRSP8(),
54 | new PopRSP64(), new PopRSP32(), new PopRSP16(), new PopRSP8(),
55 | new Add64(), new Add32(), new Add16(), new Add8(),
56 | new Sub64(), new Sub32(), new Sub16(), new Sub8(),
57 | new Xor64(), new Xor32(), new Xor16(), new Xor8(),
58 | new And64(), new And32(), new And16(), new And8(),
59 | new Or64(), new Or32(), new Or16(), new Or8(),
60 | new Nand64(), new Nand32(), new Nand16(), new Nand8(),
61 | new Nor64(), new Nor32(), new Nor16(), new Nor8(),
62 | new Shl64(), new Shl32(), new Shl16(), new Shl8(),
63 | new Read64(), new Read32(), new Read16(), new Read8(),
64 | new Write64(), new Write32(), new Write16(), new Write8(),
65 | new Jmp(),
66 | new Jne(),
67 | };
68 |
69 | int vmHandlersSize = std::size(vmHandlers);
70 |
71 | // create vector of indexes we will shuffle
72 | // create multiple instances of a single index will result in multiple handler instances
73 | std::vector indexes(vmHandlersSize);
74 | for (int i = 0; i < vmHandlersSize; i++)
75 | {
76 | for (int j = 0; j < getRandomInt(15, 30); j++)
77 | indexes.push_back(i);
78 | }
79 |
80 | // shuffle index array
81 | std::random_device rd;
82 | std::mt19937 g(rd());
83 | std::shuffle(indexes.begin(), indexes.end(), g);
84 |
85 | // generate a random number of handler instances
86 | for (int i = 0; i < indexes.size(); i++)
87 | addVmHandler(*vmHandlers[indexes[i]]);
88 |
89 | for (int i = 0; i < vmHandlersSize; i++)
90 | delete vmHandlers[i];
91 | }
92 |
93 | void VMSection::addVmHandler(VMHandler vmHandler)
94 | {
95 | vmHandler.setFileOffset(writePointer + pointerToRawData);
96 | vmHandler.setRva(fileOffsetToRva(writePointer + pointerToRawData, virtualAddress, pointerToRawData));
97 | // vmHandler.mutate();
98 | VM::vmHandlers.push_back(vmHandler);
99 | addBytes(vmHandler.getBytes());
100 | }
--------------------------------------------------------------------------------
/src/vm_section.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include "vm.h"
8 | #include "vm_handler.h"
9 | #include "util.h"
10 |
11 | class VMSection
12 | {
13 | public:
14 | void initialise(DWORD virtualAddress, DWORD pointerToRawData);
15 | bool isInitialised();
16 | DWORD getWritePointer();
17 | DWORD getWritePointerFileOffset();
18 | DWORD getWritePointerRva();
19 | std::vector getBytes();
20 | void addVmTramp(DWORD bytecodeRva);
21 | void addBytes(std::vector bytes);
22 | private:
23 | bool initialised = false;
24 | DWORD pointerToRawData;
25 | DWORD virtualAddress;
26 | DWORD writePointer;
27 | std::vector bytes;
28 |
29 | void addVmHandlers();
30 | void addVmHandler(VMHandler vmHandler);
31 | };
--------------------------------------------------------------------------------