Desmontagem e o IDA Pro na Análise de Programas
Tags: braziliandevs, cybersecurity, tooling, learning
Published: 2024-03-10 21:57:11

O processo de desmontagem, também conhecido como **disassembly**, é essencial na engenharia reversa e análise de programas binários. Envolve a tradução do código de máquina, compreensível apenas pelos computadores, para uma forma textual mais legível para os humanos. Ao desmontar um executável, revertemos o processo de compilação, permitindo a análise detalhada da funcionalidade interna do programa.

## IDA Pro 7.5:
Entre as ferramentas disponíveis para desmontagem e análise estática de programas binários, o IDA Pro 7.5 se destaca como uma escolha popular e robusta. Com uma variedade de recursos poderosos, o IDA Pro oferece uma plataforma abrangente para entender a estrutura e o comportamento de programas binários.

Com sua *capacidade*:

- _Desmontagem de Código:_  desmonta código de uma ampla variedade de arquiteturas de processadores, permitindo a análise de programas desenvolvidos para diferentes sistemas.
    
- _Identificação de Funções:_  identifica e nomeia funções no código desmontado, facilitando a compreensão da lógica do programa.
    
- _Navegação pelo Código:_  permite a navegação eficiente pelo código desmontado, facilitando a análise de fluxo de controle e de dados.
    
- _Descompilação:_  oferece recursos de descompilação, permitindo a conversão do código de montagem para um nível mais alto de abstração, tornando-o mais próximo do código-fonte original.

O *IDA Pro* se destaca como uma escolha preferida para engenheiros de segurança, analistas de malware e pesquisadores de software. Vamos explorar como este poderoso conjunto de ferramentas pode ser aplicado para entender a estrutura interna de um arquivo.

## Aplicação Prática
Para ilustrar o uso do **IDA Pro**, consideremos um exemplo simples de um programa em C. Após compilar o código em um executável, podemos analisá-lo no **IDA Pro** para entender sua estrutura interna e funcionamento. 

Código original criado em C:

```C
#include <stdio.h>
#include <stdlib.h>

int soma(int x, int y);

int main() {
	int a, b = 0;

	printf("Digite A: ");
	scanf("%d", &a);
	printf("Digite B: ");
	scanf("%d", &b);

	printf("\n%d + %d = %d\n", a, b, soma(a, b));
}

int soma(int x, int y) {
	int z;
	z = x + y;
	return(z);
}
```

Essa imagem mostra um trecho do código **assembly** gerado pelo **IDA Pro** para o programa em C fornecido.

![Imagem da geração do código de descompilação Assembly](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rg5d3w4zdt7xkyjtw4xu.png)

O código ***assembly*** gerado pelo **IDA Pro** revela cada instrução exigida pelo executável, incluindo chamadas de funções como ``printf``, ``scanf`` e a função soma.

É interessante notar como as chamadas de função em C são traduzidas para o código **assembly** pelo compilador e como o **IDA Pro** revela essa estrutura. Por exemplo, quando ocorre a soma no código **assembly**, é possível observar a instrução ``lea`` seguida por uma chamada ``printf`` com o uso do ``call`` para exibir o resultado da operação.

## Análise Detalhada de Funções
Além de mostrar cada instrução chamada pelo ``.exe``, o **IDA Pro** permite uma análise detalhada das funções específicas dentro do programa. Na imagem abaixo, podemos ver o código assembly da função soma do código em C após ser analisado. Essa representação revela como a função é implementada em código assembly e como ela interage com outras partes do programa.

![Imagem da geração do código de descompilação Assembly mostrando as funções](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2oruswbk10iyqvvlygsl.png)

Uma das vantagens do **IDA Pro** é sua capacidade de identificar e nomear automaticamente as funções no código **assembly**. Além disso, ele fornece informações úteis sobre cada função, incluindo o endereço de *início*, *tamanho* e *argumentos esperados*.

