...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package ptrace
18
19 import (
20 "encoding/binary"
21 "syscall"
22
23 "github.com/pkg/errors"
24 )
25
26 var endian = binary.LittleEndian
27
28 const syscallInstrSize = 2
29
30 const nrProcessVMReadv = 310
31 const nrProcessVMWritev = 311
32
33 func getIp(regs *syscall.PtraceRegs) uintptr {
34 return uintptr(regs.Rip)
35 }
36
37 func getRegs(pid int, regsout *syscall.PtraceRegs) error {
38 err := syscall.PtraceGetRegs(pid, regsout)
39 if err != nil {
40 return errors.Wrapf(err, "get registers of process %d", pid)
41 }
42
43 return nil
44 }
45
46 func setRegs(pid int, regs *syscall.PtraceRegs) error {
47 err := syscall.PtraceSetRegs(pid, regs)
48 if err != nil {
49 return errors.Wrapf(err, "set registers of process %d", pid)
50 }
51
52 return nil
53 }
54
55
56 func (p *TracedProgram) Syscall(number uint64, args ...uint64) (uint64, error) {
57
58 err := p.Protect()
59 if err != nil {
60 return 0, err
61 }
62
63 var regs syscall.PtraceRegs
64
65 err = getRegs(p.pid, ®s)
66 if err != nil {
67 return 0, err
68 }
69
70
71
72
73 regs.Rax = number
74 for index, arg := range args {
75
76 if index == 0 {
77 regs.Rdi = arg
78 } else if index == 1 {
79 regs.Rsi = arg
80 } else if index == 2 {
81 regs.Rdx = arg
82 } else if index == 3 {
83 regs.R10 = arg
84 } else if index == 4 {
85 regs.R8 = arg
86 } else if index == 5 {
87 regs.R9 = arg
88 } else {
89 return 0, errors.New("too many arguments for a syscall")
90 }
91 }
92 err = setRegs(p.pid, ®s)
93 if err != nil {
94 return 0, err
95 }
96
97 instruction := make([]byte, syscallInstrSize)
98 ip := getIp(p.backupRegs)
99
100
101
102 binary.LittleEndian.PutUint16(instruction, 0x050f)
103 _, err = syscall.PtracePokeData(p.pid, ip, instruction)
104 if err != nil {
105 return 0, errors.Wrapf(err, "writing data %v to %x", instruction, ip)
106 }
107
108
109 err = p.Step()
110 if err != nil {
111 return 0, err
112 }
113
114
115 err = getRegs(p.pid, ®s)
116 if err != nil {
117 return 0, err
118 }
119
120
121 return regs.Rax, p.Restore()
122 }
123
124
125 func (p *TracedProgram) JumpToFakeFunc(originAddr uint64, targetAddr uint64) error {
126 instructions := make([]byte, 16)
127
128
129
130 instructions[0] = 0x48
131 instructions[1] = 0xb8
132 endian.PutUint64(instructions[2:10], targetAddr)
133 instructions[10] = 0xff
134 instructions[11] = 0xe0
135
136 return p.PtraceWriteSlice(originAddr, instructions)
137 }
138