...
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 "golang.org/x/sys/unix"
25 )
26
27 var endian = binary.LittleEndian
28
29 const syscallInstrSize = 4
30
31 const nrProcessVMReadv = 270
32 const nrProcessVMWritev = 271
33
34
35 const nrPRStatus = 1
36
37 func getIp(regs *syscall.PtraceRegs) uintptr {
38 return uintptr(regs.Pc)
39 }
40
41 func getRegs(pid int, regsout *syscall.PtraceRegs) error {
42 err := unix.PtraceGetRegSetArm64(pid, nrPRStatus, (*unix.PtraceRegsArm64)(regsout))
43 if err != nil {
44 return errors.Wrapf(err, "get registers of process %d", pid)
45 }
46 return nil
47 }
48
49 func setRegs(pid int, regs *syscall.PtraceRegs) error {
50 err := unix.PtraceSetRegSetArm64(pid, nrPRStatus, (*unix.PtraceRegsArm64)(regs))
51 if err != nil {
52 return errors.Wrapf(err, "set registers of process %d", pid)
53 }
54 return nil
55 }
56
57
58 func (p *TracedProgram) Syscall(number uint64, args ...uint64) (uint64, error) {
59
60 err := p.Protect()
61 if err != nil {
62 return 0, err
63 }
64
65 var regs syscall.PtraceRegs
66
67 err = getRegs(p.pid, ®s)
68 if err != nil {
69 return 0, err
70 }
71
72
73
74 regs.Regs[8] = number
75 for index, arg := range args {
76
77 if index > 6 {
78 return 0, errors.New("too many arguments for a syscall")
79 } else {
80 regs.Regs[index] = arg
81 }
82 }
83 err = setRegs(p.pid, ®s)
84 if err != nil {
85 return 0, err
86 }
87
88 instruction := make([]byte, syscallInstrSize)
89 ip := getIp(p.backupRegs)
90
91
92
93 endian.PutUint32(instruction, 0xd4000001)
94 _, err = syscall.PtracePokeData(p.pid, ip, instruction)
95 if err != nil {
96 return 0, errors.Wrapf(err, "writing data %v to %x", instruction, ip)
97 }
98
99
100 err = p.Step()
101 if err != nil {
102 return 0, err
103 }
104
105
106 err = getRegs(p.pid, ®s)
107 if err != nil {
108 return 0, err
109 }
110
111 return regs.Regs[0], p.Restore()
112 }
113
114
115 func (p *TracedProgram) JumpToFakeFunc(originAddr uint64, targetAddr uint64) error {
116 instructions := make([]byte, 16)
117
118
119
120
121 endian.PutUint32(instructions[0:], 0x58000049)
122 endian.PutUint32(instructions[4:], 0xD61F0120)
123
124 endian.PutUint64(instructions[8:], targetAddr)
125
126 return p.PtraceWriteSlice(originAddr, instructions)
127 }
128