Por que não podemos entender o conteúdo de um arquivo binário depois de compilado?

11

Até onde eu sei, todo programa consiste em um pacote de instruções do processador com algumas variáveis ​​de dados específicas (float, int, char ...) para trabalhar nos registros do processador .

Então, a primeira coisa que pensei sobre isso (há muito tempo) é que, se você souber que o valor ASCII de %¨#$¨#(apenas um exemplo aleatório) pode ser interpretado como o endereço do registrador de ponteiro de pilha (apenas exemplificando) de um x86 processador. Se isso for verdade, sempre que você encontrar esse valor "ilegível" ao ler o conteúdo de um arquivo binário, poderá interpretar que o registro do ponteiro de pilha está sendo usado para gerenciar algumas variáveis ​​de dados.

Infelizmente isso não acontece. Abaixo, há um exemplo do conteúdo do ping.exeprograma do Windows aberto com notepad.exe:

Ping.exe como visto no bloco de notas do MS

É um arquivo binário e seus dados são incompreensíveis para nós, humanos (é compreensível para máquinas). Não faz sentido para ninguém, mesmo que eles conheçam o código Assembly (o nível mais baixo da linguagem de máquina).

Então, se eu entendi tudo corretamente, alguém poderia explicar

  1. Por que um código binário não pode retornar ao código do Assembly na medida em que é, no fundo, a mesma coisa?
  2. Se alguém pode entender o código de montagem, por que o binário compilado resultante desse código não é mais "legível"?
Diogo
fonte
12
Você pode, você só precisa de um desmontador .
David Schwartz
Para que eu possa desmontar qualquer arquivo .exe ??? Eu só sabia que ele funciona com código gerenciado ...
Diogo
13
Você pode desmontar qualquer executável. Se você consegue entender a saída desmontada é outra história.
David Schwartz
5
A compilação ou montagem remove muitas informações significativas para o ser humano, como nomes de variáveis, rótulos de ramificações, etc. A desmontagem obtém o fluxo de instruções, mas você ainda tem muito o que descobrir.
mpez0
1
A ofuscação do código também pode impedir a desmontagem.
math

Respostas:

13

Primeiro, os registros não têm endereços. Cada instrução em qualquer linguagem assembly é traduzida em um código de operação. Os códigos de operação no x86 podem ter um, dois, três ou até mais bytes (em alguns outros processadores eles têm "largura fixa"). Normalmente, o código de operação identifica a instrução, o modo de endereçamento e os registros envolvidos. O "modo de endereçamento" determina se mais do que o código operacional é necessário para a CPU, ou seja, o modo de endereçamento "imediato" significa que existem dados adicionais logo após (ou "imediatamente após") a instrução para essa instrução - modos de endereçamento "absoluto" significa que um O endereço de memória segue a instrução e é usado por essa instrução.

Você pode descobrir o código de operação de algo parecido MOV AL,SPou semelhante e, em seguida, procurá-lo. O x86 possui muitas instruções que funcionam no ponteiro da pilha.

Mas, por favor, saia do Notepad e use um editor hexadecimal. Eu recomendaria o HxD, embora existam muitos outros.

E @ David Schwartz está correto. Um desmontador irá percorrer um arquivo e converter os códigos de operação novamente em texto legível. O que você quer fazer é totalmente possível.

No entanto, você precisa saber onde as instruções começam no arquivo, porque, se você começar no endereço errado, alguns dados que devem ser os "operandos" dos códigos de operação (como instruções que levam um endereço para um operando ou "argumento") podem ser mal interpretado como opcodes. Saber isso requer conhecimento do formato em que o executável está, que é para Windows o formato "Portable Executable" ou PE (e geralmente é o ELF para sistemas Linux). Tenho certeza de que existem desmontadores que entendem PE, etc., mas não conheço nenhum desagrado.

LawrenceC
fonte
1
A IDA é um dos dissimuladores de PE mais comuns. Também funciona com arquivos Linux e Mac. A versão 5.0 ainda está disponível como freeware
Scott Chamberlain
1
> se você começar no endereço errado,… poderá ser mal interpretado. É por isso que todas as ocorrências de %¨#$¨#não serão necessariamente uma referência ao ponteiro da pilha; pode ser apenas o meio de dois comandos diferentes : _3p%¨#e $¨#b5F( _3p   %¨#$¨#   b5F).
21412 Synetech
12

Então, se eu entendi tudo corretamente

