mirror of
https://github.com/67-6f-64/AntiOreans-CodeDevirtualizer
synced 2026-06-08 10:18:33 +00:00
1897 lines
59 KiB
C++
1897 lines
59 KiB
C++
#include "wild_handler.hpp"
|
|
#include "instruction_emulator.hpp"
|
|
|
|
#include <idp.hpp>
|
|
|
|
#include <algorithm>
|
|
|
|
bool wild_handler::map_handler_specific(instruction_container& instructions, wild_context& context)
|
|
{
|
|
/* Placeholder for virtual function */
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::step_handler_specific(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
/* Placeholder for virtual function */
|
|
return false;
|
|
}
|
|
|
|
wild_handler::wild_handler(uint16_t index)
|
|
{
|
|
this->id = WILD_HANDLER_INVALID;
|
|
this->index = index;
|
|
|
|
this->opcode_size = OPCODE_SIZE_INVALID;
|
|
this->cmp_count = 0;
|
|
}
|
|
|
|
uint16_t wild_handler::get_id()
|
|
{
|
|
return this->id;
|
|
}
|
|
|
|
bool wild_handler::is_flow_type()
|
|
{
|
|
return (this->id == WILD_HANDLER_JUMP_INSIDE ||
|
|
this->id == WILD_HANDLER_JUMP_OUTSIDE_REGISTER ||
|
|
this->id == WILD_HANDLER_JUMP_OUTSIDE_MEMORY ||
|
|
this->id == WILD_HANDLER_JUMP_OUTSIDE_IMMEDIATE ||
|
|
this->id == WILD_HANDLER_RET ||
|
|
this->id == WILD_HANDLER_CALL ||
|
|
this->id == WILD_HANDLER_UNDEF);
|
|
}
|
|
|
|
bool wild_handler::decrypt(instruction_container& instructions, wild_context& context, uint32_t compares)
|
|
{
|
|
this->cmp_count = compares;
|
|
|
|
if (!this->decrypt_flow_data(instructions, context))
|
|
{
|
|
msg("[CodeDevirtualizer] Failed to decrypt flow data for handler %04X.\n", this->index);
|
|
return false;
|
|
}
|
|
|
|
if (!this->decrypt_key_data(instructions, context))
|
|
{
|
|
msg("[CodeDevirtualizer] Failed to decrypt key data for handler %04X.\n", this->index);
|
|
return false;
|
|
}
|
|
|
|
if (!this->map_handler(instructions, context))
|
|
{
|
|
if (!this->map_handler_specific(instructions, context))
|
|
return false;
|
|
}
|
|
|
|
this->decrypt_opcode_regions(instructions, context);
|
|
this->decrypt_opcode_size(instructions, context);
|
|
return true;
|
|
}
|
|
|
|
bool wild_handler::decrypt_key_data(instruction_container& instructions, wild_context& context)
|
|
{
|
|
this->decrypt_key_protection_template(instructions, context);
|
|
|
|
for (std::size_t i = 0; i < instructions.size(); i++)
|
|
{
|
|
if (context.is_key_access_instruction(instructions.at(i), false))
|
|
{
|
|
bool is_base_operand_key = instructions.at(i).is_operand_type(0, UD_OP_MEM);
|
|
|
|
unsigned int operand_key = (is_base_operand_key ? 0 : 1);
|
|
unsigned int operand_data = (is_base_operand_key ? 1 : 0);
|
|
|
|
wild_handler_key key_access;
|
|
|
|
key_access.id = instructions.at(i).get_operand_data<uint16_t>(operand_key);
|
|
key_access.index = instructions.at(i).get_index();
|
|
|
|
key_access.mnemonic = instructions.at(i).get_mnemonic();
|
|
key_access.operand = operand_key;
|
|
|
|
key_access.type = instructions.at(i).get_operand_type(operand_data);
|
|
key_access.size = instructions.at(i).get_operand_size(operand_data);
|
|
|
|
if (instructions.at(i).get_key_data() & HAS_KEY_DATA_FLAG)
|
|
{
|
|
if (!is_base_operand_key)
|
|
{
|
|
msg("[CodeDevirtualizer] Direct access key is not base operand.\n");
|
|
return false;
|
|
}
|
|
|
|
key_access.direct_key_parameter = true;
|
|
key_access.parameter = instructions.at(i).get_key_data() & 0x7FFFFFFF;
|
|
|
|
instructions.at(i).set_key_data(0);
|
|
}
|
|
else
|
|
{
|
|
key_access.direct_key_parameter = false;
|
|
key_access.parameter = instructions.at(i).get_params(operand_data);
|
|
}
|
|
|
|
instructions.remove(i--);
|
|
this->key_accessors.push_back(key_access);
|
|
}
|
|
}
|
|
|
|
std::sort(this->key_accessors.begin(), this->key_accessors.end());
|
|
return true;
|
|
}
|
|
|
|
void wild_handler::decrypt_key_protection_template(instruction_container& instructions, wild_context& context)
|
|
{
|
|
for (std::size_t i = 0; i < instructions.size(); i++)
|
|
{
|
|
/* 0: mov reg,unknown ptr [ebp+xx] */
|
|
if (instructions.at(i).is_mnemonic(UD_Imov) &&
|
|
instructions.at(i).is_operand_type(0, UD_OP_REG) &&
|
|
context.is_key_access_instruction(instructions.at(i), true))
|
|
{
|
|
for (std::size_t j = (i + 1), binary_offset = 0; j < instructions.size(); j++)
|
|
{
|
|
if (instructions.at(j).is_operand_type(0, UD_OP_REG) &&
|
|
instructions.at(j).is_operand_base(0, instructions.at(i), 0))
|
|
{
|
|
/* 1: ___ reg,___ */
|
|
if (binary_offset == 0 &&
|
|
instructions.at(j).compare_mnemonic(false, false, true))
|
|
{
|
|
binary_offset = j;
|
|
}
|
|
/*
|
|
2: cmp reg,0x0
|
|
3: je ___
|
|
4: ___ unknown ptr [ebp+xx],___
|
|
*/
|
|
else if (binary_offset != 0 &&
|
|
instructions.bounds(j, 3) &&
|
|
instructions.at(j).is_mnemonic(UD_Icmp) &&
|
|
instructions.at(j).is_operand_type(1, UD_OP_IMM) &&
|
|
instructions.at(j).is_operand_data(1, 0) &&
|
|
instructions.at(j + 1).is_mnemonic(UD_Ijz) &&
|
|
instructions.at(j + 2).compare_mnemonic(false, false, true) &&
|
|
instructions.at(j + 2).is_operand_type(0, UD_OP_MEM) &&
|
|
context.is_key_access_instruction(instructions.at(j + 2), true) &&
|
|
instructions.at(j + 2).is_operand_data(0, instructions.at(i), 1))
|
|
{
|
|
wild_handler_key key_access;
|
|
|
|
key_access.id = instructions.at(j + 2).get_operand_data<uint16_t>(0);
|
|
key_access.index = instructions.at(i).get_index();
|
|
|
|
key_access.mnemonic = instructions.at(j + 2).get_mnemonic();
|
|
key_access.operand = 0;
|
|
|
|
key_access.type = instructions.at(j + 2).get_operand_type(1);
|
|
key_access.size = instructions.at(j + 2).get_operand_size(0);
|
|
|
|
key_access.direct_key_parameter = false;
|
|
key_access.parameter = instructions.at(j + 2).get_params(1);
|
|
|
|
key_access.condition = [](wild_context const& context, wild_handler_key const& key_accessor) -> bool
|
|
{
|
|
uint32_t key_data = 0;
|
|
|
|
if (!context.get_key(key_accessor.id, &key_data))
|
|
return false;
|
|
|
|
return ((key_data & 1) != 0);
|
|
};
|
|
|
|
this->key_accessors.push_back(key_access);
|
|
|
|
instructions.remove(j, 3);
|
|
instructions.remove(binary_offset);
|
|
instructions.remove(i--);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::size_t wild_handler::find_first_key_after(std::size_t index)
|
|
{
|
|
for (std::size_t i = 0; i < this->key_accessors.size(); i++)
|
|
{
|
|
if (this->key_accessors.at(i).index >= index)
|
|
return i;
|
|
}
|
|
|
|
return static_cast<std::size_t>(-1);
|
|
}
|
|
|
|
std::size_t wild_handler::find_last_key_before(std::size_t index)
|
|
{
|
|
for (std::size_t i = (this->key_accessors.size() - 1); static_cast<int32_t>(i) >= 0; i--)
|
|
{
|
|
if (this->key_accessors.at(i).index <= index)
|
|
return i;
|
|
}
|
|
|
|
return static_cast<std::size_t>(-1);
|
|
}
|
|
|
|
void wild_handler::decrypt_opcode_size(instruction_container& instructions, wild_context& context)
|
|
{
|
|
if (instructions.back().is_mnemonic(UD_Iret))
|
|
this->opcode_size = OPCODE_SIZE_RETN;
|
|
else if (instructions.back().is_mnemonic(UD_Ijmp))
|
|
{
|
|
std::size_t index = (instructions.size() - 2);
|
|
|
|
if (context.is_opcode_access_instruction(instructions.at(index)))
|
|
{
|
|
if (instructions.at(index).is_mnemonic(UD_Isub))
|
|
this->opcode_size = OPCODE_SIZE_SUB;
|
|
else if (instructions.at(index).is_mnemonic(UD_Iadd))
|
|
this->opcode_size = instructions.at(index).get_operand_data<uint16_t>(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void wild_handler::decrypt_opcode_regions(instruction_container& instructions, wild_context& context)
|
|
{
|
|
for (std::size_t i = 0; i < instructions.size(); i++)
|
|
{
|
|
/* 0: mov reg,dword ptr [ebp+xx] */
|
|
if (instructions.at(i).is_mnemonic(UD_Imov) &&
|
|
instructions.at(i).is_operand_type(0, UD_OP_REG) &&
|
|
context.is_opcode_access_instruction(instructions.at(i)))
|
|
{
|
|
uint16_t opcode_offset = 0xFFFF;
|
|
|
|
ud_type type = UD_NONE;
|
|
ud_size size = UD_SIZE_NONE;
|
|
|
|
std::size_t offset = 0;
|
|
|
|
for (std::size_t j = i + 1; j < instructions.size(); j++)
|
|
{
|
|
if (instructions.at(j).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(j).is_operand_type(0, UD_OP_REG) &&
|
|
instructions.at(j).is_operand_base(0, instructions.at(i), 0) &&
|
|
instructions.at(j).is_operand_type(1, UD_OP_IMM))
|
|
{
|
|
opcode_offset = instructions.at(j).get_operand_data<uint16_t>(1);
|
|
}
|
|
else if (instructions.at(j).is_mnemonic({ UD_Imov, UD_Imovzx }) &&
|
|
instructions.at(j).is_operand_type(1, UD_OP_MEM) &&
|
|
instructions.at(j).is_operand_base(1, instructions.at(i), 0))
|
|
{
|
|
type = instructions.at(j).get_base_size_type(0, UD_SIZE_DWORD);
|
|
size = instructions.at(j).get_operand_size(1);
|
|
offset = j;
|
|
break;
|
|
}
|
|
else if (instructions.at(j).is_mnemonic(UD_Imov) &&
|
|
instructions.at(j).is_operand_type(0, UD_OP_REG) &&
|
|
instructions.at(j).is_operand_base(0, instructions.at(i), 0))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (opcode_offset != 0xFFFF && type != UD_NONE)
|
|
{
|
|
std::size_t index = offset;
|
|
std::vector<std::size_t> indexes;
|
|
|
|
while (instructions.bounds(++index) &&
|
|
index < this->flow_read_index)
|
|
{
|
|
for (std::size_t j = 0; j < this->key_accessors.size(); j++)
|
|
{
|
|
wild_handler_key& key = this->key_accessors.at(j);
|
|
|
|
if (key.index == index)
|
|
{
|
|
if (key.type == UD_OP_REG &&
|
|
instructions.at(offset).is_operand_base_family(0, static_cast<ud_type>(key.parameter)))
|
|
{
|
|
indexes.push_back(index);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (instructions.at(index).is_mnemonic(UD_Imov) &&
|
|
instructions.at(index).is_operand_type(0, UD_OP_REG) &&
|
|
instructions.at(index).is_operand_base_family(0, instructions.at(i), 0))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!indexes.empty())
|
|
this->opcode_regions.push_back({ opcode_offset, size, indexes.front(), indexes.back() });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool wild_handler::map_handler(instruction_container& instructions, wild_context& context)
|
|
{
|
|
return (this->map_handler_jmp(instructions, context) ||
|
|
this->map_handler_jcc(instructions, context) ||
|
|
this->map_handler_retn(instructions, context) ||
|
|
this->map_handler_undef(instructions, context) ||
|
|
this->map_handler_lods(instructions, context) ||
|
|
this->map_handler_stos(instructions, context) ||
|
|
this->map_handler_scas(instructions, context) ||
|
|
this->map_handler_cmps(instructions, context) ||
|
|
this->map_handler_movs(instructions, context) ||
|
|
this->map_handler_eflags(instructions, context) ||
|
|
this->map_handler_stack(instructions, context) ||
|
|
this->map_handler_reset_eflags(instructions, context) ||
|
|
this->map_handler_reset(instructions, context) ||
|
|
this->map_handler_crypt(instructions, context));
|
|
}
|
|
|
|
bool wild_handler::map_handler_jmp(instruction_container& instructions, wild_context& context)
|
|
{
|
|
if (instructions.bounds(0, 16) &&
|
|
instructions.at(0).is_mnemonic(UD_Imov) &&
|
|
instructions.at(1).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(2).is_mnemonic(UD_Imov) &&
|
|
instructions.at(3).is_mnemonic(UD_Ishl) &&
|
|
instructions.at(4).is_mnemonic(UD_Imov) &&
|
|
instructions.at(5).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(6).is_mnemonic(UD_Imov) &&
|
|
instructions.at(7).is_mnemonic(UD_Imov) &&
|
|
instructions.at(8).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(9).is_mnemonic(UD_Imov) &&
|
|
instructions.at(10).is_mnemonic(UD_Imov) &&
|
|
instructions.at(11).is_mnemonic(UD_Iand) &&
|
|
instructions.at(12).is_mnemonic(UD_Icmp) &&
|
|
instructions.at(13).is_mnemonic(UD_Ijz) &&
|
|
instructions.at(14).is_mnemonic(UD_Iand) &&
|
|
instructions.at(15).is_mnemonic(UD_Isub) &&
|
|
instructions.at(16).is_mnemonic(UD_Ijmp))
|
|
{
|
|
this->id = WILD_HANDLER_JUMP_INSIDE;
|
|
this->opcode_offsets[0] = instructions.at(1).get_loword(1);
|
|
this->opcode_offsets[1] = instructions.at(8).get_loword(1);
|
|
return true;
|
|
}
|
|
else if (instructions.bounds(0, 10) &&
|
|
instructions.at(0).is_mnemonic(UD_Imov) &&
|
|
instructions.at(1).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(2).is_mnemonic(UD_Imov) &&
|
|
instructions.at(3).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(4).is_mnemonic(UD_Imov) &&
|
|
instructions.at(4).is_operand_base(1, instructions.at(3), 0) &&
|
|
instructions.at(5).is_mnemonic(UD_Imov) &&
|
|
instructions.at(6).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(7).is_mnemonic(UD_Imov) &&
|
|
instructions.at(8).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(9).is_mnemonic(UD_Imov) &&
|
|
instructions.at(9).is_operand_base(1, instructions.at(4), 0) &&
|
|
instructions.at(10).is_mnemonic(UD_Imov))
|
|
{
|
|
this->id = WILD_HANDLER_JUMP_OUTSIDE_REGISTER;
|
|
this->opcode_offsets[0] = instructions.at(1).get_loword(1);
|
|
return true;
|
|
}
|
|
else if (instructions.bounds(0, 11) &&
|
|
instructions.at(0).is_mnemonic(UD_Imov) &&
|
|
instructions.at(1).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(2).is_mnemonic(UD_Imov) &&
|
|
instructions.at(3).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(4).is_mnemonic(UD_Imov) &&
|
|
instructions.at(4).is_operand_base(1, instructions.at(3), 0) &&
|
|
instructions.at(5).is_mnemonic(UD_Imov) &&
|
|
instructions.at(5).is_operand_base(1, instructions.at(4), 0) &&
|
|
instructions.at(6).is_mnemonic(UD_Imov) &&
|
|
instructions.at(7).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(8).is_mnemonic(UD_Imov) &&
|
|
instructions.at(9).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(10).is_mnemonic(UD_Imov) &&
|
|
instructions.at(11).is_mnemonic(UD_Imov))
|
|
{
|
|
this->id = WILD_HANDLER_JUMP_OUTSIDE_MEMORY;
|
|
this->opcode_offsets[0] = instructions.at(1).get_loword(1);
|
|
return true;
|
|
}
|
|
else if (instructions.bounds(0, 18) &&
|
|
instructions.at(0).is_mnemonic(UD_Imov) &&
|
|
instructions.at(1).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(2).is_mnemonic(UD_Imov) &&
|
|
instructions.at(3).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(4).is_mnemonic(UD_Imov) &&
|
|
instructions.at(5).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(6).is_mnemonic(UD_Imov) &&
|
|
instructions.at(7).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(7).is_operand_type(1, UD_OP_REG, UD_SIZE_DWORD) &&
|
|
instructions.at(7).is_operand_base(1, UD_R_ESP) &&
|
|
instructions.at(8).is_mnemonic(UD_Imov) &&
|
|
instructions.at(9).is_mnemonic(UD_Imov) &&
|
|
instructions.at(10).is_mnemonic(UD_Ipop) &&
|
|
instructions.at(11).is_mnemonic(UD_Ipop) &&
|
|
instructions.at(12).is_mnemonic(UD_Ipop) &&
|
|
instructions.at(13).is_mnemonic(UD_Ipop) &&
|
|
instructions.at(14).is_mnemonic(UD_Ipop) &&
|
|
instructions.at(15).is_mnemonic(UD_Ipop) &&
|
|
instructions.at(16).is_mnemonic(UD_Ipop) &&
|
|
instructions.at(17).is_mnemonic({ UD_Ipopfw, UD_Ipopfd, UD_Ipopfq }) &&
|
|
instructions.at(18).is_mnemonic(UD_Iret))
|
|
{
|
|
this->id = WILD_HANDLER_JUMP_OUTSIDE_IMMEDIATE;
|
|
this->opcode_offsets[0] = instructions.at(1).get_loword(1);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::map_handler_jcc(instruction_container& instructions, wild_context& context)
|
|
{
|
|
if (instructions.bounds(0, 14) &&
|
|
instructions.at(0).is_mnemonic(UD_Imov) &&
|
|
instructions.at(1).is_mnemonic(UD_Imov) &&
|
|
instructions.at(2).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(3).is_mnemonic(UD_Imov) &&
|
|
instructions.at(4).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(5).is_mnemonic(UD_Imov) &&
|
|
instructions.at(6).is_mnemonic(UD_Imov) &&
|
|
instructions.at(7).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(8).is_mnemonic(UD_Imov) &&
|
|
instructions.at(9).is_mnemonic(UD_Icmp) &&
|
|
instructions.at(10).is_mnemonic(UD_Ijz) &&
|
|
instructions.at(11).is_mnemonic(UD_Icmp) &&
|
|
instructions.at(12).is_mnemonic(UD_Ijz) &&
|
|
instructions.at(13).is_mnemonic(UD_Icmp) &&
|
|
instructions.at(14).is_mnemonic(UD_Ijnz))
|
|
{
|
|
std::size_t index = (instructions.size() - 25);
|
|
|
|
if (instructions.bounds(0, 25) &&
|
|
instructions.find_mnemonic_index(UD_Iret, index))
|
|
{
|
|
this->id = WILD_HANDLER_JCC_OUTSIDE;
|
|
}
|
|
else
|
|
{
|
|
this->id = WILD_HANDLER_JCC_INSIDE;
|
|
}
|
|
|
|
this->opcode_offsets[0] = instructions.at(7).get_loword(1);
|
|
return this->parse_jcc_parameters(instructions, context);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::map_handler_retn(instruction_container& instructions, wild_context& context)
|
|
{
|
|
for (std::size_t i = 2; i < 15 && i < instructions.size(); i++)
|
|
{
|
|
/* 0: std */
|
|
if (instructions.at(i).is_mnemonic(UD_Istd))
|
|
{
|
|
this->id = WILD_HANDLER_RET;
|
|
this->opcode_offsets[0] = instructions.at(1).get_loword(1);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::map_handler_undef(instruction_container& instructions, wild_context& context)
|
|
{
|
|
if (instructions.bounds(0, 10) &&
|
|
instructions.at(0).is_mnemonic(UD_Imov) &&
|
|
instructions.at(1).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(2).is_mnemonic(UD_Imov) &&
|
|
instructions.at(3).is_mnemonic(UD_Icmp) &&
|
|
instructions.at(4).is_mnemonic(UD_Ijz) &&
|
|
instructions.at(5).is_mnemonic(UD_Icmp) &&
|
|
instructions.at(6).is_mnemonic(UD_Ijz) &&
|
|
instructions.at(7).is_mnemonic(UD_Imov) &&
|
|
instructions.at(8).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(9).is_mnemonic(UD_Imov) &&
|
|
instructions.at(10).is_mnemonic(UD_Iadd))
|
|
{
|
|
this->id = WILD_HANDLER_UNDEF;
|
|
this->opcode_offsets[0] = instructions.at(1).get_loword(1);
|
|
this->opcode_offsets[1] = instructions.at(8).get_loword(1);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::map_handler_lods(instruction_container& instructions, wild_context& context)
|
|
{
|
|
std::size_t pop_index = 18;
|
|
|
|
/*
|
|
0: mov ___,___
|
|
1: and ___,___
|
|
2: pop ___
|
|
*/
|
|
if (instructions.find_mnemonic_index(UD_Ipop, pop_index) &&
|
|
instructions.at(pop_index - 2).is_mnemonic(UD_Imov) &&
|
|
instructions.at(pop_index - 1).is_mnemonic(UD_Iand))
|
|
{
|
|
std::size_t index = 2;
|
|
|
|
/* 0: push reg */
|
|
if (instructions.find_mnemonic_index(UD_Ipush, index) &&
|
|
index < 15 &&
|
|
instructions.at(index).is_operand_type(0, UD_OP_REG))
|
|
{
|
|
std::size_t memory_index = static_cast<std::size_t>(-1);
|
|
|
|
for (std::size_t i = index; i < 16 && i < instructions.size(); i++)
|
|
{
|
|
/* 0: mov unknown ptr [reg],___ */
|
|
if (instructions.at(i).is_mnemonic(UD_Imov) &&
|
|
instructions.at(i).is_operand_type(0, UD_OP_MEM))
|
|
{
|
|
memory_index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
3: cmp ___,0x0
|
|
4: je ___
|
|
5: sub ___,___
|
|
*/
|
|
if (memory_index != static_cast<std::size_t>(-1) &&
|
|
instructions.bounds(pop_index, 3) &&
|
|
instructions.at(pop_index + 1).is_mnemonic(UD_Icmp) &&
|
|
instructions.at(pop_index + 1).is_operand_type(1, UD_OP_IMM) &&
|
|
instructions.at(pop_index + 1).is_operand_data(1, 0) &&
|
|
instructions.at(pop_index + 2).is_mnemonic(UD_Ijz) &&
|
|
instructions.at(pop_index + 3).is_mnemonic(UD_Isub))
|
|
{
|
|
if (instructions.at(memory_index).is_operand_base_not(0, instructions.at(index), 0))
|
|
{
|
|
switch (instructions.at(pop_index + 3).get_operand_data(1))
|
|
{
|
|
case 1:
|
|
this->id = WILD_HANDLER_LODSB;
|
|
return true;
|
|
|
|
case 2:
|
|
this->id = WILD_HANDLER_LODSW;
|
|
return true;
|
|
|
|
case 4:
|
|
this->id = WILD_HANDLER_LODSD;
|
|
return true;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::map_handler_stos(instruction_container& instructions, wild_context& context)
|
|
{
|
|
std::size_t pop_index = 18;
|
|
|
|
/*
|
|
0: mov ___,___
|
|
1: and ___,___
|
|
2: pop ___
|
|
*/
|
|
if (instructions.find_mnemonic_index(UD_Ipop, pop_index) &&
|
|
instructions.at(pop_index - 2).is_mnemonic(UD_Imov) &&
|
|
instructions.at(pop_index - 1).is_mnemonic(UD_Iand))
|
|
{
|
|
std::size_t index = 2;
|
|
|
|
/* 0: push reg */
|
|
if (instructions.find_mnemonic_index(UD_Ipush, index) &&
|
|
index < 15 &&
|
|
instructions.at(index).is_operand_type(0, UD_OP_REG))
|
|
{
|
|
std::size_t memory_index = static_cast<std::size_t>(-1);
|
|
|
|
for (std::size_t i = index; i < 16 && i < instructions.size(); i++)
|
|
{
|
|
/* 0: mov unknown ptr [reg],___ */
|
|
if (instructions.at(i).is_mnemonic(UD_Imov) &&
|
|
instructions.at(i).is_operand_type(0, UD_OP_MEM))
|
|
{
|
|
memory_index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
3: cmp ___,0x0
|
|
4: je ___
|
|
5: sub ___,___
|
|
*/
|
|
if (memory_index != static_cast<std::size_t>(-1) &&
|
|
instructions.bounds(pop_index, 3) &&
|
|
instructions.at(pop_index + 1).is_mnemonic(UD_Icmp) &&
|
|
instructions.at(pop_index + 1).is_operand_type(1, UD_OP_IMM) &&
|
|
instructions.at(pop_index + 1).is_operand_data(1, 0) &&
|
|
instructions.at(pop_index + 2).is_mnemonic(UD_Ijz) &&
|
|
instructions.at(pop_index + 3).is_mnemonic(UD_Isub))
|
|
{
|
|
if (instructions.at(memory_index).is_operand_base(0, instructions.at(index), 0))
|
|
{
|
|
switch (instructions.at(pop_index + 3).get_operand_data(1))
|
|
{
|
|
case 1:
|
|
this->id = WILD_HANDLER_STOSB;
|
|
return true;
|
|
|
|
case 2:
|
|
this->id = WILD_HANDLER_STOSW;
|
|
return true;
|
|
|
|
case 4:
|
|
this->id = WILD_HANDLER_STOSD;
|
|
return true;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::map_handler_scas(instruction_container& instructions, wild_context& context)
|
|
{
|
|
std::size_t index = 10;
|
|
|
|
/*
|
|
11: sub ___,___
|
|
12: pushfd
|
|
*/
|
|
if (instructions.find_mnemonic_index(UD_Ipushfd, index) &&
|
|
instructions.at(index - 1).is_mnemonic(UD_Isub))
|
|
{
|
|
/*
|
|
0: cmp ___,0x0
|
|
1: je ___
|
|
2: sub ___,imm
|
|
*/
|
|
if (instructions.find_mnemonic_index(UD_Icmp, index) &&
|
|
instructions.bounds(index, 2) &&
|
|
instructions.at(index).is_operand_type(1, UD_OP_IMM) &&
|
|
instructions.at(index).is_operand_data(1, 0) &&
|
|
instructions.at(index + 1).is_mnemonic(UD_Ijz) &&
|
|
instructions.at(index + 2).is_mnemonic(UD_Isub) &&
|
|
instructions.at(index + 2).is_operand_type(1, UD_OP_IMM))
|
|
{
|
|
switch (instructions.at(index + 2).get_operand_data(1))
|
|
{
|
|
case 1:
|
|
this->id = WILD_HANDLER_SCASB;
|
|
return true;
|
|
|
|
case 2:
|
|
this->id = WILD_HANDLER_SCASW;
|
|
return true;
|
|
|
|
case 4:
|
|
this->id = WILD_HANDLER_SCASD;
|
|
return true;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::map_handler_cmps(instruction_container& instructions, wild_context& context)
|
|
{
|
|
std::size_t index = 10;
|
|
|
|
/*
|
|
0: cmp ___,___
|
|
1: pushfd
|
|
*/
|
|
if (instructions.find_mnemonic_index(UD_Ipushfd, index) &&
|
|
instructions.at(index - 1).is_mnemonic(UD_Icmp))
|
|
{
|
|
/*
|
|
0: cmp ___,0x0
|
|
1: je ___
|
|
2: sub ___,imm
|
|
3: sub ___,___
|
|
*/
|
|
if (instructions.find_mnemonic_index(UD_Icmp, index) &&
|
|
instructions.bounds(index, 3) &&
|
|
instructions.at(index).is_operand_type(1, UD_OP_IMM) &&
|
|
instructions.at(index).is_operand_data(1, 0) &&
|
|
instructions.at(index + 1).is_mnemonic(UD_Ijz) &&
|
|
instructions.at(index + 2).is_mnemonic(UD_Isub) &&
|
|
instructions.at(index + 2).is_operand_type(1, UD_OP_IMM) &&
|
|
instructions.at(index + 3).is_mnemonic(UD_Isub))
|
|
{
|
|
switch (instructions.at(index + 2).get_operand_data(1))
|
|
{
|
|
case 1:
|
|
this->id = WILD_HANDLER_CMPSB;
|
|
return true;
|
|
|
|
case 2:
|
|
this->id = WILD_HANDLER_CMPSW;
|
|
return true;
|
|
|
|
case 4:
|
|
this->id = WILD_HANDLER_CMPSD;
|
|
return true;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::map_handler_movs(instruction_container& instructions, wild_context& context)
|
|
{
|
|
std::size_t memory_index = static_cast<std::size_t>(-1);
|
|
|
|
for (std::size_t i = 10; i < 25 && i < instructions.size(); i++)
|
|
{
|
|
/* 0: mov unknown ptr [reg],___ */
|
|
if (instructions.at(i).is_mnemonic(UD_Imov) &&
|
|
instructions.at(i).is_operand_type(0, UD_OP_MEM))
|
|
{
|
|
memory_index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::size_t index = memory_index;
|
|
|
|
/*
|
|
0: cmp ___,0x0
|
|
1: je ___
|
|
2: sub ___,___
|
|
3: sub ___,imm
|
|
*/
|
|
if ((memory_index != static_cast<std::size_t>(-1) &&
|
|
instructions.find_mnemonic_index(UD_Icmp, index) &&
|
|
instructions.bounds(index, 3) &&
|
|
((index - memory_index) >= 10 && (index - memory_index) <= 20)) &&
|
|
instructions.at(index).is_operand_type(1, UD_OP_IMM) &&
|
|
instructions.at(index).is_operand_data(1, 0) &&
|
|
instructions.at(index + 1).is_mnemonic(UD_Ijz) &&
|
|
instructions.at(index + 2).is_mnemonic(UD_Isub) &&
|
|
instructions.at(index + 3).is_mnemonic(UD_Isub) &&
|
|
instructions.at(index + 3).is_operand_type(1, UD_OP_IMM))
|
|
{
|
|
switch (instructions.at(index + 3).get_operand_data(1))
|
|
{
|
|
case 1:
|
|
this->id = WILD_HANDLER_MOVSB;
|
|
return true;
|
|
|
|
case 2:
|
|
this->id = WILD_HANDLER_MOVSW;
|
|
return true;
|
|
|
|
case 4:
|
|
this->id = WILD_HANDLER_MOVSD;
|
|
return true;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::map_handler_eflags(instruction_container& instructions, wild_context& context)
|
|
{
|
|
if (instructions.bounds(0, 8) &&
|
|
instructions.at(0).is_mnemonic(UD_Imov) &&
|
|
instructions.at(1).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(2).is_mnemonic(UD_Imov) &&
|
|
instructions.at(3).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(3).is_operand_type(1, UD_OP_REG) &&
|
|
instructions.at(4).is_mnemonic(UD_Imov) &&
|
|
instructions.at(5).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(6).is_mnemonic(UD_Imov) &&
|
|
instructions.at(7).is_mnemonic(UD_Icmp) &&
|
|
instructions.at(8).is_mnemonic(UD_Ijnz))
|
|
{
|
|
this->id = WILD_HANDLER_EFLAGS;
|
|
this->opcode_offsets[0] = instructions.at(1).get_loword(1);
|
|
this->opcode_offsets[1] = instructions.at(5).get_loword(1);
|
|
return this->parse_eflags_parameters(instructions, context);
|
|
}
|
|
else
|
|
{
|
|
std::vector<std::pair<std::size_t, ud_instruction>> matches;
|
|
|
|
for (std::size_t i = 0; i < instructions.size(); i++)
|
|
{
|
|
/* 0: mov reg,dword ptr [ebp+xx] */
|
|
if (instructions.at(i).is_mnemonic(UD_Imov) &&
|
|
instructions.at(i).is_operand_type(0, UD_OP_REG) &&
|
|
context.is_opcode_access_instruction(instructions.at(i)))
|
|
{
|
|
std::size_t index = i;
|
|
ud_instruction instruction;
|
|
|
|
/* 0: add reg,___ */
|
|
if (!instructions.find_index_by_register_base(instructions.at(i).get_base_type(0), ++index, instruction) ||
|
|
instruction.is_mnemonic_not(UD_Iadd))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* 1: movzx ___,unknown ptr [reg] */
|
|
if (!instructions.find_index_by_memory_base(instructions.at(i).get_base_type(0), 1, ++index, instruction) ||
|
|
instruction.is_mnemonic_not(UD_Imovzx))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ud_type data_base = instruction.get_base_type(0);
|
|
|
|
/* 2: add reg,ebp */
|
|
if (!instructions.find_index_by_register_base(data_base, ++index, instruction) ||
|
|
instruction.is_mnemonic_not(UD_Iadd) ||
|
|
instruction.is_operand_type_not(1, UD_OP_REG, UD_SIZE_DWORD) ||
|
|
instruction.is_operand_base_not(1, UD_R_EBP))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* 3: ___ unknown ptr [reg] */
|
|
if (!instructions.find_index_by_memory_base(data_base, 0, ++index, instruction) ||
|
|
index > 20)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
matches.push_back(std::make_pair(index, instruction));
|
|
}
|
|
}
|
|
|
|
if (!matches.empty())
|
|
{
|
|
for (std::size_t i = 0; i < 2; i++)
|
|
{
|
|
uint32_t offset_count = 0;
|
|
uint32_t operation_count = 0;
|
|
|
|
for (std::size_t j = 0; j < matches.size(); j++)
|
|
{
|
|
/* 3: sub/add unknown ptr [reg],0x4 */
|
|
if (matches.at(j).second.is_mnemonic(i == 0 ? UD_Isub : UD_Iadd) &&
|
|
matches.at(j).second.is_operand_type(1, UD_OP_IMM) &&
|
|
matches.at(j).second.is_operand_data(1, 4))
|
|
{
|
|
offset_count++;
|
|
}
|
|
/* 3: push/pop unknown ptr [reg] */
|
|
else if (matches.at(j).second.is_mnemonic(i == 0 ? UD_Ipush : UD_Ipop))
|
|
{
|
|
if (matches.at(j).second.is_mnemonic(UD_Ipush) &&
|
|
instructions.bounds(matches.at(j).first, 1) &&
|
|
instructions.at(matches.at(j).first + 1).is_mnemonic({ UD_Ipopfw, UD_Ipopfd, UD_Ipopfq }))
|
|
{
|
|
break;
|
|
}
|
|
|
|
operation_count++;
|
|
}
|
|
}
|
|
|
|
if (offset_count == 1 && operation_count == 1)
|
|
{
|
|
this->id = (i == 0 ? WILD_HANDLER_PUSHFD : WILD_HANDLER_POPFD);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//bool wild_handler::map_handler_eflags(instruction_container& instructions, wild_context& context)
|
|
//{
|
|
// if (instructions.bounds(0, 8) &&
|
|
// instructions.at(0).is_mnemonic(UD_Imov) &&
|
|
// instructions.at(1).is_mnemonic(UD_Iadd) &&
|
|
// instructions.at(2).is_mnemonic(UD_Imov) &&
|
|
// instructions.at(3).is_mnemonic(UD_Iadd) &&
|
|
// instructions.at(3).is_operand_type(1, UD_OP_REG) &&
|
|
// instructions.at(4).is_mnemonic(UD_Imov) &&
|
|
// instructions.at(5).is_mnemonic(UD_Iadd) &&
|
|
// instructions.at(6).is_mnemonic(UD_Imov) &&
|
|
// instructions.at(7).is_mnemonic(UD_Icmp) &&
|
|
// instructions.at(8).is_mnemonic(UD_Ijnz))
|
|
// {
|
|
// this->id = WILD_HANDLER_EFLAGS;
|
|
// this->opcode_offsets[0] = instructions.at(1).get_loword(1);
|
|
// this->opcode_offsets[1] = instructions.at(5).get_loword(1);
|
|
// return this->parse_eflags_parameters(instructions, context);
|
|
// }
|
|
// else
|
|
// {
|
|
// const unsigned int eflag_types = 2;
|
|
//
|
|
// unsigned int read_opcode_instructions = 0;
|
|
// std::pair<std::size_t, ud_type> opcode_read_instruction[eflag_types];
|
|
//
|
|
// for (std::size_t i = 0; i < 10 && i < instructions.size() && read_opcode_instructions < 2; i++)
|
|
// {
|
|
// if (context.is_opcode_access_instruction(instructions.at(i)))
|
|
// {
|
|
// if (!read_opcode_instructions)
|
|
// opcode_read_instruction[0] = std::make_pair(i, instructions.at(i).get_base_type(0));
|
|
// else
|
|
// opcode_read_instruction[1] = std::make_pair(i, instructions.at(i).get_base_type(0));
|
|
//
|
|
// read_opcode_instructions++;
|
|
// }
|
|
// }
|
|
//
|
|
// if (read_opcode_instructions < eflag_types)
|
|
// return false;
|
|
//
|
|
// ud_instruction eflag_instructions[eflag_types];
|
|
//
|
|
// for (std::size_t i = 0; i < eflag_types; i++)
|
|
// {
|
|
// std::size_t index = opcode_read_instruction[i].first;
|
|
//
|
|
// /* 0: add reg,___ */
|
|
// if (!instructions.find_index_by_register_base(opcode_read_instruction[i].second, ++index, eflag_instructions[i]) ||
|
|
// eflag_instructions[i].is_mnemonic_not(UD_Iadd))
|
|
// {
|
|
// return false;
|
|
// }
|
|
//
|
|
// /* 1: movzx ___,unknown ptr [reg] */
|
|
// if (!instructions.find_index_by_memory_base(opcode_read_instruction[i].second, 1, ++index, eflag_instructions[i]) ||
|
|
// eflag_instructions[i].is_mnemonic_not({ UD_Imov, UD_Imovzx }))
|
|
// {
|
|
// return false;
|
|
// }
|
|
//
|
|
// /* For TIGER */
|
|
// if (eflag_instructions[i].is_mnemonic(UD_Imov))
|
|
// {
|
|
// bool found = false;
|
|
//
|
|
// for (std::size_t j = std::max(opcode_read_instruction[0].first, opcode_read_instruction[1].first) + 1; j < 10 && j < instructions.size(); j++)
|
|
// {
|
|
// if (context.is_opcode_access_instruction(instructions.at(j)))
|
|
// {
|
|
// opcode_read_instruction[i--] = std::make_pair(j, instructions.at(j).get_base_type(0));
|
|
// found = true;
|
|
// break;
|
|
// }
|
|
// }
|
|
//
|
|
// if (found)
|
|
// continue;
|
|
// }
|
|
//
|
|
// ud_type opcode_base = eflag_instructions[i].get_base_type(0);
|
|
//
|
|
// /* 2: add reg,ebp */
|
|
// if (!instructions.find_index_by_register_base(opcode_base, ++index, eflag_instructions[i]) ||
|
|
// eflag_instructions[i].is_mnemonic_not(UD_Iadd) ||
|
|
// eflag_instructions[i].is_operand_type_not(1, UD_OP_REG, UD_SIZE_DWORD) ||
|
|
// eflag_instructions[i].is_operand_base_not(1, UD_R_EBP))
|
|
// {
|
|
// return false;
|
|
// }
|
|
//
|
|
// /* 3: ___ unknown ptr [reg] */
|
|
// if (!instructions.find_index_by_memory_base(opcode_base, 0, ++index, eflag_instructions[i]) ||
|
|
// index > 20)
|
|
// {
|
|
// return false;
|
|
// }
|
|
// }
|
|
//
|
|
// for (std::size_t i = 0; i < 2; i++)
|
|
// {
|
|
// bool found = true;
|
|
//
|
|
// for (std::size_t j = 0; j < eflag_types; j++)
|
|
// {
|
|
// /* 3: sub/add unknown ptr [reg],___ */
|
|
// if (eflag_instructions[j].is_mnemonic(i == 0 ? UD_Isub : UD_Iadd))
|
|
// {
|
|
// /* 3: sub/add unknown ptr [reg],0x4 */
|
|
// if (eflag_instructions[j].is_operand_type_not(1, UD_OP_IMM) ||
|
|
// eflag_instructions[j].is_operand_data_not(1, 4))
|
|
// {
|
|
// found = false;
|
|
// break;
|
|
// }
|
|
// }
|
|
// /* 3: push/pop unknown ptr [reg] */
|
|
// else if (eflag_instructions[j].is_mnemonic_not(i == 0 ? UD_Ipush : UD_Ipop))
|
|
// {
|
|
// found = false;
|
|
// break;
|
|
// }
|
|
// }
|
|
//
|
|
// if (found)
|
|
// {
|
|
// this->id = (i == 0 ? WILD_HANDLER_PUSHFD : WILD_HANDLER_POPFD);
|
|
// this->opcode_offsets[0] = instructions.at(3).get_loword(1);
|
|
// return true;
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// return false;
|
|
//}
|
|
|
|
bool wild_handler::map_handler_stack(instruction_container& instructions, wild_context& context)
|
|
{
|
|
/*
|
|
0: mov ___,___
|
|
1: add ___,___
|
|
2: movzx ___,___
|
|
3: add ___,___
|
|
4: mov esp,___
|
|
*/
|
|
if (instructions.bounds(0, 4) &&
|
|
instructions.at(0).is_mnemonic(UD_Imov) &&
|
|
instructions.at(1).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(2).is_mnemonic(UD_Imovzx) &&
|
|
instructions.at(3).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(4).is_mnemonic(UD_Imov) &&
|
|
instructions.at(4).is_operand_type(0, UD_OP_REG, UD_SIZE_DWORD) &&
|
|
instructions.at(4).is_operand_base(0, UD_R_ESP))
|
|
{
|
|
this->id = WILD_HANDLER_LOAD_STACK;
|
|
this->opcode_offsets[0] = instructions.at(1).get_loword(1);
|
|
return true;
|
|
}
|
|
/*
|
|
0: mov ___,___
|
|
1: add ___,___
|
|
2: movzx ___,___
|
|
3: add ___,___
|
|
4: mov ___,esp
|
|
*/
|
|
else if (instructions.bounds(0, 4) &&
|
|
instructions.at(0).is_mnemonic(UD_Imov) &&
|
|
instructions.at(1).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(2).is_mnemonic(UD_Imovzx) &&
|
|
instructions.at(3).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(4).is_mnemonic(UD_Imov) &&
|
|
instructions.at(4).is_operand_type(1, UD_OP_REG, UD_SIZE_DWORD) &&
|
|
instructions.at(4).is_operand_base(1, UD_R_ESP))
|
|
{
|
|
this->id = WILD_HANDLER_STORE_STACK;
|
|
this->opcode_offsets[0] = instructions.at(1).get_loword(1);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
for (std::size_t i = 3; i < 9 && i < instructions.size(); i++)
|
|
{
|
|
/* 0: add esp,reg */
|
|
if (instructions.at(i).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(i).is_operand_type(0, UD_OP_REG, UD_SIZE_DWORD) &&
|
|
instructions.at(i).is_operand_base(0, UD_R_ESP) &&
|
|
instructions.at(i).is_operand_type(1, UD_OP_REG, UD_SIZE_DWORD) &&
|
|
instructions.at(i).is_operand_base_not(1, UD_R_ESP))
|
|
{
|
|
this->id = WILD_HANDLER_RESTORE_STACK;
|
|
this->opcode_offsets[0] = instructions.at(4).get_loword(1);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::map_handler_reset_eflags(instruction_container& instructions, wild_context& context)
|
|
{
|
|
if (instructions.bounds(0) &&
|
|
instructions.at(0).is_mnemonic(UD_Imov) &&
|
|
instructions.at(0).is_operand_type(0, UD_OP_MEM, UD_SIZE_DWORD) &&
|
|
instructions.at(0).is_operand_base(0, UD_R_EBP) &&
|
|
instructions.at(0).is_operand_type(1, UD_OP_IMM) &&
|
|
instructions.at(0).is_operand_data(1, 0) &&
|
|
this->flow_read_index == 1)
|
|
{
|
|
this->id = WILD_HANDLER_RESET_EFLAGS;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::map_handler_reset(instruction_container& instructions, wild_context& context)
|
|
{
|
|
for (std::size_t i = 0; i < 5 && i < instructions.size(); i++)
|
|
{
|
|
/* 0: mov ___,___ */
|
|
if (instructions.at(i).is_mnemonic_not(UD_Imov))
|
|
return false;
|
|
}
|
|
|
|
this->id = WILD_HANDLER_RESET;
|
|
return true;
|
|
}
|
|
|
|
bool wild_handler::map_handler_crypt(instruction_container& instructions, wild_context& context)
|
|
{
|
|
if (instructions.bounds(0, 6))
|
|
{
|
|
ud_type base = UD_NONE;
|
|
uint32_t opcodes = 0;
|
|
|
|
for (std::size_t i = 0; i < 5 && i < instructions.size(); i++)
|
|
{
|
|
/* 0: ___ unknown ptr [reg],___ */
|
|
if (instructions.at(i).is_operand_type(0, UD_OP_MEM))
|
|
return false;
|
|
|
|
/* 0: mov ___,unknown ptr [reg] */
|
|
if (instructions.at(i).is_mnemonic(UD_Imov) &&
|
|
instructions.at(i).is_operand_type(1, UD_OP_MEM))
|
|
{
|
|
/* 0: mov ___,dword ptr [ebp+xx] */
|
|
if (context.is_opcode_access_instruction(instructions.at(i)))
|
|
{
|
|
opcodes++;
|
|
}
|
|
/* 0: mov reg,dword ptr [ebp+xx] */
|
|
else if (instructions.at(i).is_operand_type(0, UD_OP_REG, UD_SIZE_DWORD) &&
|
|
instructions.at(i).is_operand_base(1, UD_R_EBP) &&
|
|
!context.get_key(instructions.at(i).get_operand_data(1), nullptr))
|
|
{
|
|
base = instructions.at(i).get_base_type(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (opcodes == 1 &&
|
|
instructions.at(5).is_operand_type(0, UD_OP_MEM, UD_SIZE_DWORD) &&
|
|
instructions.at(5).is_operand_type(1, UD_OP_REG) &&
|
|
instructions.at(5).is_operand_base(1, base))
|
|
{
|
|
this->id = WILD_HANDLER_CRYPT;
|
|
|
|
for (std::size_t i = 0; i < 5; i++)
|
|
{
|
|
if (instructions.at(i).is_mnemonic(UD_Imov) &&
|
|
instructions.at(i).is_operand_type(1, UD_OP_MEM, UD_SIZE_DWORD) &&
|
|
!context.is_opcode_access_instruction(instructions.at(i)))
|
|
{
|
|
this->opcode_offsets[1] = instructions.at(i).get_operand_data<uint16_t>(1);
|
|
}
|
|
else if (instructions.at(i).is_mnemonic(UD_Iadd) &&
|
|
instructions.at(i).is_operand_type(1, UD_OP_IMM))
|
|
{
|
|
this->opcode_offsets[0] = instructions.at(i).get_operand_data<uint16_t>(1);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::parse_jcc_parameters(instruction_container& instructions, wild_context& context)
|
|
{
|
|
if (!context.initialized_jcc_types)
|
|
{
|
|
ud_type base = UD_NONE;
|
|
|
|
for (std::size_t i = 0, index = 8; i < 17; i++)
|
|
{
|
|
while (true)
|
|
{
|
|
if (!instructions.find_mnemonic_index(UD_Icmp, ++index))
|
|
return false;
|
|
|
|
if (instructions.at(index).is_operand_type(0, UD_OP_REG, UD_SIZE_BYTE))
|
|
{
|
|
if (!base)
|
|
{
|
|
base = instructions.at(index).get_base_type(0);
|
|
break;
|
|
}
|
|
else if (instructions.at(index).is_operand_base(0, base))
|
|
break;
|
|
}
|
|
}
|
|
|
|
static const ud_mnemonic_code jcc_type_table[] =
|
|
{
|
|
UD_Ijz, UD_Ijle, UD_Ijnz, UD_Ija,
|
|
UD_Ijae, UD_Ijb, UD_Ijbe, UD_Ijg,
|
|
UD_Ijge, UD_Ijl, UD_Ijcxz, UD_Ijno,
|
|
UD_Ijnp, UD_Ijns, UD_Ijo, UD_Ijp,
|
|
UD_Ijs
|
|
};
|
|
|
|
context.set_jcc_mnemonic(instructions.at(index).get_operand_data<uint8_t>(1), jcc_type_table[i]);
|
|
}
|
|
|
|
context.initialized_jcc_types = true;
|
|
}
|
|
|
|
for (std::size_t i = 40, occurances = 0; i < instructions.size(); i++)
|
|
{
|
|
if (instructions.bounds(i, 1) &&
|
|
instructions.at(i).is_mnemonic(UD_Imov) &&
|
|
context.is_opcode_access_instruction(instructions.at(i)))
|
|
{
|
|
if (occurances == 0)
|
|
this->opcode_offsets[1] = instructions.at(i + 1).get_operand_data(1);
|
|
else if (occurances == 1)
|
|
{
|
|
this->opcode_offsets[2] = instructions.at(i + 1).get_operand_data(1);
|
|
return true;
|
|
}
|
|
|
|
occurances++;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::parse_eflags_parameters(instruction_container& instructions, wild_context& context)
|
|
{
|
|
if (!context.initialized_eflags_types)
|
|
{
|
|
ud_type base = UD_NONE;
|
|
|
|
for (std::size_t i = 0, index = 5; i < 7; i++)
|
|
{
|
|
while (true)
|
|
{
|
|
if (!instructions.find_mnemonic_index(UD_Icmp, ++index))
|
|
return false;
|
|
|
|
if (instructions.at(index).is_operand_type(0, UD_OP_REG, UD_SIZE_BYTE))
|
|
{
|
|
if (!base)
|
|
{
|
|
base = instructions.at(index).get_base_type(0);
|
|
break;
|
|
}
|
|
else if (instructions.at(index).is_operand_base(0, base))
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (context.get_mnemonic(instructions.at(index).get_operand_data(1)) != UD_Inone)
|
|
msg("[CodeDevirtualizer] EFLAGS mnemonic table corrupt with %08X.\n", context.get_mnemonic(instructions.at(index).get_operand_data(1)));
|
|
else
|
|
{
|
|
static const ud_mnemonic_code eflags_mnemonics[] = { UD_Iclc, UD_Icld, UD_Icli, UD_Icmc, UD_Istc, UD_Istd, UD_Isti };
|
|
context.set_mnemonic(instructions.at(index).get_operand_data<uint8_t>(1), eflags_mnemonics[i]);
|
|
}
|
|
}
|
|
|
|
context.initialized_eflags_types = true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wild_handler::perform_key_sequence(wild_context& context, uint32_t first_index, uint32_t last_index, uint32_t* data)
|
|
{
|
|
std::size_t first = this->find_first_key_after(first_index);
|
|
std::size_t last = this->find_last_key_before(last_index);
|
|
|
|
if (first != static_cast<std::size_t>(-1) && last != static_cast<std::size_t>(-1))
|
|
{
|
|
for (std::size_t i = first; i <= last; i++)
|
|
{
|
|
if (!this->key_accessors.at(i).perform(context, data))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wild_handler::step_handler(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
memset(context.step_params, 0, sizeof(context.step_params));
|
|
|
|
switch (this->id)
|
|
{
|
|
case WILD_HANDLER_JUMP_INSIDE:
|
|
return this->step_handler_jmp_inside(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_JUMP_OUTSIDE_REGISTER:
|
|
return this->step_handler_jmp_outside_register(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_JUMP_OUTSIDE_MEMORY:
|
|
return this->step_handler_jmp_outside_memory(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_JUMP_OUTSIDE_IMMEDIATE:
|
|
return this->step_handler_jmp_outside_immediate(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_JCC_INSIDE:
|
|
return this->step_handler_jcc_inside(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_JCC_OUTSIDE:
|
|
return this->step_handler_jcc_outside(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_RET:
|
|
return this->step_handler_ret(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_UNDEF:
|
|
return this->step_handler_undef(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_LODSB:
|
|
case WILD_HANDLER_LODSW:
|
|
case WILD_HANDLER_LODSD:
|
|
return this->step_handler_lods(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_STOSB:
|
|
case WILD_HANDLER_STOSW:
|
|
case WILD_HANDLER_STOSD:
|
|
return this->step_handler_stos(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_SCASB:
|
|
case WILD_HANDLER_SCASW:
|
|
case WILD_HANDLER_SCASD:
|
|
return this->step_handler_scas(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_CMPSB:
|
|
case WILD_HANDLER_CMPSW:
|
|
case WILD_HANDLER_CMPSD:
|
|
return this->step_handler_cmps(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_MOVSB:
|
|
case WILD_HANDLER_MOVSW:
|
|
case WILD_HANDLER_MOVSD:
|
|
return this->step_handler_movs(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_PUSHFD:
|
|
return this->step_handler_pushfd(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_POPFD:
|
|
return this->step_handler_popfd(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_EFLAGS:
|
|
return this->step_handler_eflags(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_RESTORE_STACK:
|
|
return this->step_handler_restore_stack(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_LOAD_STACK:
|
|
return this->step_handler_load_stack(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_STORE_STACK:
|
|
return this->step_handler_store_stack(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_RESET_EFLAGS:
|
|
return this->step_handler_reset_eflags(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_RESET:
|
|
return this->step_handler_reset(instructions, context, opcode);
|
|
|
|
case WILD_HANDLER_CRYPT:
|
|
return this->step_handler_crypt(instructions, context, opcode);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return this->step_handler_specific(instructions, context, opcode);
|
|
}
|
|
|
|
bool wild_handler::step_handler_jmp_inside(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
uint32_t handler_index = opcode.read<uint16_t>(this->opcode_offsets[0]);
|
|
uint32_t distance = opcode.read<uint32_t>(this->opcode_offsets[1]);
|
|
|
|
context.step_params[0] = handler_index;
|
|
context.step_params[1] = distance;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(UD_Ijmp);
|
|
instruction.set_operand_type(0, UD_OP_IMM, UD_SIZE_DWORD);
|
|
|
|
if (distance & 0x80000000)
|
|
{
|
|
instruction.set_operand_data(0, -static_cast<int32_t>(distance & 0x7FFFFFFF));
|
|
context.create_label(context.current_virtual_opcode - (distance & 0x7FFFFFFF), handler_index);
|
|
}
|
|
else
|
|
{
|
|
instruction.set_operand_data(0, distance);
|
|
context.create_label(context.current_virtual_opcode + distance, handler_index);
|
|
}
|
|
|
|
instructions.push_back(instruction);
|
|
return true;
|
|
}
|
|
|
|
bool wild_handler::step_handler_jmp_outside_register(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
uint32_t register_id = opcode.read<uint32_t>(this->opcode_offsets[0]);
|
|
|
|
context.step_params[0] = register_id;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(UD_Ijmp);
|
|
instruction.set_operand_type(0, UD_OP_REG, UD_SIZE_DWORD);
|
|
instruction.set_operand_base(0, context.get_vm_register(register_id));
|
|
|
|
instructions.push_back(instruction);
|
|
return true;
|
|
}
|
|
|
|
bool wild_handler::step_handler_jmp_outside_memory(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
uint32_t register_id = opcode.read<uint32_t>(this->opcode_offsets[0]);
|
|
|
|
context.step_params[0] = register_id;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(UD_Ijmp);
|
|
instruction.set_operand_type(0, UD_OP_MEM, UD_SIZE_DWORD);
|
|
instruction.set_operand_base(0, context.get_vm_register(register_id));
|
|
|
|
instructions.push_back(instruction);
|
|
return true;
|
|
}
|
|
|
|
bool wild_handler::step_handler_jmp_outside_immediate(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
uint32_t offset = opcode.read<uint32_t>(this->opcode_offsets[0]);
|
|
|
|
context.step_params[2] = offset;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(UD_Ijmp);
|
|
instruction.set_operand_type(0, UD_OP_IMM, UD_SIZE_DWORD);
|
|
instruction.set_operand_data(0, context.vm_imagebase + offset);
|
|
|
|
instructions.push_back(instruction);
|
|
return true;
|
|
}
|
|
|
|
bool wild_handler::step_handler_jcc_inside(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
uint32_t jcc_mnemonic_id = opcode.read<uint8_t>(this->opcode_offsets[0]);
|
|
uint32_t handler_index = opcode.read<uint16_t>(this->opcode_offsets[1]);
|
|
uint32_t distance = opcode.read<uint32_t>(this->opcode_offsets[2]);
|
|
|
|
context.step_params[0] = jcc_mnemonic_id;
|
|
context.step_params[1] = handler_index;
|
|
context.step_params[2] = distance;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(context.get_jcc_mnemonic(jcc_mnemonic_id));
|
|
instruction.set_operand_type(0, UD_OP_IMM, UD_SIZE_DWORD);
|
|
|
|
if (distance & 0x80000000)
|
|
{
|
|
instruction.set_operand_data(0, -static_cast<int32_t>(distance & 0x7FFFFFFF));
|
|
context.create_label(context.current_virtual_opcode - (distance & 0x7FFFFFFF), handler_index);
|
|
}
|
|
else
|
|
{
|
|
instruction.set_operand_data(0, distance);
|
|
context.create_label(context.current_virtual_opcode + distance, handler_index);
|
|
}
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(this->flow_read_offset), false);
|
|
}
|
|
|
|
bool wild_handler::step_handler_jcc_outside(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
uint32_t jcc_mnemonic_id = opcode.read<uint8_t>(this->opcode_offsets[0]);
|
|
uint32_t offset = opcode.read<uint32_t>(this->opcode_offsets[1]);
|
|
|
|
context.step_params[0] = jcc_mnemonic_id;
|
|
context.step_params[1] = offset;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(context.get_jcc_mnemonic(jcc_mnemonic_id));
|
|
instruction.set_operand_type(0, UD_OP_IMM, UD_SIZE_DWORD);
|
|
instruction.set_operand_data(0, context.vm_imagebase + offset);
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(this->flow_read_offset), false);
|
|
}
|
|
|
|
bool wild_handler::step_handler_ret(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
uint32_t arguments = opcode.read<uint32_t>(this->opcode_offsets[0]);
|
|
|
|
context.step_params[0] = arguments;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(UD_Iret);
|
|
|
|
if (arguments)
|
|
{
|
|
instruction.set_operand_type(0, UD_OP_IMM, UD_SIZE_WORD);
|
|
instruction.set_operand_data(0, arguments);
|
|
}
|
|
|
|
instructions.push_back(instruction);
|
|
return true;
|
|
}
|
|
|
|
bool wild_handler::step_handler_undef(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
uint32_t type = opcode.read<uint8_t>(this->opcode_offsets[0]);
|
|
|
|
context.step_params[0] = UD_Iundef;
|
|
context.step_params[1] = type;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(UD_Iundef);
|
|
|
|
instructions.push_back(instruction);
|
|
|
|
/* Decode return address and create label */
|
|
uint32_t return_address = context.vm_imagebase + opcode.read<uint32_t>(this->opcode_offsets[1]);
|
|
|
|
if (!return_address)
|
|
return false;
|
|
|
|
ud_instruction return_instruction(return_address);
|
|
return_instruction.set_input(context.to_segment(return_address));
|
|
|
|
instruction_container return_instructions;
|
|
|
|
for (std::size_t i = 0; i < 3; i++)
|
|
{
|
|
if (!return_instructions.decode_assembly(return_instruction))
|
|
return false;
|
|
|
|
if (i == 0)
|
|
instructions.back().set_index(return_address);
|
|
else
|
|
{
|
|
if (return_instruction.is_mnemonic_not(UD_Ipush) ||
|
|
return_instruction.is_operand_type_not(0, UD_OP_IMM, UD_SIZE_DWORD))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
context.create_label(context.vm_imagebase + return_instructions.at(1).get_operand_data(0), return_instructions.at(2).get_operand_data(0));
|
|
return true;
|
|
}
|
|
|
|
bool wild_handler::step_handler_lods(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
static const ud_mnemonic_code mnemonics[] = { UD_Ilodsb, UD_Ilodsw, UD_Ilodsd };
|
|
|
|
this->step_opcode_regions(context, opcode);
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(mnemonics[this->id - WILD_HANDLER_LODSB]);
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(this->flow_read_offset), false);
|
|
}
|
|
|
|
bool wild_handler::step_handler_stos(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
static const ud_mnemonic_code mnemonics[] = { UD_Istosb, UD_Istosw, UD_Istosd };
|
|
|
|
this->step_opcode_regions(context, opcode);
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(mnemonics[this->id - WILD_HANDLER_STOSB]);
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(this->flow_read_offset), false);
|
|
}
|
|
|
|
bool wild_handler::step_handler_scas(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
static const ud_mnemonic_code mnemonics[] = { UD_Iscasb, UD_Iscasw, UD_Iscasd };
|
|
|
|
this->step_opcode_regions(context, opcode);
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(mnemonics[this->id - WILD_HANDLER_SCASB]);
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(this->flow_read_offset), false);
|
|
}
|
|
|
|
bool wild_handler::step_handler_cmps(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
static const ud_mnemonic_code mnemonics[] = { UD_Icmpsb, UD_Icmpsw, UD_Icmpsd };
|
|
|
|
this->step_opcode_regions(context, opcode);
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(mnemonics[this->id - WILD_HANDLER_CMPSB]);
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(this->flow_read_offset), false);
|
|
}
|
|
|
|
bool wild_handler::step_handler_movs(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
static const ud_mnemonic_code mnemonics[] = { UD_Imovsb, UD_Imovsw, UD_Imovsd };
|
|
|
|
this->step_opcode_regions(context, opcode);
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(mnemonics[this->id - WILD_HANDLER_MOVSB]);
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(this->flow_read_offset), false);
|
|
}
|
|
|
|
bool wild_handler::step_handler_pushfd(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
this->step_opcode_regions(context, opcode);
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(UD_Ipushfd);
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(this->flow_read_offset), false);
|
|
}
|
|
|
|
bool wild_handler::step_handler_popfd(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
this->step_opcode_regions(context, opcode);
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(UD_Ipopfd);
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(this->flow_read_offset), false);
|
|
}
|
|
|
|
bool wild_handler::step_handler_eflags(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
uint32_t mnemonic_id = opcode.read<uint8_t>(this->opcode_offsets[1]);
|
|
|
|
context.step_params[0] = mnemonic_id;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(context.get_mnemonic(mnemonic_id));
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(this->flow_read_offset), false);
|
|
}
|
|
|
|
bool wild_handler::step_handler_restore_stack(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
uint32_t value = opcode.read<uint8_t>(this->opcode_offsets[0]);
|
|
|
|
context.step_params[0] = UD_Irestorestack;
|
|
context.step_params[1] = value;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(UD_Irestorestack);
|
|
instruction.set_operand_type(0, UD_OP_IMM, UD_SIZE_DWORD);
|
|
instruction.set_operand_data(0, value);
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(this->flow_read_offset), false);
|
|
}
|
|
|
|
bool wild_handler::step_handler_load_stack(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
uint32_t esp_register_id = opcode.read<uint16_t>(this->opcode_offsets[0]);
|
|
|
|
context.step_params[0] = UD_Iloadstack;
|
|
context.step_params[1] = esp_register_id;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(UD_Iloadstack);
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(this->flow_read_offset), false);
|
|
}
|
|
|
|
bool wild_handler::step_handler_store_stack(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
uint32_t esp_register_id = opcode.read<uint16_t>(this->opcode_offsets[0]);
|
|
context.set_vm_register(esp_register_id, UD_R_ESP);
|
|
|
|
context.step_params[0] = UD_Istorestack;
|
|
context.step_params[1] = esp_register_id;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(UD_Istorestack);
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(this->flow_read_offset), true);
|
|
}
|
|
|
|
bool wild_handler::step_handler_reset_eflags(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
context.step_params[0] = UD_Ireseteflags;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(UD_Ireseteflags);
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(0), true);
|
|
}
|
|
|
|
bool wild_handler::step_handler_reset(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
context.reset_key_data();
|
|
|
|
context.step_params[0] = UD_Ireset;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(UD_Ireset);
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(0), true);
|
|
}
|
|
|
|
bool wild_handler::step_handler_crypt(instruction_container& instructions, wild_context& context, opcode_reader& opcode)
|
|
{
|
|
uint32_t register_id = opcode.read<uint16_t>(this->opcode_offsets[0]);
|
|
uint32_t value = this->opcode_offsets[1];
|
|
|
|
context.step_params[0] = UD_Icrypt;
|
|
context.step_params[1] = register_id;
|
|
context.step_params[2] = value;
|
|
|
|
if (!get_many_bytes(context.vm_context + value, &value, sizeof(uint32_t)))
|
|
return false;
|
|
|
|
context.step_params[3] = value;
|
|
|
|
ud_instruction instruction(context.current_virtual_opcode);
|
|
instruction.set_mnemonic(UD_Icrypt);
|
|
instruction.set_operand_type(0, UD_OP_REG, UD_SIZE_DWORD);
|
|
instruction.set_operand_base(0, context.get_vm_register(register_id));
|
|
instruction.set_operand_type(1, UD_OP_IMM, UD_SIZE_DWORD);
|
|
instruction.set_operand_data(1, value);
|
|
|
|
instructions.push_back(instruction);
|
|
return this->step_handler_flow(context, opcode.read<uint16_t>(this->flow_read_offset), false);
|
|
}
|
|
|
|
bool wild_handler::step_opcode_regions(wild_context& context, opcode_reader& opcode)
|
|
{
|
|
uint32_t key_data = 0;
|
|
|
|
if (this->opcode_regions.empty())
|
|
{
|
|
this->perform_key_sequence(context, 0, this->flow_data_index, &key_data);
|
|
}
|
|
else
|
|
{
|
|
if (this->key_accessors.size() > 0 && this->key_accessors.at(0).index < this->opcode_regions.at(0).index_start)
|
|
this->perform_key_sequence(context, 0, this->opcode_regions.at(0).index_start - 1, &key_data);
|
|
|
|
for (std::size_t i = 0; i < this->opcode_regions.size(); i++)
|
|
{
|
|
key_data = 0;
|
|
|
|
switch (this->opcode_regions.at(i).opcode_size)
|
|
{
|
|
case UD_SIZE_BYTE:
|
|
key_data = opcode.read<uint8_t>(this->opcode_regions.at(i).opcode_offset);
|
|
break;
|
|
|
|
case UD_SIZE_WORD:
|
|
key_data = opcode.read<uint16_t>(this->opcode_regions.at(i).opcode_offset);
|
|
break;
|
|
|
|
case UD_SIZE_DWORD:
|
|
key_data = opcode.read<uint32_t>(this->opcode_regions.at(i).opcode_offset);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
uint32_t index_end = 0;
|
|
|
|
if ((i + 1) < this->opcode_regions.size())
|
|
index_end = this->opcode_regions.at(i + 1).index_start;
|
|
else
|
|
index_end = this->flow_read_index;
|
|
|
|
this->perform_key_sequence(context, this->opcode_regions.at(i).index_start, index_end - 1, &key_data);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wild_handler::step_handler_flow(wild_context& context, uint16_t raw_handler_offset, bool skip_flow_mutation)
|
|
{
|
|
if (skip_flow_mutation)
|
|
{
|
|
context.current_handler_offset = raw_handler_offset;
|
|
context.current_virtual_opcode += this->opcode_size;
|
|
}
|
|
else
|
|
{
|
|
uint32_t handler_offset = raw_handler_offset;
|
|
|
|
if (this->opcode_size == OPCODE_SIZE_SUB || this->opcode_size == OPCODE_SIZE_RETN || this->opcode_size == OPCODE_SIZE_INVALID)
|
|
return false;
|
|
|
|
if (this->flow_key_indexes.empty())
|
|
{
|
|
if (this->flow_mutation_index)
|
|
instruction::emulate(static_cast<ud_mnemonic_code>(this->flow_mutation_mnemonic), UD_SIZE_DWORD, this->flow_mutation_constant, &handler_offset);
|
|
}
|
|
else
|
|
{
|
|
std::size_t first = this->find_first_key_after(this->flow_key_indexes.front());
|
|
std::size_t last = this->find_last_key_before(this->flow_key_indexes.back());
|
|
|
|
if (first == static_cast<std::size_t>(-1) || last == static_cast<std::size_t>(-1))
|
|
return false;
|
|
|
|
bool flow_mutated = false;
|
|
|
|
for (std::size_t i = first; i <= last; i++)
|
|
{
|
|
if (this->flow_mutation_index && !flow_mutated && this->key_accessors.at(i).index > this->flow_mutation_index)
|
|
{
|
|
instruction::emulate(static_cast<ud_mnemonic_code>(this->flow_mutation_mnemonic), UD_SIZE_DWORD, this->flow_mutation_constant, &handler_offset);
|
|
flow_mutated = true;
|
|
}
|
|
|
|
if (!this->key_accessors.at(i).perform(context, &handler_offset))
|
|
return false;
|
|
}
|
|
|
|
if (this->flow_mutation_index && !flow_mutated)
|
|
instruction::emulate(static_cast<ud_mnemonic_code>(this->flow_mutation_mnemonic), UD_SIZE_DWORD, this->flow_mutation_constant, &handler_offset);
|
|
}
|
|
|
|
context.current_handler_offset = handler_offset;
|
|
context.current_virtual_opcode += this->opcode_size;
|
|
}
|
|
|
|
return true;
|
|
} |