Ensaio

A engenharia reversa precisa de um modelo maior?

Por N0zoM1z0 · 13 de outubro de 2026

Pontos principais

  • A capacidade do modelo afeta quais hipóteses um agente de IA pode propor. Sessões posteriores resolveram problemas que trabalhos anteriores haviam deixado sem solução.
  • Um compilador familiar oferece padrões concretos para um modelo especializado aprender. Algumas correspondências exatas de código de máquina dependem de padrões de código-fonte específicos e reutilizáveis.
  • Inclua o conhecimento do repositório em uma comparação justa. Um modelo menor com boa recuperação de conhecimento pode já ter informações suficientes para progredir.
  • Treine o modelo para escolher o próximo experimento útil e teste seu verificador. O feedback é útil apenas na medida em que o verificador verifica as coisas certas.
  • Avalie os resultados verificados da reconstrução juntamente com o tempo e o custo. É isso que quero medir para o fluxo de trabalho completo do agente de IA.

O que os modelos mais capazes mudaram

Desde agosto de 2026 venho explorando o quanto de engenharia reversa um agente pode realizar com acesso a um programa e uma forma de verificar seu funcionamento. A maior parte da minha experiência vem da reconstrução de jogos, especialmente Touhou. Como mudei de modelo, os repositórios mantiveram um registro do que cada sessão conseguiu recuperar.

Grande parte desse trabalho visa a reconstrução exata: compilamos a fonte mantida sob um conjunto de ferramentas histórico com versões fixas e verificamos se ela reproduz a função alvo. Quando um modelo posterior é bem-sucedido onde o trabalho anterior estagnou, as mudanças na origem mostram o que tornou esse progresso possível.

As variáveis temporárias precisavam de vidas sobrepostas

Grande parte da lógica da função de ataque TH09 já havia sido reconstruída, mas o compilador ainda armazenava resultados temporários de maneira diferente do original. O problema restante era quanto tempo esses resultados precisavam para permanecer vivos e quando seu armazenamento poderia ser reutilizado.

Um GPT-6-Sol registro de sessão relatou essa incompatibilidade após testar vários arranjos comuns de código-fonte. Quando GPT-6.1-Sol examinou o problema novamente, propôs uma hipótese útil sobre o tempo de vida dessas variáveis ​​temporárias.

A função produziu resultados temporários e os copiou em posições de animação. Em C++, um resultado temporário permanece ativo até que a expressão que o utiliza termine. O agrupamento das operações reais em uma expressão manteve esses resultados vivos juntos, de modo que o compilador não pudesse mais reutilizar o mesmo armazenamento para todos eles.

Um resultado ainda compartilha o armazenamento com um valor usado posteriormente para verificações de colisão. Dar a esse valor seu próprio tempo de vida resolveu a sobreposição restante. Após vários experimentos direcionados, uma recompilação limpa da fonte confirmou que a função completa correspondia a.

Estou interessado em saber como a descoberta e os testes se apoiaram. A hipótese sobre a vida útil dos objetos temporários deu ao agente de IA uma nova direção. O feedback do compilador ajudou a refinar essa hipótese em um arranjo de código-fonte correspondente.

Um gráfico de fluxo de controle diferente

Uma segunda função TH09 mostra por que essa nova direção pode ser importante. Aqui, o obstáculo foi a forma como diversas filiais compartilharam seu trabalho final. O trabalho anterior de GPT-6.1-Sol fez com que partes da função correspondessem, mas as ramificações ainda se uniram de maneira diferente do original.

GPT-6-Astra alterou o gráfico de fluxo de controle circundante. Os principais caminhos levaram agora a uma atualização e retorno final partilhado. Nessa estrutura de origem, o compilador combinou as ramificações da mesma forma que o original. A função completa correspondeu e uma verificação de reconstrução separada confirmou isso.

Mudar a representação abriu um espaço de pesquisa mais produtivo. Ambos os casos me dão um motivo para levar a sério a capacidade geral do modelo: um agente pode continuar tentando variações locais por um longo tempo antes de encontrar uma maneira melhor de expressar o trabalho circundante.