Nem tanto.

É um arquivo binário e seus dados são incompreensíveis para nós humanos

Normalmente, um arquivo binário é incompreensível para humanos e máquinas, especialmente quando o objetivo do arquivo é desconhecido. Observe que nem todos os arquivos binários são executáveis. Muitos arquivos binários são arquivos de dados que não contêm nenhuma instrução da máquina. É por isso que as extensões de arquivo são usadas ao nomear arquivos (em alguns sistemas operacionais). O . A extensão com foi usada pelo CP / M para indicar um arquivo executável. O . A extensão exe foi adicionada pelo MS-DOS para indicar outro formato de arquivo executável. * nixes usam o atributo execute para indicar quais arquivos podem ser executados, embora possam ser tanto scripts quanto códigos.

Como já mencionado por outros, os arquivos binários, que contêm números, devem ser visualizados por um programa hex dump ou editor hexadecimal e não por um visualizador de texto.

existe um exemplo do conteúdo do programa ping.exe

Na verdade, esse arquivo é um programa realocável e nem todos os dados nesse arquivo representam código de máquina. Há informações sobre o programa, como quais bibliotecas dinâmicas ele precisa, quais rotinas precisam ser vinculadas, requisitos para pilha e memória de programa e dados e o ponto de entrada do programa. Os operandos de endereço no arquivo podem ser valores relativos que precisam ser calculados para valores absolutos ou referências que precisam ser resolvidas.

O "arquivo de programa" no qual você provavelmente está pensando é chamado de arquivo de imagem binária ou despejo de memória de programa. Esse arquivo conteria apenas código e dados da máquina, com todas as referências de endereço definidas corretamente para execução.

mesmo se eles souberem o código Assembly (o nível mais baixo da linguagem de máquina).

A linguagem assembly não é igual à linguagem de máquina . A CPU típica (como para excluir computadores de linguagem de alto nível) aceita código de máquina como entrada, uma instrução por vez. Os operandos são registradores ou endereços de memória numérica. A linguagem Assembly é uma linguagem de nível superior que pode usar etiquetas simbólicas para locais e variáveis ​​de instruções, além de substituir códigos operacionais numéricos por mnemônicos. Um programa em linguagem assembly deve ser convertido em código / idioma da máquina antes de poder ser executado (normalmente por utilitários chamados assembler, linker e loader).

A operação reversa, desmontagem, pode ser realizada em arquivos de programa com algum sucesso e perda de informações simbólicas. A desmontagem de um despejo de memória ou arquivo de imagem de programa é mais tentativa e erro, pois os locais de código e dados precisam ser identificados manualmente.

BTW, existem pessoas que podem ler e codificar o código de máquina (numérico). É claro que isso é muito mais fácil em uma CPU ou microcontrolador de 8 bits do que em um processador CISC de 32 bits com uma dúzia de modos de endereço de memória.

serragem
fonte
3

Você não pode ver a codificação correta pretendida de um arquivo binário através do Bloco de Notas. Revise isso para referência futura. A maioria dos programas de edição de texto não analisa formatos de codificação binária e espera analisar a formatação do código de caracteres ASCII.

Portanto, a abertura de um arquivo binário em um editor de texto produzirá caracteres ASCII equivalentes que não fazem sentido no formato original dos dados binários analisados ​​pelo editor de texto. Como mencionado, editores hexadecimais, e alguns possuem recursos binários, para visualizar o conteúdo em formato binário puro.

Você está incorreto ao não entender o conteúdo de um arquivo binário. Embora eles sejam difíceis, e nas arquiteturas modernas de computadores extremamente difíceis de desmontar manualmente do binário sozinho, para instruções apropriadas reconhecidas pela CPU para execução (ou CPU emulada / virtual), etc., isso pode ser feito.

Como você acha que os emuladores são programados? O desenvolvedor precisaria conhecer opcodes para poder programar o sistema fictício para reconhecer e se comportar como o hardware real faria de alguma maneira. As documentações explicam muitas arquiteturas de CPUs e até as GPUs as possuem (embora mais secretas).

Outra coisa a se notar é que, no nível mais baixo, embora correlativo, os "dados binários" não são realmente um monte de zeros e uns, mas tensões alta e baixa amplificadas / comutadas através de um circuito elétrico como corrente.

O binário geralmente é 1: 1 com isso, por isso faz muito sentido usar o sistema de números para ele.


fonte