From 693719e732042469e4f5b745698b765d8af317b3 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 10:50:51 -0800 Subject: [PATCH 1/5] Go: update hook interface --- bindings/go/unicorn/hook.c | 12 ++++++++---- bindings/go/unicorn/hook.go | 27 +++++++++------------------ bindings/go/unicorn/hook.h | 4 ++-- bindings/go/unicorn/unicorn.go | 2 +- 4 files changed, 20 insertions(+), 25 deletions(-) diff --git a/bindings/go/unicorn/hook.c b/bindings/go/unicorn/hook.c index 4ed41b51..a2b7dc93 100644 --- a/bindings/go/unicorn/hook.c +++ b/bindings/go/unicorn/hook.c @@ -1,12 +1,16 @@ #include #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) { diff --git a/bindings/go/unicorn/hook.go b/bindings/go/unicorn/hook.go index d5dfc874..6591c46c 100644 --- a/bindings/go/unicorn/hook.go +++ b/bindings/go/unicorn/hook.go @@ -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_wrap(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end)) } else { - C.uc_hook_add_i1(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), iarg1) + 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) } hookDataMap[uptr] = data hookToUintptr[Hook(h2)] = uptr diff --git a/bindings/go/unicorn/hook.h b/bindings/go/unicorn/hook.h index 6c209516..35813a0a 100644 --- a/bindings/go/unicorn/hook.h +++ b/bindings/go/unicorn/hook.h @@ -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); diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 4f6f1f99..1f3e9094 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -39,7 +39,7 @@ type Unicorn interface { 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 Close() error } From 475c8de3dec65f1d90928e2665d767ee91880bfd Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 10:55:40 -0800 Subject: [PATCH 2/5] Go: update test hooks --- bindings/go/unicorn/hook.go | 4 ++-- bindings/go/unicorn/x86_test.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bindings/go/unicorn/hook.go b/bindings/go/unicorn/hook.go index 6591c46c..0a1a7d6f 100644 --- a/bindings/go/unicorn/hook.go +++ b/bindings/go/unicorn/hook.go @@ -100,9 +100,9 @@ func (u *uc) HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) data := &HookData{u, cb} uptr := uintptr(unsafe.Pointer(data)) if insnMode { - 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)) - } else { 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_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 diff --git a/bindings/go/unicorn/x86_test.go b/bindings/go/unicorn/x86_test.go index 67400552..aca1d3be 100644 --- a/bindings/go/unicorn/x86_test.go +++ b/bindings/go/unicorn/x86_test.go @@ -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 { From 74f783a27419d22da3c4e653aba48466a703929a Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 10:51:10 -0800 Subject: [PATCH 3/5] Go: add x86 RegWriteMmr method --- bindings/go/unicorn/unicorn.go | 1 + bindings/go/unicorn/x86.go | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 bindings/go/unicorn/x86.go diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 1f3e9094..2076fb88 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -36,6 +36,7 @@ type Unicorn interface { 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 diff --git a/bindings/go/unicorn/x86.go b/bindings/go/unicorn/x86.go new file mode 100644 index 00000000..490f7dfa --- /dev/null +++ b/bindings/go/unicorn/x86.go @@ -0,0 +1,26 @@ +package unicorn + +import ( + "unsafe" +) + +// #include +// #include +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) +} From 9f1603c15753016b8636b4be3ae1b40169c0119d Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 11:10:15 -0800 Subject: [PATCH 4/5] Go: add MemRegions --- bindings/go/unicorn/unicorn.go | 25 +++++++++++++++++++++++++ bindings/go/unicorn/unicorn_test.go | 22 ++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 2076fb88..1500627a 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -25,12 +25,18 @@ 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 @@ -104,6 +110,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 diff --git a/bindings/go/unicorn/unicorn_test.go b/bindings/go/unicorn/unicorn_test.go index caf13126..58e78431 100644 --- a/bindings/go/unicorn/unicorn_test.go +++ b/bindings/go/unicorn/unicorn_test.go @@ -37,3 +37,25 @@ 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) + } +} From 43eb9ec351c5998be0504fa39e82a8f7882a7a94 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sat, 27 Feb 2016 11:15:06 -0800 Subject: [PATCH 5/5] Go: add uc_query api --- bindings/go/unicorn/unicorn.go | 7 +++++++ bindings/go/unicorn/unicorn_test.go | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 1500627a..ecaa6336 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -48,6 +48,7 @@ type Unicorn interface { Stop() error HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) (Hook, error) HookDel(hook Hook) error + Query(queryType int) (uint64, error) Close() error } @@ -167,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) +} diff --git a/bindings/go/unicorn/unicorn_test.go b/bindings/go/unicorn/unicorn_test.go index 58e78431..6627528f 100644 --- a/bindings/go/unicorn/unicorn_test.go +++ b/bindings/go/unicorn/unicorn_test.go @@ -59,3 +59,17 @@ func TestMemRegions(t *testing.T) { 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) + } +}