As sessões posteriores também herdaram o código anterior e os experimentos fracassados já registrados. Esse trabalho acumulado fazia parte da vantagem delas. O histórico permite examinar as descobertas e suas verificações; uma comparação controlada ajudaria a separar o efeito do modelo do efeito da experiência herdada.

É isso que torna a questão interessante para mim. Algum progresso veio da descoberta de uma nova representação. Grande parte do trabalho restante envolveu testar diferentes arranjos de código-fonte em um compilador familiar. Quanto disso requer ampla capacidade de raciocínio? Quanto um modelo poderia aprender trabalhando repetidamente com esse compilador e código?

Por que um modelo especializado de IA pode funcionar bem?

Touhou nos dá uma razão concreta para esperar que essa experiência ajude. Grande parte do código do jogo vem do mesmo autor, ZUN, portanto, hábitos recorrentes são uma suposição inicial razoável. Os repositórios apoiam isso com exemplos úteis: loops relacionados e arranjos auxiliares forneceram hipóteses em todos os jogos.

Esses padrões de origem tornam-se mais específicos quando incluímos o compilador. Sob uma determinada versão e conjunto de opções, pequenas alterações na fonte podem produzir diferenças repetíveis no código de máquina. Algumas dessas diferenças são surpreendentemente obscuras.

Em TH095, por exemplo, até mesmo o nome de uma variável local pode afetar o local onde VC7.1 a armazenou. Mover sua declaração não resolveu o layout de armazenamento. No entanto, uma função anterior revelou um padrão de nomenclatura que afetou a escolha do compilador. Isso sugeriu uma hipótese mais promissora para reconstruir Supervisor::LoadDat.

A reutilização desse padrão para a variável de tamanho de arquivo produziu o layout necessário sem adicionar armazenamento. A função completa então correspondeu.

Este é um detalhe muito específico que um modelo de IA de uso geral pode não saber quando encontra o problema pela primeira vez. Um modelo especializado para este compilador poderia ver muitos desses casos e aprender quais variações do código-fonte valem a pena testar primeiro.

A oportunidade é especialmente clara em problemas de correspondência final onde já entendemos o comportamento. Estamos então perguntando qual arranjo comum de código-fonte este compilador transforma nas instruções observadas. A especialização poderia ajudar o modelo a propor essas formas de forma mais eficiente, enquanto o alvo ainda determina quais hipóteses sobreviverão.

Padrões úteis devem manter seu contexto. TH08 usa uma versão Visual C++ anterior a TH095 e TH09. TH04 usa um compilador diferente da era DOS. Sua reconstrução do código do jogador precisava de diferentes hipóteses sobre os padrões do código-fonte e como o código compilado era vinculado a um executável. Ter o mesmo autor nos dá uma expectativa inicial, mas cada alvo nos diz se se aplica. Um modelo especializado precisaria distinguir esses contextos.

Onde essa experiência deve ser armazenada?

Antes de decidir ensinar esses padrões por meio do treinamento de modelos, eu examinaria o conhecimento que já mantemos no repositório. No ensaio anterior, escrevi sobre isso se tornar a memória de trabalho do projeto. Essa memória inclui lições de compilador, juntamente com a fonte e os experimentos fracassados ​​que os tornaram úteis.

Ao recuperar esse registro, um agente pode começar com um resultado conhecido e inspecionar como o alcançamos. Também pode evitar alternativas que já falharam no mesmo contexto. O ponto inicial melhora sem alterar os parâmetros treinados do modelo.

Ao reconstruir a função de TH09 para criar inimigos, uma sessão GPT-6-Luna-max tirou uma hipótese do código-fonte TH08 relacionado. Esse código anterior sugeria como organizar o loop e lidar com falhas dentro dele. As próprias evidências de TH09 forneceram detalhes específicos do jogo. As reconstruções da fonte confirmaram que a função completa correspondia.

