unicorn/bindings/go/unicorn/hook.go
2016-07-27 05:16:12 -07:00

130 lines
3.6 KiB
Go

package unicorn
import (
"errors"
"sync"
"unsafe"
)
/*
#include <unicorn/unicorn.h>
#include "hook.h"
*/
import "C"
type HookData struct {
Uc Unicorn
Callback interface{}
}
type Hook uint64
var hookDataLock sync.RWMutex
var hookDataMap = make(map[uintptr]*HookData)
func getHookData(user unsafe.Pointer) *HookData {
hookDataLock.RLock()
defer hookDataLock.RUnlock()
return hookDataMap[uintptr(user)]
}
//export hookCode
func hookCode(handle unsafe.Pointer, addr uint64, size uint32, user unsafe.Pointer) {
hook := getHookData(user)
hook.Callback.(func(Unicorn, uint64, uint32))(hook.Uc, uint64(addr), uint32(size))
}
//export hookMemInvalid
func hookMemInvalid(handle unsafe.Pointer, typ C.uc_mem_type, addr uint64, size int, value int64, user unsafe.Pointer) bool {
hook := getHookData(user)
return hook.Callback.(func(Unicorn, int, uint64, int, int64) bool)(hook.Uc, int(typ), addr, size, value)
}
//export hookMemAccess
func hookMemAccess(handle unsafe.Pointer, typ C.uc_mem_type, addr uint64, size int, value int64, user unsafe.Pointer) {
hook := getHookData(user)
hook.Callback.(func(Unicorn, int, uint64, int, int64))(hook.Uc, int(typ), addr, size, value)
}
//export hookInterrupt
func hookInterrupt(handle unsafe.Pointer, intno uint32, user unsafe.Pointer) {
hook := getHookData(user)
hook.Callback.(func(Unicorn, uint32))(hook.Uc, intno)
}
//export hookX86In
func hookX86In(handle unsafe.Pointer, port, size uint32, user unsafe.Pointer) uint32 {
hook := getHookData(user)
return hook.Callback.(func(Unicorn, uint32, uint32) uint32)(hook.Uc, port, size)
}
//export hookX86Out
func hookX86Out(handle unsafe.Pointer, port, size, value uint32, user unsafe.Pointer) {
hook := getHookData(user)
hook.Callback.(func(Unicorn, uint32, uint32, uint32))(hook.Uc, port, size, value)
}
//export hookX86Syscall
func hookX86Syscall(handle unsafe.Pointer, user unsafe.Pointer) {
hook := getHookData(user)
hook.Callback.(func(Unicorn))(hook.Uc)
}
func (u *uc) HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) (Hook, error) {
var callback unsafe.Pointer
var insn C.int
var insnMode bool
switch htype {
case HOOK_BLOCK, HOOK_CODE:
callback = C.hookCode_cgo
case HOOK_MEM_READ, HOOK_MEM_WRITE, HOOK_MEM_READ | HOOK_MEM_WRITE:
callback = C.hookMemAccess_cgo
case HOOK_INTR:
callback = C.hookInterrupt_cgo
case HOOK_INSN:
insn = C.int(extra[0])
insnMode = true
switch insn {
case X86_INS_IN:
callback = C.hookX86In_cgo
case X86_INS_OUT:
callback = C.hookX86Out_cgo
case X86_INS_SYSCALL, X86_INS_SYSENTER:
callback = C.hookX86Syscall_cgo
default:
return 0, errors.New("Unknown instruction type.")
}
default:
// 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 {
callback = C.hookMemInvalid_cgo
} else {
return 0, errors.New("Unknown hook type.")
}
}
var h2 C.uc_hook
data := &HookData{u, cb}
uptr := uintptr(unsafe.Pointer(data))
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_wrap(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end))
}
hookDataLock.Lock()
hookDataMap[uptr] = data
hookDataLock.Unlock()
u.hooks[Hook(h2)] = uptr
return Hook(h2), nil
}
func (u *uc) HookDel(hook Hook) error {
if uptr, ok := u.hooks[hook]; ok {
delete(u.hooks, hook)
hookDataLock.Lock()
delete(hookDataMap, uptr)
hookDataLock.Unlock()
}
return errReturn(C.uc_hook_del(u.handle, C.uc_hook(hook)))
}