You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
4.3 KiB
179 lines
4.3 KiB
4 years ago
|
#include "obfuscation.hpp"
|
||
|
using namespace asmjit;
|
||
|
|
||
|
namespace obfuscation
|
||
|
{
|
||
|
obfuscate::obfuscate(instruction_info_t info)
|
||
|
:
|
||
|
instruction(info)
|
||
|
{
|
||
|
// idk what i did to zydis but + 1 fixed it?
|
||
|
// this is brutal... TODO: figure out tf is going on here...
|
||
|
switch (instruction.first.mnemonic + 1)
|
||
|
{
|
||
|
case ZYDIS_MNEMONIC_JLE:
|
||
|
case ZYDIS_MNEMONIC_JB:
|
||
|
case ZYDIS_MNEMONIC_JBE:
|
||
|
case ZYDIS_MNEMONIC_JCXZ:
|
||
|
case ZYDIS_MNEMONIC_JECXZ:
|
||
|
case ZYDIS_MNEMONIC_JKNZD:
|
||
|
case ZYDIS_MNEMONIC_JKZD:
|
||
|
case ZYDIS_MNEMONIC_JL:
|
||
|
case ZYDIS_MNEMONIC_JNB:
|
||
|
case ZYDIS_MNEMONIC_JNBE:
|
||
|
case ZYDIS_MNEMONIC_JNL:
|
||
|
case ZYDIS_MNEMONIC_JNLE:
|
||
|
case ZYDIS_MNEMONIC_JNO:
|
||
|
case ZYDIS_MNEMONIC_JNP:
|
||
|
case ZYDIS_MNEMONIC_JNS:
|
||
|
case ZYDIS_MNEMONIC_JNZ:
|
||
|
case ZYDIS_MNEMONIC_JO:
|
||
|
case ZYDIS_MNEMONIC_JP:
|
||
|
case ZYDIS_MNEMONIC_JRCXZ:
|
||
|
case ZYDIS_MNEMONIC_JS:
|
||
|
case ZYDIS_MNEMONIC_JZ:
|
||
|
{
|
||
|
const auto rva_fix_offset = instruction.first.length -
|
||
|
(instruction.first.operands[0].size / 8);
|
||
|
|
||
|
const auto rva_fix_addr =
|
||
|
instruction.second.data() + rva_fix_offset;
|
||
|
|
||
|
reloc_t inline_jmp_reloc
|
||
|
{
|
||
|
reloc_type::next_instruction_addr,
|
||
|
JMP_RIP_ADDR_IDX
|
||
|
};
|
||
|
|
||
|
reloc_t inline_jmp_branch
|
||
|
{
|
||
|
reloc_type::jcc,
|
||
|
JMP_RIP_ADDR_IDX,
|
||
|
*reinterpret_cast<std::int32_t*>(rva_fix_addr)
|
||
|
};
|
||
|
|
||
|
std::printf(" > fixing JCC rva...\n");
|
||
|
std::printf(" > new rva = 0x%x\n", JMP_RIP_SIZE);
|
||
|
std::printf(" > old rva = 0x%x\n",
|
||
|
*reinterpret_cast<std::int32_t*>(rva_fix_addr));
|
||
|
|
||
|
// when you inherit obfuscate please be mindful of JCC rvas...
|
||
|
*reinterpret_cast<std::int32_t*>(rva_fix_addr) = JMP_RIP_SIZE;
|
||
|
|
||
|
gadget_stack.push_back({ instruction.second, {} });
|
||
|
gadget_stack.push_back({ jmp_rip, inline_jmp_reloc });
|
||
|
gadget_stack.push_back({ jmp_rip, inline_jmp_branch });
|
||
|
break;
|
||
|
}
|
||
|
case ZYDIS_MNEMONIC_JMP:
|
||
|
{
|
||
|
const auto rva_fix_offset = instruction.first.length -
|
||
|
(instruction.first.operands[0].size / 8);
|
||
|
|
||
|
const auto rva_fix_addr =
|
||
|
instruction.second.data() + rva_fix_offset;
|
||
|
|
||
|
reloc_t inline_jmp_reloc
|
||
|
{
|
||
|
reloc_type::jcc,
|
||
|
JMP_RIP_ADDR_IDX,
|
||
|
*reinterpret_cast<std::int32_t*>(rva_fix_addr)
|
||
|
};
|
||
|
|
||
|
gadget_stack.push_back({ jmp_rip, inline_jmp_reloc });
|
||
|
break;
|
||
|
}
|
||
|
case ZYDIS_MNEMONIC_RET:
|
||
|
{
|
||
|
gadget_stack.push_back({ instruction.second, {} });
|
||
|
break;
|
||
|
}
|
||
|
default: // not a JCC, JMP, or RET...
|
||
|
{
|
||
|
reloc_t inline_jmp_reloc
|
||
|
{
|
||
|
reloc_type::next_instruction_addr,
|
||
|
JMP_RIP_ADDR_IDX
|
||
|
};
|
||
|
|
||
|
gadget_stack.push_back({ instruction.second, {} });
|
||
|
gadget_stack.push_back({ jmp_rip, inline_jmp_reloc });
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
auto obfuscate::get_size() const -> std::uint32_t
|
||
|
{
|
||
|
std::uint32_t result = 0u;
|
||
|
for (auto& gadget : gadget_stack)
|
||
|
result += gadget.first.size();
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
auto obfuscate::get_instruc() const -> ZydisDecodedInstruction
|
||
|
{
|
||
|
return instruction.first;
|
||
|
}
|
||
|
|
||
|
auto obfuscate::get_gadget() const -> gadget_stack_t
|
||
|
{
|
||
|
return gadget_stack;
|
||
|
}
|
||
|
|
||
|
mutation::mutation(instruction_info_t info)
|
||
|
: obfuscate(info)
|
||
|
{
|
||
|
JitRuntime rt;
|
||
|
CodeHolder push_code, pop_code;
|
||
|
|
||
|
push_code.init(rt.environment());
|
||
|
pop_code.init(rt.environment());
|
||
|
|
||
|
std::random_device rd;
|
||
|
std::mt19937 gen(rd());
|
||
|
|
||
|
std::vector<std::uint8_t> stack_palindrome;
|
||
|
std::uniform_int_distribution<> push_reg(0, 15), num_push(1, 10);
|
||
|
x86::Assembler push_asm(&push_code), pop_asm(&pop_code);
|
||
|
const auto push_pop_num = num_push(gen);
|
||
|
std::vector<x86::Gpq> reg_nums;
|
||
|
|
||
|
// generate random amount of pushes and subsequent pops...
|
||
|
for (auto idx = 0u; idx < push_pop_num; ++idx)
|
||
|
{
|
||
|
const auto reg_num = push_reg(gen);
|
||
|
const auto gp_reg = x86::Gpq(reg_num);
|
||
|
|
||
|
reg_nums.push_back(gp_reg);
|
||
|
push_asm.push(gp_reg);
|
||
|
}
|
||
|
|
||
|
stack_palindrome.insert
|
||
|
(
|
||
|
stack_palindrome.end(),
|
||
|
push_asm.bufferData(),
|
||
|
push_asm.bufferData() +
|
||
|
push_asm.code()->codeSize()
|
||
|
);
|
||
|
|
||
|
std::reverse(reg_nums.begin(), reg_nums.end());
|
||
|
for (auto idx = 0u; idx < push_pop_num; ++idx)
|
||
|
pop_asm.pop(reg_nums[idx]);
|
||
|
|
||
|
stack_palindrome.insert
|
||
|
(
|
||
|
stack_palindrome.end(),
|
||
|
pop_asm.bufferData(),
|
||
|
pop_asm.bufferData() +
|
||
|
pop_asm.code()->codeSize()
|
||
|
);
|
||
|
|
||
|
// insert the stack palandrome before the actual
|
||
|
// instruction gets executed...
|
||
|
gadget_stack.insert(
|
||
|
gadget_stack.begin(),
|
||
|
{ std::move(stack_palindrome), {reloc_type::none, NULL, NULL } });
|
||
|
}
|
||
|
}
|