#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