-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathreplace.go
More file actions
77 lines (69 loc) · 1.74 KB
/
replace.go
File metadata and controls
77 lines (69 loc) · 1.74 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
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 the first "length" bytes of caller,
// without modify any instruction in "old". When "length" is negative, it will
// return at the first return instruction in the caller.
func Replace(caller, old, new interface{}, length 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(), length)
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
}