Talvez você conheça o Hiew (abreviação de Hacker's View), um poderoso editor hexadecimal que reconhece formatos de executáveis como PE e ELF e é capaz de editar suas características, disassemblar código em x86 e ARM e muito mais. Se ainda não conhece, comenta aí que num momento oportuno volto para falar mais dele. 😉
Neste artigo apresento o Hiewix, um novo programa feito pelo mesmo desenvolvedor do Hiew, Eugeny Suslikov, mais conhecido por seu nick SEN. Nesta leitura, você vai descobrir:
- Para que serve o Hiewix e o problema que ele vem resolver.
- Os poderes e limitações do Hiewix.
- Se vale a pena ou não comprá-lo. 💸
O Hiewix é para os momentos em que você não conhece a estrutura de determinado arquivo binário. Logo, seu intuito não é servir para editar arquivos PE, ELF ou Mach-O. Na real, a versão atual nem é capaz de modificar arquivos abertos, mas sim de trabalhar para reconhecer, com a sua ajuda, arquivos desconhecidos.
Nada melhor que um exemplo para entender o poder do Hiewix. Recomendo acompanhar o artigo baixando a versão demo do Hiewix no site oficial e a ISO do Math Invaders para extrair o GAME.PAK que vamos utilizar como exemplo.
Considere um formato de arquivo binários, ou seja, cuja estrutura e conteúdo não sejam facilmente deduzíveis, utilizado num jogo qualquer. O nome do nosso arquivo é GAME.PAK, então vamos chamá-lo de arquivo PAK, mas não conhecemos sua estrutura ainda. A figura 1 mostra a tela do Hiewix v1.10.633 ao abrir o arquivo pela primeira vez.
Figura 1 - Tela inicial do Hiewix ao abrir o arquivo GAME.PAK
O Hiewix nos dá algumas opções iniciais para carregar o arquivo:
- Main parser é o parser principal. O padrão é Binary(internal), que não faz nenhuma análise no arquivo. É nossa única opção numa primeira vez.
- Base address configura o primeiro endereço mostrado na tela do Hiewix para o conteúdo do arquivo. Por exemplo, se você digitar "10" (sem aspas), o primeiro byte do arquivo começará no endereço 0x10 e todos os comandos do Hiewix vão trabalhar a partir deste endereço base.
- Codesize permite configurar, se o arquivo contiver bytecode, (bytes que representam instruções para a CPU) o tipo de código para 16, 32 ou 64-bits. O Hiewix assume a arquitetura x86. Para arquivos de dados, a opção é Data.
- Second parser permite carregar um segundo parser além do principal para rodar sobre o arquivo. Mais sobre parsers em breve.
Ao clicar em OK com as opções padrão selecionadas somos apresentados a uma tela bem parecida com a de um editor hexadecimal comum, mostrada na figura 2.
Figura 2 - arquivo GAME.PAK aberto no Hiewix
parte 1 e a parte 2). Na parte 1, usei o Kaitai Struct e o Hiew. Já na parte 2, utilizei também o ImHex editor. Na época ainda não tinha Hiewix. 😄
NOTA: Se ao bater o olho nos bytes deste arquivo você achou esse formato familiar, provavelmente já fez engenharia reversa em jogos antigos ou assistiu a um dos vídeos sobre a engenharia reversa que fiz no jogo Math Invaders (veja aO Hiewix criou um segmento padrão de dados de tamanho 0x15EB759, que no caso é o tamanho total do arquivo (22,984,537 bytes). Este segmento, assim como outros que porventura sejam criados, só fazem sentido na interface do Hiewix e servem para organizar diferentes segmentos de dados ou código que você descubra. Nada no arquivo é alterado com a criação deles. Alías, lembre-se: o Hiewix abre o arquivo com permissão de leitura somente.
Uma vez o arquivo aberto, cabe a nós entender sua estrutura. Isso pode ser feito diretamente para formatos simples, mas formatos mais complexos podem exigir a engenharia reversa do executável que abre o arquivo analisado. Conforme formos compreendendo os dados no arquivo, vamos dando comandos no Hiewix que reflitam o que entendemos sobre tais dados.
Comandos do Hiewix
Os comandos são para você descrever o tipo de dado no qual o cursor se encontra. Por exemplo, por conta da análise deste arquivo PAK que já fiz, sei que os primeiros quatro bytes deste arquivo representam uma DWORD (double word), ou seja, um número de 4 bytes que nos diz quantos arquivos existem neste .PAK (o .PAK é uma espécie de sistema de arquivos rústico implementado num único arquivo que contém vários arquivos). Para descobrir como cheguei a esta conclusão, assista os vídeos de engenharia reversa no Math Invaders. 😉
Se os primeiros quatro bytes são uma DWORD, eu dou um clique no primeiro byte da DWORD (0x56 na figura 3) e clico no pequeno botão de um balãozinho com as lestras dd (de define dword) para produzir o efeito mostrado na figura 3.
Figura 3 - Primeira DWORD definida com o Hiewix no GAME.PAK
Perceba o efeito: O Hiewix pula uma linha na visualização após o fim da DWORD (ou seja, após o quarto byte) e muda a representação na coluna da direita para "dd 00000056", que indica que ela é uma DWORD e seu valor é 0x56 em little-endian.
Ao definir números, é possível ter algum controle sobre sua representação. Por exemplo, posso selecionar os mesmos quatro bytes da minha DWORD e clicar novamente no botão dd para definir um array de um elemento com representação decimal. Dessa forma, o valor é apresentado em decimal na coluna da direita, como mostra a figura 4.
Figura 4 - DWORD redefinida como array de um elemento com visualização em decimal
A ideia é que você vá descrevendo os conjuntos de bytes do arquivo com os comandos disponíveis no Hiewix, o que me lembra bastante o IDA, da Hex-Rays.
Os principais comandos disponíveis no Hiewix estão a seguir (o texto do ícone de cada botão, quando existe, está entre parênteses):
- Name (ab), define um nome para o byte, que aparecerá na aba Names, mostrada como Names(0) na Figura 2.
- Code (add), diz que o byte deve ser interpretado como código. Está desabilitado pois estamos num segmento de dados.
- Byte (db), define um byte.
- Word (dw), define uma WORD de dois bytes.
- Dword (dd), define uma DWORD de quatro bytes.
- Qword (dq), define uma QWORD de oito bytes.
- Float (df), define o tipo de dados float para números reais.
- Double (dF), define o tipo de dados double para números reais.
- Dump, ainda não entendi. 😄
- Byteline, define um conjunto de bytes sem interpretação.
- Asciiz (a), define uma string ASCII.
- Unicode, define uma string Unicode.
- Comment line, insere um comentário acima da linha.
- Comment on line, insere um comentário à direita da linha (na coluna da direita).
A figura 5 mostra as três primeiras entradas do arquivo PAK totalmente definidas e com comentários e nomes criados.
Figura 5 - Definições dos campos da estrutura do PAK
O texto em vermelho descreve o tipo de definição que usei, ou seja, os botões que apertei para definir os dados. Como também usei nomes, a aba Names à esquerda mostra os quatro nomes que defini. A ideia é poder dar um duplo-clique no endereço do nome (coluna address) para que o Hiewix navegue direto para lá.
Também é possível marcar pontos como favoritos no arquivo que serão mostrados na aba Bookmarks. Para isso, basta selecionar o byte desejado clicar à esquerda da linha.
Com estes poderes, o Hiewix nos permite ter uma visualização muito melhor do conteúdo do arquivo. Algo similar aos Templates no 010 Editor ou às structs do Kaitai Struct. A diferença é que o Hiewix nos permite criar a estrutura interativamente e não só programaticamente.
Criando parsers
Na versão paga, você até pode salvar o estado atual (com suas definições feitas) para este arquivo específico e depois carregá-lo. No entanto, se uma definição se repete muito (como é o caso das 86 entradas neste arquivo PAK) ou se você precisar abrir outros arquivos com a mesma estrutura, não faria sentido ter que definir todos os campos manualmente. Para estes casos, o Hiewix oferece o recurso de criação de parsers, ou seja, de pequenos programas que irão entender o conteúdo do arquivo para você. O software oferece duas APIs, uma em C e outra em Lua para tal. O pacote da versão paga vem com um exemplo em C++ um pouco difícil de entender e um esqueleto em Lua, sem um exemplos completo. Com alguma luta, consegui escrever um parser em C/C++ e compilá-lo com o Visual Studio 2022. O código basicamente automatiza o que fizemos na mão, mas com algumas ressalvas. A principal função é a ParseFile(), que mostro abaixo:
/* * Math Invaders' PAK file parser for Hiewix * Author: mer0x36 * Date: December 2024 * * Compile with: * cl pak.cpp /link /out:pak.hwx32 kernel32.lib Hiewix32.lib /dll /subsystem:windows * * Then copy te pak.hwx32 to Hiewix root folder and load the PAK file * You can download the GAME.PAK file from * https://archive.org/details/MathInvaders (it's in the ISO file) */ #include <fcntl.h> #include <inttypes.h> #include <io.h> #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include "HiewixExport.h" // API version: 110 #define NAME_LEN 64 // Compile with: // cl pak.cpp /link /out:pak.hwx32 kernel32.lib Hiewix32.lib /dll /subsystem:windows long __stdcall DllMain(void *hModule, unsigned long reason, void *lpReserved) { return 1; } HWX_EXPORT int ApiVersionUsed() { return HWX_API_VERSION; } HWX_EXPORT unsigned long HwxID() { return 0; } HWX_EXPORT const wchar_t *HwxTitle() { return L"Math Invaders PAK"; } HWX_EXPORT unsigned long HwxFlags() { return 0; } // PAK entry struct typedef struct { char name[NAME_LEN]; uint32_t offset; } entry; HWX_EXPORT bool IKnowThisFile(HWX_PREFILE_DATA *p_hwx_prefile_data) { p_hwx_prefile_data->_decode_engine = decode_engine_none; return true; } HWX_EXPORT bool ParseFile(HWX_FILE_DATA *p_hwx_file_data) { uint32_t nentries = 0; __int64 addr = 0; struct _stat st; const int file_index = p_hwx_file_data->_file_index; // Read the first DWORD from the file as it contains its number of entries int fd = ::_wopen(p_hwx_file_data->_filename, _O_RDONLY); if (fd == -1) return false; if ( ::_read(fd, &nentries, sizeof(nentries)) != sizeof(nentries) ) return false; // We'll use st.st_size to get the filesize if (::_fstat(fd, &st) != 0) return false; ::_close(fd); // Adds a data segment for the PAK header const __int64 headerSize = (nentries + 1) * sizeof(entry) + sizeof(uint32_t); HwxFileAddDataSegment(file_index, 0, 0, headerSize, 0); HwxFileSegmentName(file_index, 0, L"PAK_Header"); HwxFileSegmentCollapse(file_index, 0, false); // Adds a data segment for the PAK contents (right after header) HwxFileAddDataSegment(file_index, headerSize, headerSize, st.st_size-headerSize, 0); HwxFileSegmentName(file_index, headerSize, L"PAK_Contents"); HwxFileSegmentCollapse(file_index, headerSize, false); // Add a comment above the first line HwxFileCommentline(file_index, 0, L"PAK file start"); // Set number format to decimal HwxFileMakeDec(file_index); // Define a Dword HwxFileMakeDword(file_index, addr); // Set number format back to hex (default) HwxFileMakeHex(file_index); HwxFileCommentOnline(file_index, addr, L"number of entries"); addr += sizeof(uint32_t); // Loop that defines the entries for (int i=0; i < nentries; i++) { // Define a string, a comment, then advances 16 bytes HwxFileMakeStringAsciiz(file_index, addr, NAME_LEN); HwxFileCommentOnline(file_index, addr, L"file path"); addr += NAME_LEN; // Define a DWORD, a comment, then advances 4 bytes HwxFileMakeDword(file_index, addr); HwxFileCommentOnline(file_index, addr, L"file offset"); addr += sizeof(uint32_t); } return true; }
O código completo será disponibilizado em breve.
Após compilado, o arquivo é uma DLL com extensão .hwx32 que deve ser colocado no diretório raiz do Hiewix. Dessa forma, ao abrir um novo arquivo, será possível escolher o nosso parser personalizado como mostra a figura 6.
Figura 6 - Nosso parser personalizado para escolha ao carregar um novo arquivo
O resultado você vê na figura 7. O arquivo é totalmente parseado (sim, um neologismo - e por que não?), dois segmentos são criados e vários comentários feitos.
Figura 7 - PAK parseado com nosso parser personalizado
Neste parser optei por não criar nomes para o código ficar menor. Ao invés de nomes, criei um segundo segmento, algo que só parece ser possível através da API por enquanto.
Já dá para perceber o poder que o Hiewix tem. Imagine que você pode criar parsers para qualquer tipo de arquivo que desejar. Se somar o poder o Kaitai Struct (que emite parsers em C++), fica mais poderoso ainda. No entanto, o Hiewix ainda está em desenvolvimento e é possível que muitas coisas mudem, inclusive na API, então recomendo segurar sua peteca antes de sair por aí criando parsers.
Vale a pena comprar?
O software me pareceu muito bom, mas há alguns pontos que requerem atenção na minha opinião, embora as coisas possam mudar muito em breve. São eles:
Prós
- Velocidade. O Hiewix é escrito em C/C++ como tudo o que o SEN faz. E tudo acontece muito rápido no software. Isso é algo que eu valorizo muito, especialmente depois da invasão destes apps escritos em JavaScript para desktop que são uma carroça.
- Há quatro opções para marcar um endereço: nome, comentário acima da linha, comentário à direita da linha e favorito (bookmark). Muito legal essa versatilidade e muito similar ao Hiew, com o comentário acima talvez inspirado no IDA?
- Possibilidade de rodar um segundo parser, deixando ainda mais versátil. A API também sugere parsers reentrantes, mas não encontrei muita informação a respeito.
- A criação de tabelas (abas na parte de baixo da janela), que não mostrei aqui, mas é exibida na captura de tela aqui (abas Header, Dir, Sections, etc).
- Para um software pago, o preço é razoável: 50 dólares (aproximadamente R$ 300,00) por um ano e você renova se quiser as atualizações depois deste período. Para quem trabalha com arquivos desconhecidos com frequência, pode justificar o investimento.
Contras
-
Em minha opinião, o software ainda vai amadurecer. Há um pequeno bug na visualização das colunas e
não dá para controlar o tamanho da janela inicial do software(basta ir no menu Options e clicar em Save as default), por exemplo. Outros recursos dos quais senti a falta:- Criação de novos segmentos através da interface gráfica.
- Possibilidade de exportar os bytes, como no Hiew.
-
Redefinir uma Dword como decimal pela API como fiz na interface gráfica. Bem, pode ser que haja uma maneira, mas ainda não descobri(basta usar HwxFileMakeDec() e depois voltar para hexadecimal com a HwxFileMakeHex()). - Suporte a outras arquiteturas além de x86 para segmentos de código.
- A API, por enquanto, me pareceu um pouco difícil de usar e não há documentação além de um arquivo de cabeçalho com os protótipos das funções da API.
- Como todos os outros softwares do SEN, o Hiewix é nativo para Windows, mas consegui rodá-lo no Ubuntu com Wine sem problemas aparentes.
Espero que este artigo tenha sido útil para conhecer esta nova ferramenta e/ou como uma introdução no conceito de parsing de arquivos binários. Como sempre, fique junto e lembre-se que você pode apoiar a Mente Binária para que artigos como esse continuem sendo publicados. Um abraço e happy hacking!
Atualização em 10/12/2024: O autor do software leu o artigo e entrou em contato explicando alguns dos "contras".
- 1