-static int run_op(struct guest_info * info, v3_op_type_t op_type, addr_t src_addr, addr_t dst_addr, int op_size);
+static int run_op(struct guest_info * info, v3_op_type_t op_type, addr_t src_addr, addr_t dst_addr, int src_op_size, int dst_op_size);
// We emulate up to the next 4KB page boundry
static int emulate_string_write_op(struct guest_info * info, struct x86_instr * dec_instr,
addr_t tmp_rcx = 0;
addr_t src_addr = 0;
+ if (dec_instr->dst_operand.operand != write_gva) {
+ PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
+ (void *)dec_instr->dst_operand.operand, (void *)write_gva);
+ return -1;
+ }
+
+ emulation_length = ( (dec_instr->str_op_length < (0x1000 - PAGE_OFFSET_4KB(write_gva))) ?
+ dec_instr->str_op_length :
+ (0x1000 - PAGE_OFFSET_4KB(write_gva)));
+
+ /* ** Fix emulation length so that it doesn't overrun over the src page either ** */
+ tmp_rcx = emulation_length;
+
+
+
+
if (dec_instr->op_type == V3_OP_MOVS) {
- PrintError("MOVS emulation\n");
- if (dec_instr->dst_operand.operand != write_gva) {
- PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
- (void *)dec_instr->dst_operand.operand, (void *)write_gva);
+ // figure out addresses here....
+ if (info->mem_mode == PHYSICAL_MEM) {
+ if (guest_pa_to_host_va(info, dec_instr->src_operand.operand, &src_addr) == -1) {
+ PrintError("Could not translate write Source (Physical) to host VA\n");
+ return -1;
+ }
+ } else {
+ if (guest_va_to_host_va(info, dec_instr->src_operand.operand, &src_addr) == -1) {
+ PrintError("Could not translate write Source (Virtual) to host VA\n");
return -1;
}
+ }
- emulation_length = ( (dec_instr->str_op_length < (0x1000 - PAGE_OFFSET_4KB(write_gva))) ?
- dec_instr->str_op_length :
- (0x1000 - PAGE_OFFSET_4KB(write_gva)));
- /* ** Fix emulation length so that it doesn't overrun over the src page either ** */
+ if (dec_instr->dst_operand.size == 1) {
+ movs8((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
+ } else if (dec_instr->dst_operand.size == 2) {
+ movs16((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
+ } else if (dec_instr->dst_operand.size == 4) {
+ movs32((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
+#ifdef __V3_64BIT__
+ } else if (dec_instr->dst_operand.size == 8) {
+ movs64((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
+#endif
+ } else {
+ PrintError("Invalid operand length\n");
+ return -1;
+ }
+ info->vm_regs.rdi += emulation_length;
+ info->vm_regs.rsi += emulation_length;
- PrintDebug("STR_OP_LEN: %d, Page Len: %d\n",
- (uint_t)dec_instr->str_op_length,
- (uint_t)(0x1000 - PAGE_OFFSET_4KB(write_gva)));
- PrintDebug("Emulation length: %d\n", emulation_length);
- tmp_rcx = emulation_length;
-
+ // RCX is only modified if the rep prefix is present
+ if (dec_instr->prefixes.rep == 1) {
+ info->vm_regs.rcx -= emulation_length;
+ }
+ } else if (dec_instr->op_type == V3_OP_STOS) {
- // figure out addresses here....
- if (info->mem_mode == PHYSICAL_MEM) {
- if (guest_pa_to_host_va(info, dec_instr->src_operand.operand, &src_addr) == -1) {
- PrintError("Could not translate write Source (Physical) to host VA\n");
- return -1;
- }
+ if (dec_instr->dst_operand.size == 1) {
+ stos8((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
+ } else if (dec_instr->dst_operand.size == 2) {
+ stos16((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
+ } else if (dec_instr->dst_operand.size == 4) {
+ stos32((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
+#ifdef __V3_64BIT__
+ } else if (dec_instr->dst_operand.size == 8) {
+ stos64((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
+#endif
} else {
- if (guest_va_to_host_va(info, dec_instr->src_operand.operand, &src_addr) == -1) {
- PrintError("Could not translate write Source (Virtual) to host VA\n");
- return -1;
- }
+ PrintError("Invalid operand length\n");
+ return -1;
}
+ info->vm_regs.rdi += emulation_length;
+
+ // RCX is only modified if the rep prefix is present
+ if (dec_instr->prefixes.rep == 1) {
+ info->vm_regs.rcx -= emulation_length;
+ }
- PrintDebug("Dst Operand: %p (size=%d), Src Operand: %p\n",
- (void *)dec_instr->dst_operand.operand,
- dec_instr->dst_operand.size,
- (void *)dec_instr->src_operand.operand);
- PrintDebug("Dst Addr: %p, Src Addr: %p\n", (void *)dst_addr, (void *)src_addr);
+ } else {
+ PrintError("Unimplemented String operation\n");
+ return -1;
+ }
- //return -1;
+ if (write_fn(write_gpa, (void *)dst_addr, emulation_length, priv_data) != emulation_length) {
+ PrintError("Did not fully read hooked data\n");
+ return -1;
+ }
+ if (emulation_length == dec_instr->str_op_length) {
+ info->rip += dec_instr->instr_length;
+ }
-
+ return emulation_length;
+}
- if (dec_instr->dst_operand.size == 1) {
- movs8((addr_t *)dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
- } else if (dec_instr->dst_operand.size == 2) {
- movs16((addr_t *)dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
- } else if (dec_instr->dst_operand.size == 4) {
- movs32((addr_t*)dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
- } else {
- PrintError("Invalid operand length\n");
+static int emulate_xchg_write_op(struct guest_info * info, struct x86_instr * dec_instr,
+ addr_t write_gva, addr_t write_gpa, addr_t dst_addr,
+ int (*write_fn)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
+ void * priv_data) {
+ addr_t src_addr = 0;
+ addr_t em_dst_addr = 0;
+ int src_op_len = 0;
+ int dst_op_len = 0;
+ PrintDebug("Emulating XCHG write\n");
+
+ if (dec_instr->src_operand.type == MEM_OPERAND) {
+ if (dec_instr->src_operand.operand != write_gva) {
+ PrintError("XCHG: Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
+ (void *)dec_instr->src_operand.operand, (void *)write_gva);
return -1;
}
+
+ src_addr = dst_addr;
+ } else if (dec_instr->src_operand.type == REG_OPERAND) {
+ src_addr = dec_instr->src_operand.operand;
+ } else {
+ src_addr = (addr_t)&(dec_instr->src_operand.operand);
+ }
- if (write_fn(write_gpa, (void *)dst_addr, emulation_length, priv_data) != emulation_length) {
- PrintError("Did not fully read hooked data\n");
+
+ if (dec_instr->dst_operand.type == MEM_OPERAND) {
+ if (dec_instr->dst_operand.operand != write_gva) {
+ PrintError("XCHG: Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
+ (void *)dec_instr->dst_operand.operand, (void *)write_gva);
return -1;
}
+
+ em_dst_addr = dst_addr;
+ } else if (dec_instr->src_operand.type == REG_OPERAND) {
+ em_dst_addr = dec_instr->src_operand.operand;
+ } else {
+ em_dst_addr = (addr_t)&(dec_instr->src_operand.operand);
+ }
+
+ dst_op_len = dec_instr->dst_operand.size;
+ src_op_len = dec_instr->src_operand.size;
+
+ PrintDebug("Dst_Addr = %p, SRC operand = %p\n",
+ (void *)dst_addr, (void *)src_addr);
- PrintDebug("RDI=%p, RSI=%p, RCX=%p\n",
- (void *)*(addr_t *)&(info->vm_regs.rdi),
- (void *)*(addr_t *)&(info->vm_regs.rsi),
- (void *)*(addr_t *)&(info->vm_regs.rcx));
+ if (run_op(info, dec_instr->op_type, src_addr, em_dst_addr, src_op_len, dst_op_len) == -1) {
+ PrintError("Instruction Emulation Failed\n");
+ return -1;
+ }
- info->vm_regs.rdi += emulation_length;
- info->vm_regs.rsi += emulation_length;
- info->vm_regs.rcx -= emulation_length;
+ if (write_fn(write_gpa, (void *)dst_addr, dst_op_len, priv_data) != dst_op_len) {
+ PrintError("Did not fully write hooked data\n");
+ return -1;
+ }
+
+ info->rip += dec_instr->instr_length;
+
+ return dst_op_len;
+}
+
+
+
+static int emulate_xchg_read_op(struct guest_info * info, struct x86_instr * dec_instr,
+ addr_t read_gva, addr_t read_gpa, addr_t src_addr,
+ int (*read_fn)(addr_t guest_addr, void * dst, uint_t length, void * priv_data),
+ int (*write_fn)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
+ void * priv_data) {
+ addr_t em_src_addr = 0;
+ addr_t em_dst_addr = 0;
+ int src_op_len = 0;
+ int dst_op_len = 0;
+
+ PrintDebug("Emulating XCHG Read\n");
+
+ if (dec_instr->src_operand.type == MEM_OPERAND) {
+ if (dec_instr->src_operand.operand != read_gva) {
+ PrintError("XCHG: Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
+ (void *)dec_instr->src_operand.operand, (void *)read_gva);
+ return -1;
+ }
- PrintDebug("RDI=%p, RSI=%p, RCX=%p\n",
- (void *)*(addr_t *)&(info->vm_regs.rdi),
- (void *)*(addr_t *)&(info->vm_regs.rsi),
- (void *)*(addr_t *)&(info->vm_regs.rcx));
+ em_src_addr = src_addr;
+ } else if (dec_instr->src_operand.type == REG_OPERAND) {
+ em_src_addr = dec_instr->src_operand.operand;
+ } else {
+ em_src_addr = (addr_t)&(dec_instr->src_operand.operand);
+ }
+
+
- if (emulation_length == dec_instr->str_op_length) {
- info->rip += dec_instr->instr_length;
+ if (dec_instr->dst_operand.type == MEM_OPERAND) {
+ if (dec_instr->dst_operand.operand != read_gva) {
+ PrintError("XCHG: Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
+ (void *)dec_instr->dst_operand.operand, (void *)read_gva);
+ return -1;
}
+
+ em_dst_addr = src_addr;
+ } else if (dec_instr->src_operand.type == REG_OPERAND) {
+ em_dst_addr = dec_instr->src_operand.operand;
+ } else {
+ em_dst_addr = (addr_t)&(dec_instr->src_operand.operand);
+ }
+
+ dst_op_len = dec_instr->dst_operand.size;
+ src_op_len = dec_instr->src_operand.size;
+
+ PrintDebug("Dst_Addr = %p, SRC operand = %p\n",
+ (void *)em_dst_addr, (void *)em_src_addr);
+
- return emulation_length;
+ if (read_fn(read_gpa, (void *)src_addr, src_op_len, priv_data) != src_op_len) {
+ PrintError("Did not fully read hooked data\n");
+ return -1;
}
-
+ if (run_op(info, dec_instr->op_type, em_src_addr, em_dst_addr, src_op_len, dst_op_len) == -1) {
+ PrintError("Instruction Emulation Failed\n");
+ return -1;
+ }
+
+ if (write_fn(read_gpa, (void *)src_addr, dst_op_len, priv_data) != dst_op_len) {
+ PrintError("Did not fully write hooked data\n");
+ return -1;
+ }
+ info->rip += dec_instr->instr_length;
- return -1;
+ return dst_op_len;
}
-
int v3_emulate_write_op(struct guest_info * info, addr_t write_gva, addr_t write_gpa, addr_t dst_addr,
int (*write_fn)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
void * priv_data) {
uchar_t instr[15];
int ret = 0;
addr_t src_addr = 0;
- int op_len = 0;
+ int src_op_len = 0;
+ int dst_op_len = 0;
PrintDebug("Emulating Write for instruction at %p\n", (void *)(addr_t)(info->rip));
PrintDebug("GVA=%p\n", (void *)write_gva);
return -1;
}
+ /*
+ * Instructions needing to be special cased.... *
+ */
if (dec_instr.is_str_op) {
return emulate_string_write_op(info, &dec_instr, write_gva, write_gpa, dst_addr, write_fn, priv_data);
+ } else if (dec_instr.op_type == V3_OP_XCHG) {
+ return emulate_xchg_write_op(info, &dec_instr, write_gva, write_gpa, dst_addr, write_fn, priv_data);
}
+
if ((dec_instr.dst_operand.type != MEM_OPERAND) ||
(dec_instr.dst_operand.operand != write_gva)) {
PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
src_addr = (addr_t)&(dec_instr.src_operand.operand);
}
- op_len = dec_instr.dst_operand.size;
+ dst_op_len = dec_instr.dst_operand.size;
+ src_op_len = dec_instr.src_operand.size;
PrintDebug("Dst_Addr = %p, SRC operand = %p\n",
(void *)dst_addr, (void *)src_addr);
- if (run_op(info, dec_instr.op_type, src_addr, dst_addr, op_len) == -1) {
+ if (run_op(info, dec_instr.op_type, src_addr, dst_addr, src_op_len, dst_op_len) == -1) {
PrintError("Instruction Emulation Failed\n");
return -1;
}
- if (write_fn(write_gpa, (void *)dst_addr, op_len, priv_data) != op_len) {
- PrintError("Did not fully read hooked data\n");
+ if (write_fn(write_gpa, (void *)dst_addr, dst_op_len, priv_data) != dst_op_len) {
+ PrintError("Did not fully write hooked data\n");
return -1;
}
info->rip += dec_instr.instr_length;
- return op_len;
+ return dst_op_len;
}
int v3_emulate_read_op(struct guest_info * info, addr_t read_gva, addr_t read_gpa, addr_t src_addr,
- int (*read_fn)(addr_t guest_addr, void * dst, uint_t length, void * priv_data),
+ int (*read_fn)(addr_t guest_addr, void * dst, uint_t length, void * priv_data),
+ int (*write_fn)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
void * priv_data) {
struct x86_instr dec_instr;
uchar_t instr[15];
int ret = 0;
addr_t dst_addr = 0;
- int op_len = 0;
+ int src_op_len = 0;
+ int dst_op_len = 0;
PrintDebug("Emulating Read for instruction at %p\n", (void *)(addr_t)(info->rip));
- PrintDebug("GVA=%p\n", (void *)write_gva);
+ PrintDebug("GVA=%p\n", (void *)read_gva);
if (info->mem_mode == PHYSICAL_MEM) {
ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
if (dec_instr.is_str_op) {
PrintError("String operations not implemented on fully hooked regions\n");
return -1;
+ } else if (dec_instr.op_type == V3_OP_XCHG) {
+ return emulate_xchg_read_op(info, &dec_instr, read_gva, read_gpa, src_addr, read_fn, write_fn, priv_data);
}
dst_addr = (addr_t)&(dec_instr.dst_operand.operand);
}
- op_len = dec_instr.src_operand.size;
+ src_op_len = dec_instr.src_operand.size;
+ dst_op_len = dec_instr.dst_operand.size;
PrintDebug("Dst_Addr = %p, SRC Addr = %p\n",
(void *)dst_addr, (void *)src_addr);
- if (read_fn(read_gpa, (void *)src_addr,op_len, priv_data) != op_len) {
+ if (read_fn(read_gpa, (void *)src_addr, src_op_len, priv_data) != src_op_len) {
PrintError("Did not fully read hooked data\n");
return -1;
}
- if (run_op(info, dec_instr.op_type, src_addr, dst_addr, op_len) == -1) {
+ if (run_op(info, dec_instr.op_type, src_addr, dst_addr, src_op_len, dst_op_len) == -1) {
PrintError("Instruction Emulation Failed\n");
return -1;
}
info->rip += dec_instr.instr_length;
- return op_len;
+ return src_op_len;
}
-static int run_op(struct guest_info * info, v3_op_type_t op_type, addr_t src_addr, addr_t dst_addr, int op_size) {
+static int run_op(struct guest_info * info, v3_op_type_t op_type, addr_t src_addr, addr_t dst_addr, int src_op_size, int dst_op_size) {
- if (op_size == 1) {
+ if (src_op_size == 1) {
+ PrintDebug("Executing 8 bit instruction\n");
switch (op_type) {
case V3_OP_ADC:
case V3_OP_MOV:
mov8((addr_t *)dst_addr, (addr_t *)src_addr);
break;
+
+ case V3_OP_MOVZX:
+ movzx8((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
+ break;
+ case V3_OP_MOVSX:
+ movsx8((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
+ break;
+
case V3_OP_NOT:
not8((addr_t *)dst_addr);
break;
return -1;
}
- } else if (op_size == 2) {
+ } else if (src_op_size == 2) {
+ PrintDebug("Executing 16 bit instruction\n");
switch (op_type) {
case V3_OP_ADC:
case V3_OP_MOV:
mov16((addr_t *)dst_addr, (addr_t *)src_addr);
break;
+ case V3_OP_MOVZX:
+ movzx16((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
+ break;
+ case V3_OP_MOVSX:
+ movsx16((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
+ break;
case V3_OP_NOT:
not16((addr_t *)dst_addr);
break;
return -1;
}
- } else if (op_size == 4) {
+ } else if (src_op_size == 4) {
+ PrintDebug("Executing 32 bit instruction\n");
switch (op_type) {
case V3_OP_ADC:
case V3_OP_MOV:
mov32((addr_t *)dst_addr, (addr_t *)src_addr);
break;
+
case V3_OP_NOT:
not32((addr_t *)dst_addr);
break;
}
#ifdef __V3_64BIT__
- } else if (op_size == 8) {
-
+ } else if (src_op_size == 8) {
+ PrintDebug("Executing 64 bit instruction\n");
switch (op_type) {
case V3_OP_ADC:
case V3_OP_MOV:
mov64((addr_t *)dst_addr, (addr_t *)src_addr);
break;
+
case V3_OP_NOT:
not64((addr_t *)dst_addr);
break;