Files

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