|
|
|
@ -5,6 +5,8 @@ namespace vm
|
|
|
|
|
{
|
|
|
|
|
namespace handler
|
|
|
|
|
{
|
|
|
|
|
using instr_callback_t = bool(*)(const zydis_decoded_instr_t& instr);
|
|
|
|
|
|
|
|
|
|
enum extention_t
|
|
|
|
|
{
|
|
|
|
|
none,
|
|
|
|
@ -16,351 +18,57 @@ namespace vm
|
|
|
|
|
{
|
|
|
|
|
const char* name;
|
|
|
|
|
u8 imm_size;
|
|
|
|
|
std::vector<std::vector<u8>> signature;
|
|
|
|
|
std::vector<instr_callback_t> signature;
|
|
|
|
|
extention_t extention;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
namespace profile
|
|
|
|
|
{
|
|
|
|
|
// store a value from the stack into scratch register X (RDI+X)...
|
|
|
|
|
// where X is an 8bit immediate value...
|
|
|
|
|
// MOV RDX, [RBP]
|
|
|
|
|
// ADD RBP, 8
|
|
|
|
|
// MOV [RAX+RDI], RDX
|
|
|
|
|
inline vm::handler::profile_t sregq =
|
|
|
|
|
{
|
|
|
|
|
"SREGQ", 8,
|
|
|
|
|
{
|
|
|
|
|
{ 0x48, 0x8B, 0x55, 0x0 }, // mov rdx, [rbp+0]
|
|
|
|
|
{ 0x48, 0x83, 0xC5, 0x8 }, // add rbp, 8
|
|
|
|
|
{ 0x48, 0x89, 0x14, 0x38 }, // mov [rax+rdi], rdx
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t sregdw =
|
|
|
|
|
{
|
|
|
|
|
"SREGDW", 8,
|
|
|
|
|
{
|
|
|
|
|
{ 0x8B, 0x55, 0x00 },
|
|
|
|
|
{ 0x48, 0x83, 0xC5, 0x04 },
|
|
|
|
|
{ 0x89, 0x14, 0x38 }
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t sregw =
|
|
|
|
|
{
|
|
|
|
|
"SREGW", 8,
|
|
|
|
|
{
|
|
|
|
|
{ 0x66, 0x8B, 0x55, 0x00 }, // mov dx, [rbp]
|
|
|
|
|
{ 0x48, 0x83, 0xC5, 0x02 }, // add rbp, 0x02
|
|
|
|
|
{ 0x66, 0x89, 0x14, 0x38 } // mov [rax+rdi], dx
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// load scratch register value onto virtual stack...
|
|
|
|
|
inline vm::handler::profile_t lregq =
|
|
|
|
|
{
|
|
|
|
|
"LREGQ", 8,
|
|
|
|
|
{
|
|
|
|
|
{0x48, 0x8B, 0x14, 0x38}, // mov rdx, [rax+rdi]
|
|
|
|
|
{0x48, 0x83, 0xED, 0x08}, // sub rbp, 8
|
|
|
|
|
{0x48, 0x89, 0x55, 0x0} // mov [rbp+0], rdx
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
> 0x00007FF64724445C mov edx, [rax+rdi*1]
|
|
|
|
|
> 0x00007FF647244463 sub rbp, 0x04
|
|
|
|
|
> 0x00007FF647246333 mov [rbp], edx
|
|
|
|
|
*/
|
|
|
|
|
inline vm::handler::profile_t lregdw =
|
|
|
|
|
{
|
|
|
|
|
"LREGDW", 8,
|
|
|
|
|
{
|
|
|
|
|
{ 0x8B, 0x14, 0x38 },
|
|
|
|
|
{ 0x48, 0x83, 0xED, 0x04 },
|
|
|
|
|
{ 0x89, 0x55, 0x00 }
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// load constant value into stack....
|
|
|
|
|
inline vm::handler::profile_t lconstq =
|
|
|
|
|
{
|
|
|
|
|
"LCONSTQ", 64,
|
|
|
|
|
{
|
|
|
|
|
{0x48, 0x83, 0xED, 0x08}, // sub rbp, 8
|
|
|
|
|
{0x48, 0x89, 0x45, 0x00} // mov [rbp+0], rax
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// load 1 byte constant zero extended into 2bytes on the stack...
|
|
|
|
|
inline vm::handler::profile_t lconstbzx =
|
|
|
|
|
{
|
|
|
|
|
"LCONSTBZX", 8,
|
|
|
|
|
{
|
|
|
|
|
{0x48, 0x83, 0xED, 0x02}, // sub rbp, 2
|
|
|
|
|
{0x66, 0x89, 0x45, 0x00} // mov [rbp+0], ax
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t lconstbsx =
|
|
|
|
|
{
|
|
|
|
|
"LCONSTBSX", 8,
|
|
|
|
|
{
|
|
|
|
|
{ 0x98 },
|
|
|
|
|
{ 0x48, 0x83, 0xED, 0x04 },
|
|
|
|
|
{ 0x89, 0x45, 0x00 }
|
|
|
|
|
},
|
|
|
|
|
vm::handler::extention_t::sign_extend
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// load 4 byte constant value sign extended qword into vsp...
|
|
|
|
|
inline vm::handler::profile_t lconstbsx1 =
|
|
|
|
|
{
|
|
|
|
|
"LCONSTBSX", 8,
|
|
|
|
|
// MOV RDX, [RBP]
|
|
|
|
|
[](const zydis_decoded_instr_t& instr) -> bool
|
|
|
|
|
{
|
|
|
|
|
{0x48, 0x98}, // cdqe
|
|
|
|
|
{0x48, 0x83, 0xED, 0x8}, // sub rbp, 8
|
|
|
|
|
{0x48, 0x89, 0x45, 0x0}, // mov [rbp+0], rax
|
|
|
|
|
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
|
|
|
|
|
instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
|
|
|
|
instr.operands[0].reg.value == ZYDIS_REGISTER_RDX &&
|
|
|
|
|
instr.operands[1].type == ZYDIS_OPERAND_TYPE_MEMORY &&
|
|
|
|
|
instr.operands[1].mem.base == ZYDIS_REGISTER_RBP;
|
|
|
|
|
},
|
|
|
|
|
vm::handler::extention_t::sign_extend
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// load 4 byte constant value sign extended qword into vsp...
|
|
|
|
|
inline vm::handler::profile_t lconstdsx =
|
|
|
|
|
{
|
|
|
|
|
"LCONSTDSX", 32,
|
|
|
|
|
{
|
|
|
|
|
{0x48, 0x98}, // cdqe
|
|
|
|
|
{0x48, 0x83, 0xED, 0x8}, // sub rbp, 8
|
|
|
|
|
{0x48, 0x89, 0x45, 0x0}, // mov [rbp+0], rax
|
|
|
|
|
// ADD RBP, 8
|
|
|
|
|
[](const zydis_decoded_instr_t& instr) -> bool
|
|
|
|
|
{
|
|
|
|
|
return instr.mnemonic == ZYDIS_MNEMONIC_ADD &&
|
|
|
|
|
instr.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
|
|
|
|
instr.operands[0].reg.value == ZYDIS_REGISTER_RBP &&
|
|
|
|
|
instr.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
|
|
|
|
|
instr.operands[1].imm.value.u == 8;
|
|
|
|
|
},
|
|
|
|
|
vm::handler::extention_t::sign_extend
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// load 2 byte constant value sign extended qword into vsp...
|
|
|
|
|
inline vm::handler::profile_t lconstwsx =
|
|
|
|
|
{
|
|
|
|
|
"LCONSTWSX", 16,
|
|
|
|
|
{
|
|
|
|
|
{0x48, 0x98}, // cdqe
|
|
|
|
|
{0x48, 0x83, 0xED, 0x8}, // sub rbp, 8
|
|
|
|
|
{0x48, 0x89, 0x45, 0x0}, // mov [rbp+0], rax
|
|
|
|
|
},
|
|
|
|
|
vm::handler::extention_t::sign_extend
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t lconstw =
|
|
|
|
|
{
|
|
|
|
|
"LCONSTW", 8,
|
|
|
|
|
{
|
|
|
|
|
{ 0x48, 0x83, 0xED, 0x02 }, // sub rbp, 0x02
|
|
|
|
|
{ 0x66, 0x89, 0x45, 0x00 } // mov [rbp], ax
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t lconstdw =
|
|
|
|
|
{
|
|
|
|
|
"LCONSTDW", 32,
|
|
|
|
|
{
|
|
|
|
|
{ 0x48, 0x83, 0xED, 0x04 },
|
|
|
|
|
{ 0x89, 0x45, 0x00 }
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t pushvsp =
|
|
|
|
|
{
|
|
|
|
|
"PUSHVSP", 0,
|
|
|
|
|
{
|
|
|
|
|
{0x48, 0x89, 0xE8}, // mov rax, rbp
|
|
|
|
|
{0x48, 0x83, 0xED, 0x08}, // sub rbp, 8
|
|
|
|
|
{0x48, 0x89, 0x45, 0x0} // mov [rbp+0], rax
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// add two stack values together...
|
|
|
|
|
inline vm::handler::profile_t addq =
|
|
|
|
|
{
|
|
|
|
|
"ADDQ", 0,
|
|
|
|
|
{
|
|
|
|
|
{0x48, 0x1, 0x45, 0x8}, // add [rbp+8], rax
|
|
|
|
|
{0x9C}, // pushfq
|
|
|
|
|
{0x8F, 0x45, 0x0} // pop qword ptr [rbp+0]
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t adddw =
|
|
|
|
|
{
|
|
|
|
|
"ADDDW", 0,
|
|
|
|
|
{
|
|
|
|
|
{ 0x01, 0x45, 0x08 }, // add [rbp+0x08], eax
|
|
|
|
|
{ 0x9C }, // pushfq
|
|
|
|
|
{ 0x8F, 0x45, 0x00 } // pop [rbp]
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// two qwords on the top of the stack together then not the result...
|
|
|
|
|
// ~(VSP[0] | VSP[1])...
|
|
|
|
|
inline vm::handler::profile_t nandq =
|
|
|
|
|
{
|
|
|
|
|
"NANDQ", 0,
|
|
|
|
|
{
|
|
|
|
|
{0x48, 0x8B, 0x45, 0x0}, // mov rax, [rbp+0]
|
|
|
|
|
{0x48, 0x8B, 0x55, 0x8}, // mov rdx, [rbp+8]
|
|
|
|
|
{0x48, 0xF7, 0xD0}, // not rax
|
|
|
|
|
{0x48, 0xF7, 0xD2}, // not rdx
|
|
|
|
|
{0x48, 0x21, 0xD0}, // and rax, rdx
|
|
|
|
|
{0x48, 0x89, 0x45, 0x8}, // mov [rbp+8], rax
|
|
|
|
|
{0x9C}, // pushfq
|
|
|
|
|
{0x8F, 0x45, 0x0} // pop qword ptr [rbp+0]
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// leaves the virtual machine...
|
|
|
|
|
inline vm::handler::profile_t vmexit =
|
|
|
|
|
{
|
|
|
|
|
"VMEXIT", 0,
|
|
|
|
|
{
|
|
|
|
|
{0x48, 0x89, 0xec}, // mov rsp, rbp
|
|
|
|
|
{0x9d}, // popfq
|
|
|
|
|
{0xc3} // ret
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t jmp =
|
|
|
|
|
{
|
|
|
|
|
"JMP", 0,
|
|
|
|
|
{
|
|
|
|
|
{ 0x8B, 0x75, 0x00 }, // mov esi, [rbp]
|
|
|
|
|
{ 0x48, 0x01, 0xC6 }, // add rsi, rax
|
|
|
|
|
{ 0x48, 0x89, 0xF3 }, // mov rbx, rsi
|
|
|
|
|
{ 0x48, 0x03, 0x75, 0x00 } // add rsi, [rbp]
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t readw =
|
|
|
|
|
{
|
|
|
|
|
"READW", 0,
|
|
|
|
|
{
|
|
|
|
|
{ 0x48, 0x8B, 0x45, 0x00 }, // mov rax, [rbp]
|
|
|
|
|
{ 0x48, 0x83, 0xC5, 0x06 }, // add rbp, 0x06
|
|
|
|
|
{ 0x36, 0x66, 0x8B, 0x00 }, // mov ax, ss:[rax]
|
|
|
|
|
{ 0x66, 0x89, 0x45, 0x00 } // mov [rbp], ax
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t writeq =
|
|
|
|
|
{
|
|
|
|
|
"WRITEQ", 0,
|
|
|
|
|
{
|
|
|
|
|
{ 0x48, 0x8B, 0x45, 0x00 }, // mov rax, [rbp]
|
|
|
|
|
{ 0x48, 0x8B, 0x55, 0x08 }, // mov rdx, [rbp+0x08]
|
|
|
|
|
{ 0x48, 0x83, 0xC5, 0x10 }, // add rbp, 0x10
|
|
|
|
|
{ 0x36, 0x48, 0x89, 0x10 }, // mov ss:[rax], rdx
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t writeq1 =
|
|
|
|
|
{
|
|
|
|
|
"WRITEQ", 0,
|
|
|
|
|
// MOV [RAX+RDI], RDX
|
|
|
|
|
[](const zydis_decoded_instr_t& instr) -> bool
|
|
|
|
|
{
|
|
|
|
|
{ 0x48, 0x8B, 0x45, 0x00 }, // mov rax, [rbp]
|
|
|
|
|
{ 0x48, 0x8B, 0x55, 0x08 }, // mov rdx, [rbp+0x08]
|
|
|
|
|
{ 0x48, 0x83, 0xC5, 0x10 }, // add rbp, 0x10
|
|
|
|
|
{ 0x48, 0x89, 0x10 } // mov [rax], rdx
|
|
|
|
|
return instr.mnemonic == ZYDIS_MNEMONIC_MOV &&
|
|
|
|
|
instr.operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY &&
|
|
|
|
|
(instr.operands[0].mem.base == ZYDIS_REGISTER_RAX ||
|
|
|
|
|
instr.operands[0].mem.base == ZYDIS_REGISTER_RDI) &&
|
|
|
|
|
(instr.operands[0].mem.index == ZYDIS_REGISTER_RDI ||
|
|
|
|
|
instr.operands[0].mem.index == ZYDIS_REGISTER_RAX) &&
|
|
|
|
|
instr.operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER &&
|
|
|
|
|
instr.operands[1].reg.value == ZYDIS_REGISTER_RDX;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t shrw =
|
|
|
|
|
{
|
|
|
|
|
"SHRW", 0,
|
|
|
|
|
{
|
|
|
|
|
{ 0x66, 0x8B, 0x45, 0x00 },
|
|
|
|
|
{ 0x8A, 0x4D, 0x02 },
|
|
|
|
|
{ 0x48, 0x83, 0xED, 0x06 },
|
|
|
|
|
{ 0x66, 0xD3, 0xE8 },
|
|
|
|
|
{ 0x66, 0x89, 0x45, 0x08 },
|
|
|
|
|
{ 0x9C },
|
|
|
|
|
{ 0x8F, 0x45, 0x00 }
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t shrdw =
|
|
|
|
|
{
|
|
|
|
|
"SHRDW", 0,
|
|
|
|
|
{
|
|
|
|
|
{ 0x8B, 0x45, 0x00 },
|
|
|
|
|
{ 0x8A, 0x4D, 0x04 },
|
|
|
|
|
{ 0x48, 0x83, 0xED, 0x06 },
|
|
|
|
|
{ 0xD3, 0xE8 },
|
|
|
|
|
{ 0x89, 0x45, 0x08 },
|
|
|
|
|
{ 0x9C },
|
|
|
|
|
{ 0x8F, 0x45, 0x00 }
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t shrq =
|
|
|
|
|
{
|
|
|
|
|
"SHRQ", 0,
|
|
|
|
|
{
|
|
|
|
|
{ 0x48, 0x8B, 0x45, 0x00 },
|
|
|
|
|
{ 0x8A, 0x4D, 0x08 },
|
|
|
|
|
{ 0x48, 0x83, 0xED, 0x06 },
|
|
|
|
|
{ 0x48, 0xD3, 0xE8 },
|
|
|
|
|
{ 0x48, 0x89, 0x45, 0x08 },
|
|
|
|
|
{ 0x9C },
|
|
|
|
|
{ 0x8F, 0x45, 0x00 },
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t nanddw =
|
|
|
|
|
{
|
|
|
|
|
"NANDDW", 0,
|
|
|
|
|
{
|
|
|
|
|
{ 0x48, 0xF7, 0x55, 0x00 }, // not qword ptr [rbp+0]
|
|
|
|
|
{ 0x8B, 0x45, 0x00 }, // mov eax, [rbp+0]
|
|
|
|
|
{ 0x48, 0x83, 0xED, 0x04 }, // sub rbp, 4
|
|
|
|
|
{ 0x21, 0x45, 0x08 }, // and [rbp+8], eax
|
|
|
|
|
{ 0x9C }, // pushfq
|
|
|
|
|
{ 0x8F, 0x45, 0x00 } // pop qword ptr [rbp+0]
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline vm::handler::profile_t lvsp =
|
|
|
|
|
{
|
|
|
|
|
"LVSP", 0,
|
|
|
|
|
{
|
|
|
|
|
{ 0x48, 0x8B, 0x6D, 0x00 } // mov rbp, [rbp]
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline std::vector<vm::handler::profile_t*> all =
|
|
|
|
|
{
|
|
|
|
|
&sregq,
|
|
|
|
|
&lregq,
|
|
|
|
|
&lconstq,
|
|
|
|
|
&lconstdsx,
|
|
|
|
|
&lconstwsx,
|
|
|
|
|
&lconstbzx,
|
|
|
|
|
&addq,
|
|
|
|
|
&nandq,
|
|
|
|
|
&pushvsp,
|
|
|
|
|
&vmexit,
|
|
|
|
|
&jmp,
|
|
|
|
|
&adddw,
|
|
|
|
|
&writeq,
|
|
|
|
|
&sregw,
|
|
|
|
|
&lconstw,
|
|
|
|
|
&shrw,
|
|
|
|
|
&shrq,
|
|
|
|
|
&writeq1,
|
|
|
|
|
&readw,
|
|
|
|
|
&lregdw,
|
|
|
|
|
&shrdw,
|
|
|
|
|
&sregdw,
|
|
|
|
|
&lconstbsx,
|
|
|
|
|
&lconstbsx1,
|
|
|
|
|
&shrq,
|
|
|
|
|
&lvsp,
|
|
|
|
|
&lconstdw,
|
|
|
|
|
&nanddw
|
|
|
|
|
&sregq
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|