Merge branch 'batch_reg' of https://github.com/lunixbochs/unicorn into lunixbochs-batch_reg

This commit is contained in:
Nguyen Anh Quynh 2016-04-06 09:39:22 +08:00
commit 721f17eb74
20 changed files with 1412 additions and 1152 deletions

23
bindings/go/unicorn/uc.c Normal file
View file

@ -0,0 +1,23 @@
#include <stdlib.h>
#include <unicorn/unicorn.h>
#include "_cgo_export.h"
uc_err uc_reg_read_batch_helper(uc_engine *handle, int *regs, uint64_t *val_out, int count) {
void **val_ref = malloc(sizeof(void *) * count);
for (int i = 0; i < count; i++) {
val_ref[i] = (void *)&val_out[i];
}
uc_err ret = uc_reg_read_batch(handle, regs, val_ref, count);
free(val_ref);
return ret;
}
uc_err uc_reg_write_batch_helper(uc_engine *handle, int *regs, uint64_t *val_in, int count) {
const void **val_ref = malloc(sizeof(void *) * count);
for (int i = 0; i < count; i++) {
val_ref[i] = (void *)&val_in[i];
}
uc_err ret = uc_reg_write_batch(handle, regs, val_ref, count);
free(val_ref);
return ret;
}

2
bindings/go/unicorn/uc.h Normal file
View file

@ -0,0 +1,2 @@
uc_err uc_reg_read_batch_helper(uc_engine *handle, int *regs, uint64_t *val_out, int count);
uc_err uc_reg_write_batch_helper(uc_engine *handle, int *regs, uint64_t *val_in, int count);

View file

@ -7,8 +7,10 @@ import (
) )
/* /*
#cgo CFLAGS: -O3
#cgo LDFLAGS: -lunicorn #cgo LDFLAGS: -lunicorn
#include <unicorn/unicorn.h> #include <unicorn/unicorn.h>
#include "uc.h"
*/ */
import "C" import "C"
@ -41,7 +43,9 @@ type Unicorn interface {
MemReadInto(dst []byte, addr uint64) error MemReadInto(dst []byte, addr uint64) error
MemWrite(addr uint64, data []byte) error MemWrite(addr uint64, data []byte) error
RegRead(reg int) (uint64, error) RegRead(reg int) (uint64, error)
RegReadBatch(regs []int) ([]uint64, error)
RegWrite(reg int, value uint64) error RegWrite(reg int, value uint64) error
RegWriteBatch(regs []int, vals []uint64) error
RegReadMmr(reg int) (*X86Mmr, error) RegReadMmr(reg int) (*X86Mmr, error)
RegWriteMmr(reg int, value *X86Mmr) error RegWriteMmr(reg int, value *X86Mmr) error
Start(begin, until uint64) error Start(begin, until uint64) error
@ -117,6 +121,38 @@ func (u *uc) RegRead(reg int) (uint64, error) {
return uint64(val), errReturn(ucerr) return uint64(val), errReturn(ucerr)
} }
func (u *uc) RegWriteBatch(regs []int, vals []uint64) error {
if len(regs) == 0 {
return nil
}
if len(vals) < len(regs) {
regs = regs[:len(vals)]
}
cregs := make([]C.int, len(regs))
for i, v := range regs {
cregs[i] = C.int(v)
}
cregs2 := (*C.int)(unsafe.Pointer(&cregs[0]))
cvals := (*C.uint64_t)(unsafe.Pointer(&vals[0]))
ucerr := C.uc_reg_write_batch_helper(u.handle, cregs2, cvals, C.int(len(regs)))
return errReturn(ucerr)
}
func (u *uc) RegReadBatch(regs []int) ([]uint64, error) {
if len(regs) == 0 {
return nil, nil
}
cregs := make([]C.int, len(regs))
for i, v := range regs {
cregs[i] = C.int(v)
}
cregs2 := (*C.int)(unsafe.Pointer(&cregs[0]))
vals := make([]uint64, len(regs))
cvals := (*C.uint64_t)(unsafe.Pointer(&vals[0]))
ucerr := C.uc_reg_read_batch_helper(u.handle, cregs2, cvals, C.int(len(regs)))
return vals, errReturn(ucerr)
}
func (u *uc) MemRegions() ([]*MemRegion, error) { func (u *uc) MemRegions() ([]*MemRegion, error) {
var regions *C.struct_uc_mem_region var regions *C.struct_uc_mem_region
var count C.uint32_t var count C.uint32_t

View file

@ -46,8 +46,8 @@ typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
typedef uc_err (*query_t)(struct uc_struct *uc, uc_query_type type, size_t *result); typedef uc_err (*query_t)(struct uc_struct *uc, uc_query_type type, size_t *result);
// return 0 on success, -1 on failure // return 0 on success, -1 on failure
typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int regid, void *value); typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int regid, const void *value); typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
typedef void (*reg_reset_t)(struct uc_struct *uc); typedef void (*reg_reset_t)(struct uc_struct *uc);

