-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathhook.go
More file actions
161 lines (142 loc) · 4.17 KB
/
Copy pathhook.go
File metadata and controls
161 lines (142 loc) · 4.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
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
type fastHookMap struct {
vals []*HookData
sync.RWMutex
}
func (m *fastHookMap) insert(h *HookData) uintptr {
// don't change this to defer
m.Lock()
for i, v := range m.vals {
if v == nil {
m.vals[i] = h
m.Unlock()
return uintptr(i)
}
}
i := len(m.vals)
m.vals = append(m.vals, h)
m.Unlock()
return uintptr(i)
}
func (m *fastHookMap) get(i unsafe.Pointer) *HookData {
m.RLock()
// TODO: nil check?
v := m.vals[uintptr(i)]
m.RUnlock()
return v
}
func (m *fastHookMap) remove(i uintptr) {
m.Lock()
m.vals[i] = nil
m.Unlock()
}
var hookMap fastHookMap
//export hookCode
func hookCode(handle unsafe.Pointer, addr uint64, size uint32, user unsafe.Pointer) {
hook := hookMap.get(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 := hookMap.get(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 := hookMap.get(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 := hookMap.get(user)
hook.Callback.(func(Unicorn, uint32))(hook.Uc, intno)
}
//export hookX86In
func hookX86In(handle unsafe.Pointer, port, size uint32, user unsafe.Pointer) uint32 {
hook := hookMap.get(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 := hookMap.get(user)
hook.Callback.(func(Unicorn, uint32, uint32, uint32))(hook.Uc, port, size, value)
}
//export hookX86Syscall
func hookX86Syscall(handle unsafe.Pointer, user unsafe.Pointer) {
hook := hookMap.get(user)
hook.Callback.(func(Unicorn))(hook.Uc)
}
//export hookX86Cpuid
func hookX86Cpuid(handle unsafe.Pointer, user unsafe.Pointer) bool {
hook := hookMap.get(user)
return hook.Callback.(func(Unicorn) bool)(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
case X86_INS_CPUID, X86_INS_RDTSC, X86_INS_RDTSCP:
callback = C.hookX86Cpuid_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 := hookMap.insert(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))
}
// TODO: could move Hook and uptr onto HookData and just return it
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)
hookMap.remove(uptr)
}
return errReturn(C.uc_hook_del(u.handle, C.uc_hook(hook)))
}