forked from pmmp/bds-modding-devkit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtracer.py
More file actions
executable file
·141 lines (130 loc) · 4.88 KB
/
Copy pathtracer.py
File metadata and controls
executable file
·141 lines (130 loc) · 4.88 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
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
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import frida
import sys
import json
import argparse
import subprocess
import base64
import time
def validateMode(mode):
if mode not in 'rw':
raise argparse.ArgumentTypeError('Unknown mode')
return mode
parser = argparse.ArgumentParser(description='bedrock_server packet tracer')
parser.add_argument('mode', help='"r" - read, "w" - write', type=validateMode)
parser.add_argument('processName', default='bedrock_server_symbols.debug')
args = parser.parse_args()
stopped = False
try:
session = frida.attach(args.processName)
except frida.ProcessNotFoundError:
sys.exit('Could not find bedrock_server process')
except frida.PermissionDeniedError as e:
sys.exit(e)
logpath = './packets_' + str(time.time()) + '.txt'
logfile = open(logpath, 'wb')
def onMessage(message, data):
if message['type'] == 'error':
print(message['stack'])
return
try:
logfile.write(str.encode(message['payload']) + b':' + base64.b64encode(data) + b'\n')
except:
print(message)
def onExit():
print("Server process died!\n")
global stopped
stopped = True
try:
script = session.create_script("""recv('input', function(message) {
var mode = message.mode;
var doRead = mode.includes('r');
var doWrite = mode.includes('w');
var file = message.file;
var count = 0;
var lib = Process.getModuleByName(file);
for (const exportedFunc of lib.enumerateSymbols(file)) {
if (exportedFunc.type !== 'function') {
continue;
}
if (!exportedFunc.name.includes('Packet')) {
continue;
}
if (doRead && !exportedFunc.name.startsWith('_ZN6Packet') && ( //exclude generic encode
exportedFunc.name.endsWith('Packet4readER20ReadOnlyBinaryStream') ||
exportedFunc.name.endsWith('Packet5_readER20ReadOnlyBinaryStream') ||
exportedFunc.name.endsWith('Packet5_readER20ReadOnlyBinaryStreamRKN6cereal13ReflectionCtxE')
)) {
console.log("Hooking function " + exportedFunc.name);
Interceptor.attach(exportedFunc.address, {
onEnter: function(args) {
//this used to be arg1, but changed to arg2 in 1.20
//perhaps some return-over-stack compiler optimisation generated more args?
this.pointer = args[2];
},
onLeave: function(retval) {
//read from std::string_view in 1.21.50
var baseAddr = this.pointer.add(32);
var bufferAddr = baseAddr;
var rlen = baseAddr.add(8).readULong();
var bytes = bufferAddr.readPointer().readByteArray(rlen);
if (bytes === null) {
console.log("Unexpected null payload from " + exportedFunc.name);
} else {
send('read', bytes);
}
}
});
count++;
}
if (doWrite && !exportedFunc.name.startsWith('_ZNK6Packet') && (
exportedFunc.name.endsWith('Packet5writeER12BinaryStream') ||
exportedFunc.name.endsWith('Packet26writeWithSerializationModeER12BinaryStreamRKN6cereal13ReflectionCtxENSt3__18optionalI17SerializationModeEE')
)) {
console.log("Hooking function " + exportedFunc.name);
try{
Interceptor.attach(exportedFunc.address, {
onEnter: function(args) {
this.pointer = args[1];
},
onLeave: function(retval) {
//read from std::string_view in 1.21.50
var baseAddr = this.pointer.add(32);
var bufferAddr = baseAddr;
var rlen = baseAddr.add(8).readULong();
var bytes = bufferAddr.readPointer().readByteArray(rlen);
if (bytes === null) {
console.log("Unexpected null payload from " + exportedFunc.name);
} else {
send('write', bytes);
}
}
});
count++;
} catch (e) {
console.log("Error intercepting function " + exportedFunc.name + ": " + e.toString());
}
}
}
console.log("Hooked " + count + " functions. Ready.");
});
""")
script.on('message', onMessage)
script.load()
script.post({
'type': 'input',
'mode': args.mode,
'file': args.processName
})
session.on('detached', onExit)
print("Tracer setup, waiting for data\n")
while not stopped:
time.sleep(1)
logfile.close()
print('Packet logs written to ' + logpath)
print("Bye\n")
sys.exit(0)
except KeyboardInterrupt:
logfile.close()
sys.exit(0)