Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
ch55x_firmware_extractor — Extrator de firmware para microprocessadores CH55x | Kitploit
Ferramentas/GitHubGitHub/finngineering/ch55x_firmware_extractor
Segurança de Sistemas EmbarcadosExploraçãoEngenharia ReversaHacking de HardwareSegurança de HardwareSegurança de Hardware e IoTAnálise de Firmware
GitHubfinngineering/ch55x_firmware_extractor

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

ch55x_firmware_extractor

Extrator de firmware para microprocessadores CH55x

Ver Repositório
126há 8 mesesAinda não revisado

Extrator de firmware CH55x

O extrator de firmware CH55x é utilizado para ler o firmware de circuitos integrados CH55x. Não há suporte interno nos dispositivos para ler diretamente o firmware através do bootloader. No entanto, existe uma funcionalidade para verificar o conteúdo do firmware de 8 em 8 bytes em relação aos dados fornecidos. Esta funcionalidade é vulnerável a um ataque de temporização clássico, e é isso que é explorado aqui para permitir a extração do firmware desses dispositivos. O bootloader pode ser acessado via USB ou UART. Este extrator de firmware funciona apenas através de UART, pois a latência mais alta do USB tornaria este ataque difícil. Os chips testados são CH552 e CH554, e versões do bootloader 2.4 e 2.5. A solução de hardware para o extrator de firmware é baseada em um STM32 Blue Pill, pois são facilmente disponíveis, baratos e possuem o desempenho necessário.

Anatomia do exploit

O bootloader foi previamente lido do dispositivo e seu protocolo de comunicação foi engenhado reversamente. Abaixo está um comando de verificação aproximadamente correto e a função de verificação usada no bootloader. Existem algumas proteções em vigor, que exigem que o comprimento seja múltiplo de 8, o endereço esteja alinhado a um limite de 8 bytes, o endereço esteja abaixo de 0x3800 e que não haja erros de verificação anteriores. A última proteção significa que é necessário reiniciar o CH55x após cada verificação malsucedida.

Podemos ver que a função de verificação retorna imediatamente quando um byte da verificação falha. Isso significa que quanto mais bytes estiverem corretos, mais tempo a função de verificação levará. Este é o exemplo clássico de um ataque de temporização que pode ser explorado.

root@kitploit:~
unsigned char verifycmd[] = {
//  0x57, 0xab, // UART magic not included to verify function
    0xa6,       // Verify command
    5 + len,    // Constant 5 plus length of data to verify
    0,          // Unused
    addr_low,   // Low byte of address
    addr_high,  // High byte of address
    0, 0, 0,    // Unused
    0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, // Data to verify against
    checksum
}

unsigned char verify(unsignec char *cmdbuffer)
{
    static char prev_verify_error;

    unsigned char len = cmdbuffer[1]-5
    unsigned short addr = cmdbuffer[3] + cmdbuffer[4] << 8;
    if (len & 0x07 || addr & 0x07 || addr > 0x3800 || prev_verify_error) {
        return 0xfe;
    }

    for (int i=0; i < len; i++) {
        // Key can be set through bootloader, and CBYTE[] means code memory
        if(key[i & 0x07] ^ cmdbuffer[8+i] ^ CBYTE[addr+i]) {
            prev_verify_error = 1;
            return 0xf5;
        }
    }
    return 0;
}

Através de tentativa e erro, descobrimos que cada byte correto estende o tempo de execução da função de verificação em aproximadamente 4,2 µs. A taxa de transmissão usada pelo bootloader para comunicação UART é 57600 (independentemente do que você ler em outros lugares), o que significa que a transmissão de um bit leva aproximadamente 17,4 µs. A relação entre esses dois tempos é importante, porque parece que a resposta é enviada com um jitter também de ~17 µs. Estamos então tentando distinguir respostas que diferem em 4,2 µs no tempo de resposta da função de verificação, mas podem diferir em até 17 µs devido ao jitter da UART (temporização do clock). Esta parece ser uma tarefa difícil, mas é possível fazê-la por meios estatísticos.

Podemos determinar se um byte estava correto ou não tentando verificá-lo várias vezes e registrando os resultados. Suponha, por exemplo, que o menor tempo possível para receber uma resposta se o primeiro byte estiver errado seja 30 µs. Então, com o jitter da UART, podemos esperar um tempo máximo de resposta de 30 µs + 17,4 µs = 47,4 µs para um primeiro byte inválido. Ao mesmo tempo, um primeiro byte válido e um segundo byte inválido empurrariam essa "faixa" para 34,2 µs a 51,6 µs. Adicionando algumas margens, podemos concluir que o primeiro caractere foi inválido caso o tempo de resposta seja menor que ~33 µs. Da mesma forma, podemos dizer que o primeiro caractere foi válido caso o tempo de resposta seja maior que 48 µs. Esta é a base do ataque de temporização usado para extrair o firmware.

