Editor de Hexa

Alguém teria algum bom editor hexa para indicar? Eu estou desenvolvendo uma aplicação em C que trabalha com arquivos binários e preciso de um bom editor para visualizar os arquivos gerados para fazer alguns testes.

Não sei se é “bom”. Eu normalmente uso um plugin do Notepad++ que permite editar arquivos em hexa. Entretanto, deve haver editores mais decentes e especializados.

Eu acabei de baixar o plugin pra notepad++ para trabalhar com arquivos em hexa, como eu procedo com a instalação?

No Bing, pegue o primeiro link da consulta “notepad++ hex plugin install”

http://www.hhdsoftware.com/free-hex-editor - Ideal para arquivos gigantes
http://www.softcircuits.com/cygnus/ - Mais simples

Já que estamos escovando bits aqui, para ver dados de um canal socket:
http://www.wireshark.org/

Obrigado entanglement e ViniGodoy
ViniGodoy interessante esse wireshark. Quando eu terminar minha aplicação atual eu estava pensando em fazer uma em C que utilizasse redes e daí o wireshark será util.
Já tô vendo umas coisa sobre ele no google. Obrigado

A propósito ViniGodoy, instalei o editor hdd e abri um arquivo binário para testes. Tem uma tabela que contém caracteres hexa e tem uma outra coluna à direita com caracteres estranhos. O que essa coluna à direita representa?

A representação ascii desses caracteres. Geralmente não vai fazer sentido mesmo, a menos que no meio do arquivo tenha um texto. Quando isso ocorrer, aí será bem útil.

Eu costumo sempre carregar para lá e para cá um programa (em C++ mesmo, cujos fontes até perdi - a data do executável que tenho é de 1997, mas acho que escrevi esse programa ainda antes) que faz um “dump” de arquivos binários. (Mais ou menos o que esse editor hexadecimal faz). Um exemplo da saída desse programa:

0000    CA FE BA BE 00 00 00 32  00 0D 0A 00 03 00 0A 07   .■.....2........
0010    00 0B 07 00 0C 01 00 06  3C 69 6E 69 74 3E 01 00   ........<init>..
0020    03 28 29 56 01 00 04 43  6F 64 65 01 00 0F 4C 69   .()V...Code...Li
0030    6E 65 4E 75 6D 62 65 72  54 61 62 6C 65 01 00 0A   neNumberTable...
0040    53 6F 75 72 63 65 46 69  6C 65 01 00 0A 43 6F 6E   SourceFile...Con
0050    74 61 2E 6A 61 76 61 0C  00 04 00 05 01 00 0D 43   ta.java........C
0060    6F 6E 74 61 43 6F 72 72  65 6E 74 65 01 00 05 43   ontaCorrente...C
0070    6F 6E 74 61 00 20 00 02  00 03 00 00 00 00 00 01   onta. ..........
0080    00 00 00 04 00 05 00 01  00 06 00 00 00 1D 00 01   ................
0090    00 01 00 00 00 05 2A B7  00 01 B1 00 00 00 01 00   ......*.........
00A0    07 00 00 00 06 00 01 00  00 00 2A 00 01 00 08 00   ..........*.....
00B0    00 00 02 00 09                                     .....

Isso é um “dump” de um arquivo .class. Note que todos os arquivos .class começam pelos bytes: CA FE BA BE - algo bem Schwarzeneggeriano: “café, babe!”

Fiz uma função para isso em java:

[code]
private static String toHex(int value, int size)
{
String hex = Integer.toHexString(value).toUpperCase();

    while (hex.length() < size)
        hex = "0" + hex;

    return hex;
}

private static char shortToChar(short character, char nonPrintable)
{
    return character < 0x20 ? nonPrintable : (char) character;
}

/**
 * Mount a String containing all bytebuffer data in a dump format. The 
 * dump format below use 16 bytes per line and '.' as a non-printable.:
 * 
 * <pre>
 *      [0000] 54 68 69 73 20 69 73 20 61 20 73 61 6D 70 6C 65 |This is a sample
 *      [0010] 20 64 75 6D 70 13 66 6F 72 6D 61 74 21          | dump.format!
 * </pre>
 * 
 * The <code>nonPrintable</code> replaces some non-printable characters,
 * such as line feed. This can be seen between the words "dump format" in
 * the sample.
 * 
 * @param data The bytebuffer data to dump. Using this method will not
 *        affect the ByteBuffer position.
 * @param bytesPerLine Number of bytes to print in one line.
 * @param nonPrintable Character that will replace non-printable chars.
 * @return The dump string.
 * @see #getDumpString(ByteBuffer)
 */
