commit
5ede98abec
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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, ®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 {
|
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)
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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:
|
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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user