Utilizando o extrator de firmware

Esta não é uma ferramenta completamente automática para extração de firmware - será necessária modificação do código fonte e recompilação (usando VS Code com PlatformIO). A principal razão para isso é que as características exatas de temporização para cada byte diferem entre configurações e precisarão ser ajustadas. O processo de ajuste poderia ser automatizado, mas este não era o objetivo deste projeto. O ajuste principal é feito através da variável prober_limits. Por exemplo, prober_limits[0] contém os limites para o byte 0 dos 8 bytes a serem verificados. Caso o tempo de resposta seja inferior a .invalid_under_time, sabemos que o byte era inválido. Caso seja superior a .valid_over_time, sabemos que o byte estava correto. Há também um .min_delta que permite avançar para o próximo byte antes de saber com certeza se o byte está correto ou não.

root@kitploit:~
struct ProberByteLimits prober_limits[8] = {
    {
        // Byte 0
        .invalid_under_time = 33,
        .valid_over_time = 50,
        .min_delta = 30
    }, // ...

Para encontrar os valores adequados a usar, é recomendado definir .invalid_under_time para 0, .valid_over_time para, por exemplo, 100, e .min_delta pode ser mantido em 30. Isso significa que o sondador falhará ao encontrar o primeiro byte correto, mas o progresso será impresso na UART do PC host. Você verá algo parecido com:

root@kitploit:~
[0x0000]=0x01? min=31 max=47 tries=63
               min=31 max=48 tries=127
               min=31 max=48 tries=191
               min=30 max=48 tries=255
               min=30 max=48 tries=319

Desde que o primeiro caractere testado seja inválido, podemos usar esses valores min/max com um deslocamento de 1 ou 2 para determinar os limites adequados. Por exemplo, acima, poderíamos definir .invalid_under_time para 33 e .valid_over_time para 50. O sondador deve então tentar diferentes valores até encontrar um válido, que se pareceria com o seguinte:

root@kitploit:~
...
[0x0000]=0x7d? min=31 max=39 tries= 7
[0x0000]=0x02? min=40 max=56 tries= 7
[0x0001]=0x01? min=35 max=52 tries=34

Vemos que a última tentativa no endereço 0x0000 teve um tempo máximo de resposta de 56 µs, o que significa que esse era o byte correto. O sondador então avança para o próximo byte e continua o processo. Observe que todos os limites dos 8 bytes devem ser ajustados separadamente, mas uma vez feito, funcionará para toda a memória. Quando 8 bytes corretos forem encontrados, ele os imprimirá no formato ihex:

root@kitploit:~
:0800000002002932ffffffff9f

Registrar a saída UART em um arquivo de texto permite usar grep para ^: e extrair o conteúdo completo da memória no formato ihex.

Circuito

Um circuito de exemplo para extração de firmware é mostrado abaixo. Dois transistores permitem desligar a alimentação do CH55x a partir do Blue Pill. Isso é recomendado em vez de usar apenas o reset por software, porque o reset por software só funciona quando o CH55x está no modo bootloader (e o bootloader tem um tempo limite após o qual inicia o código da aplicação). Os resistores na UART para o CH55x estão incluídos porque suspeito que pull-ups internos no CH55x possam realimentar energia para ele a partir da UART mesmo quando a alimentação está desligada. O resistor de 10k entre V33 e P3.6 é necessário para colocar o CH55x no modo bootloader. No Blue Pill, o PA11 está ligado ao pino RX da UART para poder temporizar a resposta usando o timer 1.

Circuito do extrator de firmware CH55x

Conclusão

Ajustando e usando esta ferramenta, o firmware dos dispositivos CH55x pode ser extraído. O processo de extração não é rápido, mas extrairá os 14 kb em um ou dois dias. Depende um pouco do ajuste e de quão bem a tabela de frequência usada corresponde ao assembler real do firmware. Infelizmente, o código fonte está um pouco bagunçado. Fiz esta ferramenta porque precisava do firmware de um dispositivo CH554, e agora que o obtive, não há motivo real para trabalhar na ferramenta em si. No entanto, ela deve ser útil caso alguém precise extrair firmware de dispositivos CH55x.

Baixar ferramenta