├── 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 | }; --------------------------------------------------------------------------------