View file

@ -386,6 +386,34 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value);
UNICORN_EXPORT UNICORN_EXPORT
uc_err uc_reg_read(uc_engine *uc, int regid, void *value); uc_err uc_reg_read(uc_engine *uc, int regid, void *value);
/*
Write multiple register values.
@uc: handle returned by uc_open()
@rges: array of register IDs to store
@value: pointer to array of register values
@count: length of both *regs and *vals
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_reg_write_batch(uc_engine *uc, int *regs, void *const *vals, int count);
/*
Read multiple register values.
@uc: handle returned by uc_open()
@rges: array of register IDs to retrieve
@value: pointer to array of values to hold registers
@count: length of both *regs and *vals
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_reg_read_batch(uc_engine *uc, int *regs, void **vals, int count);
/* /*
Write to a range of bytes in memory. Write to a range of bytes in memory.

View file

@ -5,10 +5,10 @@
#define UC_QEMU_TARGET_ARM_H #define UC_QEMU_TARGET_ARM_H
// functions to read & write registers // functions to read & write registers
int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value); int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value); int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
void arm_reg_reset(struct uc_struct *uc); void arm_reg_reset(struct uc_struct *uc);
void arm64_reg_reset(struct uc_struct *uc); void arm64_reg_reset(struct uc_struct *uc);

View file

@ -23,10 +23,14 @@ void arm64_reg_reset(struct uc_struct *uc)
env->pc = 0; env->pc = 0;
} }
int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value) int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28)
*(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0]; *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0];
else { else {
@ -46,14 +50,19 @@ int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
break; break;
} }
} }
}
return 0; return 0;
} }
int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28)
ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0] = *(uint64_t *)value; ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0] = *(uint64_t *)value;
else { else {
@ -76,6 +85,7 @@ int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
break; break;
} }
} }
}
return 0; return 0;
} }

View file

@ -27,12 +27,16 @@ void arm_reg_reset(struct uc_struct *uc)
env->pc = 0; env->pc = 0;
} }
int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value) int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{ {
CPUState *mycpu; CPUState *mycpu;
int i;
mycpu = first_cpu; mycpu = first_cpu;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12)
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0]; *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0];
else { else {
@ -54,14 +58,19 @@ int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
break; break;
} }
} }
}
return 0; return 0;
} }
int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12)
ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value; ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value;
else { else {
@ -85,6 +94,7 @@ int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
break; break;
} }
} }
}
return 0; return 0;
} }

View file

@ -136,10 +136,14 @@ void x86_reg_reset(struct uc_struct *uc)
} }
} }
int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
switch(regid) { switch(regid) {
default: default:
break; break;
@ -148,7 +152,7 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
floatx80 reg = X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d; floatx80 reg = X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d;
cpu_get_fp80(value, value+sizeof(uint64_t), reg); cpu_get_fp80(value, value+sizeof(uint64_t), reg);
} }
return 0; continue;
case UC_X86_REG_FPSW: case UC_X86_REG_FPSW:
{ {
uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus; uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus;
@ -156,10 +160,10 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11; fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11;
*(uint16_t*) value = fpus; *(uint16_t*) value = fpus;
} }
return 0; continue;
case UC_X86_REG_FPCW: case UC_X86_REG_FPCW:
*(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc;
return 0; continue;
case UC_X86_REG_FPTAG: case UC_X86_REG_FPTAG:
{ {
#define EXPD(fp) (fp.l.upper & 0x7fff) #define EXPD(fp) (fp.l.upper & 0x7fff)
@ -189,7 +193,7 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
} }
*(uint16_t*) value = fptag; *(uint16_t*) value = fptag;
} }
return 0; continue;
} }
switch(uc->mode) { switch(uc->mode) {
@ -200,19 +204,19 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
default: break; default: break;
case UC_X86_REG_ES: case UC_X86_REG_ES:
*(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].selector; *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].selector;
return 0; continue;
case UC_X86_REG_SS: case UC_X86_REG_SS:
*(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].selector; *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].selector;
return 0; continue;
case UC_X86_REG_DS: case UC_X86_REG_DS:
*(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].selector; *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].selector;
return 0; continue;
case UC_X86_REG_FS: case UC_X86_REG_FS:
*(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].selector; *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].selector;
return 0; continue;
case UC_X86_REG_GS: case UC_X86_REG_GS:
*(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].selector; *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].selector;
return 0; continue;
} }
// fall-thru // fall-thru
case UC_MODE_32: case UC_MODE_32:
@ -616,15 +620,19 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
break; break;
#endif #endif
} }
}
return 0; return 0;
} }
int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
switch(regid) { switch(regid) {
default: default:
break; break;
@ -634,17 +642,17 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
uint16_t upper = *(uint16_t*) (value + sizeof(uint64_t)); uint16_t upper = *(uint16_t*) (value + sizeof(uint64_t));
X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper); X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper);
} }
return 0; continue;
case UC_X86_REG_FPSW: case UC_X86_REG_FPSW:
{ {
uint16_t fpus = *(uint16_t*) value; uint16_t fpus = *(uint16_t*) value;
X86_CPU(uc, mycpu)->env.fpus = fpus & ~0x3800; X86_CPU(uc, mycpu)->env.fpus = fpus & ~0x3800;
X86_CPU(uc, mycpu)->env.fpstt = (fpus >> 11) & 0x7; X86_CPU(uc, mycpu)->env.fpstt = (fpus >> 11) & 0x7;
} }
return 0; continue;
case UC_X86_REG_FPCW: case UC_X86_REG_FPCW:
X86_CPU(uc, mycpu)->env.fpuc = *(uint16_t *)value; X86_CPU(uc, mycpu)->env.fpuc = *(uint16_t *)value;
return 0; continue;
case UC_X86_REG_FPTAG: case UC_X86_REG_FPTAG:
{ {
int i; int i;
@ -654,7 +662,7 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
fptag >>= 2; fptag >>= 2;
} }
return 0; continue;
} }
break; break;
} }
@ -668,19 +676,19 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
default: break; default: break;
case UC_X86_REG_ES: case UC_X86_REG_ES:
X86_CPU(uc, mycpu)->env.segs[R_ES].selector = *(uint16_t *)value; X86_CPU(uc, mycpu)->env.segs[R_ES].selector = *(uint16_t *)value;
return 0; continue;
case UC_X86_REG_SS: case UC_X86_REG_SS:
X86_CPU(uc, mycpu)->env.segs[R_SS].selector = *(uint16_t *)value; X86_CPU(uc, mycpu)->env.segs[R_SS].selector = *(uint16_t *)value;
return 0; continue;
case UC_X86_REG_DS: case UC_X86_REG_DS:
X86_CPU(uc, mycpu)->env.segs[R_DS].selector = *(uint16_t *)value; X86_CPU(uc, mycpu)->env.segs[R_DS].selector = *(uint16_t *)value;
return 0; continue;
case UC_X86_REG_FS: case UC_X86_REG_FS:
X86_CPU(uc, mycpu)->env.segs[R_FS].selector = *(uint16_t *)value; X86_CPU(uc, mycpu)->env.segs[R_FS].selector = *(uint16_t *)value;
return 0; continue;
case UC_X86_REG_GS: case UC_X86_REG_GS:
X86_CPU(uc, mycpu)->env.segs[R_GS].selector = *(uint16_t *)value; X86_CPU(uc, mycpu)->env.segs[R_GS].selector = *(uint16_t *)value;
return 0; continue;
} }
// fall-thru // fall-thru
case UC_MODE_32: case UC_MODE_32:
@ -1101,6 +1109,7 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
break; break;
#endif #endif
} }
}
return 0; return 0;
} }

View file

@ -5,8 +5,8 @@
#define UC_QEMU_TARGET_I386_H #define UC_QEMU_TARGET_I386_H
// functions to read & write registers // functions to read & write registers
int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value); int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
void x86_reg_reset(struct uc_struct *uc); void x86_reg_reset(struct uc_struct *uc);

View file

@ -25,10 +25,14 @@ void m68k_reg_reset(struct uc_struct *uc)
env->pc = 0; env->pc = 0;
} }
int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value) int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7)
*(int32_t *)value = M68K_CPU(uc, mycpu)->env.aregs[regid - UC_M68K_REG_A0]; *(int32_t *)value = M68K_CPU(uc, mycpu)->env.aregs[regid - UC_M68K_REG_A0];
else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7) else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7)
@ -41,14 +45,19 @@ int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
break; break;
} }
} }
}
return 0; return 0;
} }
int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7)
M68K_CPU(uc, mycpu)->env.aregs[regid - UC_M68K_REG_A0] = *(uint32_t *)value; M68K_CPU(uc, mycpu)->env.aregs[regid - UC_M68K_REG_A0] = *(uint32_t *)value;
else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7) else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7)
@ -64,7 +73,7 @@ int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
break; break;
} }
} }
}
return 0; return 0;
} }

View file

@ -5,8 +5,8 @@
#define UC_QEMU_TARGET_M68K_H #define UC_QEMU_TARGET_M68K_H
// functions to read & write registers // functions to read & write registers
int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value); int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
void m68k_reg_reset(struct uc_struct *uc); void m68k_reg_reset(struct uc_struct *uc);

View file

@ -39,10 +39,14 @@ void mips_reg_reset(struct uc_struct *uc)
env->active_tc.PC = 0; env->active_tc.PC = 0;
} }
int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value) int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31)
*(int32_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0]; *(int32_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0];
else { else {
@ -53,14 +57,19 @@ int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
break; break;
} }
} }
}
return 0; return 0;
} }
int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31)
MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0] = *(uint32_t *)value; MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0] = *(uint32_t *)value;
else { else {
@ -74,7 +83,7 @@ int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
break; break;
} }
} }
}
return 0; return 0;
} }

View file

@ -5,8 +5,8 @@
#define UC_QEMU_TARGET_MIPS_H #define UC_QEMU_TARGET_MIPS_H
// functions to read & write registers // functions to read & write registers
int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value); int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
void mips_reg_reset(struct uc_struct *uc); void mips_reg_reset(struct uc_struct *uc);

View file

@ -39,10 +39,14 @@ void sparc_reg_reset(struct uc_struct *uc)
env->regwptr = env->regbase; env->regwptr = env->regbase;
} }
int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0];
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
@ -59,14 +63,19 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
break; break;
} }
} }
}
return 0; return 0;
} }
int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint32_t *)value; SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint32_t *)value;
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
@ -87,6 +96,7 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
break; break;
} }
} }
}
return 0; return 0;
} }

View file

@ -5,8 +5,8 @@
#define UC_QEMU_TARGET_SPARC_H #define UC_QEMU_TARGET_SPARC_H
// functions to read & write registers // functions to read & write registers
int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value); int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
void sparc_reg_reset(struct uc_struct *uc); void sparc_reg_reset(struct uc_struct *uc);

View file

@ -39,10 +39,14 @@ void sparc_reg_reset(struct uc_struct *uc)
env->regwptr = env->regbase; env->regwptr = env->regbase;
} }
int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
*(int64_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0];
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
@ -59,14 +63,19 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
break; break;
} }
} }
}
return 0; return 0;
} }
int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint64_t *)value; SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint64_t *)value;
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
@ -84,7 +93,7 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
break; break;
} }
} }
}
return 0; return 0;
} }

View file

@ -101,6 +101,7 @@ SOURCES += sample_x86.c
SOURCES += shellcode.c SOURCES += shellcode.c
SOURCES += mem_apis.c SOURCES += mem_apis.c
SOURCES += sample_x86_32_gdt_and_seg_regs.c SOURCES += sample_x86_32_gdt_and_seg_regs.c
SOURCES += sample_batch_reg.c
endif endif
ifneq (,$(findstring m68k,$(UNICORN_ARCHS))) ifneq (,$(findstring m68k,$(UNICORN_ARCHS)))
SOURCES += sample_m68k.c SOURCES += sample_m68k.c
@ -114,7 +115,7 @@ all: clean_bins $(BINARY)
clean_bins: clean_bins:
rm -rf *.o $(OBJS_ELF) $(BINARY) $(SAMPLEDIR)/*.exe $(SAMPLEDIR)/*.static $(OBJDIR)/lib$(LIBNAME)* $(OBJDIR)/$(LIBNAME)* rm -rf *.o $(OBJS_ELF) $(BINARY) $(SAMPLEDIR)/*.exe $(SAMPLEDIR)/*.static $(OBJDIR)/lib$(LIBNAME)* $(OBJDIR)/$(LIBNAME)*
rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k shellcode mem_apis sample_x86_32_gdt_and_seg_regs rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k shellcode mem_apis sample_x86_32_gdt_and_seg_regs sample_batch_reg
clean_libs: clean_libs:
rm -rf libunicorn*.so libunicorn*.lib libunicorn*.dylib unicorn*.dll unicorn*.lib rm -rf libunicorn*.so libunicorn*.lib libunicorn*.dylib unicorn*.dll unicorn*.lib

View file

@ -0,0 +1,90 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unicorn/unicorn.h>
int syscall_abi[] = {UC_X86_REG_RAX, UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, UC_X86_REG_R10, UC_X86_REG_R8, UC_X86_REG_R9};
uint64_t vals[7] = {200, 10, 11, 12, 13, 14, 15};
// This part of the API is less... clean... because Unicorn supports arbitrary register types.
// So the least intrusive solution is passing individual pointers.
// On the plus side, you only need to make this pointer array once.
void *ptrs[7];
void uc_perror(const char *func, uc_err err) {
fprintf(stderr, "Error in %s(): %s\n", func, uc_strerror(err));
}
#define BASE 0x10000
// mov rax, 100; mov rdi, 1; mov rsi, 2; mov rdx, 3; mov r10, 4; mov r8, 5; mov r9, 6; syscall
#define CODE "\x48\xc7\xc0\x64\x00\x00\x00\x48\xc7\xc7\x01\x00\x00\x00\x48\xc7\xc6\x02\x00\x00\x00\x48\xc7\xc2\x03\x00\x00\x00\x49\xc7\xc2\x04\x00\x00\x00\x49\xc7\xc0\x05\x00\x00\x00\x49\xc7\xc1\x06\x00\x00\x00\x0f\x05"
void hook_syscall(uc_engine *uc, void *user_data) {
int i;
uc_reg_read_batch(uc, syscall_abi, ptrs, 7);
printf("syscall: {");
for (i = 0; i < 7; i++) {
if (i != 0) printf(", ");
printf("%llu", vals[i]);
}
printf("}\n");
}
void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_data) {
printf("HOOK_CODE: 0x%llx, 0x%x\n", addr, size);
}
int main() {
int i;
// set up register pointers
for (i = 0; i < 7; i++) {
ptrs[i] = &vals[i];
}
uc_err err;
uc_engine *uc;
if ((err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc))) {
uc_perror("uc_open", err);
return 1;
}
// reg_write_batch
printf("reg_write_batch({200, 10, 11, 12, 13, 14, 15})\n");
if ((err = uc_reg_write_batch(uc, syscall_abi, ptrs, 7))) {
uc_perror("uc_reg_write_batch", err);
return 1;
}
// reg_read_batch
memset(vals, 0, sizeof(vals));
if ((err = uc_reg_read_batch(uc, syscall_abi, ptrs, 7))) {
uc_perror("uc_reg_read_batch", err);
return 1;
}
printf("reg_read_batch = {");
for (i = 0; i < 7; i++) {
if (i != 0) printf(", ");
printf("%llu", vals[i]);
}
printf("}\n");
// syscall
printf("\n");
printf("running syscall shellcode\n");
uc_hook sys_hook;
if ((err = uc_hook_add(uc, &sys_hook, UC_HOOK_INSN, hook_syscall, NULL, 1, 0, UC_X86_INS_SYSCALL))) {
uc_perror("uc_hook_add", err);
return 1;
}
if ((err = uc_mem_map(uc, BASE, 0x1000, UC_PROT_ALL))) {
uc_perror("uc_mem_map", err);
return 1;
}
if ((err = uc_mem_write(uc, BASE, CODE, sizeof(CODE) - 1))) {
uc_perror("uc_mem_write", err);
return 1;
}
if ((err = uc_emu_start(uc, BASE, BASE + sizeof(CODE) - 1, 0, 0))) {
uc_perror("uc_emu_start", err);
return 1;
}
}

22
uc.c
View file

@ -332,10 +332,10 @@ uc_err uc_close(uc_engine *uc)
UNICORN_EXPORT UNICORN_EXPORT
uc_err uc_reg_read(uc_engine *uc, int regid, void *value) uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count)
{ {
if (uc->reg_read) if (uc->reg_read)
uc->reg_read(uc, regid, value); uc->reg_read(uc, (unsigned int *)ids, vals, count);
else else
return -1; // FIXME: need a proper uc_err return -1; // FIXME: need a proper uc_err
@ -344,10 +344,10 @@ uc_err uc_reg_read(uc_engine *uc, int regid, void *value)
UNICORN_EXPORT UNICORN_EXPORT
uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) uc_err uc_reg_write_batch(uc_engine *uc, int *ids, void *const *vals, int count)
{ {
if (uc->reg_write) if (uc->reg_write)
uc->reg_write(uc, regid, value); uc->reg_write(uc, (unsigned int *)ids, vals, count);
else else
return -1; // FIXME: need a proper uc_err return -1; // FIXME: need a proper uc_err
@ -355,6 +355,20 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value)
} }
UNICORN_EXPORT
uc_err uc_reg_read(uc_engine *uc, int regid, void *value)
{
return uc_reg_read_batch(uc, &regid, &value, 1);
}
UNICORN_EXPORT
uc_err uc_reg_write(uc_engine *uc, int regid, const void *value)
{
return uc_reg_write_batch(uc, &regid, (void *const *)&value, 1);
}
// check if a memory area is mapped // check if a memory area is mapped
// this is complicated because an area can overlap adjacent blocks // this is complicated because an area can overlap adjacent blocks
static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size) static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size)