"O modelo não sabia daquela peculiaridade do compilador" e "o modelo não pôde usá-lo" são problemas diferentes. A recuperação pode resolver o primeiro, mas transformar esse fato em um candidato útil ainda dá trabalho. E se o código-fonte candidato falhar, o modelo deverá decidir o que o resultado significa para sua próxima tentativa. Conhecer o padrão relevante é apenas o começo desse processo.

Por esse motivo, eu incluiria um modelo menor de IA de uso geral com boa recuperação em qualquer comparação. Fornecer a mesma biblioteca de experiência nos ajudaria a identificar o que o treinamento agrega: melhor geração de candidatos, melhores decisões após feedback ou ambos.

Aprendendo o próximo experimento útil

Essas decisões após feedback são o que eu mais gostaria de estudar. Na reconstrução agente, o modelo propõe uma explicação e a testa em relação ao programa. Mesmo quando o código-fonte candidato falha, o resultado pode restringir as possibilidades restantes e sugerir um próximo experimento mais útil.

Considere novamente o exemplo dos resultados temporários. Sua fonte final mostra o arranjo que funcionou, mas o caminho para essa fonte contém mais informações. Cada um dos experimentos a seguir ajudou a identificar o que ainda precisava ser mudado.

Experimentar O que seu resultado nos ensinou
Tente uma maneira diferente de copiar os resultados O código de cópia muda, mas a função ainda é diferente.
Use os valores retornados diretamente A cópia segue o padrão original, mas o armazenamento temporário ainda é diferente.
Mantenha todas as variáveis temporárias válidas ao mesmo tempo Eles obtêm armazenamento separado, mas ainda se sobrepõe a um valor usado posteriormente para verificações de colisão.
Mantenha o valor de verificação de colisão separado Uma recompilação limpa da fonte confirma a correspondência completa.

Experimentos selecionados da reconstrução da função de ataque acima, agrupados pelo que nos ensinaram.

Um registro de treinamento que mantenha essa sequência pode ensinar mais do que apenas a fonte final. Ele conecta cada mudança proposta a um resultado observado e à próxima decisão. Manter variações ineficazes também é importante: elas informam a um agente posterior quais hipóteses já foram testadas naquele contexto.

Eu gostaria que o modelo aprendesse como usar o feedback. Um resultado neutro é um motivo para reconsiderar a variação; uma incompatibilidade alterada pode apontar para outra causa. Quando as edições locais deixarem de ser informativas, o agente deverá ser capaz de revisitar a representação da fonte ou inspecionar as evidências novamente.

Aprender a fazer essas escolhas requer autonomia. Às vezes, o próximo passo útil é inspecionar outro chamador em vez de compilar outra edição. Uma sequência rígida de reescritas necessárias eliminaria essa escolha, juntamente com parte do comportamento que queremos que o modelo aprenda.

Por que a engenharia reversa é interessante para aprendizagem por reforço

Uma reconstrução com escopo definido oferece um ambiente prático para estudar essas escolhas. Com as versões do alvo e do compilador fixadas, muitos experimentos de código-fonte dão feedback rápido e repetível. O agente pode compilar um candidato, examinar as diferenças e escolher o próximo passo.

A aprendizagem por reforço poderia treinar esse processo de tomada de decisão por meio do feedback que recebe. Um candidato aceito por meio de uma verificação definida nos dá um resultado concreto, enquanto a sequência de tentativas nos permite observar quanto trabalho foi necessário para alcançá-lo.

Já existem pesquisas apoiando essa direção. LLM4Decompile estuda modelos especializados para descompilação. AutoDecompiler treina o refinamento em várias rodadas usando feedback do compilador e de execução. Seus estudos se concentram na recuperação funcional. Para este trabalho, eu os usaria como ponto de partida para a tarefa relacionada de encontrar uma fonte que corresponda à saída de um compilador histórico.

Porém, para alcançar uma tarefa tão bem definida, talvez precisemos primeiro estabelecer quais recursos uma função possui ou criar uma nova forma de observar o comportamento do programa durante a execução. Em TH08, por exemplo, uma diferença de colisão levou de volta à forma como o programa original lidava com cálculos de ponto flutuante. Antes que o agente pudesse testar uma correção útil, ele precisava decidir o que medir.

