
Historiador de firmware apenas binário que aprende a localizar funções em binários brutos extraindo funções conhecidas de binários semelhantes, permitindo correspondência rápida de funções sem desmontagem para análise de firmware embarcado.
Polypyus aprende a localizar funções em binários brutos extraindo funções conhecidas de binários semelhantes. Assim, é um historiador de firmware. Polypyus funciona sem desmontar esses binários, o que é uma vantagem para binários complexos de desmontar e onde ferramentas comuns perdem funções. Além disso, a abordagem somente binária o torna muito rápido, executando em poucos segundos. No entanto, essa abordagem exige que os binários sejam da mesma arquitetura e tenham opções de compilador semelhantes.
Polypyus integra-se ao fluxo de trabalho de ferramentas existentes como Ghidra, IDA, BinDiff e Diaphora. Por exemplo, pode importar funções previamente anotadas e aprender com elas, e também exportar funções encontradas para serem importadas no IDA. Como Polypyus usa limites bastante rigorosos, em nossos experimentos ele encontrou apenas correspondências corretas. Embora isso gere menos resultados do que em ferramentas existentes, é um bom ponto de partida para carregar essas correspondências no IDA para melhorar seus resultados de análise automática e então executar o BinDiff por cima.
Ao trabalhar com binários de firmware brutos, nomeadamente várias versões de firmware Bluetooth Broadcom e Cypress, descobrimos que a análise automática do IDA muitas vezes identificava incorretamente os inícios de funções. No IDA Pro 6.8 a análise automática é um pouco mais agressiva, gerando mais resultados, mas também mais falsos positivos. No geral, o IDA Pro 7.2 era mais pessimista, mas perdia muitas funções. Isso resultou em apenas algumas correspondências do BinDiff entre nossos firmwares no IDA Pro 6.8 e nenhuma correspondência útil no IDA Pro 7.2.
Curiosamente, o BinDiff frequentemente falhava em identificar funções que, exceto por branches, eram byte-idênticas. Observe que o Polypyus busca exatamente essas funções byte-idênticas. Supomos que o BinDiff falha nessas funções devido a um grafo de chamadas diferente produzido por funções ausentes e falsos positivos. Às vezes, essas funções já eram reconhecidas pelo IDA, mas frequentemente o IDA não as reconhecia como código ou não as marcava como função. Note que o Diaphora tem problemas semelhantes, pois exporta funções identificadas pelo IDA antes de processá-las posteriormente. O gráfico a seguir mostra um benchmark no binário de firmware Bluetooth CYW20735B1 que compara vários desmontadores e como as falhas do desmontador resultam em problemas subsequentes de diffing.
Além disso, embora tenhamos descoberto que o Amnesia encontra muitas funções, ele também encontra muitos falsos positivos. No entanto, muitas funções têm uma configuração de stack frame semelhante no início. Assim, o Polypyus tem uma opção para aprender inícios comuns de funções a partir dos binários de entrada anotados e aplicar isso a outros binários para identificar funções sem corresponder seus nomes. Esta etapa opcional é aplicada apenas nas regiões onde nenhuma função foi localizada anteriormente, dessa forma o método de inícios comuns de funções e a descoberta principal de funções não entram em conflito.
Como esses correspondentes trabalham no binário bruto, eles não dependem de um desmontador. Isso também tem uma desvantagem importante: se houver opções de compilador diferentes ou uma arquitetura de destino diferente, o Polypyus não detectará funções semelhantes. Além disso, embora as correspondências identificadas sejam muito confiáveis, a identificação do início da função é um pouco menos confiável, portanto use esta última com cuidado. A seguir, você pode ver que os kits de avaliação Cypress são muito semelhantes entre si, mas o firmware do MacBook é muito diferente.
Polypyus cria correspondentes binários difusos comparando funções comuns em uma coleção de binários de firmware anotados.
Atualmente, as seguintes anotações são suportadas:
patch.elf, que é um arquivo ELF especial contendo apenas definições de símbolos..symdefs como produzido pela maioria dos compiladores ARM..csv com um formato documentado na pasta firmware.Essas anotações contêm o endereço, tamanho e nome de funções conhecidas. Quanto mais semelhanças os binários de entrada na coleção de histórico tiverem, melhor para o desempenho e resultados do Polypyus. Dadas várias funções ligeiramente diferentes, o Polypyus cria correspondentes muito bons.
Polypyus requer Python 3 >= 3.6. Aconselhamos o uso de um virtualenv para a instalação a seguir. Clone este repositório e, nesta pasta, execute:
pip install .
Após a instalação, os seguintes comandos estão disponíveis:
polypyus-guipolypyus-cliPolypyus está disponível através de uma interface gráfica e uma interface de linha de comando.
Tanto a GUI polypyus-gui quanto a CLI polypyus-cli aceitam estes argumentos durante a invocação:
--verbose é o nível de verbosidade. Por padrão, mostra avisos -v mostra informações -vv mostra informações de depuração.
--project define a localização do arquivo de projeto. É um caminho de arquivo ou ":memory:".
--help Mostra mensagem de ajuda.
A opção de projeto facilita armazenar seu trabalho para diferentes contextos em diferentes arquivos e também reabri-los novamente.
O fluxo de trabalho geral da GUI vai do lado esquerdo da janela para o direito.
Primeiro, binários são adicionados ao histórico. Em seguida, anotações de símbolos para as entradas
no histórico são adicionadas.
Depois, binários alvo podem ser adicionados.
Para a correspondência, clique em Create matchers from history. Uma vez que os correspondentes são criados, alvos individuais
podem ser selecionados, ou todos os alvos podem ser correspondidos selecionando batch match.
Finalmente, os resultados podem ser exportados para um arquivo .csv.
A seguir, você pode ver um vídeo de demonstração onde Polypyus leva apenas alguns segundos para aprender a partir de dois binários de entrada, anotá-los, criar correspondentes e aplicar correspondências a um novo binário.
A vantagem de usar a CLI é sua capacidade de ser automatizada. Atualmente, o formato de saída da CLI está sujeito a alterações. No entanto, aqui está um exemplo de chamada:
polypyus-cli --history firmware/history/20819-A1.bin --annotation firmware/history/20819-A1_patch.elf --history firmware/history/20735B1.bin --annotation firmware/history/20735B1_patch.elf --project test.sqlite
polypyus-cli --target firmware/history/20739B1.bin --project test.sqlite
O primeiro comando cria test.sqlite como um novo arquivo de projeto e importa 20819-A1.bin e 20735B1.bin
com seus respectivos arquivos patch.elf.
A segunda invocação reutiliza o mesmo arquivo de projeto e corresponde ao binário 20739B1.bin.
Para cada comando, o número de --history e --annotation precisa corresponder.
Esses dois comandos também poderiam ser combinados em um, adicionando o argumento --target ao primeiro comando.