Por exemplo, ao analisar o código assembly da função ``soma``, o **IDA Pro** pode fornecer detalhes como o endereço de início da função, o tamanho do código assembly que compõe a função e os argumentos que ela espera receber. Essas informações são essenciais para entender a estrutura e o comportamento do programa em um nível baixo do sistema.

![Imagem da geração de funções utilizadas](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j1998fya9z7t3cdoir5v.png)

Também oferece a capacidade de visualizar as ``strings`` utilizadas pelo programa. Essas ``strings`` podem conter mensagens de texto, nomes de variáveis, chamadas de sistema e outros dados importantes para entender a funcionalidade do programa. A visualização das ``strings`` pelo **IDA Pro** ajuda os analistas a identificarem rapidamente informações relevantes no código binário.

![Imagem da geração de strings utilizadas](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n5bg7yrej6n6aim9vd4i.png)

É importante notar todas as iterações com o usuário, como mensagens de entrada e saída. Por exemplo, ele pode destacar automaticamente ``strings`` como "Digite A:" e "Digite B:", que representam solicitações de entrada de dados pelo programa. Essa marcação facilita a identificação e compreensão das interações entre o programa e o usuário durante a execução.

## Plugins e Extensões
Além das poderosas ferramentas padrão oferecidas pelo IDA Pro, o software também suporta uma variedade de plugins e extensões que fornecem funcionalidades adicionais para análise de programas binários. Esses plugins podem ser desenvolvidos pela comunidade ou por terceiros e oferecem uma ampla gama de recursos, desde descompilação até análise específica de vulnerabilidades.

## Descompilação de Pseudocódigo
Essa ferramenta é capaz de traduzir o código de máquina em um nível mais alto de abstração, fornecendo uma representação mais próxima do código-fonte original. Por exemplo, o trecho de código C fornecido pode ser o resultado da descompilação de um programa binário, oferecendo uma visão mais legível e compreensível do funcionamento do programa.

```C
int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  unsigned int v5; // [rsp+28h] [rbp-8h] BYREF
  unsigned int v6; // [rsp+2Ch] [rbp-4h] BYREF

  _main(argc, argv, envp);
  v5 = 0;
  printf("Digite A: ");
  scanf("%d", &v6);
  printf("Digite B: ");
  scanf("%d", &v5);
  v3 = soma(v6, v5);
  printf("\n%d + %d = %d\n", v6, v5, v3);
  return 0;
}
```

Embora o código descompilado possa não ser idêntico ao código-fonte original, ele ainda oferece uma perspectiva sobre a lógica e a estrutura do programa. 

## Análise de Código com Estruturas Condicionais

O IDA Pro também permite a análise de estruturas condicionais, como aquelas definidas pelas instruções ``if``, ``else if`` e ``else`` em programas em C. Vamos considerar o seguinte exemplo de código em C:

```C
#include <stdio.h>
#include <stdlib.h>

int soma(int x, int y);

int main(){
    int a = 100;

    if (a == 0) {
        printf("Variavel A vale zero!");
    }
    else if (a < 10) {
        printf("o A é menor que 10");
    }
    else if (a < 20) {
        printf("o A é menor que 20");
    }
    else if (a == 100){
        printf("o A vale 100");
    }
    else{
        printf("Isso é um erro");
    }

    return 0;
}
```

Quando compilado e analisado, obtemos uma representação em código assembly que reflete a lógica das estruturas condicionais do programa. Essa análise pode ajudar a entender como as decisões são tomadas dentro do programa e como diferentes caminhos de execução são seguidos com base nas condições definidas.

![Imagem da geração do assembly mostrando a iteração do programa com as estruturas de comparação](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/thrmz5q0qvsy098zj7mb.png)

Identifica as iterações das estruturas condicionais presentes no código original e as expressa de uma forma mais legível para os humanos. As divisões por setas ao longo do código descompilado indicam claramente as diferentes iterações através das estruturas condicionais, facilitando a compreensão do fluxo de execução.

