-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathreplace.go
75 lines (67 loc) · 1.62 KB
/
replace.go
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
package hookingo
import (
"reflect"
)
// HookCaller applies a group of hooks in the caller, by changing the relative
// address in some call instructions. It is not concurrent safe, need special
// attention.
type HookCaller interface {
// Disable disables the hooks and restores the calls to the original function,
// the hook can be enabled later using the returned Enabler.
Disable() Enabler
// Count returns the total number of modified call instructions. If the hooks
// are disabled, it returns 0.
Count() int
}
type hookCaller struct {
old uintptr
new uintptr
pos []uintptr
dis bool
}
func (h *hookCaller) Disable() Enabler {
setCall(h.pos, h.old)
h.dis = true
return &enableCaller{h: h}
}
func (h *hookCaller) Count() int {
if h.dis {
return 0
}
return len(h.pos)
}
type enableCaller struct {
h *hookCaller
}
func (e *enableCaller) Enable() {
setCall(e.h.pos, e.h.new)
e.h.dis = false
}
// Replace the calls to "old" with "new" in caller, without modify any instructions in "old"
func Replace(caller, old, new interface{}, limit int) (h HookCaller, err error) {
vf := reflect.ValueOf(old)
vt := reflect.ValueOf(new)
if vf.Type() != vt.Type() {
return nil, ErrDifferentType
}
if vf.Kind() != reflect.Func {
return nil, ErrInputType
}
vc := reflect.ValueOf(caller)
if vc.Kind() != reflect.Func {
return nil, ErrInputType
}
as, err := findCall(vc.Pointer(), vf.Pointer(), limit)
if err != nil {
return nil, err
}
if err = batchProtect(as); err != nil {
return nil, err
}
hk := &hookCaller{}
setCall(as, vt.Pointer())
hk.pos = as
hk.old = vf.Pointer()
hk.new = vt.Pointer()
return hk, nil
}