Merge pull request #444 from lunixbochs/master

catch up on Go bindings
This commit is contained in:
Nguyen Anh Quynh 2016-02-28 03:45:42 +08:00
commit 5ede98abec
7 changed files with 118 additions and 28 deletions

View File

@ -1,12 +1,16 @@
#include <unicorn/unicorn.h> #include <unicorn/unicorn.h>
#include "_cgo_export.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) { uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
return uc_hook_add(handle, h2, type, callback, (void *)user, arg1); 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) { 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, arg1, arg2); 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) { void hookCode_cgo(uc_engine *handle, uint64_t addr, uint32_t size, uintptr_t user) {

View File

@ -63,23 +63,21 @@ func hookX86Syscall(handle unsafe.Pointer, user unsafe.Pointer) {
hook.Callback.(func(Unicorn))(hook.Uc) 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 callback unsafe.Pointer
var iarg1 C.int var insn C.int
var uarg1, uarg2 C.uint64_t var insnMode bool
rangeMode := false
switch htype { switch htype {
case HOOK_BLOCK, HOOK_CODE: case HOOK_BLOCK, HOOK_CODE:
rangeMode = true
callback = C.hookCode_cgo callback = C.hookCode_cgo
case HOOK_MEM_READ, HOOK_MEM_WRITE, HOOK_MEM_READ | HOOK_MEM_WRITE: case HOOK_MEM_READ, HOOK_MEM_WRITE, HOOK_MEM_READ | HOOK_MEM_WRITE:
rangeMode = true
callback = C.hookMemAccess_cgo callback = C.hookMemAccess_cgo
case HOOK_INTR: case HOOK_INTR:
callback = C.hookInterrupt_cgo callback = C.hookInterrupt_cgo
case HOOK_INSN: case HOOK_INSN:
iarg1 = C.int(extra[0]) insn = C.int(extra[0])
switch iarg1 { insnMode = true
switch insn {
case X86_INS_IN: case X86_INS_IN:
callback = C.hookX86In_cgo callback = C.hookX86In_cgo
case X86_INS_OUT: case X86_INS_OUT:
@ -93,7 +91,6 @@ func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) {
// special case for mask // special case for mask
if htype&(HOOK_MEM_READ_UNMAPPED|HOOK_MEM_WRITE_UNMAPPED|HOOK_MEM_FETCH_UNMAPPED| 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 { HOOK_MEM_READ_PROT|HOOK_MEM_WRITE_PROT|HOOK_MEM_FETCH_PROT) != 0 {
rangeMode = true
callback = C.hookMemInvalid_cgo callback = C.hookMemInvalid_cgo
} else { } else {
return 0, errors.New("Unknown hook type.") 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 var h2 C.uc_hook
data := &HookData{u, cb} data := &HookData{u, cb}
uptr := uintptr(unsafe.Pointer(data)) uptr := uintptr(unsafe.Pointer(data))
if rangeMode { if insnMode {
if len(extra) == 2 { 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)
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)
} else { } 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 hookDataMap[uptr] = data
hookToUintptr[Hook(h2)] = uptr hookToUintptr[Hook(h2)] = uptr

View File

@ -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_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_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_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); 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); 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); void hookMemAccess_cgo(uc_engine *handle, uc_mem_type type, uint64_t addr, int size, int64_t value, uintptr_t user);

View File

@ -25,22 +25,30 @@ func errReturn(err C.uc_err) error {
return nil return nil
} }
type MemRegion struct {
Begin, End uint64
Prot int
}
type Unicorn interface { type Unicorn interface {
MemMap(addr, size uint64) error MemMap(addr, size uint64) error
MemMapProt(addr, size uint64, prot int) error MemMapProt(addr, size uint64, prot int) error
MemMapPtr(addr, size uint64, prot int, ptr unsafe.Pointer) error MemMapPtr(addr, size uint64, prot int, ptr unsafe.Pointer) error
MemProtect(addr, size uint64, prot int) error MemProtect(addr, size uint64, prot int) error
MemUnmap(addr, size uint64) error MemUnmap(addr, size uint64) error
MemRegions() ([]*MemRegion, error)
MemRead(addr, size uint64) ([]byte, error) MemRead(addr, size uint64) ([]byte, error)
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)
RegWrite(reg int, value uint64) error RegWrite(reg int, value uint64) error
RegWriteMmr(reg int, value *X86Mmr) error
Start(begin, until uint64) error Start(begin, until uint64) error
StartWithOptions(begin, until uint64, options *UcOptions) error StartWithOptions(begin, until uint64, options *UcOptions) error
Stop() 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 HookDel(hook Hook) error
Query(queryType int) (uint64, error)
Close() error Close() error
} }
@ -103,6 +111,25 @@ func (u *uc) RegRead(reg int) (uint64, error) {
return uint64(val), errReturn(ucerr) 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, &regions, &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 { func (u *uc) MemWrite(addr uint64, data []byte) error {
if len(data) == 0 { if len(data) == 0 {
return nil return nil
@ -141,3 +168,9 @@ func (u *uc) MemProtect(addr, size uint64, prot int) error {
func (u *uc) MemUnmap(addr, size uint64) 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))) 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)
}

View File

@ -37,3 +37,39 @@ func TestDoubleClose(t *testing.T) {
t.Fatal(err) 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)
}
}

View 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)
}

View File

@ -96,7 +96,7 @@ func TestX86InOut(t *testing.T) {
default: default:
return 0 return 0
} }
}, X86_INS_IN) }, 1, 0, X86_INS_IN)
mu.HookAdd(HOOK_INSN, func(_ Unicorn, port, size, value uint32) { mu.HookAdd(HOOK_INSN, func(_ Unicorn, port, size, value uint32) {
outCalled = true outCalled = true
var err error var err error
@ -111,7 +111,7 @@ func TestX86InOut(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
}, X86_INS_OUT) }, 1, 0, X86_INS_OUT)
if err := mu.Start(ADDRESS, ADDRESS+uint64(len(code))); err != nil { if err := mu.Start(ADDRESS, ADDRESS+uint64(len(code))); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -132,7 +132,7 @@ func TestX86Syscall(t *testing.T) {
mu.HookAdd(HOOK_INSN, func(_ Unicorn) { mu.HookAdd(HOOK_INSN, func(_ Unicorn) {
rax, _ := mu.RegRead(X86_REG_RAX) rax, _ := mu.RegRead(X86_REG_RAX)
mu.RegWrite(X86_REG_RAX, rax+1) mu.RegWrite(X86_REG_RAX, rax+1)
}, X86_INS_SYSCALL) }, 1, 0, X86_INS_SYSCALL)
mu.RegWrite(X86_REG_RAX, 0x100) mu.RegWrite(X86_REG_RAX, 0x100)
err = mu.Start(ADDRESS, ADDRESS+uint64(len(code))) err = mu.Start(ADDRESS, ADDRESS+uint64(len(code)))
if err != nil { if err != nil {