parent
a9c482fb13
commit
786ecb2f81
@ -1,18 +1,5 @@
|
|||||||
---
|
---
|
||||||
BasedOnStyle: Microsoft
|
BasedOnStyle: Chromium
|
||||||
AlignAfterOpenBracket: Align
|
|
||||||
AllowAllArgumentsOnNextLine: 'true'
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: 'true'
|
|
||||||
AllowShortIfStatementsOnASingleLine: Never
|
|
||||||
BreakBeforeBraces: Allman
|
|
||||||
IndentWidth: '4'
|
|
||||||
Language: Cpp
|
|
||||||
NamespaceIndentation: All
|
|
||||||
SpacesInAngles: 'true'
|
|
||||||
SpacesInCStyleCastParentheses: 'true'
|
|
||||||
SpacesInContainerLiterals: 'true'
|
|
||||||
SpacesInParentheses: 'true'
|
|
||||||
SpacesInSquareBrackets: 'true'
|
|
||||||
UseTab: Never
|
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
# This file is automatically generated from cmake.toml - DO NOT EDIT
|
||||||
|
# See https://github.com/build-cpp/cmkr for more information
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
|
# Regenerate CMakeLists.txt automatically in the root project
|
||||||
|
set(CMKR_ROOT_PROJECT OFF)
|
||||||
|
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||||
|
set(CMKR_ROOT_PROJECT ON)
|
||||||
|
|
||||||
|
# Bootstrap cmkr
|
||||||
|
include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT)
|
||||||
|
if(CMKR_INCLUDE_RESULT)
|
||||||
|
cmkr()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Enable folder support
|
||||||
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Create a configure-time dependency on cmake.toml to improve IDE support
|
||||||
|
if(CMKR_ROOT_PROJECT)
|
||||||
|
configure_file(cmake.toml cmake.toml COPYONLY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
project(vmassembler)
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
|
||||||
|
if(CMAKE_FOLDER)
|
||||||
|
set(CMAKE_FOLDER "${CMAKE_FOLDER}/dependencies")
|
||||||
|
else()
|
||||||
|
set(CMAKE_FOLDER dependencies)
|
||||||
|
endif()
|
||||||
|
add_subdirectory(dependencies)
|
||||||
|
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
|
||||||
|
|
||||||
|
# Target vmassembler
|
||||||
|
set(CMKR_TARGET vmassembler)
|
||||||
|
set(vmassembler_SOURCES "")
|
||||||
|
|
||||||
|
list(APPEND vmassembler_SOURCES
|
||||||
|
"src/compiler.cpp"
|
||||||
|
"src/main.cpp"
|
||||||
|
"src/parser.cpp"
|
||||||
|
"include/compiler.hpp"
|
||||||
|
"include/gen_code.hpp"
|
||||||
|
"include/parser.hpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND vmassembler_SOURCES
|
||||||
|
cmake.toml
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMKR_SOURCES ${vmassembler_SOURCES})
|
||||||
|
add_executable(vmassembler)
|
||||||
|
|
||||||
|
if(vmassembler_SOURCES)
|
||||||
|
target_sources(vmassembler PRIVATE ${vmassembler_SOURCES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT)
|
||||||
|
if(NOT CMKR_VS_STARTUP_PROJECT)
|
||||||
|
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT vmassembler)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${vmassembler_SOURCES})
|
||||||
|
|
||||||
|
target_compile_definitions(vmassembler PRIVATE
|
||||||
|
NOMINMAX
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_features(vmassembler PRIVATE
|
||||||
|
cxx_std_20
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(vmassembler PRIVATE
|
||||||
|
include
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(vmassembler PRIVATE
|
||||||
|
vmprofiler
|
||||||
|
xtils
|
||||||
|
cli-parser
|
||||||
|
linux-pe
|
||||||
|
)
|
||||||
|
|
||||||
|
unset(CMKR_TARGET)
|
||||||
|
unset(CMKR_SOURCES)
|
||||||
|
|
@ -0,0 +1,12 @@
|
|||||||
|
[project]
|
||||||
|
name = "vmassembler"
|
||||||
|
|
||||||
|
[subdir.dependencies]
|
||||||
|
|
||||||
|
[target.vmassembler]
|
||||||
|
type = "executable"
|
||||||
|
compile-features = ["cxx_std_20"]
|
||||||
|
sources = ["src/**.cpp", "include/**.hpp"]
|
||||||
|
include-directories = ["include"]
|
||||||
|
link-libraries = ["vmprofiler", "xtils", "cli-parser", "linux-pe"]
|
||||||
|
compile-definitions = ["NOMINMAX"]
|
@ -0,0 +1,162 @@
|
|||||||
|
include_guard()
|
||||||
|
|
||||||
|
# Change these defaults to point to your infrastructure if desired
|
||||||
|
set(CMKR_REPO "https://github.com/build-cpp/cmkr" CACHE STRING "cmkr git repository" FORCE)
|
||||||
|
set(CMKR_TAG "archive_264e4ace" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
|
||||||
|
|
||||||
|
# Set these from the command line to customize for development/debugging purposes
|
||||||
|
set(CMKR_EXECUTABLE "" CACHE FILEPATH "cmkr executable")
|
||||||
|
set(CMKR_SKIP_GENERATION OFF CACHE BOOL "skip automatic cmkr generation")
|
||||||
|
|
||||||
|
# Disable cmkr if generation is disabled
|
||||||
|
if(DEFINED ENV{CI} OR CMKR_SKIP_GENERATION)
|
||||||
|
message(STATUS "[cmkr] Skipping automatic cmkr generation")
|
||||||
|
macro(cmkr)
|
||||||
|
endmacro()
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Disable cmkr if no cmake.toml file is found
|
||||||
|
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml")
|
||||||
|
message(AUTHOR_WARNING "[cmkr] Not found: ${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml")
|
||||||
|
macro(cmkr)
|
||||||
|
endmacro()
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Convert a Windows native path to CMake path
|
||||||
|
if(CMKR_EXECUTABLE MATCHES "\\\\")
|
||||||
|
string(REPLACE "\\" "/" CMKR_EXECUTABLE_CMAKE "${CMKR_EXECUTABLE}")
|
||||||
|
set(CMKR_EXECUTABLE "${CMKR_EXECUTABLE_CMAKE}" CACHE FILEPATH "" FORCE)
|
||||||
|
unset(CMKR_EXECUTABLE_CMAKE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Helper macro to execute a process (COMMAND_ERROR_IS_FATAL ANY is 3.19 and higher)
|
||||||
|
function(cmkr_exec)
|
||||||
|
execute_process(COMMAND ${ARGV} RESULT_VARIABLE CMKR_EXEC_RESULT)
|
||||||
|
if(NOT CMKR_EXEC_RESULT EQUAL 0)
|
||||||
|
message(FATAL_ERROR "cmkr_exec(${ARGV}) failed (exit code ${CMKR_EXEC_RESULT})")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Windows-specific hack (CMAKE_EXECUTABLE_PREFIX is not set at the moment)
|
||||||
|
if(WIN32)
|
||||||
|
set(CMKR_EXECUTABLE_NAME "cmkr.exe")
|
||||||
|
else()
|
||||||
|
set(CMKR_EXECUTABLE_NAME "cmkr")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Use cached cmkr if found
|
||||||
|
set(CMKR_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_cmkr_${CMKR_TAG}")
|
||||||
|
set(CMKR_CACHED_EXECUTABLE "${CMKR_DIRECTORY}/bin/${CMKR_EXECUTABLE_NAME}")
|
||||||
|
|
||||||
|
if(NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE AND CMKR_EXECUTABLE MATCHES "^${CMAKE_CURRENT_BINARY_DIR}/_cmkr")
|
||||||
|
message(AUTHOR_WARNING "[cmkr] Upgrading '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
|
||||||
|
unset(CMKR_EXECUTABLE CACHE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMKR_EXECUTABLE AND EXISTS "${CMKR_EXECUTABLE}")
|
||||||
|
message(VERBOSE "[cmkr] Found cmkr: '${CMKR_EXECUTABLE}'")
|
||||||
|
elseif(CMKR_EXECUTABLE AND NOT CMKR_EXECUTABLE STREQUAL CMKR_CACHED_EXECUTABLE)
|
||||||
|
message(FATAL_ERROR "[cmkr] '${CMKR_EXECUTABLE}' not found")
|
||||||
|
else()
|
||||||
|
set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
|
||||||
|
message(VERBOSE "[cmkr] Bootstrapping '${CMKR_EXECUTABLE}'")
|
||||||
|
|
||||||
|
message(STATUS "[cmkr] Fetching cmkr...")
|
||||||
|
if(EXISTS "${CMKR_DIRECTORY}")
|
||||||
|
cmkr_exec("${CMAKE_COMMAND}" -E rm -rf "${CMKR_DIRECTORY}")
|
||||||
|
endif()
|
||||||
|
find_package(Git QUIET REQUIRED)
|
||||||
|
cmkr_exec("${GIT_EXECUTABLE}"
|
||||||
|
clone
|
||||||
|
--config advice.detachedHead=false
|
||||||
|
--branch ${CMKR_TAG}
|
||||||
|
--depth 1
|
||||||
|
${CMKR_REPO}
|
||||||
|
"${CMKR_DIRECTORY}"
|
||||||
|
)
|
||||||
|
message(STATUS "[cmkr] Building cmkr...")
|
||||||
|
cmkr_exec("${CMAKE_COMMAND}"
|
||||||
|
--no-warn-unused-cli
|
||||||
|
"${CMKR_DIRECTORY}"
|
||||||
|
"-B${CMKR_DIRECTORY}/build"
|
||||||
|
"-DCMAKE_BUILD_TYPE=Release"
|
||||||
|
"-DCMAKE_INSTALL_PREFIX=${CMKR_DIRECTORY}"
|
||||||
|
"-DCMKR_GENERATE_DOCUMENTATION=OFF"
|
||||||
|
)
|
||||||
|
cmkr_exec("${CMAKE_COMMAND}"
|
||||||
|
--build "${CMKR_DIRECTORY}/build"
|
||||||
|
--config Release
|
||||||
|
--parallel
|
||||||
|
)
|
||||||
|
cmkr_exec("${CMAKE_COMMAND}"
|
||||||
|
--install "${CMKR_DIRECTORY}/build"
|
||||||
|
--config Release
|
||||||
|
--prefix "${CMKR_DIRECTORY}"
|
||||||
|
--component cmkr
|
||||||
|
)
|
||||||
|
if(NOT EXISTS ${CMKR_EXECUTABLE})
|
||||||
|
message(FATAL_ERROR "[cmkr] Failed to bootstrap '${CMKR_EXECUTABLE}'")
|
||||||
|
endif()
|
||||||
|
cmkr_exec("${CMKR_EXECUTABLE}" version)
|
||||||
|
message(STATUS "[cmkr] Bootstrapped ${CMKR_EXECUTABLE}")
|
||||||
|
endif()
|
||||||
|
execute_process(COMMAND "${CMKR_EXECUTABLE}" version
|
||||||
|
RESULT_VARIABLE CMKR_EXEC_RESULT
|
||||||
|
)
|
||||||
|
if(NOT CMKR_EXEC_RESULT EQUAL 0)
|
||||||
|
message(FATAL_ERROR "[cmkr] Failed to get version, try clearing the cache and rebuilding")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# This is the macro that contains black magic
|
||||||
|
macro(cmkr)
|
||||||
|
# When this macro is called from the generated file, fake some internal CMake variables
|
||||||
|
get_source_file_property(CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}" CMKR_CURRENT_LIST_FILE)
|
||||||
|
if(CMKR_CURRENT_LIST_FILE)
|
||||||
|
set(CMAKE_CURRENT_LIST_FILE "${CMKR_CURRENT_LIST_FILE}")
|
||||||
|
get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# File-based include guard (include_guard is not documented to work)
|
||||||
|
get_source_file_property(CMKR_INCLUDE_GUARD "${CMAKE_CURRENT_LIST_FILE}" CMKR_INCLUDE_GUARD)
|
||||||
|
if(NOT CMKR_INCLUDE_GUARD)
|
||||||
|
set_source_files_properties("${CMAKE_CURRENT_LIST_FILE}" PROPERTIES CMKR_INCLUDE_GUARD TRUE)
|
||||||
|
|
||||||
|
file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_PRE)
|
||||||
|
|
||||||
|
# Generate CMakeLists.txt
|
||||||
|
cmkr_exec("${CMKR_EXECUTABLE}" gen
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_POST)
|
||||||
|
|
||||||
|
# Delete the temporary file if it was left for some reason
|
||||||
|
set(CMKR_TEMP_FILE "${CMAKE_CURRENT_SOURCE_DIR}/CMakerLists.txt")
|
||||||
|
if(EXISTS "${CMKR_TEMP_FILE}")
|
||||||
|
file(REMOVE "${CMKR_TEMP_FILE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT CMKR_LIST_FILE_SHA256_PRE STREQUAL CMKR_LIST_FILE_SHA256_POST)
|
||||||
|
# Copy the now-generated CMakeLists.txt to CMakerLists.txt
|
||||||
|
# This is done because you cannot include() a file you are currently in
|
||||||
|
configure_file(CMakeLists.txt "${CMKR_TEMP_FILE}" COPYONLY)
|
||||||
|
|
||||||
|
# Add the macro required for the hack at the start of the cmkr macro
|
||||||
|
set_source_files_properties("${CMKR_TEMP_FILE}" PROPERTIES
|
||||||
|
CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 'Execute' the newly-generated CMakeLists.txt
|
||||||
|
include("${CMKR_TEMP_FILE}")
|
||||||
|
|
||||||
|
# Delete the generated file
|
||||||
|
file(REMOVE "${CMKR_TEMP_FILE}")
|
||||||
|
|
||||||
|
# Do not execute the rest of the original CMakeLists.txt
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
# Resume executing the unmodified CMakeLists.txt
|
||||||
|
endif()
|
||||||
|
endmacro()
|
@ -0,0 +1,54 @@
|
|||||||
|
# This file is automatically generated from cmake.toml - DO NOT EDIT
|
||||||
|
# See https://github.com/build-cpp/cmkr for more information
|
||||||
|
|
||||||
|
# Create a configure-time dependency on cmake.toml to improve IDE support
|
||||||
|
if(CMKR_ROOT_PROJECT)
|
||||||
|
configure_file(cmake.toml cmake.toml COPYONLY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# vmprofiler
|
||||||
|
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
|
||||||
|
if(CMAKE_FOLDER)
|
||||||
|
set(CMAKE_FOLDER "${CMAKE_FOLDER}/vmprofiler")
|
||||||
|
else()
|
||||||
|
set(CMAKE_FOLDER vmprofiler)
|
||||||
|
endif()
|
||||||
|
add_subdirectory(vmprofiler)
|
||||||
|
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
|
||||||
|
|
||||||
|
# Target cli-parser
|
||||||
|
set(CMKR_TARGET cli-parser)
|
||||||
|
set(cli-parser_SOURCES "")
|
||||||
|
|
||||||
|
set(CMKR_SOURCES ${cli-parser_SOURCES})
|
||||||
|
add_library(cli-parser INTERFACE)
|
||||||
|
|
||||||
|
if(cli-parser_SOURCES)
|
||||||
|
target_sources(cli-parser INTERFACE ${cli-parser_SOURCES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_include_directories(cli-parser INTERFACE
|
||||||
|
cli-parser
|
||||||
|
)
|
||||||
|
|
||||||
|
unset(CMKR_TARGET)
|
||||||
|
unset(CMKR_SOURCES)
|
||||||
|
|
||||||
|
# Target xtils
|
||||||
|
set(CMKR_TARGET xtils)
|
||||||
|
set(xtils_SOURCES "")
|
||||||
|
|
||||||
|
set(CMKR_SOURCES ${xtils_SOURCES})
|
||||||
|
add_library(xtils INTERFACE)
|
||||||
|
|
||||||
|
if(xtils_SOURCES)
|
||||||
|
target_sources(xtils INTERFACE ${xtils_SOURCES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_include_directories(xtils INTERFACE
|
||||||
|
xtils
|
||||||
|
)
|
||||||
|
|
||||||
|
unset(CMKR_TARGET)
|
||||||
|
unset(CMKR_SOURCES)
|
||||||
|
|
@ -0,0 +1,9 @@
|
|||||||
|
[subdir.vmprofiler]
|
||||||
|
|
||||||
|
[target.cli-parser]
|
||||||
|
type = "interface"
|
||||||
|
include-directories = ["cli-parser"]
|
||||||
|
|
||||||
|
[target.xtils]
|
||||||
|
type = "interface"
|
||||||
|
include-directories = ["xtils"]
|
@ -1 +1 @@
|
|||||||
Subproject commit 0f6ba9bad30d67f25f01b6c1e872077efdff61d4
|
Subproject commit 14cc72c0ff121d13f2ba26be34d1e99492aad296
|
@ -1 +1 @@
|
|||||||
Subproject commit 7c32517322c29a866cbb1e67fb9051efa2e05553
|
Subproject commit db7526d989bdfecb6fac2079929efce94cead52c
|
@ -0,0 +1,131 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vmprofiler.hpp>
|
||||||
|
#include <xtils.hpp>
|
||||||
|
#include <parser.hpp>
|
||||||
|
|
||||||
|
namespace vm {
|
||||||
|
/// <summary>
|
||||||
|
/// struct containing encoded data for a given virtual instruction...
|
||||||
|
/// </summary>
|
||||||
|
struct vinstr_data {
|
||||||
|
/// <summary>
|
||||||
|
/// vm handler index also known as the opcode...
|
||||||
|
/// </summary>
|
||||||
|
std::uint8_t vm_handler;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// this field contains the second operand if any...
|
||||||
|
/// </summary>
|
||||||
|
std::uint64_t operand;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// size in bits of the second operand if any... zero if none...
|
||||||
|
/// </summary>
|
||||||
|
std::uint8_t imm_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// struct containing all information for a label...
|
||||||
|
/// </summary>
|
||||||
|
struct vlabel_data {
|
||||||
|
/// <summary>
|
||||||
|
/// name of the label...
|
||||||
|
/// </summary>
|
||||||
|
std::string label_name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// vector of encoded virtual instructions...
|
||||||
|
/// </summary>
|
||||||
|
std::vector<vinstr_data> vinstrs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// struct containing compiled virtual instructions (encoded and encrypted) for
|
||||||
|
/// a given label...
|
||||||
|
/// </summary>
|
||||||
|
struct compiled_label_data {
|
||||||
|
/// <summary>
|
||||||
|
/// label name...
|
||||||
|
/// </summary>
|
||||||
|
std::string label_name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// relative virtual address from vm_entry to the virtual instructions...
|
||||||
|
/// </summary>
|
||||||
|
std::uintptr_t alloc_rva;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// encrypted relative virtual address from vm_entry to virtual
|
||||||
|
/// instructions...
|
||||||
|
/// </summary>
|
||||||
|
std::uintptr_t enc_alloc_rva;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// vector of bytes containing the raw, encrypted virtual instructions...
|
||||||
|
/// </summary>
|
||||||
|
std::vector<std::uint8_t> vinstrs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// class containing member functions used to encode and encrypted virtual
|
||||||
|
/// instructions...
|
||||||
|
/// </summary>
|
||||||
|
class compiler_t {
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// default constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vmctx">pointer to a vm context object which has already been
|
||||||
|
/// init...</param>
|
||||||
|
explicit compiler_t(vm::ctx_t* vmctx);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// encode virtual instructions from parser::virt_labels
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>returns a vector of labels containing encoded virtual
|
||||||
|
/// instructions</returns>
|
||||||
|
std::vector<vlabel_data>* encode();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// encrypt virtual instructions from parser::virt_labels
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>returns a vector of compiled labels containing encoded and
|
||||||
|
/// encrypted virtual instructions...</returns>
|
||||||
|
std::vector<compiled_label_data> encrypt();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// <summary>
|
||||||
|
/// encrypt virtual instructions rva... <a
|
||||||
|
/// href="https://back.engineering/17/05/2021/#vm_entry">read more here...</a>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rva">relative virtual address to encrypted virtual
|
||||||
|
/// instructions...</param> <returns></returns>
|
||||||
|
std::uint64_t encrypt_rva(std::uint64_t rva);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// pointer to the vmctx passed in by the constructor...
|
||||||
|
/// </summary>
|
||||||
|
vm::ctx_t* vmctx;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// transformations used to decrypt the opcode operand extracted from
|
||||||
|
/// calc_jmp... you can read more <a
|
||||||
|
/// href="https://back.engineering/17/05/2021/#calc_jmp">here...</a>
|
||||||
|
/// </summary>
|
||||||
|
transform::map_t calc_jmp_transforms;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// vector of encoded labels...
|
||||||
|
/// </summary>
|
||||||
|
std::vector<vlabel_data> virt_labels;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// vector of decoded zydis instructions containing the native instructions to
|
||||||
|
/// encrypt the virtual instruction rva which will be pushed onto the stack
|
||||||
|
/// prior to jmping to vm entry...
|
||||||
|
/// </summary>
|
||||||
|
std::vector<zydis_decoded_instr_t> encrypt_vinstrs_rva;
|
||||||
|
};
|
||||||
|
} // namespace vm
|
@ -1,194 +1,211 @@
|
|||||||
#include "compiler.h"
|
#include <compiler.hpp>
|
||||||
|
|
||||||
namespace vm
|
namespace vm {
|
||||||
{
|
compiler_t::compiler_t(vm::ctx_t* vmctx) : vmctx(vmctx) {
|
||||||
compiler_t::compiler_t( vm::ctx_t *vmctx ) : vmctx( vmctx )
|
if (!parse_t::get_instance()->for_each([&](_vlabel_meta* label_data) -> bool {
|
||||||
{
|
std::printf(
|
||||||
if ( !parse_t::get_instance()->for_each( [ & ]( _vlabel_meta *label_data ) -> bool {
|
"> checking label %s for invalid instructions... number of "
|
||||||
std::printf( "> checking label %s for invalid instructions... number of instructions = %d\n",
|
"instructions = %d\n",
|
||||||
label_data->label_name.c_str(), label_data->vinstrs.size() );
|
label_data->label_name.c_str(), label_data->vinstrs.size());
|
||||||
|
|
||||||
const auto result = std::find_if(
|
const auto result = std::find_if(
|
||||||
label_data->vinstrs.begin(), label_data->vinstrs.end(),
|
label_data->vinstrs.begin(), label_data->vinstrs.end(),
|
||||||
[ & ]( const _vinstr_meta &vinstr ) -> bool {
|
[&](const _vinstr_meta& vinstr) -> bool {
|
||||||
std::printf( "> vinstr name = %s, has imm = %d, imm = 0x%p\n", vinstr.name.c_str(),
|
std::printf("> vinstr name = %s, has imm = %d, imm = 0x%p\n",
|
||||||
vinstr.has_imm, vinstr.imm );
|
vinstr.name.c_str(), vinstr.has_imm, vinstr.imm);
|
||||||
|
|
||||||
for ( auto &vm_handler : vmctx->vm_handlers )
|
for (auto& vm_handler : vmctx->vm_handlers)
|
||||||
if ( vm_handler.profile && vm_handler.profile->name == vinstr.name )
|
if (vm_handler.profile &&
|
||||||
return false;
|
vm_handler.profile->name == vinstr.name)
|
||||||
|
return false;
|
||||||
std::printf( "[!] this vm protected file does not have the vm handler for: %s...\n",
|
|
||||||
vinstr.name.c_str() );
|
std::printf(
|
||||||
|
"[!] this vm protected file does not have the vm handler "
|
||||||
return true;
|
"for: %s...\n",
|
||||||
} );
|
vinstr.name.c_str());
|
||||||
|
|
||||||
return result == label_data->vinstrs.end();
|
return true;
|
||||||
} ) )
|
});
|
||||||
{
|
|
||||||
std::printf( "[!] binary does not have the required vm handlers...\n" );
|
return result == label_data->vinstrs.end();
|
||||||
exit( -1 );
|
})) {
|
||||||
}
|
std::printf("[!] binary does not have the required vm handlers...\n");
|
||||||
|
exit(-1);
|
||||||
if ( !vm::handler::get_operand_transforms( vmctx->calc_jmp, calc_jmp_transforms ) )
|
}
|
||||||
{
|
|
||||||
std::printf( "[!] failed to extract calc_jmp transformations...\n" );
|
if (!vm::handler::get_operand_transforms(vmctx->calc_jmp,
|
||||||
exit( -1 );
|
calc_jmp_transforms)) {
|
||||||
}
|
std::printf("[!] failed to extract calc_jmp transformations...\n");
|
||||||
|
exit(-1);
|
||||||
if ( !vm::instrs::get_rva_decrypt( vmctx->vm_entry, encrypt_vinstrs_rva ) )
|
}
|
||||||
{
|
|
||||||
std::printf( "[!] failed to extract virtual instruction rva decryption instructions...\n" );
|
if (!vm::instrs::get_rva_decrypt(vmctx->vm_entry, encrypt_vinstrs_rva)) {
|
||||||
exit( -1 );
|
std::printf(
|
||||||
}
|
"[!] failed to extract virtual instruction rva decryption "
|
||||||
|
"instructions...\n");
|
||||||
if ( !vm::transform::inverse_transforms( encrypt_vinstrs_rva ) )
|
exit(-1);
|
||||||
{
|
}
|
||||||
std::printf( "[!] failed to inverse virtual instruction rva decrypt instructions...\n" );
|
|
||||||
exit( -1 );
|
if (!vm::transform::inverse_transforms(encrypt_vinstrs_rva)) {
|
||||||
|
std::printf(
|
||||||
|
"[!] failed to inverse virtual instruction rva decrypt "
|
||||||
|
"instructions...\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<vlabel_data>* compiler_t::encode() {
|
||||||
|
parse_t::get_instance()->for_each([&](_vlabel_meta* label_data) -> bool {
|
||||||
|
virt_labels.push_back({label_data->label_name});
|
||||||
|
for (const auto& vinstr : label_data->vinstrs) {
|
||||||
|
for (auto idx = 0u; idx < 256; ++idx) {
|
||||||
|
const auto& vm_handler = vmctx->vm_handlers[idx];
|
||||||
|
if (vm_handler.profile &&
|
||||||
|
!vinstr.name.compare(vm_handler.profile->name)) {
|
||||||
|
virt_labels.back().vinstrs.push_back(
|
||||||
|
{(std::uint8_t)idx, vinstr.imm, vm_handler.profile->imm_size});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
std::vector< vlabel_data > *compiler_t::encode()
|
});
|
||||||
{
|
|
||||||
parse_t::get_instance()->for_each( [ & ]( _vlabel_meta *label_data ) -> bool {
|
return &virt_labels;
|
||||||
virt_labels.push_back( { label_data->label_name } );
|
}
|
||||||
for ( const auto &vinstr : label_data->vinstrs )
|
|
||||||
{
|
std::vector<compiled_label_data> compiler_t::encrypt() {
|
||||||
for ( auto idx = 0u; idx < 256; ++idx )
|
std::vector<compiled_label_data> result;
|
||||||
|
const auto end_of_module = vmctx->image_size + vmctx->image_base;
|
||||||
|
|
||||||
|
// decryption key starts off as the image
|
||||||
|
// base address of the virtual instructions...
|
||||||
|
std::uintptr_t decrypt_key = end_of_module, start_addr;
|
||||||
|
if (vmctx->exec_type == vmp2::exec_type_t::backward)
|
||||||
|
std::for_each(
|
||||||
|
virt_labels.begin()->vinstrs.begin(),
|
||||||
|
virt_labels.begin()->vinstrs.end(), [&](const vinstr_data& vinstr) {
|
||||||
|
(++decrypt_key) += vinstr.imm_size ? vinstr.imm_size / 8 : 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto opcode_fetch = std::find_if(
|
||||||
|
vmctx->calc_jmp.begin(), vmctx->calc_jmp.end(),
|
||||||
|
[](const zydis_instr_t& instr_data) -> bool {
|
||||||
|
// mov/movsx/movzx rax/eax/ax/al, [rsi]
|
||||||
|
return instr_data.instr.operand_count > 1 &&
|
||||||
|
(instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
|
||||||
|
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
|
||||||
|
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX) &&
|
||||||
|
instr_data.instr.operands[0].type ==
|
||||||
|
ZYDIS_OPERAND_TYPE_REGISTER &&
|
||||||
|
util::reg::to64(instr_data.instr.operands[0].reg.value) ==
|
||||||
|
ZYDIS_REGISTER_RAX &&
|
||||||
|
instr_data.instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
|
||||||
|
instr_data.instr.operands[1].mem.base == ZYDIS_REGISTER_RSI;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (opcode_fetch == vmctx->calc_jmp.end()) {
|
||||||
|
std::printf(
|
||||||
|
"> critical error trying to find opcode fetch inside of "
|
||||||
|
"compiler_t::encrypt...\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
start_addr = decrypt_key - 1; // make it zero based...
|
||||||
|
std::for_each(
|
||||||
|
virt_labels.begin(), virt_labels.end(), [&](vm::vlabel_data& label) {
|
||||||
|
// sometimes there is a mov al, [rsi-1]... we want that disp...
|
||||||
|
if (opcode_fetch->instr.operands[1].mem.disp.has_displacement)
|
||||||
|
start_addr +=
|
||||||
|
std::abs(opcode_fetch->instr.operands[1].mem.disp.value);
|
||||||
|
|
||||||
|
decrypt_key = start_addr;
|
||||||
|
result.push_back({label.label_name, start_addr});
|
||||||
|
|
||||||
|
if (vmctx->exec_type == vmp2::exec_type_t::forward) {
|
||||||
|
std::for_each(
|
||||||
|
label.vinstrs.begin(), label.vinstrs.end(),
|
||||||
|
[&](vm::vinstr_data& vinstr) {
|
||||||
|
std::uint8_t opcode = vinstr.vm_handler;
|
||||||
|
std::uint64_t operand = 0u;
|
||||||
|
|
||||||
|
// encrypt opcode...
|
||||||
|
std::tie(opcode, decrypt_key) = vm::instrs::encrypt_operand(
|
||||||
|
calc_jmp_transforms, vinstr.vm_handler, decrypt_key);
|
||||||
|
|
||||||
|
// if there is an operand then we will encrypt that as well..
|
||||||
|
if (vmctx->vm_handlers[vinstr.vm_handler].imm_size) {
|
||||||
|
auto& vm_handler_transforms =
|
||||||
|
vmctx->vm_handlers[vinstr.vm_handler].transforms;
|
||||||
|
std::tie(operand, decrypt_key) = vm::instrs::encrypt_operand(
|
||||||
|
vm_handler_transforms, vinstr.operand, decrypt_key);
|
||||||
|
} else // else just push back the opcode...
|
||||||
{
|
{
|
||||||
const auto &vm_handler = vmctx->vm_handlers[ idx ];
|
result.back().vinstrs.push_back(opcode);
|
||||||
if ( vm_handler.profile && !vinstr.name.compare( vm_handler.profile->name ) )
|
return; // finished here...
|
||||||
{
|
|
||||||
virt_labels.back().vinstrs.push_back(
|
|
||||||
{ ( std::uint8_t )idx, vinstr.imm, vm_handler.profile->imm_size } );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} );
|
|
||||||
|
|
||||||
return &virt_labels;
|
result.back().vinstrs.push_back(opcode);
|
||||||
}
|
for (auto idx = 0u;
|
||||||
|
idx < vmctx->vm_handlers[vinstr.vm_handler].imm_size / 8;
|
||||||
|
++idx)
|
||||||
|
result.back().vinstrs.push_back(
|
||||||
|
reinterpret_cast<std::uint8_t*>(&vinstr.operand)[idx]);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
std::for_each(
|
||||||
|
label.vinstrs.begin(), label.vinstrs.end(),
|
||||||
|
[&](vm::vinstr_data& vinstr) {
|
||||||
|
std::uint8_t opcode = vinstr.vm_handler;
|
||||||
|
std::uint64_t operand = 0u;
|
||||||
|
|
||||||
|
// encrypt opcode...
|
||||||
|
std::tie(opcode, decrypt_key) = vm::instrs::encrypt_operand(
|
||||||
|
calc_jmp_transforms, vinstr.vm_handler, decrypt_key);
|
||||||
|
|
||||||
|
// if there is an operand then we will encrypt that as well..
|
||||||
|
if (vmctx->vm_handlers[vinstr.vm_handler].imm_size) {
|
||||||
|
auto& vm_handler_transforms =
|
||||||
|
vmctx->vm_handlers[vinstr.vm_handler].transforms;
|
||||||
|
std::tie(operand, decrypt_key) = vm::instrs::encrypt_operand(
|
||||||
|
vm_handler_transforms, vinstr.operand, decrypt_key);
|
||||||
|
} else // else just push back the opcode...
|
||||||
|
{
|
||||||
|
result.back().vinstrs.insert(result.back().vinstrs.begin(), 1,
|
||||||
|
opcode);
|
||||||
|
return; // finished here...
|
||||||
|
}
|
||||||
|
|
||||||
std::vector< compiled_label_data > compiler_t::encrypt()
|
// operand goes first, then opcode when vip advances
|
||||||
{
|
// backwards...
|
||||||
std::vector< compiled_label_data > result;
|
std::vector<std::uint8_t> _temp;
|
||||||
const auto end_of_module = vmctx->image_size + vmctx->image_base;
|
for (auto idx = 0u;
|
||||||
|
idx < vmctx->vm_handlers[vinstr.vm_handler].imm_size / 8;
|
||||||
// decryption key starts off as the image
|
++idx)
|
||||||
// base address of the virtual instructions...
|
_temp.push_back(
|
||||||
std::uintptr_t decrypt_key = end_of_module, start_addr;
|
reinterpret_cast<std::uint8_t*>(&operand)[idx]);
|
||||||
if ( vmctx->exec_type == vmp2::exec_type_t::backward )
|
|
||||||
std::for_each( virt_labels.begin()->vinstrs.begin(), virt_labels.begin()->vinstrs.end(),
|
result.back().vinstrs.insert(result.back().vinstrs.begin(),
|
||||||
[ & ]( const vinstr_data &vinstr ) {
|
_temp.begin(), _temp.end());
|
||||||
( ++decrypt_key ) += vinstr.imm_size ? vinstr.imm_size / 8 : 0;
|
result.back().vinstrs.insert(
|
||||||
} );
|
result.back().vinstrs.begin() + _temp.size(), opcode);
|
||||||
|
});
|
||||||
const auto opcode_fetch = std::find_if(
|
|
||||||
vmctx->calc_jmp.begin(), vmctx->calc_jmp.end(), []( const zydis_instr_t &instr_data ) -> bool {
|
|
||||||
// mov/movsx/movzx rax/eax/ax/al, [rsi]
|
|
||||||
return instr_data.instr.operand_count > 1 &&
|
|
||||||
( instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOV ||
|
|
||||||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVSX ||
|
|
||||||
instr_data.instr.mnemonic == ZYDIS_MNEMONIC_MOVZX ) &&
|
|
||||||
instr_data.instr.operands[ 0 ].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
|
||||||
util::reg::to64( instr_data.instr.operands[ 0 ].reg.value ) == ZYDIS_REGISTER_RAX &&
|
|
||||||
instr_data.instr.operands[ 1 ].type == ZYDIS_OPERAND_TYPE_MEMORY &&
|
|
||||||
instr_data.instr.operands[ 1 ].mem.base == ZYDIS_REGISTER_RSI;
|
|
||||||
} );
|
|
||||||
|
|
||||||
if ( opcode_fetch == vmctx->calc_jmp.end() )
|
|
||||||
{
|
|
||||||
std::printf( "> critical error trying to find opcode fetch inside of compiler_t::encrypt...\n" );
|
|
||||||
exit( 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start_addr = decrypt_key - 1; // make it zero based...
|
result.back().enc_alloc_rva = encrypt_rva(start_addr);
|
||||||
std::for_each( virt_labels.begin(), virt_labels.end(), [ & ]( vm::vlabel_data &label ) {
|
start_addr +=
|
||||||
// sometimes there is a mov al, [rsi-1]... we want that disp...
|
result.back().vinstrs.size() - 1; // make it zero based...
|
||||||
if ( opcode_fetch->instr.operands[ 1 ].mem.disp.has_displacement )
|
});
|
||||||
start_addr += std::abs( opcode_fetch->instr.operands[ 1 ].mem.disp.value );
|
|
||||||
|
|
||||||
decrypt_key = start_addr;
|
|
||||||
result.push_back( { label.label_name, start_addr } );
|
|
||||||
|
|
||||||
if ( vmctx->exec_type == vmp2::exec_type_t::forward )
|
|
||||||
{
|
|
||||||
std::for_each( label.vinstrs.begin(), label.vinstrs.end(), [ & ]( vm::vinstr_data &vinstr ) {
|
|
||||||
std::uint8_t opcode = vinstr.vm_handler;
|
|
||||||
std::uint64_t operand = 0u;
|
|
||||||
|
|
||||||
// encrypt opcode...
|
|
||||||
std::tie( opcode, decrypt_key ) =
|
|
||||||
vm::instrs::encrypt_operand( calc_jmp_transforms, vinstr.vm_handler, decrypt_key );
|
|
||||||
|
|
||||||
// if there is an operand then we will encrypt that as well..
|
|
||||||
if ( vmctx->vm_handlers[ vinstr.vm_handler ].imm_size )
|
|
||||||
{
|
|
||||||
auto &vm_handler_transforms = vmctx->vm_handlers[ vinstr.vm_handler ].transforms;
|
|
||||||
std::tie( operand, decrypt_key ) =
|
|
||||||
vm::instrs::encrypt_operand( vm_handler_transforms, vinstr.operand, decrypt_key );
|
|
||||||
}
|
|
||||||
else // else just push back the opcode...
|
|
||||||
{
|
|
||||||
result.back().vinstrs.push_back( opcode );
|
|
||||||
return; // finished here...
|
|
||||||
}
|
|
||||||
|
|
||||||
result.back().vinstrs.push_back( opcode );
|
|
||||||
for ( auto idx = 0u; idx < vmctx->vm_handlers[ vinstr.vm_handler ].imm_size / 8; ++idx )
|
|
||||||
result.back().vinstrs.push_back( reinterpret_cast< std::uint8_t * >( &vinstr.operand )[ idx ] );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::for_each( label.vinstrs.begin(), label.vinstrs.end(), [ & ]( vm::vinstr_data &vinstr ) {
|
|
||||||
std::uint8_t opcode = vinstr.vm_handler;
|
|
||||||
std::uint64_t operand = 0u;
|
|
||||||
|
|
||||||
// encrypt opcode...
|
|
||||||
std::tie( opcode, decrypt_key ) =
|
|
||||||
vm::instrs::encrypt_operand( calc_jmp_transforms, vinstr.vm_handler, decrypt_key );
|
|
||||||
|
|
||||||
// if there is an operand then we will encrypt that as well..
|
|
||||||
if ( vmctx->vm_handlers[ vinstr.vm_handler ].imm_size )
|
|
||||||
{
|
|
||||||
auto &vm_handler_transforms = vmctx->vm_handlers[ vinstr.vm_handler ].transforms;
|
|
||||||
std::tie( operand, decrypt_key ) =
|
|
||||||
vm::instrs::encrypt_operand( vm_handler_transforms, vinstr.operand, decrypt_key );
|
|
||||||
}
|
|
||||||
else // else just push back the opcode...
|
|
||||||
{
|
|
||||||
result.back().vinstrs.insert( result.back().vinstrs.begin(), 1, opcode );
|
|
||||||
return; // finished here...
|
|
||||||
}
|
|
||||||
|
|
||||||
// operand goes first, then opcode when vip advances backwards...
|
|
||||||
std::vector< std::uint8_t > _temp;
|
|
||||||
for ( auto idx = 0u; idx < vmctx->vm_handlers[ vinstr.vm_handler ].imm_size / 8; ++idx )
|
|
||||||
_temp.push_back( reinterpret_cast< std::uint8_t * >( &operand )[ idx ] );
|
|
||||||
|
|
||||||
result.back().vinstrs.insert( result.back().vinstrs.begin(), _temp.begin(), _temp.end() );
|
|
||||||
result.back().vinstrs.insert( result.back().vinstrs.begin() + _temp.size(), opcode );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
result.back().enc_alloc_rva = encrypt_rva( start_addr );
|
|
||||||
start_addr += result.back().vinstrs.size() - 1; // make it zero based...
|
|
||||||
} );
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint64_t compiler_t::encrypt_rva( std::uint64_t rva )
|
return result;
|
||||||
{
|
}
|
||||||
for ( auto &instr : encrypt_vinstrs_rva )
|
|
||||||
rva = vm::transform::apply( instr.operands[ 0 ].size, instr.mnemonic, rva,
|
|
||||||
transform::has_imm( &instr ) ? instr.operands[ 1 ].imm.value.u : 0 );
|
|
||||||
|
|
||||||
return rva;
|
std::uint64_t compiler_t::encrypt_rva(std::uint64_t rva) {
|
||||||
}
|
for (auto& instr : encrypt_vinstrs_rva)
|
||||||
} // namespace vm
|
rva = vm::transform::apply(
|
||||||
|
instr.operands[0].size, instr.mnemonic, rva,
|
||||||
|
transform::has_imm(&instr) ? instr.operands[1].imm.value.u : 0);
|
||||||
|
|
||||||
|
return rva;
|
||||||
|
}
|
||||||
|
} // namespace vm
|
@ -1,130 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <vmprofiler.hpp>
|
|
||||||
#include <xtils.hpp>
|
|
||||||
|
|
||||||
#include "parser.h"
|
|
||||||
|
|
||||||
namespace vm
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// struct containing encoded data for a given virtual instruction...
|
|
||||||
/// </summary>
|
|
||||||
struct vinstr_data
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// vm handler index also known as the opcode...
|
|
||||||
/// </summary>
|
|
||||||
std::uint8_t vm_handler;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// this field contains the second operand if any...
|
|
||||||
/// </summary>
|
|
||||||
std::uint64_t operand;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// size in bits of the second operand if any... zero if none...
|
|
||||||
/// </summary>
|
|
||||||
std::uint8_t imm_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// struct containing all information for a label...
|
|
||||||
/// </summary>
|
|
||||||
struct vlabel_data
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// name of the label...
|
|
||||||
/// </summary>
|
|
||||||
std::string label_name;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// vector of encoded virtual instructions...
|
|
||||||
/// </summary>
|
|
||||||
std::vector< vinstr_data > vinstrs;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// struct containing compiled virtual instructions (encoded and encrypted) for a given label...
|
|
||||||
/// </summary>
|
|
||||||
struct compiled_label_data
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// label name...
|
|
||||||
/// </summary>
|
|
||||||
std::string label_name;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// relative virtual address from vm_entry to the virtual instructions...
|
|
||||||
/// </summary>
|
|
||||||
std::uintptr_t alloc_rva;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// encrypted relative virtual address from vm_entry to virtual instructions...
|
|
||||||
/// </summary>
|
|
||||||
std::uintptr_t enc_alloc_rva;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// vector of bytes containing the raw, encrypted virtual instructions...
|
|
||||||
/// </summary>
|
|
||||||
std::vector< std::uint8_t > vinstrs;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// class containing member functions used to encode and encrypted virtual instructions...
|
|
||||||
/// </summary>
|
|
||||||
class compiler_t
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// <summary>
|
|
||||||
/// default constructor
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="vmctx">pointer to a vm context object which has already been init...</param>
|
|
||||||
explicit compiler_t( vm::ctx_t *vmctx );
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// encode virtual instructions from parser::virt_labels
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>returns a vector of labels containing encoded virtual instructions</returns>
|
|
||||||
std::vector< vlabel_data > *encode();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// encrypt virtual instructions from parser::virt_labels
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>returns a vector of compiled labels containing encoded and encrypted virtual
|
|
||||||
/// instructions...</returns>
|
|
||||||
std::vector< compiled_label_data > encrypt();
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// <summary>
|
|
||||||
/// encrypt virtual instructions rva... <a href="https://back.engineering/17/05/2021/#vm_entry">read more
|
|
||||||
/// here...</a>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="rva">relative virtual address to encrypted virtual instructions...</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
std::uint64_t encrypt_rva( std::uint64_t rva );
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// pointer to the vmctx passed in by the constructor...
|
|
||||||
/// </summary>
|
|
||||||
vm::ctx_t *vmctx;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// transformations used to decrypt the opcode operand extracted from calc_jmp...
|
|
||||||
/// you can read more <a href="https://back.engineering/17/05/2021/#calc_jmp">here...</a>
|
|
||||||
/// </summary>
|
|
||||||
transform::map_t calc_jmp_transforms;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// vector of encoded labels...
|
|
||||||
/// </summary>
|
|
||||||
std::vector< vlabel_data > virt_labels;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// vector of decoded zydis instructions containing the native instructions to encrypt the virtual instruction
|
|
||||||
/// rva which will be pushed onto the stack prior to jmping to vm entry...
|
|
||||||
/// </summary>
|
|
||||||
std::vector< zydis_decoded_instr_t > encrypt_vinstrs_rva;
|
|
||||||
};
|
|
||||||
} // namespace vm
|
|
@ -1,37 +1,30 @@
|
|||||||
#include "parser.h"
|
#include <parser.hpp>
|
||||||
|
|
||||||
parse_t::parse_t()
|
parse_t::parse_t() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
auto parse_t::get_instance() -> parse_t *
|
auto parse_t::get_instance() -> parse_t* {
|
||||||
{
|
static parse_t obj;
|
||||||
static parse_t obj;
|
return &obj;
|
||||||
return &obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_t::add_label( std::string label_name )
|
void parse_t::add_label(std::string label_name) {
|
||||||
{
|
// remove ":" from the end of the label name...
|
||||||
// remove ":" from the end of the label name...
|
label_name.erase(label_name.end() - 1);
|
||||||
label_name.erase( label_name.end() - 1 );
|
virt_labels.push_back({label_name});
|
||||||
virt_labels.push_back( { label_name } );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_t::add_vinstr( std::string vinstr_name )
|
void parse_t::add_vinstr(std::string vinstr_name) {
|
||||||
{
|
virt_labels.back().vinstrs.push_back({vinstr_name, false, 0u});
|
||||||
virt_labels.back().vinstrs.push_back( { vinstr_name, false, 0u } );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_t::add_vinstr( std::string vinstr_name, std::uintptr_t imm_val )
|
void parse_t::add_vinstr(std::string vinstr_name, std::uintptr_t imm_val) {
|
||||||
{
|
virt_labels.back().vinstrs.push_back({vinstr_name, true, imm_val});
|
||||||
virt_labels.back().vinstrs.push_back( { vinstr_name, true, imm_val } );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_t::for_each( callback_t callback )
|
bool parse_t::for_each(callback_t callback) {
|
||||||
{
|
for (auto& entry : virt_labels)
|
||||||
for ( auto &entry : virt_labels )
|
if (!callback(&entry))
|
||||||
if ( !callback( &entry ) )
|
return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
Loading…
Reference in new issue