forked from brahma-adshonor/gohook
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hook.go
172 lines (139 loc) · 3.92 KB
/
hook.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
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
162
163
164
165
166
167
168
169
170
171
172
package gohook
import (
"bytes"
"errors"
"fmt"
"reflect"
"unsafe"
)
type HookInfo struct {
Mode int
Info *CodeInfo
Target reflect.Value
Replacement reflect.Value
Trampoline reflect.Value
}
var (
archMode = 64
g_all = make(map[uintptr]HookInfo)
)
func init() {
sz := unsafe.Sizeof(uintptr(0))
if sz == 4 {
archMode = 32
}
}
func GetArchMode() int {
return archMode
}
// valueStruct is taken from runtime source code.
// it may be changed in later release
type valueStruct struct {
typ uintptr
ptr uintptr
}
func getDataPtrFromValue(v reflect.Value) uintptr {
return (uintptr)((*valueStruct)(unsafe.Pointer(&v)).ptr)
}
func ShowDebugInfo() string {
buff := bytes.NewBuffer(make([]byte, 0, 256))
for k, v := range g_all {
s := fmt.Sprintf("hook function at addr:%x, how:%s, num of instruction fixed:%d\n", k, v.Info.How, len(v.Info.Fix))
buff.WriteString(s)
for _, f := range v.Info.Fix {
s = fmt.Sprintf("==@%08x new inst:", f.Addr)
buff.WriteString(s)
for _, c := range f.Code {
s = fmt.Sprintf("%02x ", c)
buff.WriteString(s)
}
s = fmt.Sprintf("\n")
buff.WriteString(s)
}
}
return string(buff.Bytes())
}
func Hook(target, replacement, trampoline interface{}) error {
t := reflect.ValueOf(target)
r := reflect.ValueOf(replacement)
t2 := reflect.ValueOf(trampoline)
return doHook(archMode, false, t, r, t2)
}
func HookByIndirectJmp(target, replacement, trampoline interface{}) error {
t := reflect.ValueOf(target)
r := reflect.ValueOf(replacement)
t2 := reflect.ValueOf(trampoline)
return doHook(archMode, true, t, r, t2)
}
func UnHook(target interface{}) error {
t := reflect.ValueOf(target)
return doUnHook(t.Pointer())
}
func HookMethod(instance interface{}, method string, replacement, trampoline interface{}) error {
target := reflect.TypeOf(instance)
m, ok := target.MethodByName(method)
if !ok {
return fmt.Errorf("unknown method %s.%s()", target.Name(), method)
}
r := reflect.ValueOf(replacement)
t := reflect.ValueOf(trampoline)
return doHook(archMode, false, m.Func, r, t)
}
func UnHookMethod(instance interface{}, methodName string) error {
target := reflect.TypeOf(instance)
m, ok := target.MethodByName(methodName)
if !ok {
return errors.New(fmt.Sprintf("unknown method %s", methodName))
}
return UnHook(m.Func.Interface())
}
func doUnHook(target uintptr) error {
info, ok := g_all[target]
if !ok {
return errors.New("target not exist")
}
CopyInstruction(target, info.Info.Origin)
if info.Info.How == "fix" {
for _, v := range info.Info.Fix {
CopyInstruction(v.Addr, v.Code)
}
}
if info.Trampoline.IsValid() {
CopyInstruction(info.Trampoline.Pointer(), info.Info.TrampolineOrig)
}
delete(g_all, target)
return nil
}
func doHook(mode int, rdxIndirect bool, target, replacement, trampoline reflect.Value) error {
if target.Kind() != reflect.Func {
return fmt.Errorf("target must be a Func")
}
if replacement.Kind() != reflect.Func {
return fmt.Errorf("replacement must be a Func")
}
if target.Type() != replacement.Type() {
return fmt.Errorf("target and replacement must have the same type %s != %s", target.Type().Name(), replacement.Type().Name())
}
tp := uintptr(0)
if trampoline.IsValid() {
if trampoline.Kind() != reflect.Func {
return fmt.Errorf("replacement must be a Func")
}
if target.Type() != trampoline.Type() {
return fmt.Errorf("target and trampoline must have the same type %s != %s", target.Type().Name(), trampoline.Type().Name())
}
tp = trampoline.Pointer()
}
doUnHook(target.Pointer())
replaceAddr := replacement.Pointer()
if rdxIndirect {
// get data ptr out of a reflect value.
replaceAddr = getDataPtrFromValue(replacement)
}
info, err := hookFunction(mode, rdxIndirect, target.Pointer(), replaceAddr, tp)
if err != nil {
return err
}
g_all[target.Pointer()] = HookInfo{Mode: mode, Info: info, Target: target, Replacement: replacement, Trampoline: trampoline}
return nil
}