Estruturas de Tabelas de Importação e Realocação em Arquivos PE

Tabela de Importação

Visualização da Tabela de Importação

No cabeçalho opcional IMAGE_OPTIONAL_HEADER, o campo DataDirectory fornece uma estrutura de diretório de dados, definida como:

typedef struct _DIRETORIO_DADOS {
    DWORD   EnderecoRVA;       // RVA relativo ao diretório
    DWORD   TamanhoTotal;      // Tamanho do item do diretório
} DIRETORIO_DADOS, *PDIRETORIO_DADOS;

EnderecoRVA: RVA (Endereço Virtual Rleativo) após o carregamento do PE na memória.

TamanhoTotal: Tamanho da tabela de importação.

O FOA (Offset no Arquivo) da tabela de importação pode ser determinado através da conversão de endereços conforme a estrutura do PE.

Estrutura da Tabela de Importação

A estrutura IMAGE_IMPORT_DESCRIPTOR é definida assim:

typedef struct _DESCRITOR_IMPORTACAO {
    union {
        DWORD   Caracteristicas;        // 0 para descritor nulo de encerramento
        DWORD   PrimeiroThunkOriginal;  // RVA para IAT original não vinculada
    } DUMMYUNIONNAME;
    DWORD   CarimboTempo;               // 0 se não vinculado, -1 se vinculado com timestamp real
    DWORD   CadeiaEncaminhador;         // -1 se não houver encaminhadores
    DWORD   NomeModulo;                 // RVA para o nome do módulo
    DWORD   PrimeiroThunk;              // RVA para IAT (com endereços reais se vinculado)
} DESCRITOR_IMPORTACAO;
typedef DESCRITOR_IMPORTACAO UNALIGNED *PDESCRITOR_IMPORTACAO;

No assembly, a estrutura é representada como:

DESCRITOR_IMPORTACAO STRUCT
    union
        Caracteristicas dd      ?
        PrimeiroThunkOriginal dd ?
    ends
    CarimboTempo dd ?
    CadeiaEncaminhador dd ?
    NomeModulo dd ?
    PrimeiroThunk dd ?
DESCRITOR_IMPORTACAO ENDS

PrimeiroThunkOriginal: Aponta para uma tabela RVA com nomes ou números de ordem das funções importadas, usando a estrutura IMAGE_THUNK_DATA.

NomeModulo: RVA para o nome do módulo importado.

PrimeiroThunk: Aponta para a RVA da IAT (Import Address Table). Antes do carregamento, contém os mesmos dados que PrimeiroThunkOriginal; após o carregamento, é preenchido com endereços reais das funções.

IMAGE_THUNK_DATA

A estrutura IMAGE_THUNK_DATA tem versões de 32 e 64 bits. A definição para 32 bits:

typedef struct _DADO_THUNK32 {
    union {
        DWORD EncaminhadorString;   // PBYTE
        DWORD Funcao;               // PDWORD
        DWORD Ordem;                // Valor de ordem se bit mais alto for 1
        DWORD EnderecoDados;        // RVA para IMAGE_IMPORT_BY_NAME se bit mais alto não for 1
    } u1;
} DADO_THUNK32;
typedef DADO_THUNK32 * PDADO_THUNK32;

No assembly:

DADO_THUNK32 STRUCT
    union u1
        EncaminhadorString dd ?
        Funcao dd ?
        Ordem dd ?
        EnderecoDados dd ?
    ends
DADO_THUNK32 ENDS

Ordem: Válido quando o bit mais alto de IMAGE_THUNK_DATA é 1, representando o número de ordem da função importada.

EnderecoDados: Aponta para IMAGE_IMPORT_BY_NAME quando o bit mais alto não é 1, indicando importação por nome.

Ordem e EnderecoDados são mutualmente exclusivos, determinados pelo bit mais alto. Se for 1, usa-se a ordem; caso contrário, usa-se o nome.

IMAGE_IMPORT_BY_NAME

A estrutura IMAGE_IMPORT_BY_NAME é definida como:

typedef struct _NOME_IMPORTACAO {
    WORD    Dica;
    CHAR   NomeFuncao[1];
} NOME_IMPORTACAO, *PNOME_IMPORTACAO;

Dica: Número de ordem da função na tabela de exportação, opcional.

NomeFuncao: String terminada em NULL com o nome da função importada. A definição com array de tamanho 1 permite acesso flexível a strings de comprimento variável.

Diferença entre OriginalFirstThunk e FirstThunk

Ambos os campos em IMAGE_IMPORT_DESCRIPTOR apontam para estruturas IMAGE_THUNK_DATA, mas diferem após o carregamento. No disco, ambos contêm RVAs para nomes ou ordens de funções. Na memória, PrimeiroThunkOriginal mantém os dados originais (tabela de nomes de importação, INT), enquanto PrimeiroThunk é preenchido pelo loader do Windows com endereços reais das funções (tabela de endereços de importação, IAT).

Análise Manual da Tabela de Importação

Para analisar manualmente, localize o diretório de dados no índice 4 e siga os RVAs para entender as estruturas de importação.

Tabela de Realocação

A tabela de realocação é encontrada no índice 5 do diretório de dados. A estrutura IMAGE_BASE_RELOCATION é:

typedef struct _REALOCACAO_BASE {
    DWORD   EnderecoBase;
    DWORD   TamanhoBloco;
//  WORD    DeslocamentoTipo[1];
} REALOCACAO_BASE;
typedef REALOCACAO_BASE UNALIGNED * PREALOCACAO_BASE;

No assembly:

REALOCACAO_BASE STRUCT
    EnderecoBase dd ?
    TamanhoBloco dd ?
REALOCACAO_BASE ENDS

A tabela é composta por múltiplas estruturas REALOCACAO_BASE.

EnderecoBase: RVA inicial dos dados de realocação.

TamanhoBloco: Tamanho total do bloco, incluindo a estrutura base e os dados de realocação. A estrutura base tem 8 bytes, e TamanhoBloco é 8 + N*WORD.

DeslocamentoTipo: Array de WORDs, onde cada elemetno tem 4 bits altos para o tipo e 12 bits baixos para o offset dentro da seção. O RVA para realocação é calculado como EnderecoBase + offset. No Win32, o tipo comum é IMAGE_REL_BASED_HIGHLOW.

Valores de DeslocamentoTipo

Os tipos de realocação são definidos em Winnt.h:

#define TIPO_REALOC_ABSOLUTO         0
#define TIPO_REALOC_ALTO             1
#define TIPO_REALOC_BAIXO            2
#define TIPO_REALOC_ALTO_BAIXO       3
#define TIPO_REALOC_AJUSTE_ALTO      4
#define TIPO_REALOC_ESPECIFICO_MAQ_5 5
#define TIPO_REALOC_RESERVADO        6
#define TIPO_REALOC_ESPECIFICO_MAQ_7 7
#define TIPO_REALOC_ESPECIFICO_MAQ_8 8
#define TIPO_REALOC_ESPECIFICO_MAQ_9 9
#define TIPO_REALOC_DIR64            10

Tags: PE Windows engenharia reversa Tabela de Importação Tabela de Realocação

Publicado em 7-21 14:33