
TRANSFORMERS: Forged to Fight é um jogo de combate 3D onde você assume o controle de alguns dos soldados mais carismáticos diretamente do universo Transformers. Estamos falando de grandes nomes como Optimus Prime, Megatron, Bumblebee, Ratchet, Soundwave e Grindor – nada menos. Sim, você leu certo. Seus personagens favoritos de qualquer Transformers
Este pacote contém uma inicialização offline funcional de Transformers: Forged to Fight, além de todas as ferramentas, patches e notas de engenharia reversa usadas para chegar lá. Ele foi feito para ser pego por alguém que tenha tempo e energia para dar o próximo e muito maior passo, que é reconstruir o conteúdo do lado do servidor do jogo do zero. Tudo aqui está documentado para que você não precise começar do zero como eu fiz.
Leia este arquivo inteiro antes de mexer em qualquer coisa. A seção "Gotchas" em particular vai te poupar dias.
O jogo inicializa completamente offline e atinge sua tela inicial interativa real sem nenhum servidor ao vivo por perto. A partir da tela inicial, os menus navegam sem travar: a base, a lista de robôs (com um robô presente na conta), a seleção de modo de luta, a tela de cristais, e os pop-ups e dicas habituais. O fluxo completo de login é concluído, todos os subsistemas online se conectam, e a experiência inicial e os portões do tutorial são limpos. A luta introdutória roteirizada (Optimus vs Starscream) até chega ao ponto de começar a carregar a batalha, e os modelos 3D dos personagens renderizam e animam.
Esta foi a parte difícil e está resolvida. O cliente em si está vivo novamente offline.
A jogabilidade real não funciona. A história não mostra missões, e as lutas não conseguem carregar completamente. Isso não é um bug e não é algo que um patch possa corrigir.
Forged to Fight era totalmente autoritativo no servidor. O aplicativo no telefone é essencialmente uma tela com controles. Quase nada do jogo vivia no aplicativo. Cada missão, cada luta, cada escalação inimiga, as estatísticas e habilidades de todo o elenco, a economia e todo o equilíbrio viviam nos servidores da Kabam e eram transmitidos para o dispositivo a cada sessão. Quando os servidores foram desligados no início de 2020, esse banco de dados de conteúdo foi junto, e nunca foi liberado ou arquivado publicamente em nenhum lugar que eu possa alcançar.
Então a situação se divide claramente em duas. A arte e o áudio sobreviveram, porque eles estão embutidos
no aplicativo (veja re_notes/ASSET_INVENTORY.txt). Cada personagem é um pacote completo de asset da Unity
contendo o modelo, texturas, rig, clipes de animação, controladores de animação, efeitos
e áudio. Os ambientes, edifícios, interface, retratos, cenas e diálogos também estão
todos lá. O que não sobreviveu foram os dados que diziam ao jogo quais desses assets usar,
como montá-los em uma luta ou missão, e quais eram os números reais de cada robô. Todas as peças estão presentes.
Só não resta nada que saiba como juntá-las. Reconstruir isso é todo o trabalho que resta.
Há quatro partes móveis. Juntas, elas fazem o jogo não modificado pensar que está falando com a Kabam.
Patches binários nativos. O jogo é Unity IL2CPP, então a lógica vive em uma biblioteca ARM compilada,
libil2cpp.so, não em arquivos de script editáveis. patches/patch_il2cpp.py reescreve
seis funções nessa biblioteca para passar pelas verificações de servidor morto: ele derrota
dois caminhos de pinning de certificado para que nosso próprio certificado TLS seja aceito, força o bloco
de registro do gerenciador a ser executado mesmo que a configuração ao vivo seja nula, permite que o login
seja bem-sucedido com nossa sessão de dispositivo local e silencia os erros fatais do subsistema que, de outra forma,
exibiriam o diálogo "falha ao fazer login". Ele também reinjeta uma única entrada de dependência (veja a
seção Gotchas) para que o hook em tempo de execução realmente carregue. A saída é libil2cpp.patched.so.
Um servidor Sparx falso. server/fakeserver.py faz o papel do backend da Kabam. Ele escuta nas
portas TLS 443 e HTTP 80 simples e responde às chamadas de API do jogo. Respostas pré-definidas ficam em
server/responses/, um arquivo por endpoint, nomeado por método e caminho, por exemplo,
GET__account_data.json. Alguns endpoints são respondidos dinamicamente em código, em vez de
a partir de um arquivo, porque o jogo espera que eles ecoem valores da requisição (os endpoints
do tutorial e o endpoint de detalhes do herói). O envelope de resposta é
{"error":null,"result": ...}. Note que dentro dos payloads de erro do Sparx, o campo é escrito
err, não error. Esse detalhe é importante e fácil de perder.
Um hook nativo em tempo de execução. tools/nativehook/ compila libdothook.so, uma pequena biblioteca que é
carregada no jogo na inicialização e registra cada chave de dados que o jogo lê, além de alguns
ajustes de comportamento direcionados. Este é o ciclo de feedback que tornou todo o resto possível:
ele diz exatamente o que o jogo está pedindo para que você possa sintetizar uma resposta e verificar
se funciona. É um hook inline de sobrescrita de byte puro instalado antes da execução, porque a ferramenta
normal para isso (Frida) trava sob a camada de tradução ARM do emulador.
Configuração do dispositivo. O emulador tem que enviar os domínios da Kabam para o PC e confiar no
certificado falso. tools/provision_ldplayer.sh faz isso em uma única etapa: ele envia a biblioteca
patcheada e o hook, redireciona os hostnames da Kabam para o endereço LAN do PC via arquivo hosts,
monta a CA falsa no armazenamento de confiança do sistema e relaxa o SELinux. Execute-o após cada
reinicialização do emulador, porque essas montagens não sobrevivem a uma reinicialização.
O fluxo de dados em tempo de execução é: o jogo faz uma chamada HTTPS para um domínio da Kabam, o arquivo hosts
a envia para o PC, o servidor falso responde com uma resposta de server/responses/, a biblioteca
patcheada aceita o certificado e a resposta, e o hook registra o que foi lido. Esse loop é como cada
tela nesta compilação foi trazida à vida.
README.md este arquivo
TECHNICAL_NOTES.md a referência técnica mais aprofundada: patches, formatos de dados recuperados, descobertas
patches/
patch_il2cpp.py os seis patches nativos mais a reinjeção de dependência
disasm_fn.py auxiliar: desmontar uma função em um offset
find_callers.py auxiliar: encontrar chamadores de uma função
find_str_ref.py auxiliar: encontrar referências a uma string
server/
fakeserver.py o servidor Sparx falso
gen_certs.sh regenerar o certificado TLS e a CA (execute isto, veja abaixo)
setup_device.sh referência de configuração de rede e confiança do lado do dispositivo
iterate.sh loop rápido de reinicialização e captura
responses/ um arquivo JSON por endpoint que o jogo chama
tools/
provision_ldplayer.sh reprovisionamento único do emulador para o estado funcional
setup_arm64.sh notas de configuração do toolchain
decompile_targets.py acionar o descompilador headless do Ghidra em offsets escolhidos
find_xrefs.py busca de referências cruzadas no binário
apply_labels.py aplicar rótulos de símbolos IL2CPP
light_analyze.py auxiliares leves de análise estática
frida_attach.py auxiliares Frida (mantidos para referência, veja a nota sobre libnb)
frida_run.py
hook_dot.js
nativehook/
hook.c fonte do libdothook.so, o hook em tempo de execução
libdothook.so hook pré-compilado, arm64
deploy.sh compilar e implantar o hook
relaunch_and_capture.sh reiniciar o jogo e capturar logs
hook/dothook.c variante anterior do hook, mantida para referência
re_notes/
dump.cs o dump IL2CPP completo: todas as classes, métodos e campos do jogo
decomp_out.c corpos descompilados de funções chave
decompile_targets.txt os offsets que valem a pena descompilar
ASSET_INVENTORY.txt quais arte e áudio já estão embutidos no aplicativo
re_notes/dump.cs é o arquivo mais valioso para o trabalho que resta. É o
modelo de tipos completo do jogo: toda classe, todo método e, crucialmente, todo campo de dados
que o cliente lê do servidor. É o seu mapa de toda a API do backend. Quando você precisar
saber qual deve ser a forma de uma resposta, a resposta está lá.
Estes foram deixados de fora de propósito, porque são grandes, ou protegidos por direitos autorais, ou secretos, ou você deveria gerar os seus próprios.
com.kabam.bigrobot, versão 9.2.0). Tem cerca de 800 MB. Obtenha sua própria
cópia. O nome do pacote e a versão estão em TECHNICAL_NOTES.md.libil2cpp.so original e os assets do jogo. Ambos saem diretamente do APK. Descompacte
o APK, a biblioteca está em lib/arm64-v8a/, os assets estão em assets/.server/gen_certs.sh para criar seu próprio
par correspondente, depois aponte o armazenamento de confiança do dispositivo para a nova CA.patches/patch_il2cpp.py contra o libil2cpp.so
original do APK.re_notes/dump.cs a partir da biblioteca do APK e dos metadados globais.Você precisa do APK instalado em um emulador com capacidade de tradução ARM (LDPlayer 9 foi usado, com root e sistema gravável), Python no PC e os itens da seção acima.
bash server/gen_certs.sh.python patches/patch_il2cpp.py caminho/para/o/libil2cpp.so/original --apply.tools/nativehook/deploy.sh.python server/fakeserver.py. Ele precisa estar acessível
nas portas 443 e 80 a partir do emulador.bash tools/provision_ldplayer.sh <seu-IP-LAN-PC>. Execute novamente após
cada reinicialização do emulador.Se travar no login, verifique o primeiro item da seção Gotchas antes de qualquer outra coisa.
Estes são os que me custaram horas. Eles estão escritos para que não custem o mesmo para você.
libdothook.so. Os bytes e offsets exatos estão documentados no
script de patch e em TECHNICAL_NOTES.md.provision_ldplayer.sh ou nada se conectará.err, não error. Usar o errado produz
respostas que o cliente ignora silenciosamente ou trata incorretamente.Este é o trabalho real, e é grande. Aqui está a forma dele e por onde começar.
O objetivo é recriar, manualmente, o conteúdo do lado do servidor que costumava ser transmitido para o cliente: as quests e missões, os mapas e suas escalações inimigas, o elenco completo com as estatísticas e habilidades de cada robô, as fórmulas de combate e a economia. Nada disso existe mais, então tudo tem que ser criado do zero, nas formas exatas que o cliente espera.
O método que funciona é o loop em torno do qual este projeto foi construído. Execute o jogo com o hook
anexado. O hook registra cada chave que o cliente lê. Quando o cliente pede algo que você
não forneceu, você vê exatamente o que ele queria. Você então sintetiza uma resposta na
forma correta, coloca em server/responses/ ou adiciona ao manipulador dinâmico em
fakeserver.py, reinicia e verifica se o cliente aceita e avança. Repita. Cada
tela na compilação atual foi trazida exatamente dessa forma. re_notes/dump.cs informa a
forma de cada estrutura antes mesmo de você executar, porque ele lista todos os campos que o cliente lê.
Uma ordem sensata para atacar:
decompile_targets.py) e leia
os campos exatos.ASSET_INVENTORY.txt, então você
está apenas criando números e definições de habilidades, não assets.TECHNICAL_NOTES.md para as chaves.Seja realista sobre a escala. Mesmo para jogos onde os fãs salvaram os dados do servidor ao vivo antes do desligamento, montar um servidor privado é um longo projeto. Aqui não há dados salvos para começar, então cada número e cada habilidade tem que ser pesquisado ou reinventado e então verificado contra o cliente. Este é um esforço de várias pessoas e vários anos se o objetivo for o jogo real. Dito isso, o caminho não é mais um mistério. A inicialização está resolvida, o ciclo de feedback existe, o modelo de tipos foi extraído e os assets estão intactos. O que resta é uma grande quantidade de cuidadosa reconstrução de dados, não mais engenharia reversa do desconhecido.
Comece com TECHNICAL_NOTES.md. É a referência técnica mais aprofundada, com os patches
exatos, os formatos de dados recuperados e as descobertas específicas, em mais detalhes do que este
README. Depois execute o loop.
Boa sorte. Agora é uma máquina real. Só precisa que seu conteúdo seja reconstruído.