Atualizado: 16/11/2025

Este conteúdo é original e não foi gerado por inteligência artificial.

Sobrescrevendo Funções de Bibliotecas com LD_PRELOAD em Assembly NASM

Uma das características mais notáveis da linkagem dinâmica em Linux é a capacidade de sobrescrever (override) funções de uma biblioteca compartilhada com a sua própria implementação. O loader dinâmico suporta uma variável de ambiente especial, a LD_PRELOAD, que permite pré-carregar uma biblioteca antes de todas as outras.

Quando a LD_PRELOAD é definida com o caminho para uma biblioteca .so, o loader carrega essa biblioteca primeiro. Se o programa principal ou qualquer outra biblioteca tentar usar uma função que já foi definida na biblioteca pré-carregada, a versão da LD_PRELOAD terá prioridade e será executada em vez da original.

Essa técnica nos permite modificar o comportamento de um programa mesmo que ele já esteja compilado e não tenhamos acesso ao seu código fonte. Ela é frequentemente usada para fins de depuração, monitoramento (profiling) ou para fornecer versões mais otimizadas de funções padrão do sistema, como malloc.

Exemplo Prático: Sobrescrevendo a printf

Vamos demonstrar essa técnica sobrescrevendo a função printf da biblioteca C.

Primeiro, temos um programa simples, app.asm, que usa a printf padrão para imprimir uma mensagem:

global _start
extern printf

section .data
    message: db "Hello World", 10, 0

section .text
_start:
    lea rdi, [rel message]
    xor rax, rax
    call printf

    mov rax, 60
    syscall

Vamos compilar e executar este programa normalmente:

$ nasm -felf64 app.asm -o app.o
$ ld --dynamic-linker=/lib64/ld-linux-x86-64.so.2 -lc app.o -o app
$ ./app
Hello World

Como esperado, o programa imprime a mensagem "Hello World".

Agora, vamos criar nossa própria versão da printf em um arquivo chamado print.asm. Esta nova função irá ignorar quaisquer parâmetros e simplesmente imprimir uma mensagem fixa.

global printf:function

section .data
    message: db "Função printf sobrescrita!", 10, 0
    len equ $-message

section .text
printf:
    mov rax, 1                 ; syscall write
    mov rdi, 1                 ; stdout
    lea rsi, [rel message]     ; Nossa mensagem fixa
    mov rdx, len               ; Tamanho da nossa mensagem
    syscall
    ret

É crucial que nossa função tenha exatamente o mesmo nome do símbolo que queremos sobrescrever: printf.

Vamos compilar este arquivo como uma biblioteca compartilhada:

$ nasm -felf64 print.asm -o print.o
$ ld -shared print.o -o libprint.so

Agora vem a parte principal. Usamos a variável LD_PRELOAD para instruir o loader a pré-carregar nossa libprint.so e, em seguida, executamos o programa app original sem recompilá-lo:

$ export LD_PRELOAD=./libprint.so
$ ./app
Função printf sobrescrita!

O resultado mudou! Embora o programa app não tenha sido modificado, a chamada call printf foi interceptada. O loader dinâmico, ao ver que o símbolo printf já estava disponível na nossa biblioteca pré-carregada, usou a nossa versão em vez da versão da libc.

Para desativar o pré-carregamento e voltar ao comportamento normal, basta limpar a variável de ambiente:

$ unset LD_PRELOAD
$ ./app
Hello World

Resumo do Processo

O processo completo para testar a sobrescrita de função é:

# 1. Compilar o programa original
$ nasm -felf64 app.asm -o app.o
$ ld --dynamic-linker=/lib64/ld-linux-x86-64.so.2 -lc app.o -o app
$ ./app
Hello World

# 2. Criar a biblioteca com a função sobrescrita
$ nasm -felf64 print.asm -o print.o
$ ld -shared print.o -o libprint.so

# 3. Usar LD_PRELOAD para executar o programa original com a função interceptada
$ export LD_PRELOAD=./libprint.so
$ ./app
Função printf sobrescrita!

# 4. Limpar a variável de ambiente para voltar ao normal
$ unset LD_PRELOAD

Resumo

  • A variável de ambiente LD_PRELOAD permite forçar o carregamento de uma biblioteca compartilhada antes de todas as outras.
  • Se a biblioteca pré-carregada definir um símbolo (como uma função) com o mesmo nome de um símbolo em outra biblioteca, a versão pré-carregada terá precedência.
  • Essa técnica permite interceptar e substituir funções de sistema ou de outras bibliotecas, modificando o comportamento de executáveis existentes sem a necessidade de recompilação.
Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com