96 lines
5.2 KiB
Lua
96 lines
5.2 KiB
Lua
-- Read-only: decode the captured battle with the client's own protobuf parser.
|
|
-- This does not start battles, modify actors, replace handlers, or change saves.
|
|
do
|
|
local captureHash = __CAPTURE_HASH__
|
|
if _G.__gacBattleWireProbeV2Hash ~= captureHash then
|
|
_G.__gacBattleWireProbeV2Hash = captureHash
|
|
local function log(text)
|
|
CS.UnityEngine.Debug.Log('[GAC_BATTLE_WIRE] ' .. captureHash .. ' ' .. tostring(text))
|
|
end
|
|
local ok, err = pcall(function()
|
|
local typeName = __TYPE_NAME__
|
|
local assemblies = CS.System.AppDomain.CurrentDomain:GetAssemblies()
|
|
local messageType = nil
|
|
for i = 0, assemblies.Length - 1 do
|
|
messageType = assemblies[i]:GetType(typeName)
|
|
if messageType ~= nil then break end
|
|
end
|
|
if messageType == nil then error('message type not found: ' .. typeName) end
|
|
-- IL2CPP builds can expose the parser as a non-public member.
|
|
-- Include both visibility levels instead of assuming a public getter.
|
|
local flags = CS.System.Reflection.BindingFlags.Public
|
|
+ CS.System.Reflection.BindingFlags.NonPublic
|
|
+ CS.System.Reflection.BindingFlags.Static
|
|
+ CS.System.Reflection.BindingFlags.Instance
|
|
local properties = messageType:GetProperties(flags)
|
|
local parser, descriptor = nil, nil
|
|
log('message_type=' .. tostring(messageType.FullName) .. ' properties=' .. tostring(properties.Length))
|
|
for i = 0, properties.Length - 1 do
|
|
local property = properties[i]
|
|
local getter = property:GetGetMethod(true)
|
|
if getter ~= nil and getter.IsStatic then
|
|
local propertyType = tostring(property.PropertyType.FullName)
|
|
log('static_property=' .. tostring(property.Name) .. ' type=' .. propertyType)
|
|
if string.find(propertyType, 'Google.Protobuf.MessageParser', 1, true) then
|
|
parser = property:GetValue(nil, nil)
|
|
elseif propertyType == 'Google.Protobuf.Reflection.MessageDescriptor' then
|
|
descriptor = property:GetValue(nil, nil)
|
|
end
|
|
end
|
|
end
|
|
local fields = messageType:GetFields(flags)
|
|
for i = 0, fields.Length - 1 do
|
|
local field = fields[i]
|
|
local fieldType = tostring(field.FieldType.FullName)
|
|
log('member=' .. tostring(field.Name) .. ' type=' .. fieldType .. ' static=' .. tostring(field.IsStatic))
|
|
if field.IsStatic then
|
|
if parser == nil and string.find(fieldType, 'Google.Protobuf.MessageParser', 1, true) then
|
|
parser = field:GetValue(nil)
|
|
elseif descriptor == nil and fieldType == 'Google.Protobuf.Reflection.MessageDescriptor' then
|
|
descriptor = field:GetValue(nil)
|
|
end
|
|
end
|
|
end
|
|
local bytes = CS.System.Convert.FromBase64String(__PAYLOAD__)
|
|
local message = nil
|
|
if parser ~= nil then
|
|
message = parser:ParseFrom(bytes)
|
|
else
|
|
-- A generated message can decode through MergeFrom even when
|
|
-- its static parser metadata was stripped from reflection.
|
|
message = CS.System.Activator.CreateInstance(messageType)
|
|
local methods = messageType:GetMethods(flags)
|
|
local merge = nil
|
|
for i = 0, methods.Length - 1 do
|
|
local method = methods[i]
|
|
local parameters = method:GetParameters()
|
|
if not method.IsStatic and parameters.Length == 1
|
|
and tostring(parameters[0].ParameterType.FullName) == 'Google.Protobuf.CodedInputStream' then
|
|
merge = method
|
|
break
|
|
end
|
|
end
|
|
if merge == nil then error('no parser or CodedInputStream decoder on ' .. typeName) end
|
|
local input = CS.Google.Protobuf.CodedInputStream(bytes)
|
|
local arguments = CS.System.Array.CreateInstance(typeof(CS.System.Object), 1)
|
|
arguments:SetValue(input, 0)
|
|
merge:Invoke(message, arguments)
|
|
end
|
|
log('type=' .. typeName .. ' bytes=' .. tostring(bytes.Length))
|
|
log('decoded=' .. message:ToString())
|
|
if descriptor ~= nil then
|
|
local fields = descriptor.Fields:InFieldNumberOrder()
|
|
local iterator = fields:GetEnumerator()
|
|
while iterator:MoveNext() do
|
|
local field = iterator.Current
|
|
local nested = field.MessageType
|
|
log('field=' .. tostring(field.FieldNumber) .. ' name=' .. tostring(field.Name)
|
|
.. ' type=' .. tostring(field.FieldType)
|
|
.. ' nested=' .. (nested ~= nil and tostring(nested.FullName) or ''))
|
|
end
|
|
end
|
|
end)
|
|
if not ok then log('probe_error=' .. tostring(err)) end
|
|
end
|
|
end
|