public static String getDumpString(ByteBuffer data, int bytesPerLine,
        char nonPrintable)
{
    if (data == null || !data.hasRemaining())
        return "";

    int oldPosition = data.position();

    StringBuilder result = new StringBuilder();

    int line = 0;

    while (data.hasRemaining())
    {
        StringBuilder hexPart = new StringBuilder(3 * bytesPerLine);
        StringBuilder asciiPart = new StringBuilder(bytesPerLine);
        int bytesWritten = 0;
        result.append("[").append(toHex(line * bytesPerLine, 4)).append(
                "] ");

        while (data.hasRemaining() && bytesWritten < bytesPerLine)
        {
            short ch = getUnsignedByte(data);
            hexPart.append(toHex(ch, 2)).append(" ");
            asciiPart.append(shortToChar(ch, nonPrintable));
            bytesWritten++;
        }

        while (bytesWritten++ < bytesPerLine)
            hexPart.append("   ");

        result.append(hexPart).append("|").append(asciiPart).append("\n");
        line++;
    }

    data.position(oldPosition);

    return result.toString();
}

/**
 * Mount a String containing all bytebuffer data in a dump format. The dump
 * format is just like the above:
 * 
 * <pre>
 *      [0000] 54 68 69 73 20 69 73 20 61 20 73 61 6D 70 6C 65 |This is a sample
 *      [0010] 20 64 75 6D 70 13 66 6F 72 6D 61 74 21          | dump.format!
 * </pre>
 * 
 * This method uses 16 bytes per line and '·' to replace non-printable
 * characters.
 * 
 * @param data The bytebuffer data to dump. Using this method will not
 *        affect the ByteBuffer position.
 * @return The dump string.
 * @see #getDumpString(ByteBuffer, int, char)
 */
public static String getDumpString(ByteBuffer data)
{
    return getDumpString(data, 16, '.');
}[/code]

No JDK da Sun existe uma classe - sun.misc.HexDumpEncoder - que faz mais ou menos isso que o ViniGodoy implementou, só que essa classe está bugada e não consegue imprimir direito buffers de bytes cujo comprimento não seja múltiplo de 16. Como essa é uma classe “interna” da Sun, ela não será corrigida a menos que alguém da Sun resolva corrigir isso.

Esse código acima está intencionalmente nojento pq foi otimizado.

Daria para faze-lo muito mais simples com o string.format, mas como usávamos para rastrear um protocolo com tempos de resposta realmente baixos, tivemos que otimiza-lo e fazer muitas coisas no braço.

http://mh-nexus.de/en/hxd/

Esse normalmente é o meu debugador para microcontroladores.

Dois meses depois…

Estava fazendo uns exercícios de um livro de C que estou lendo (e já estou acabando…) e um deles é proposto a criação de algo parecido com o do entanglement e do Vinícius. Não está aquelas coisas, mas funciona :smiley:

Segue o código (editado para refletir a funcionalidade explicada pelo entanglement na próxima página):

[code]/*

  • File: hexdump.c
  • @author David Buzatto
    */

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NUM_BYTES 16

void dump( FILE *file );
void printHeader( void );
void printLine( const int *chars, int offsetLabel, int until );

int main( int argc, char *argv[] ) {

if ( argc == 2 ) {

    char *filename = argv[1];
    FILE *file = fopen( filename, "rb" );

    if ( file != NULL ) {

        dump( file );
        fclose( file );
        return EXIT_SUCCESS;

    } else {

        fprintf( stderr, "hexdump didn't find \"%s\"", filename );
        return EXIT_FAILURE;

    }

} else {

    fprintf( stderr, "Usage: hexdump filename" );
    return EXIT_FAILURE;

}

}

void dump( FILE *file ) {

int contOffset = 0;
int cont = 0;
int ch;
int previousChars[NUM_BYTES];
int chars[NUM_BYTES];
bool starAlreadyPrinted = false;

printHeader();

while ( ( ch = getc( file ) ) != EOF ) {

    if ( cont < NUM_BYTES ) {

        chars[cont] = ch;
        cont++;

    } else {

        int equal = memcmp( chars, previousChars, sizeof( int ) * NUM_BYTES );

        if ( equal == 0 ) {
            if ( !starAlreadyPrinted ) {
                printf( "*\n" );
                starAlreadyPrinted = true;
            }
        } else {
            printLine( chars, contOffset, NUM_BYTES );
            starAlreadyPrinted = false;
        }

        memcpy( previousChars, chars, sizeof( int ) * NUM_BYTES );

        chars[0] = ch;
        cont = 1;

        contOffset += NUM_BYTES;

    }

}

printLine( chars, contOffset, cont );

}

void printHeader( void ) {

int i;
printf( "Offset  " );

int total = NUM_BYTES * 3 - 4;

for ( i = 0; i < total / 2; i++ ) {
    printf( " " );
}

printf( "Bytes" );

for ( ; i < total; i++ ) {
    printf( " " );
}

printf( "Characters\n" );

printf( "------  " );

for ( i = 0; i < NUM_BYTES - 1; i++ ) {
    printf( "---" );
}

printf( "--  " );

for ( i = 0; i < NUM_BYTES; i++ ) {
    printf( "-" );
}

printf ( "\n" );

}