Isto sugere outro papel para um modelo amplamente capaz: em primeiro lugar, ajudar a tornar o problema verificável. Uma vez que essa verificação exista, podemos investigar até onde uma política de pesquisa aprendida pode chegar com ela.

Quando o verificador está errado

Quando usamos uma verificação no treinamento, sua cobertura passa a fazer parte do ambiente de aprendizagem. Chamo essa referência ou verificador de oracle. Mesmo uma resposta repetível precisa ser entendida pelos aspectos que ela realmente verifica.

TH08 mostrou o quanto pode se esconder fora dessa cobertura. Algumas funções reconstruídas passaram em suas comparações exatas com constantes flutuantes erradas. O comparador ajustou os endereços realocados antes de verificar as instruções, mas verificou os valores por trás desses endereços somente quando eles foram explicitamente registrados para verificação. Outras referências literais poderiam passar sem que seus valores fossem examinados.

Para resolver essa lacuna, uma auditoria mais ampla encontrou constantes incorretas em funções que já haviam passado na verificação. Em um cálculo, o código-fonte reconstruído adicionou 1.0f, enquanto o original adicionou 32.0f.

Um modelo recompensado pela verificação antiga poderia aprender a produzir uma reconstrução incorreta. Não treinamos um modelo RL usando esse verificador. A falha que observamos estava na própria verificação. Mas se usássemos isso como recompensa, o mesmo ponto cego passaria a fazer parte do ambiente de aprendizagem.

Um teste funcional pode ter um ponto cego semelhante. Pesquisas usando difusão diferencial em descompiladores LLM encontraram diferenças comportamentais fora dos testes fornecidos. Portanto, precisamos entender um teste aprovado em termos dos casos que ele exerce. Da mesma forma, uma correspondência de instrução deve ser entendida em termos dos bytes e dos dados que ela verifica.

Antes de usar qualquer tipo de verificação como recompensa, eu testaria com resultados deliberadamente incorretos. Eu também manteria a aceitação final separada do código-fonte que o agente de IA pode editar. O modelo deve passar na verificação reconstruindo o programa corretamente. Caso contrário, simplesmente copiar uma matriz de bytes do destino poderia enganar um sistema de pontuação ingênuo sem recuperar o código-fonte útil.

Aprimorar o aluno e melhorar seu verificador pertencem ao mesmo problema de pesquisa. À medida que o aluno melhora na otimização do feedback que lhe damos, compreender esse feedback também se torna mais importante.

Uma comparação que vale a pena fazer

Com essas verificações implementadas, eu iniciaria a comparação em uma família de tarefas fixa VC7.1. Primeiro, eu estabeleceria linhas de base para um modelo forte de IA de uso geral e um modelo menor. Adicionar conhecimento do repositório ao modelo menor mostraria quais mudanças na recuperação. A partir daí, a especialização supervisionada e uma versão treinada em RL nos permitiriam examinar o que o treinamento acrescenta.

Para tornar essas comparações informativas, cada modelo receberia as mesmas evidências e ferramentas alvo. Para comparações específicas de treinamento, eu também manteria o modelo base e o conhecimento disponível fixos. Testes repetidos ajudariam a distinguir uma estratégia de busca confiável de uma solução candidata que tivesse sucesso por acaso.

Eu separaria então duas condições iniciais: reconstruir uma função a partir de suas instruções e fechar as últimas diferenças na fonte mantida. Um modelo de IA especializado pode ser excelente na segunda tarefa, enquanto um modelo de IA de uso geral faz grande parte do trabalho necessário para alcançá-la. Medi-los separadamente revelaria essa divisão de trabalho.

Ambas as tarefas precisam de exemplos de teste excluídos do treinamento e recuperação. Jogos Touhou relacionados compartilham o código do mecanismo. Excluir um jogo do treinamento ainda poderia deixar funções quase idênticas no conjunto de treinamento. Em vez disso, eu excluiria grupos inteiros de código-fonte relacionado e manteria suas respostas verificadas fora dos dados de treinamento e da biblioteca de recuperação.

