Fundamentos de Engenharia Reversa
Apoie este trabalho
  • 🙌Apresentação
  • 🥇Introdução
    • 👀Antes de começar
  • 🔢Números
    • Sistemas de Numeração
    • O Byte
    • Números Negativos
    • Cálculos com Binários
  • 🧵Cadeias de Texto
    • ASCII
    • Unicode
    • C Strings
  • 🗂️Arquivos
    • Formatos
  • 💼O formato PE
    • Cabeçalhos
      • MS-DOS
      • COFF
      • Opcional
      • Diretórios de Dados
      • Cabeçalhos das Seções
    • Seções
    • Import Table
    • Endereçamento
  • 🚗Execução de Programas
    • Executáveis
    • Bibliotecas
    • Processos
  • 🖼️Windows API
    • Caixas de Mensagens
    • Manipulação de Arquivos
    • Acesso ao Registro
  • ⚙️Assembly
    • Registradores
    • Instruções Básicas
    • Funções e Pilha
  • 🐞Depuração
    • O Debugger
    • Disassembly
    • Breakpoints
    • Manipulação do Fluxo
    • Patches
  • Apêndices
    • Tabela ASCII
    • Tabela ISO-8859-1/Latin-1
    • Exemplos de Código em Assembly
    • Funções da API do Windows
    • Ferramentas
  • Referências
Powered by GitBook
On this page
  • Import Directory Table
  • RvaImportLookupTable
  • Name
  • RvaImportAddressTable
  • Exercícios

Was this helpful?

Edit on GitHub
Export as PDF
  1. O formato PE

Import Table

Foi visto que no diretório de dados Import Table há um ponteiro para a IDT (Import Directory Table), apontado pelo valor do campo VirtualAddress. Vamos conhecer essa IDT de uma vez.

Import Directory Table

A IDT é um array de estruturas do tipo IMAGE_IMPORT_DESCRIPTOR definidas a seguir:

typedef struct {
    uint32_t RvaImportLookupTable; // Antigo OriginalFistThink
    uint32_t TimeDateStamp;
    uint32_t ForwarderChain;
    uint32_t Name;
    uint32_t RvaImportAddressTable; // Antigo FirstThunk (ou Thunk Table)
} IMAGE_IMPORT_DESCRIPTOR;

Não se deve confundir esta IDT (Import Descriptor Table) com outra IDT (Interrupt Descriptor Table). Esta última é uma estrutura que mapeia interrupções para seus devidos handlers, assunto que foge do escopo deste livro.

O número de elementos do array de estruturas IMAGE_IMPORT_DESCRIPTOR é igual ao número de bibliotecas que o executável PE depende, ou seja, o número de diferentes DLLs das quais o executável importa funções. Há ainda um elemento final, completamente zerado (preenchido com null bytes) para indicar o fim do array.

RvaImportLookupTable

O campo RvaImportLookupTable (antigamente conhecido por OriginalFirstThunk que era unido com Characteristics) aponta para uma tabela chamada de Import Lookup Table (ILT)

Import Lookup Table (ILT)

Essa tabela é um array de números de 64-bits (ou 32-bits para PE32). Para cada um desses números, seu bit mais significativo (MSB - Most Significant Bit), se ligado, define que a função será importada por número. Se desligado, a função é importada por nome. Os bits remanescentes guardam um endereço para uma estrutura que finalmente contém o nome da função. Essa estrutura é chamada de Hint/Name Table.

Hint/Name Table

Os elementos desta tabela obedecem a seguinte estrutura:

typedef struct {
	uint16_t Hint;
	uint8_t Name[1];
} IMAGE_IMPORT_BY_NAME;

Onde Name possui tamanho variável pois contém o nome da função a ser importada.

Note que o número de entradas na ILT (número de elementos deste array) é igual ao número de funções importadas por uma DLL em particular definida na IDT.

Name

Este campo contém o endereço de uma string que é o nome da DLL importada. Por exemplo: SHELL32.dll. A string é terminada em null.

RvaImportAddressTable

Este campo aponta finalmente para o que chamamos de IAT (Import Address Table), muito conhecida por quem faz engenharia reversa. Essa tabela é em princípio idêntica à Import Lookup Table, mas no processo de carregamento do executável (load time, que estudaremos mais à frente no livro), ela é preenchida com os endereços reais das funções importadas. Isto porque um executável dinamicamente linkado não sabe, antes de ser carregado em memória, qual o endereço de cada função de cada DLL que ele precisa chamar.

É importante lembrar o conceito de biblioteca compartilhada aqui. A ideia é ter apenas uma cópia dela carregada em memória e todos os programas que a utilizam podem chamar suas funções. Esta é a razão para o longo esquema de preenchimento da IAT pelo loader.

Exercícios

Para fixar este conteúdo, é importante validar o que foi aprendido. Abra o executável da calculadora no DIE, marque a caixa Advanced se já não estiver marcada e clique no botão PE como a imagem a seguir mostra:

No menu da esquerda, vá em IMAGE_NT_HEADERS -> IMAGE_OPTIONAL_HEADER -> IMAGE_DIRECTORY_ENTRIES e copie o endereço (coluna Address) do segundo diretório, que é justamente o endereço da IDT, como a imagem a seguir ilustra:

Perceba que o DIE chama o campo VirtualAddress dos diretórios apenas de Address. Inconsistências assim podem ocorrer em várias ferramentas e literaturas, mas se você souber do que se trata, vai sempre se dar bem, mesmo que nomes diferentes sejam usados para se referir à mesma coisa.

Agora no HxD, abra o mesmo binário e vá até este offset da IDT com o Ctrl+G. No binário que usei aqui o endereço é 0x38f8.

Lá, os primeiros quatros bytes são o valor do campo RvaImportLookupTable do primeiro elemento do array. Se você seguir este offset, vai chegar na ILT. O primeiro elemento da ILT é um número de 64-bits, ou seja, de 8 bytes que aponta para a Hint/Name Table. Nesta tabela, o nome da função começa no terceiro byte conforme definição, logo após o campo Hint.

Como desafio adicional, descubra à qual DLL a função pertence apenas olhando para a imagem anterior. Dica: busque pelo campo Name da IDT e siga o valor que ele contém neste binário.

PreviousSeçõesNextEndereçamento

Last updated 11 days ago

Was this helpful?

💼
Obtendo informações avançadas sobre o PE no DIE
Visualizando o diretório de Imports (Import Table) no DIE
Olhando a IDT, ILT e Hint/Name Table no HxD