commit
5ede98abec
@ -1,12 +1,16 @@
|
||||
#include <unicorn/unicorn.h>
|
||||
#include "_cgo_export.h"
|
||||
|
||||
uc_err uc_hook_add_i1(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, int arg1) {
|
||||
return uc_hook_add(handle, h2, type, callback, (void *)user, arg1);
|
||||
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
|
||||
void *user_data, uint64_t begin, uint64_t end, ...);
|
||||
|
||||
|
||||
uc_err uc_hook_add_wrap(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end) {
|
||||
return uc_hook_add(handle, h2, type, callback, (void *)user, begin, end);
|
||||
}
|
||||
|
||||
uc_err uc_hook_add_u2(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t arg1, uint64_t arg2) {
|
||||
return uc_hook_add(handle, h2, type, callback, (void *)user, arg1, arg2);
|
||||
uc_err uc_hook_add_insn(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end, int insn) {
|
||||
return uc_hook_add(handle, h2, type, callback, (void *)user, begin, end, insn);
|
||||
}
|
||||
|
||||
void hookCode_cgo(uc_engine *handle, uint64_t addr, uint32_t size, uintptr_t user) {
|
||||
|
@ -63,23 +63,21 @@ func hookX86Syscall(handle unsafe.Pointer, user unsafe.Pointer) {
|
||||
hook.Callback.(func(Unicorn))(hook.Uc)
|
||||
}
|
||||
|
||||
func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) {
|
||||
func (u *uc) HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) (Hook, error) {
|
||||
var callback unsafe.Pointer
|
||||
var iarg1 C.int
|
||||
var uarg1, uarg2 C.uint64_t
|
||||
rangeMode := false
|
||||
var insn C.int
|
||||
var insnMode bool
|
||||
switch htype {
|
||||
case HOOK_BLOCK, HOOK_CODE:
|
||||
rangeMode = true
|
||||
callback = C.hookCode_cgo
|
||||
case HOOK_MEM_READ, HOOK_MEM_WRITE, HOOK_MEM_READ | HOOK_MEM_WRITE:
|
||||
rangeMode = true
|
||||
callback = C.hookMemAccess_cgo
|
||||
case HOOK_INTR:
|
||||
callback = C.hookInterrupt_cgo
|
||||
case HOOK_INSN:
|
||||
iarg1 = C.int(extra[0])
|
||||
switch iarg1 {
|
||||
insn = C.int(extra[0])
|
||||
insnMode = true
|
||||
switch insn {
|
||||
case X86_INS_IN:
|
||||
callback = C.hookX86In_cgo
|
||||
case X86_INS_OUT:
|
||||
@ -93,7 +91,6 @@ func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) {
|
||||
// special case for mask
|
||||
if htype&(HOOK_MEM_READ_UNMAPPED|HOOK_MEM_WRITE_UNMAPPED|HOOK_MEM_FETCH_UNMAPPED|
|
||||
HOOK_MEM_READ_PROT|HOOK_MEM_WRITE_PROT|HOOK_MEM_FETCH_PROT) != 0 {
|
||||
rangeMode = true
|
||||
callback = C.hookMemInvalid_cgo
|
||||
} else {
|
||||
return 0, errors.New("Unknown hook type.")
|
||||
@ -102,16 +99,10 @@ func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) {
|
||||
var h2 C.uc_hook
|
||||
data := &HookData{u, cb}
|
||||
uptr := uintptr(unsafe.Pointer(data))
|
||||
if rangeMode {
|
||||
if len(extra) == 2 {
|
||||
uarg1 = C.uint64_t(extra[0])
|
||||
uarg2 = C.uint64_t(extra[1])
|
||||
} else {
|
||||
uarg1, uarg2 = 1, 0
|
||||
}
|
||||
C.uc_hook_add_u2(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), uarg1, uarg2)
|
||||
if insnMode {
|
||||
C.uc_hook_add_insn(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end), insn)
|
||||
} else {
|
||||
C.uc_hook_add_i1(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), iarg1)
|
||||
C.uc_hook_add_wrap(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end))
|
||||
}
|
||||
hookDataMap[uptr] = data
|
||||
hookToUintptr[Hook(h2)] = uptr
|
||||
|
@ -1,5 +1,5 @@
|
||||
uc_err uc_hook_add_i1(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, int arg1);
|
||||
uc_err uc_hook_add_u2(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t arg1, uint64_t arg2);
|
||||
uc_err uc_hook_add_wrap(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end);
|
||||
uc_err uc_hook_add_insn(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end, int insn);
|
||||
void hookCode_cgo(uc_engine *handle, uint64_t addr, uint32_t size, uintptr_t user);
|
||||
bool hookMemInvalid_cgo(uc_engine *handle, uc_mem_type type, uint64_t addr, int size, int64_t value, uintptr_t user);
|
||||
void hookMemAccess_cgo(uc_engine *handle, uc_mem_type type, uint64_t addr, int size, int64_t value, uintptr_t user);
|
||||
|
@ -25,22 +25,30 @@ func errReturn(err C.uc_err) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type MemRegion struct {
|
||||
Begin, End uint64
|
||||
Prot int
|
||||
}
|
||||
|
||||
type Unicorn interface {
|
||||
MemMap(addr, size uint64) error
|
||||
MemMapProt(addr, size uint64, prot int) error
|
||||
MemMapPtr(addr, size uint64, prot int, ptr unsafe.Pointer) error
|
||||
MemProtect(addr, size uint64, prot int) error
|
||||
MemUnmap(addr, size uint64) error
|
||||
MemRegions() ([]*MemRegion, error)
|
||||
MemRead(addr, size uint64) ([]byte, error)
|
||||
MemReadInto(dst []byte, addr uint64) error
|
||||
MemWrite(addr uint64, data []byte) error
|
||||
RegRead(reg int) (uint64, error)
|
||||
RegWrite(reg int, value uint64) error
|
||||
RegWriteMmr(reg int, value *X86Mmr) error
|
||||
Start(begin, until uint64) error
|
||||
StartWithOptions(begin, until uint64, options *UcOptions) error
|
||||
Stop() error
|
||||
HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error)
|
||||
HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) (Hook, error)
|
||||
HookDel(hook Hook) error
|
||||
Query(queryType int) (uint64, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
@ -103,6 +111,25 @@ func (u *uc) RegRead(reg int) (uint64, error) {
|
||||
return uint64(val), errReturn(ucerr)
|
||||
}
|
||||
|
||||
func (u *uc) MemRegions() ([]*MemRegion, error) {
|
||||
var regions *C.struct_uc_mem_region
|
||||
var count C.uint32_t
|
||||
ucerr := C.uc_mem_regions(u.handle, ®ions, &count)
|
||||
if ucerr != C.UC_ERR_OK {
|
||||
return nil, errReturn(ucerr)
|
||||
}
|
||||
ret := make([]*MemRegion, count)
|
||||
tmp := (*[1 << 30]C.struct_uc_mem_region)(unsafe.Pointer(regions))[:count]
|
||||
for i, v := range tmp {
|
||||
ret[i] = &MemRegion{
|
||||
Begin: uint64(v.begin),
|
||||
End: uint64(v.end),
|
||||
Prot: int(v.perms),
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (u *uc) MemWrite(addr uint64, data []byte) error {
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
@ -141,3 +168,9 @@ func (u *uc) MemProtect(addr, size uint64, prot int) error {
|
||||
func (u *uc) MemUnmap(addr, size uint64) error {
|
||||
return errReturn(C.uc_mem_unmap(u.handle, C.uint64_t(addr), C.size_t(size)))
|
||||
}
|
||||
|
||||
func (u *uc) Query(queryType int) (uint64, error) {
|
||||
var ret C.size_t
|
||||
ucerr := C.uc_query(u.handle, C.uc_query_type(queryType), &ret)
|
||||
return uint64(ret), errReturn(ucerr)
|
||||
}
|
||||
|
@ -37,3 +37,39 @@ func TestDoubleClose(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemRegions(t *testing.T) {
|
||||
mu, err := NewUnicorn(ARCH_X86, MODE_32)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = mu.MemMap(0x1000, 0x1000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
regions, err := mu.MemRegions()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(regions) != 1 {
|
||||
t.Fatalf("returned wrong number of regions: %d != 1", len(regions))
|
||||
}
|
||||
r := regions[0]
|
||||
if r.Begin != 0x1000 || r.End != 0x1fff || r.Prot != 7 {
|
||||
t.Fatalf("incorrect region: %#v", r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuery(t *testing.T) {
|
||||
mu, err := NewUnicorn(ARCH_ARM, MODE_THUMB)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mode, err := mu.Query(QUERY_MODE)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if mode != MODE_THUMB {
|
||||
t.Fatal("query returned invalid mode: %d != %d", mode, MODE_THUMB)
|
||||
}
|
||||
}
|
||||
|
26
bindings/go/unicorn/x86.go
Normal file
26
bindings/go/unicorn/x86.go
Normal file
@ -0,0 +1,26 @@
|
||||
package unicorn
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// #include <unicorn/unicorn.h>
|
||||
// #include <unicorn/x86.h>
|
||||
import "C"
|
||||
|
||||
type X86Mmr struct {
|
||||
Selector uint16
|
||||
Base uint64
|
||||
Limit uint32
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
func (u *uc) RegWriteMmr(reg int, value *X86Mmr) error {
|
||||
var val C.uc_x86_mmr
|
||||
val.selector = C.uint16_t(value.Selector)
|
||||
val.base = C.uint64_t(value.Base)
|
||||
val.limit = C.uint32_t(value.Limit)
|
||||
val.flags = C.uint32_t(value.Flags)
|
||||
ucerr := C.uc_reg_write(u.handle, C.int(reg), unsafe.Pointer(&val))
|
||||
return errReturn(ucerr)
|
||||
}
|
@ -96,7 +96,7 @@ func TestX86InOut(t *testing.T) {
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}, X86_INS_IN)
|
||||
}, 1, 0, X86_INS_IN)
|
||||
mu.HookAdd(HOOK_INSN, func(_ Unicorn, port, size, value uint32) {
|
||||
outCalled = true
|
||||
var err error
|
||||
@ -111,7 +111,7 @@ func TestX86InOut(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}, X86_INS_OUT)
|
||||
}, 1, 0, X86_INS_OUT)
|
||||
if err := mu.Start(ADDRESS, ADDRESS+uint64(len(code))); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -132,7 +132,7 @@ func TestX86Syscall(t *testing.T) {
|
||||
mu.HookAdd(HOOK_INSN, func(_ Unicorn) {
|
||||
rax, _ := mu.RegRead(X86_REG_RAX)
|
||||
mu.RegWrite(X86_REG_RAX, rax+1)
|
||||
}, X86_INS_SYSCALL)
|
||||
}, 1, 0, X86_INS_SYSCALL)
|
||||
mu.RegWrite(X86_REG_RAX, 0x100)
|
||||
err = mu.Start(ADDRESS, ADDRESS+uint64(len(code)))
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user