
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.
Um artigo que explica os detalhes internos foi publicado no Workshop on Binary Analysis Research (BAR) 2021 com o título Polypyus - The Firmware Historian. Alguns detalhes adicionais também estão contidos na apresentação final da tese de Mestrado de Jan, que aborda os problemas encontrados ao trabalhar com abordagens convencionais de diffing binário no modo ARM Thumb2, e como a abordagem alternativa somente binária funciona.
Os símbolos vazados no formato patch.elf ou .symdefs contêm apenas nomes de funções e
variáveis globais. No entanto, também existem alguns arquivos de projeto Eclipse .pdom
no WICED Studio 6.2 e 6.4. Estes contêm informações de tipo adicionais. O Eclipse os usa
internamente para preenchimento automático, pesquisa de funções, etc., e podemos utilizá-los na engenharia reversa
para adicionar informações de tipo. Como os arquivos .pdom contêm apenas informações parciais e em cache, pode
ser útil combinar vários deles.
Em uma primeira etapa, exportamos informações de tipo .pdom para um banco de dados SQLite. A exportação
leva algum tempo, mas pode até ser abortada e continuada posteriormente. A exportação funciona da seguinte forma:
java -jar pdom/export/export.jar -P BCM20739-B0.1462220149391.pdom
A importação PDOM procura nomes de funções em um banco de dados IDA, os consulta no PDOM para procurar
informações de tipo e, em seguida, aplica essas informações de tipo ao banco de dados IDA. Assim, o banco de dados IDA
precisa conter nomes de funções corretos antecipadamente. Em princípio, estes podem ser criados com os
scripts import_export do Polypyus. No entanto, os scripts um pouco mais avançados
que suportam importação PDOM também podem lidar com seções patch.elf. Execute o importador da seguinte forma:
T=0x1 (Alt-g).patch.elf (Select file).20739mapb0.h para nomear registros de hardware (Import map.h).Este script foi testado no IDA Pro 7.4 e 7.5.
Após alguns testes internos, podemos recomendar o seguinte fluxo de trabalho ao trabalhar com IDA Pro e Polypyus:
Alt-g, T=0x1).0x0 com rx, RAM em 0x200000 com rwx (pelo menos para o firmware Bluetooth).0x4 (o).
No firmware CYW20735 ele aponta para 0x3bc+1. Volte um byte e crie uma função (p)....agora seu banco de dados IDA pode estar um pouco útil :) Ainda há muitas coisas que o desmontador não consegue lidar no ARM Thumb2, mas muito melhor do que qualquer coisa que o IDA faz sozinho.
A pasta firmware contém vários firmwares com e sem símbolos.
Tudo em history contém símbolos, tudo em targets está sem símbolos.
Para a série Samsung, S8 também inclui Note 8 e S8+ etc., e o S10/S20 também inclui tudo do S10e até o Note 20 5G.
A qualidade dos dumps pode variar, alguns são com RAM e outros são apenas ROM. Temos acesso à maioria dos dispositivos nesta lista. Se precisar de um dump com os níveis de patch mais recentes e incluindo RAM, sinta-se à vontade para nos contatar.
Alguns dispositivos mencionados no artigo não estão incluídos aqui, pois podem não ser dispositivos apenas para pesquisa, etc. Alguns iPhones e MacBooks também estão faltando, pois os temos como dispositivos apenas para pesquisa, mas o dump original não era. Esses dispositivos serão adicionados em breve :)
Há um arquivo .editorconfig neste repositório. Ele configura estilo de indentação, charset e separadores de linha. Siga esta configuração ao contribuir, o que pode ser facilitado se você usar um plugin IDE para .editorconfig.
Para instalar dependências de teste, execute
pip install '.[test]'
isso instalará pacotes que são necessários apenas para executar casos de teste.
As dependências de desenvolvimento fornecem, por exemplo, stubs para tipos de pacote. Para instalá-las, execute
pip install '.[development]'
pytest executará todos os testes.
O projeto usa tox para executar testes localmente contra diferentes versões do Python. O Tox está configurado para testar as versões 3.6, 3.7, 3.8 e 3.9. Para executar o tox, instale as dependências de teste e instale essas 4 versões mencionadas do Python. Nossa maneira recomendada de instalar e gerenciar várias versões do Python é o pyenv.
Passos:
pyenv install 3.9.1
pyenv install 3.8.6
pyenv install 3.7.9
pyenv install 3.6.12
pyenv virtualenv 3.9.1 polypyus
penv local polypyus 3.8.6 3.7.9 3.6.12
pip install '.[test]'
pip install '.[development]'
toxO Polypyus usa GitHub Actions para execuções de teste automatizadas e algumas verificações de linting. Se você quiser, pode executar as etapas de linting localmente com hooks de pré-commit do git.
Toda vez antes de um novo commit ser criado, isso acionará o linting e mostrará os problemas que impediriam este código de ser aprovado na etapa de linting do GitHub Actions. Também formatará arquivos alterados com black.
pip install '.[development]'
pre-commit install
Agradecemos a Anna Stichling por criar o logotipo do Polypyus. Agradecemos também a Christian Blichmann e Joxean Koret pelo feedback.
Polypyus é open-source e licenciado sob a GPLv3.
| Chip | Dispositivo | Data de compilação | Símbolos |
|---|
| BCM20703A2 | MacBook/iMac 2016-2017 | Oct 22 2015 | ✔ |
| CYW20719B1 | Placa de avaliação | Jan 17 2017 | ✔ |
| CYW20735B1 | Placa de avaliação | Jan 18 2018 | ✔ |
| CYW20819A1 | Placa de avaliação | May 22 2018 | ✔ |
| Chip | Dispositivo | Data de compilação | Símbolos |
|---|
| BCM2046A2 | iMac Late 2009 | 2007? | - |
| BCM2070B0 | MacBook 2011, Thinkpad T420 | Jul 9 2008 | - |
| BCM20702A1 | Dongle USB Asus | Feb (?) 2010 | - |
| BCM4345B0 | iPhone 6 | Jul 15 2013 | - |
| BCM4335C0 | Google Nexus 5 | Dec 11 2012 | - |
| BCM4345B0 | Google Nexus 6P / Galaxy S6 | Oct 23 2014 | - |
| BCM43430A1 | Raspberry Pi 3 e Zero W | Jun 2 2014 | - |
| BCM4345C0 | Raspberry Pi 3+ e 4 | Aug 19 2014 | - |
| BCM4347B0 | Série Samsung Galaxy S8 | Jun 3 2016 | - |
| BCM4375B1 | Série Samsung Galaxy S10/20 | Apr 13 2018 | - |
| BCM4378B1 | iPhone 11/SE2 | Oct 25 2018 | Strings |