Para estes exemplos, o resultado seria correspondências completas e verificadas de forma independente. Orçamentos iguais para propostas de candidatos ou tentativas de compilação ajudariam a comparar a qualidade da pesquisa. Medir o tempo e o custo totais, incluindo a compilação, mostraria se essa qualidade produz um fluxo de trabalho eficiente. Os custos de formação devem ser medidos separadamente.

Ambas as medidas são importantes. Uma proposta barata pode levar a um fluxo de trabalho caro se causar mais compilações que não fornecem informações úteis. Por outro lado, um modelo mais lento pode ser mais econômico se encontrar uma experiência útil mais cedo. A comparação deve incluir esses custos.

A contagem dos resultados aceitos também mantém o progresso intermediário em perspectiva. Um TH09 candidato para salvar repetição parecia promissor porque a função compilada tinha o tamanho esperado, mas uma comparação completa ainda encontrou diferenças substanciais. Mudanças na forma como o compilador organiza as instruções também podem fazer o candidato parecer mais próximo do alvo, sem resolver o problema subjacente. Esses diagnósticos podem orientar o próximo experimento, mas eu validaria qualquer recompensa por “chegar mais perto” em relação à verificação de aceitação total.

Eu estaria interessado no padrão desses resultados. Se um modelo de IA especializado funciona bem em uma família de compiladores familiar, essa vantagem sobreviverá a uma mudança no conjunto de ferramentas? E uma vez que ambos os modelos de IA tenham uma boa recuperação, quanto o treinamento ainda acrescenta? As respostas nos ajudariam a decidir onde cada tipo de modelo é mais útil.

Que tipo de agente de IA isso sugere?

Se os modelos acabarem por ajudar em diferentes fases, um acordo útil poderá ser um agente amplo com acesso a um modelo de IA especializado. Depois que uma tarefa se torna uma pesquisa familiar do compilador, ela pode solicitar candidatos ao modelo de IA especializado. Se os resultados deixarem de fazer sentido, o agente mais amplo poderá retornar à evidência alvo ou investigar a própria medição.

Nesse arranjo, a especialização torna-se uma ferramenta que o agente pode escolher à medida que a investigação se desenvolve. O agente mantém a liberdade de mudar a direção que tornou possíveis os avanços anteriores.

Isto decorre naturalmente da mudança industrial que descrevi no ensaio anterior. Ser capaz de realizar muito mais experimentos muda a forma como organizamos o trabalho. Também nos dá uma razão para perguntar quais decisões necessitam de um julgamento amplo e quais melhoram através da experiência repetida com uma determinada arte.

Por enquanto, o modelo geral mais forte conquistou seu lugar no meu trabalho ao resolver problemas que eu havia deixado em aberto. Esses sucessos me fazem querer estudar o processo: quanto dependia da amplitude do modelo e quanto poderia ser feito por um modelo treinado especificamente para esse tipo de reconstrução?

Os repositórios nos fornecem uma maneira de testar a pergunta. Gostaria de usar esse registro para construir a comparação e ver o que aprendemos.

Evidências e atribuição de modelo

As notas detalhadas de evidências incluem as comparações registradas e o contexto dos experimentos.

Os exemplos descrevem comparações históricas em nível de função registradas nos commits vinculados. As verificações de tempo de execução de todo o jogo são marcos separados. Os registros de origem e correspondentes foram revisados em 13 de outubro de 2026.

O rótulo TH09 gpt-dots significa GPT-6-Astra. O modelo associado a gpt-web mudou ao longo do tempo, de modo que o rótulo por si só não consegue identificar o modelo usado em uma execução específica. Nomes de modelos explícitos nos outros commits citados fornecem a atribuição registrada. Esses históricos não incluem medições consistentes de custo ou esforço para cada execução.

As comparações propostas de modelos especializados e treinamento RL são experimentos futuros. As histórias do projeto os motivam. Nenhum modelo especializado treinado foi avaliado para este ensaio.

Top