-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathpro.lua
More file actions
329 lines (306 loc) · 11.9 KB
/
pro.lua
File metadata and controls
329 lines (306 loc) · 11.9 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
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
-- pro protocol
pro_proto = Proto("pro","Pokemon Revolution Offline protocol")
--[[
give pecha berry to pokemon 1 (will swap the item if needed):
/giveitem 1, 525
take item of Pokemon 1
/takeitem 1
]]--
Packet = {header, description, parameters = {}}
function Packet:new(o)
o = o or {} -- create object if user does not provide one
setmetatable(o, self)
self.__index = self
self.header = o[1]
self.description = o[2]
self.parameters = o[3]
return o
end
clientToServerPacketInfos = {
Packet.new{"N", "Talk to NPC", {"NPC ID"}},
-- param a to receive details
-- param l to receive the list
Packet.new{"p", "Request Pokedex", "a: details, l: list"},
Packet.new{"h", "Evolution accept"},
Packet.new{"j", "Evolution cancel"},
Packet.new{"+", "Login"},
Packet.new{"(", "Battle action"},
Packet.new{"R", "Dialogue choice"},
Packet.new{"M", "PC"},
Packet.new{"?", "Reorder pokemon"},
Packet.new{"}", "[DEPRECATED] Move", {"Direction"}},
Packet.new{"#", "Move", {"Direction"}},
-- This does the same as '{' to send a chat message but in practice is only used for surf, destroy and dive commands
Packet.new{"w", "Send surf, destroy and dive"},
Packet.new{"a", "Shop move learner"},
Packet.new{".", "Shop egg learner"},
Packet.new{"c", "Shop pokemart"},
--[[
#155 Escape Rope
> *|.|155|.\
> -|.\
> k|.|pokecenter lavender|.\
> S|.\
> *|.|317|.|1|.\ use item 317 (HM01 - Cut) on Pokemon 1
< ^|.|348|.|Cut|.|1|.|30|.\
> ^|.|1|.|1|.\ make pokemon1 forget attack1
- 8/10/15 useItem out of combat
- 2/13/14/3/9 useItem on Pokemon out of combat
- 5 useItem in combat
- 2 useItem on Pokemon in combat
]]--
Packet.new{"*", "Use item"},
Packet.new{":", "Guild logo"},
Packet.new{"mb", "Valid action"},
Packet.new{"l", "Purchase coin"},
Packet.new{"]", "Purchase guild logo"},
Packet.new{"z", "Purchase egg move"},
Packet.new{"b", "Purchase move"},
Packet.new{"RE", "Send report"},
Packet.new{"f", "Show friend"},
Packet.new{"ah", "Ban"},
Packet.new{"btt", "Ban speedhack"},
Packet.new{"id", "Ban injection"},
Packet.new{"sh", "Ban speedhack"},
-- when entering a new zone or interacting with an NPC
Packet.new{"S", "Synchronize character"},
Packet.new{"-", "Ask NPC refresh"},
-- k|.|pokecenter lavender|.\
Packet.new{"k", "Request wild pokemon map", {"Map name"}},
-- follow an instruction like Use Item (*)
Packet.new{"^", "Teach move", {"PokemonUid", "MoveUid"}},
Packet.new{"{", "Send message", {"Message"}},
Packet.new{"1", "Heartbeat 1 (anti-cheat)"},
-- Was used to ask the server to refresh the player on the other client around
Packet.new{"2", "Heartbeat 2 (anti-cheat)"},
Packet.new{"x", "Ready for Battle"},
-- for any ping
Packet.new{"_", "Pong"},
-- only for "'" request
Packet.new{"'", "Pong '"},
Packet.new{"M", "Request PC box"},
Packet.new{")", "Login success" },
-- just a guess
Packet.new{"g", "Send online info to friend" },
Packet.new{"=", "Show mailbox" },
Packet.new{"<", "Move move up" },
Packet.new{">", "Move move down" },
Packet.new{",", "Reset IVs" },
Packet.new{"RE", "Send report" }
}
serverToClientPacketInfos = {
Packet.new{"w", "Chat message", {"Message"}},
Packet.new{".", "Ping ."},
Packet.new{"-", "???"},
Packet.new{"U", "[OBSOLETE] Other player info", {{"Nickname"}}},
Packet.new{"E", "Game time"},
Packet.new{"i", "Character informations"},
Packet.new{"(", "Cooldowns ???"},
Packet.new{"]", "Guild logo add"},
Packet.new{";", "Guild logo remove"},
Packet.new{"o", "Handle shop"},
Packet.new{"l", "Move relearn"},
Packet.new{",", "Egg move relearn"},
Packet.new{"7", "Error rising badge"}, -- You will be unable to use Pokemon from other regions in this region until you earn the Rising Badge!
Packet.new{"8", "Error invalid region trade"}, -- The person you are trading with can not take Pokemon from another region.
Packet.new{"9", "Error trade pokemon quest item"}, -- You can not trade a Pokemon that it is holding a Quest Item.
Packet.new{"0", "Error trade legendary"}, -- You can not trade a Legendary Pokemon.
Packet.new{"'", "Ping '"},
Packet.new{"k", "Map wild pokemon"},
Packet.new{"x", "Pokemon happyness"},
Packet.new{"p", "Pokedex message"},
Packet.new{"t", "Trade"},
Packet.new{"tb", "Trade accept? with args"},
Packet.new{"tu", "Trade update"},
Packet.new{"ta", "Trade accept"},
Packet.new{"tc", "Trade cancel"},
Packet.new{"m", "Start combat"},
Packet.new{"h", "Evolution"},
Packet.new{"z", "Receive position"},
Packet.new{"pm", "Private message"},
Packet.new{"&", "Item list"},
Packet.new{"^", "Learning move"},
Packet.new{"mb", "Action condition"},
Packet.new{"!", "Show battle"},
Packet.new{"@", "NPC"},
Packet.new{"*", "NPC list"},
Packet.new{"a", "Battle text"},
Packet.new{"$", "Use bike", 1, "always 1?"},
Packet.new{"%", "Use surf"},
Packet.new{"r", "Handle script"},
Packet.new{"c", "Chat create channel"},
Packet.new{"g", "Friend connection alert"},
Packet.new{"f", "Friend list sort"},
Packet.new{"[", "Roster sort"},
Packet.new{"e", "Send meteo"},
Packet.new{"u", "???"},
Packet.new{"S", "Avatar location"},
Packet.new{"s", "???"},
Packet.new{"q", "Map load"},
Packet.new{"y", "Guild info"},
Packet.new{"i", "Guild join"},
Packet.new{"d", "Money"},
Packet.new{"(", "Fishing cooldown"},
Packet.new{"5", "Login (ping _)"},
Packet.new{"6", "Login invalid user"},
Packet.new{"1", "Create NPC"},
Packet.new{")", "Login queue (ping _)"},
Packet.new{"R", "Dialogue"},
Packet.new{"#", "Profile update"},
Packet.new{"C", "Channel list", {{"Count", "ID", "Name"}}},
Packet.new{"=", "Other player info", {{"Nickname", "x", "y"}}},
Packet.new{"<", "Inspection info", {{"Nickname", "Wins", "Losses", "Disconnects", "Subscription date", "?", "Play time", "Total Pokemon", "Appearance"}}}
}
local endOfPacket = "%.\\\r\n"
function dissectParameters(packetInfo, packetTree, data, offset, packet)
local parameterId = 1
local index = 0
while true do
-- no regexp in Lua, its pattern matching has some limitations
local parameterStart, parameterEnd, parameter = packet:find("(.-|)%.|", index)
if parameter == nil then
parameterStart, parameterEnd, parameter = packet:find("(.-|)%.\\", index)
end
-- do not even try to understand this, just because a Lua array starts at 1 it is a freaking mess
local loffset = 1
if parameter == nil then break end
local subParams = {}
local subIndex = 0
local subId = 1
while true do
local subParameterStart, subParameterEnd, subParameter = parameter:find("(.-)|", subIndex)
if subParameter == nil then break end
subParams[subId] = {subParameterStart, subParameterEnd, subParameter}
subIndex = subParameterEnd + 1
subId = subId + 1
end
-- parameter:sub(1, parameter:len() - 1) remove the trailing '|'
local parameterName = "Parameter" .. parameterId
local subParametersNames
if packetInfo.parameters ~= nil
and packetInfo.parameters[parameterId] ~= nil
then
if type(packetInfo.parameters[parameterId]) == "string" then
parameterName = packetInfo.parameters[parameterId]
elseif type(packetInfo.parameters[parameterId]) == "table" then
subParametersNames = packetInfo.parameters[parameterId]
end
end
local subParamsTree = packetTree:add(data.buffer(offset + parameterStart + loffset, parameter:len() - 1),
parameterName .. ": " .. parameter:sub(1, parameter:len() - 1))
if #subParams > 1 then
local i = 1
while i <= #subParams do
local iString = "" .. i
if i < 10 then
istring = "0" .. iString
end
-- loffset - 1 because the subParameterStart was starting at 1
local subParameterName = "SubParameter" .. iString
if subParametersNames ~= nil
and subParametersNames[i] ~= nil
and type(subParametersNames[i]) == "string"
then
subParameterName = subParametersNames[i]
end
subParamsTree:add(data.buffer(offset + parameterStart + loffset - 1 + subParams[i][1], subParams[i][3]:len()),
subParameterName .. ": " .. subParams[i][3])
i = i + 1
end
end
parameterId = parameterId + 1
index = parameterEnd + 1
end
end
function dissectPacket(packetInfo, data, packetStart, packetEnd, packet, headersFound)
local packetTree = data.tree:add(data.buffer(packetStart - 1, packetEnd - packetStart), "Description: " .. packetInfo.description)
packetTree:add(data.buffer(packetStart - 1, packetInfo.header:len()), "Header: " .. packetInfo.header)
local parametersStart, parametersEnd, parameters
if packetInfo.header == "U" then
parametersStart, parametersEnd, parameters = packet:find("U(.*)")
parametersStart = parametersStart - 3
else
parametersStart, parametersEnd, parameters = packet:find(".-|%.|(.*)")
end
if parameters ~= nil then
dissectParameters(packetInfo, packetTree, data, packetStart + parametersStart, parameters)
end
packetTree:add(data.buffer(packetStart - 1, packetEnd - packetStart), "Packet: " .. packet)
packetFound = true
localPacketFound = true
if headersFound[packetInfo.description] == nil then
headersFound[packetInfo.description] = 0
end
headersFound[packetInfo.description] = headersFound[packetInfo.description] + 1
end
function bindPacket(packetList, data)
local packetFound = false
local index = 1
local headersFound = {}
while true do
local packetStart, packetEnd, packet = data.proData:find("(.-" .. endOfPacket .. ")", index)
if packet == nil then break end
local localPacketFound = false
for i, packetInfo in ipairs(packetList) do
if packet:find(packetInfo.header .. "|", 1, true) == 1 then
dissectPacket(packetInfo, data, packetStart, packetEnd, packet, headersFound)
packetFound = true
localPacketFound = true
break
end
end
if localPacketFound == false and packet:find(serverToClientPacketInfos[4].header, 1, true) == 1 then
dissectPacket(serverToClientPacketInfos[4], data, packetStart, packetEnd, packet, headersFound)
packetFound = true
localPacketFound = true
elseif localPacketFound == false then
local headerStart, headerEnd, header = packet:find("(.-|)", index)
dissectPacket(Packet:new{header, "UNKNOWN"}, data, packetStart, packetEnd, packet, headersFound)
end
index = packetEnd + 1
end
index = 1
for headerName, headerCount in pairs(headersFound) do
if index ~= 1 then
data.infoField = data.infoField .. "|"
end
data.infoField = data.infoField .. headerName
if headerCount > 1 then
data.infoField = data.infoField .. [[(x]] .. headerCount .. [[)]]
end
index = index + 1
end
return packetFound
end
-- create a function to dissect it
function pro_proto.dissector(buffer,pinfo,tree)
pinfo.cols.protocol = "PRO"
local data = {
buffer = buffer,
pinfo = pinfo,
proData = "",
tree = tree:add(pro_proto, buffer(), "PRO Protocol ProData"),
infoField = ""
}
local i = 0
while i < buffer:len() do
data.proData = data.proData .. string.char(bit.bxor(buffer(i,1):uint(), 1))
i = i + 1
end
local packetFound = false
if pinfo.src_port == 800 then
data.infoField = "[s]"
data.tree:add(buffer(0,buffer:len()), "server -> client")
packetFound = bindPacket(serverToClientPacketInfos, data)
else
data.infoField = "[c]"
data.tree:add(buffer(0,buffer:len()), "client -> server")
packetFound = bindPacket(clientToServerPacketInfos, data)
end
pinfo.cols.info = data.infoField;
-- data.tree:add(buffer(0,buffer:len()), data.proData)
end
-- load the tcp.port table
tcp_table = DissectorTable.get("tcp.port")
-- register our protocol to handle tcp port 800
tcp_table:add(800,pro_proto)