Por exemplo, quando o código passa por um bloco ``if``, como aquele que em assembly seria representado por ``cmp [rbp+var_4], 0``, o IDA Pro mostra essa iteração claramente, evidenciando a comparação da região da pilha com zero para determinar se retorna 1 ou 0.
Essa representação com divisões por setas torna ainda mais claro o fluxo de execução através das estruturas condicionais, facilitando a compreensão da lógica do programa.

## Descompilação de Pseudocódigo
Agora, se seguirmos o mesmo procedimento anterior e utilizarmos o descompilador para gerar um pseudocódigo a partir do novo executável, obteremos o seguinte resultado:

```C
int __cdecl main(int argc, const char **argv, const char **envp)
{
  _main(argc, argv, envp);
  printf("o A vale 100");
  return 0;
}
```

Isso ocorre porque o descompilador reconheceu que, no código original, a variável A sempre possui o valor 100, e por isso determinou que as outras linhas não são alcançadas.

Se alterarmos a variável A agora para receber um valor variável:

```C
#include <stdio.h>
#include <stdlib.h>

int soma(int x, int y);

int main(){
    int a = 0;
	printf("Digite o valor para A:");
	scanf("%d", &a);

    if (a == 0) {
        printf("Variavel A vale zero!");
    }
    else if (a < 10) {
        printf("o A é menor que 10");
    }
    else if (a < 20) {
        printf("o A é menor que 20");
    }
    else if (a == 100){
        printf("o A vale 100");
    }
    else{
        printf("Isso é um erro");
    }

    return 0;
}
```

Agora utilizando a ferramenta de descompilação temos o seguinte retorno: 

```C
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+2Ch] [rbp-4h] BYREF

  _main(argc, argv, envp);
  v4 = 0;
  printf("Digite o valor de A:");
  scanf("%d", &v4);
  if ( v4 )
  {
    if ( v4 > 9 )
    {
      if ( v4 > 19 )
      {
        if ( v4 == 100 )
          printf("o A vale 100");
        else
          printf("Isso Ã© um erro");
      }
      else
      {
        printf("o A Ã© menor que 20");
      }
    }
    else
    {
      printf("o A Ã© menor que 10");
    }
  }
  else
  {
    printf("Variavel A vale zero!");
  }
  return 0;
}
```

Podemos observar que o descompilador verifica a existência da variável v4 e, em seguida, inicia o processo de verificação utilizando a estrutura IF. Embora o pseudocódigo resultante não seja perfeito, às vezes é mais simples compreendê-lo do que analisar o código assembly diretamente.

## Depuração em Tempo Real:

Além de suas capacidades de análise estática também pode ser usado para depuração em tempo real, permitindo aos usuários acompanhar a execução do programa e examinar o estado dos registradores e da memória durante a execução. Isso é particularmente útil para identificar problemas e entender o comportamento dinâmico do programa.

![Imagem de depuração em tempo real](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hnh3izkyu4wh4txpyjah.png)

Durante a depuração em tempo real exibe informações detalhadas sobre o estado dos registradores, permitindo que os usuários observem como os valores dos registradores mudam à medida que o programa é executado. Essas informações são cruciais para entender o fluxo de controle e a manipulação de dados pelo programa em tempo real.

![Imagem de depuração em tempo real mostrando os registradores no processo de execução](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zoxmtpmpmxw9bd8u9rd1.png)

## Conclusão

Este mini artigo buscou demonstrar algumas das formas eficazes de utilização do IDA Pro e da desmontagem de código, proporcionando uma visão básica dessas ferramentas. É importante ressaltar que as técnicas apresentadas aqui representam apenas o básico, e há uma infinidade de outras maneiras de aproveitar ao máximo o potencial do IDA Pro para análise de binários. O objetivo principal é fornecer uma introdução acessível a essas ferramentas, incentivando estudos mais aprofundados e uma compreensão mais completa de suas capacidades.