Toolkit para acelerar engenharia reversa de jogos/app IL2CPP usando:
- GameGuardian (dump em runtime)
- Ghidra (análise estática, com scripts Java)
- Python (normalização e geração de scripts no PC)
Tudo é pensado para ser reaproveitado em qualquer app, mudando apenas os dumps e os endereços que você descobriu.
Você pode usar este toolkit de duas maneiras:
- Dentro de um projeto maior (por exemplo, um mod-menu específico de um jogo):
- Clone o projeto principal (exemplo):
git clone https://github.com/ON00dev/il2cpp-help.git cd il2cpp-help - Coloque a pasta
il2cpp-help/dentro da raiz desse projeto (ou mantenha como submódulo).
- Clone o projeto principal (exemplo):
- Como repositório separado apenas da ferramenta:
- Clone diretamente:
git clone https://github.com/ON00dev/il2cpp-help.git cd il2cpp-help - Use
il2cpp-help/como raiz de trabalho e mantenha os arquivos de jogo (mem_addresses.txt, dumps, etc.) em uma pasta ao lado ou num repo específico de jogo.
- Clone diretamente:
Nos exemplos abaixo, vou assumir que:
- Você está dentro do repositório principal que contém a pasta
il2cpp-help/. - O terminal já está posicionado na raiz desse repositório (por exemplo, após
cd il2cpp-help).
GG/gg_dump_libs.lua– dump delibil2cpp.so,libunity.so,libmain.so, etc.gg_dump_around_results.lua– dump de memória ao redor de resultados do GG.
ghidra/auto_mark_and_report.java– script Java que marca endereços e exporta refs para CSV.import_segments_from_dir.java– script Java que importa segmentos diretamente dos dumps (GG_dumps_<package>).
tools/normalize_mem_addresses.py– normalizamem_addresses.txtpara uso no Ghidra.generate_frida.py– gera script Frida a partir de umconfig.json+re_index.json.merge_gg_dumps.py– mescla páginas de dump das libs em arquivos_merged.bindentro deil2cpp-help/out.report_local_dumps.py– gera relatório CSV dos dumps localizados de resultados (GG_dumps_results_*).
Arquivos de trabalho esperados na raiz do projeto principal (fora de il2cpp-help):
mem_addresses.txt– lista de endereços descobertos via GameGuardian.
- No GameGuardian:
- Rodar
gg_dump_libs.luapara capturar libs importantes (il2cpp, unity, main) uma vez, com o jogo carregado (ex.: após login ou lobby). - Rodar
gg_dump_around_results.luase quiser dumps locais ao redor de valores encontrados. - Opcional: usar
gg_find_energy_shield.luapara ajudar a filtrar candidatos de Energia/Blindagem.
- Rodar
- No PC:
- Organizar os dumps em
GG/dumps/(dentro do repo principal), preservando a estruturaGG_dumps_<package>/. - (Opcional) Rodar
tools/merge_gg_dumps.pyse quiser gerarlibil2cpp.so_merged.binelibmain.so_merged.binemil2cpp-help/out. - Preencher/atualizar
enderecos_memoria.txtcom os endereços achados no GG. - Rodar
tools/normalize_mem_addresses.pypara gerar arquivos de apoio para o Ghidra.
- Organizar os dumps em
- No Ghidra:
- Importar segmentos das libs diretamente dos dumps
GG_dumps_<package>usandoghidra/import_segments_from_dir.java(ou importar_merged.binse preferir). - Rodar
ghidra/auto_mark_and_report.javapassando os endereços normalizados. - Salvar o CSV de refs como
il2cpp-help/out/ghidra_refs.csv.
- Importar segmentos das libs diretamente dos dumps
- No PC novamente:
- Rodar
tools/consolidate_rev_data.pypara geraril2cpp-help/out/re_index.json. - Criar um
config_<jogo>.jsoncom as features de mod. - Rodar
tools/generate_frida.py config_<jogo>.json <saida>.jspara gerar um script Frida de mod.
- Rodar
As seções abaixo detalham cada etapa.
Script: GG/gg_dump_libs.lua
Fluxo:
- Copiar
gg_dump_libs.luapara a pasta de scripts do GameGuardian no device/emulador. - Abrir o jogo.
- Abrir o GG, selecionar o processo do jogo.
- Rodar
gg_dump_libs.lua:- O script pede para você deixar o jogo carregado (por exemplo depois do login ou no lobby).
- Depois mostra um menu com:
Dumpar TODOS os módulos alvo- Ou módulos específicos (
libil2cpp.so,libunity.so, etc.).
- Dumps são gravados em:
/sdcard/Download/GG_dumps_<package>/...- Dentro dessa pasta, cada lib terá subpastas do tipo
libil2cpp.so_<base>,libmain.so_<base>, etc.
- Copiar essa pasta inteira para o PC, em:
GG/dumps/GG_dumps_<package>/
Script: GG/gg_dump_around_results.lua
Fluxo:
- Com o jogo rodando, usar GG para:
- Encontrar valores (moedas, vida, munição etc.).
- Refine até ficar com uma lista pequena de endereços relevantes.
- Deixar esses resultados selecionados (lista de Results do GG).
- Rodar
gg_dump_around_results.lua:- Ele pega até 500 resultados atuais.
- Para cada um, dumpa uma janela de ±0x1000 bytes.
- Os dumps e um
index.txtsão gravados em:/sdcard/Download/GG_dumps_results_<package>/
- Copiar essa pasta para o PC se quiser analisar com Ghidra/hexdump, em:
GG/dumps/GG_dumps_results_<package>/
- Esses dumps de resultados não são usados no merge das libs, mas podem ser relatados depois com
tools/report_local_dumps.py.
Script: GG/gg_find_energy_shield.lua
Fluxo:
- Copiar
gg_find_energy_shield.luapara a pasta de scripts do GG. - Abrir o jogo, selecionar o processo no GG e rodar o script.
- Escolher o tipo de valor inicial (
DWORDouFLOAT). - Usar o menu em etapas:
- Energia:
- Etapa 1: buscar 100 antes de gastar.
- Etapa 2: após gastar (valor cai).
- Etapa 3: após regenerar (valor volta para 100).
- Blindagem:
- Etapa 1: buscar 100 com blindagem cheia.
- Etapa 2: após levar dano (cai de 100).
- Etapa 3: após regenerar só a Energia (blindagem continua baixa).
- Energia:
- Cada etapa é chamada manualmente abrindo o GG; o script fica em loop esperando você abrir o GG de novo, sem depender de caixas de diálogo que travam quando troca de app.
- No final de cada fluxo (Energia/Blindagem), ele carrega os candidatos na lista de resultados do GG para você testar/congelar/refinar.
Esse script não participa direto do pipeline com Ghidra, mas ajuda a encontrar endereços candidatos de Energia/Blindagem para depois registrar em enderecos_memoria.txt.
Arquivo de entrada esperado na raiz do repo principal:
enderecos_memoria.txt
Formatos aceitos:
- Formato “novo” (recomendado), separado por
;(sem módulo obrigatório):
Nome;0xENDERECO;Tipo;Modulo
Moedas;0x7DB3D3F71CBC;DWORD;libil2cpp
Gemas;0x7DB3D3F71CC0;DWORD;libil2cpp
VidaEscudo;0x7DB3E1D5A98C;FLOAT;libil2cpp
Missil;0x7DB2E309A500;DWORD;libil2cpp
- Formato “livre” anotado à mão, sem módulo, usando
Nome #ENDERECO Tipo:
Moedas #7DB3D3F71CBC DWORD
Gemas #7DB3D3F71CC0 DWORD
VidaEscudo #7DB3E1D5A98C FLOAT
Missil #7DB2E309A500 DWORD/WORD
Script: il2cpp-help/tools/normalize_mem_addresses.py
Uso (a partir da raiz do projeto principal, o script vai perguntar pelos caminhos e sugerir padrões):
python il2cpp-help\tools\normalize_mem_addresses.pyEle gera:
Ele vai perguntar:
- Caminho do arquivo com endereços do GG (default:
enderecos_memoria.txt). - Caminho de saída para endereços do Ghidra (default:
il2cpp-help/out/ghidra_addresses.txt). - Caminho de saída para CSV normalizado (default:
il2cpp-help/out/memory_addresses.csv).
Ele gera:
il2cpp-help/out/ghidra_addresses.txt– lista de endereços em formato0x..., um por linha.il2cpp-help/out/memory_addresses.csv– CSV com colunasname,address,type,module.
Esse arquivo ghidra_addresses.txt é o que você cola dentro do Ghidra.
Scripts Java:
il2cpp-help/ghidra/import_segments_from_dir.javail2cpp-help/ghidra/auto_mark_and_report.java
Em vez de gerar um _merged.bin gigante, o fluxo recomendado é criar blocos de memória a partir dos próprios dumps GG_dumps_<package>/<tag>, usando o script Java.
- Copiar
il2cpp-help/ghidra/import_segments_from_dir.javapara a pasta de scripts do Ghidra ou adicionar a pasta via Script Manager. - Criar um programa vazio no projeto (por exemplo, um novo programa “raw” para ARM64).
- Abrir o Script Manager, filtrar por linguagem
Javae executarimport_segments_from_dir. - Quando o script pedir a pasta da sessão, selecionar:
GG/dumps/GG_dumps_<package>/<tag>/
- Quando pedir o nome da biblioteca, informar:
libil2cpp.so(oulibmain.so, conforme o que você quer importar).
- O script:
- Procura subpastas como
libil2cpp.so_<base>dentro da sessão. - Para cada
.binno padrão...-<start>-<end>.bin, cria um bloco de memória emcurrentProgramno intervalo[start, end). - Marca os blocos como somente leitura (read = true, write = false, execute = false).
- Procura subpastas como
- Depois de importar os segmentos, você pode rodar a análise do Ghidra normalmente nesse programa.
Se preferir continuar com _merged.bin, ainda pode usar tools/merge_gg_dumps.py e importar o binário como Raw Binary, mas o fluxo com import_segments_from_dir.java evita problemas de memória (heap) em merges muito grandes.
- Copiar
il2cpp-help/ghidra/auto_mark_and_report.javapara a pasta de scripts do Ghidra ou adicionar a pasta via Script Manager. - Abrir no Ghidra o programa onde os blocos de memória das libs já estão carregados (via
import_segments_from_dir.javaou import de_merged.bin). - Abrir o Script Manager, filtrar por
Javae executarauto_mark_and_report. - Quando o script pedir “Endereços”:
- Abrir
il2cpp-help/out/ghidra_addresses.txtno editor e copiar todo o conteúdo. - Colar no diálogo do Ghidra (um ou vários endereços, tanto faz).
- Abrir
- O script vai pedir um arquivo CSV para salvar o relatório:
- Escolher
il2cpp-help/out/ghidra_refs.csv(ou salvar com esse nome).
- Escolher
Saída do script:
- Cria (se não existir) labels para cada endereço (ex.:
Var_0x...). - Encontra todas as referências a esses endereços.
- Gera um CSV com colunas:
var_address,var_label,ref_address,function_name
Esse CSV é usado na próxima etapa.
Script: il2cpp-help/tools/consolidate_rev_data.py (o script pergunta pelos caminhos dos arquivos)
Pré-requisitos:
- CSV com endereços normalizados (por padrão
il2cpp-help/out/memory_addresses.csv). - CSV com refs do Ghidra (por padrão
il2cpp-help/out/ghidra_refs.csv).
Uso:
python il2cpp-help\tools\consolidate_rev_data.pySaída principal (por padrão il2cpp-help/out/re_index.json), com duas visões:
variables: lista de variáveis que você marcou no GG:name,address,type,modulerefs: lista de refs cruas comaddress(call site) efunction(nome da função no Ghidra).
functions: lista de funções que tocam nessas variáveis:name: nome da função (ex.:Health_ApplyDamage).module: módulo associado (ex.:libil2cpp).call_sites: lista de endereços onde a função aparece como referência.variables: lista de variáveis associadas àquela função, cada uma comname/address/type/module.
Essa visão orientada a funções é a que você usa para localizar e alterar métodos no smali/mod menu.
Script: il2cpp-help/tools/generate_frida.py
Você define um JSON de configuração por jogo, por exemplo:
config_aircombat.json:
{
"game": {
"name": "Air Combat Online",
"package": "com.vector.apexcombat.google"
},
"features": [
{
"id": "infinite_coins",
"label": "Moedas infinitas",
"kind": "write_value",
"target_var": "Moedas",
"value": 999999999
},
{
"id": "godmode",
"label": "Godmode Vida/Escudo",
"kind": "hook_function",
"target_var": "VidaEscudo",
"preferred_function": "Health_ApplyDamage",
"patch": "skip_damage"
}
]
}Campos importantes:
target_vardeve bater comnameemre_index.json.kindpode ser:write_value– escreve um valor direto na memória.hook_function– gera um hook básico na função associada.
Uso:
python il2cpp-help\tools\generate_frida.py config_aircombat.json aircombat_mod.js [caminho_do_re_index.json]Pré-requisito:
re_index.jsongerado no passo 4 (por padrãoil2cpp-help/out/re_index.json).
Saída:
aircombat_mod.js– script Frida que:- Dentro de
Java.perform(...)aplica writes (Memory.write...) para featureswrite_value. - Cria
Interceptor.attach(...)nas funções associadas parahook_function.
- Dentro de
Esse script pode ser carregado via Frida:
frida -U -n <processo> -l aircombat_mod.js- GG:
- Encontrar valores importantes (vida, moedas, armas...).
- Dump de libs com
gg_dump_libs.lua. - Opcional: dump local com
gg_dump_around_results.lua.
- PC:
- Copiar dumps para
GG/dumps/.... - Registrar endereços em
enderecos_memoria.txt. - Rodar
il2cpp-help/tools/normalize_mem_addresses.py.
- Copiar dumps para
- Ghidra:
- Importar segmentos das libs (il2cpp/main) a partir de
GG/dumps/...comil2cpp-help/ghidra/import_segments_from_dir.java(ou importar_merged.binse preferir). - Rodar
il2cpp-help/ghidra/auto_mark_and_report.javacomil2cpp-help/out/ghidra_addresses.txt. - Salvar CSV em
il2cpp-help/out/ghidra_refs.csv.
- Importar segmentos das libs (il2cpp/main) a partir de
- PC:
- Rodar
il2cpp-help/tools/consolidate_rev_data.py→il2cpp-help/out/re_index.json. - Criar
config_<jogo>.jsoncom as features. - Rodar
il2cpp-help/tools/generate_frida.py→ script Frida pronto para uso.
- Rodar
Com isso, grande parte do trabalho pesado de engenharia reversa fica padronizado e reaproveitável entre jogos diferentes.