void printLine( const int *chars, int offsetLabel, int until ) {

int i;
printf( "%06X  ", offsetLabel );

for ( i = 0; i < until; i++ ) {
    printf( "%02X ", chars[i] );
}

for ( i = until; i < NUM_BYTES; i++ ) {
    printf( "   " ) ;
}

printf( " " );

for ( i = 0; i < until; i++ ) {
    printf( "%c", isprint( chars[i] ) ? chars[i] : '.' );
}

printf( "\n" );

}[/code]

Ei davidbuzatto obrigado pelo fonte, funcionou igual aos editores citados pelos colegas.

David, esqueci de mencionar que há uma coisa que os programas que efetuam dumps binários costumam fazer também.

Quando há várias linhas repetidas (isso é muito comum em arquivos binários cheios de zeros binários) então as linhas são omitidaa e em seu lugar aparece uma estrela, assim:

0000    D0 CF 11 E0 A1 B1 1A E1  00 00 00 00 00 00 00 00   ................
0010    00 00 00 00 00 00 00 00  3E 00 03 00 FE FF 09 00   ........>...■...
0020    06 00 00 00 00 00 00 00  00 00 00 00 01 00 00 00   ................
0030    01 00 00 00 00 00 00 00  00 10 00 00 02 00 00 00   ................
0040    01 00 00 00 FE FF FF FF  00 00 00 00 00 00 00 00   ....■...........
0050    FF FF FF FF FF FF FF FF  FF FF FF FF FF FF FF FF   ................
*
0200    FD FF FF FF FE FF FF FF  FE FF FF FF FE FF FF FF   ²...■...■...■...
0210    FF FF FF FF FF FF FF FF  FF FF FF FF FF FF FF FF   ................
*
0400    52 00 6F 00 6F 00 74 00  20 00 45 00 6E 00 74 00   R.o.o.t. .E.n.t.
0410    72 00 79 00 00 00 00 00  00 00 00 00 00 00 00 00   r.y.............
0420    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
*
0440    16 00 05 00 FF FF FF FF  FF FF FF FF 01 00 00 00   ................
0450    61 F9 56 88 0A 34 D0 11  A9 6B 00 C0 4F D7 05 A2   a.V..4...k..O...
0460    00 00 00 00 00 00 00 00  00 00 00 00 30 76 B3 89   ............0v..
0470    E1 9A CB 01 03 00 00 00  C0 00 00 00 00 00 00 00   ................
0480    43 00 4F 00 4E 00 54 00  45 00 4E 00 54 00 53 00   C.O.N.T.E.N.T.S.
0490    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
*
04C0    12 00 02 01 FF FF FF FF  FF FF FF FF FF FF FF FF   ................
04D0    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   ................
*
04F0    00 00 00 00 00 00 00 00  9C 00 00 00 00 00 00 00   ................

No exemplo acima, as linhas 0060, 0070… até 01F0 contém o mesmo valor que a linha 0050 (um monte de FF).

Oi entanglement. Não sabia desse detalhe!
Acabei de corrigir e programa para fazer da forma que você explicou.

Muito obrigado!

[]´s

Exemplo.
Entrada:asiudyuaisydas asasasasasasas asasasasasasas xxxxxxxxxxxxxx xxxxxxxxxxxxxx xxxxxxxxxxxxxx xxxxxxxxxxxxxx bbbbbbbccccccc bbbbbbbccccccc bbbbbbbccccccc ashdhsgdhasgdj asdasdasddasds asdasdasdsd

Saída:[code]Offset Bytes Characters


000000 61 73 69 75 64 79 75 61 69 73 79 64 61 73 0D 0A asiudyuaisydas…
000010 61 73 61 73 61 73 61 73 61 73 61 73 61 73 0D 0A asasasasasasas…
*
000030 78 78 78 78 78 78 78 78 78 78 78 78 78 78 0D 0A xxxxxxxxxxxxxx…
*
000070 62 62 62 62 62 62 62 63 63 63 63 63 63 63 0D 0A bbbbbbbccccccc…
*
0000A0 61 73 68 64 68 73 67 64 68 61 73 67 64 6A 0D 0A ashdhsgdhasgdj…
0000B0 61 73 64 61 73 64 61 73 64 64 61 73 64 73 0D 0A asdasdasddasds…
0000C0 61 73 64 61 73 64 61 73 64 73 64 asdasdasdsd[/code]

entanglement, essa separação de dois espaços entre os oito primeiros e oito últimos bytes é comum tbm? Fica mais fácil de visualizar.

Sr David Buzatto,

poderia entrar em contato,
desejo um programa em C para ler balanças eletronica. Uma toledo modalidade 9091.

obrigado

abrilsul@ig.com.br

Mineiro