// Copyright (c) 2022, _xeroxz // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // 3. Neither the name of the copyright holder nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // #pragma once #include #include #include #include #include #include #define XED_ENCODER extern "C" { #include #include } /// /// this namespace encompasses the code for transforming relocations. /// namespace theo::obf::transform { /// /// lambda function which takes in a 64bit value (relocation address) and a /// 32bit value (random value used in transformation). /// using transform_t = std::function; /// /// operation_t is the base class for all types of transformations. classes that /// inherit this class are singleton and simply call the super constructor /// (operation_t::operation_t). /// class operation_t { public: /// /// explicit constructor for operation_t /// /// lambda function when executed applies /// transformations. type of transformation, such /// as XOR, ADD, SUB, etc... explicit operation_t(transform_t op, xed_iclass_enum_t type) : m_transform(op), m_type(type) {} /// /// generates a native transform instruction given an existing instruction. it /// works like so: /// /// mov rax, &MessageBoxA ; original instruction with relocation /// /// ; this function takes the first operand and out of the original /// ; instruction and uses it to generate a transformation. /// /// xor rax, 0x39280928 ; this would be an example output for the xor /// ;operation. /// /// /// instruction with a relocation to generate a /// transformation for. random 32bit number used in /// the generate transform. returns the bytes of the native /// instruction that was encoded. std::vector native(const xed_decoded_inst_t* inst, std::uint32_t imm) { std::uint32_t inst_len = {}; std::uint8_t inst_buff[XED_MAX_INSTRUCTION_BYTES]; xed_error_enum_t err; xed_encoder_request_init_from_decode((xed_decoded_inst_s*)inst); xed_encoder_request_t* req = (xed_encoder_request_t*)inst; switch (m_type) { case XED_ICLASS_ROR: case XED_ICLASS_ROL: xed_encoder_request_set_uimm0(req, imm, 1); break; default: xed_encoder_request_set_uimm0(req, imm, 4); break; } xed_encoder_request_set_iclass(req, m_type); xed_encoder_request_set_operand_order(req, 1, XED_OPERAND_IMM0); if ((err = xed_encode(req, inst_buff, sizeof(inst_buff), &inst_len)) != XED_ERROR_NONE) { spdlog::error("failed to encode instruction... reason: {}", xed_error_enum_t2str(err)); assert(err == XED_ERROR_NONE); } return std::vector(inst_buff, inst_buff + inst_len); } /// /// gets the inverse operation of the current operation. /// /// the inverse operation of the current operation. xed_iclass_enum_t inverse() { return m_inverse_op[m_type]; } /// /// gets a pointer to the lambda function which contains the transform logic. /// /// a pointer to the lambda function which contains the transform /// logic. transform_t* get_transform() { return &m_transform; } /// /// gets the operation type. such as XED_ICLASS_ADD, XED_ICLASS_SUB, etc... /// /// the operation type. such as XED_ICLASS_ADD, XED_ICLASS_SUB, /// etc... xed_iclass_enum_t type() { return m_type; } /// /// generate a random number in a range. /// /// lowest value of the range. /// highest value of the range. /// a random value in a range. static std::size_t random(std::size_t lowest, std::size_t largest) { std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution distr(lowest, largest); return distr(gen); } private: transform_t m_transform; xed_iclass_enum_t m_type; std::map m_inverse_op = { {XED_ICLASS_ADD, XED_ICLASS_SUB}, {XED_ICLASS_SUB, XED_ICLASS_ADD}, {XED_ICLASS_ROL, XED_ICLASS_ROR}, {XED_ICLASS_ROR, XED_ICLASS_ROL}, {XED_ICLASS_XOR, XED_ICLASS_XOR}}; }; } // namespace theo::obf::transform