Escolar Documentos
Profissional Documentos
Cultura Documentos
net/publication/340470076
CITATION READS
1 311
4 authors, including:
SEE PROFILE
All content following this page was uploaded by Marcus Felipe Botacin on 07 April 2020.
4
Introdução à Engenharia Reversa de Aplicações
Maliciosas em Ambientes Linux
Marcus Botacin1 , Lucas Galante2 , Otávio Silva2 , and Paulo Lício de Geus2
1 Universidade Federal do Paraná (UFPR)
2 Universidade Estadual de Campinas (UNICAMP)
Abstract
Malicious software have been evolving to look even more indubious to the targeted sys-
tem. Moreover, they have been relying on obfuscation and anti-analysis techniques to
avoid their behavior being discovered during their execution, thus making forensic pro-
cedures harder to be conducted on a proper manner. Reverse engineering is an useful
procedure to handle such type of threat, pinpointing the best inspection paths to be fol-
lowed by analysts, such as how to unpack a given sample or which protection techniques
are implemented by a sample. In this course, we present reverse engineering techniques
to analyze malicious software samples, thus introducing the reader to general malware
handling procedures. The course introduces techniques both in userland as well as in the
OS kernel, including dynamic application tracing, debugging and rootkit techniques.
Resumo
Aplicações maliciosas têm evoluído de forma a cada vez mais permanecerem ocultas no
sistema alvo. Além disso, essas aplicações utilizam de técnicas de ofuscação e/ou anti-
análise a fim de evitar a descoberta de seu comportamento durante a execução, impe-
dindo que atividades de perícia forense computacional sejam realizadas adequadamente.
A engenharia reversa é um processo útil na análise desse tipo de aplicação, uma vez
que pode-se descobrir quais caminhos seguir em uma perícia, por exemplo, como desem-
pacotar a aplicação ou que tipo de truques ela usa para evitar ser destrinchada. Neste
minicurso, apresentamos técnicas de engenharia reversa para análise de aplicações mali-
ciosas tomando como base o ambiente Linux, visando introduzir os participantes ao tema
e capacitá-los no tratamento de aplicações maliciosas em geral. O curso aborda técnicas
tanto em modo usuário quanto em modo kernel do sistema operacional, incluindo o traço
dinâmico de aplicações, técnicas de depuração e de rootkits.
4.1. Introdução
A plataforma Linux tem se consolidado como uma das principais plataformas para o
desenvolvimento de novas tecnologias no mundo contemporâneo. Atualmente, ela su-
porta desde ambientes de computação em nuvem (cloud) [Venezla 2012] até o sistema
operacional para smartphones Android [Android 2017]. Contudo, ao mesmo tempo
em que proporciona o desenvolvimento de novas tecnologias, a plataforma Linux torna-
se alvo de ataques, passando a requerer o desenvolvimento de ferramentas de análise de
binários [Afonso et al. 2015] e para procedimentos forenses [Vecchia and Coral 2014].
Um dos principais vetores de ataque contra a plataforma Linux são códigos ma-
liciosos (malicious software ou malware), que são arquivos executáveis que apresentam
deliberadamente intenções prejudiciais à sistemas computacionais [Skoudis and Zeltser
2003], o que pode incluir do vazamento de informações sensíveis do usuário ao controle
total do sistema infectado. Na prática, ataques por malware contra a plataforma Linux
são frequentes e causam prejuízos significativos. Em 2016, a botnet Mirai [Fruhlinger
2018] causou interrupções na conexão à Internet da costa Atlântica dos Estados Unidos.
Em 2017, o ransomware Erebus [Z. Chang 2017] sequestrou os servidores de um prove-
dor de conteúdo sul-coreano em troca de resgate.
Para se prevenir e combater ataques por malware, diversas técnicas de análise são
empregadas, dentre as quais se destaca a engenharia reversa dos códigos maliciosos. A
engenharia reversa consiste em inspecionar o binário malicioso de modo a compreen-
der seu funcionamento, identificar seu alvo no sistema infectado e potencialmente criar
mecanismos para a defesa contra este tipo de ameaça. As técnicas de engenharia re-
versa apresentam muitas estratégias comuns a diferentes plataformas, como a execução
do binário desconhecido em um ambiente controlado (sandbox). Entretanto, diferentes
plataformas apresentam especificidades quanto ao alvo da execução em sandbox. Como
exemplo, enquanto na plataforma Windows exemplares de malware afetam o subsistema
de chaves de registro [Botacin et al. 2018], na plataforma Linux, exemplares de malware
afetam o subsistema de arquivo /proc [Galante et al. 2018], de modo que entender as
particularidades das técnicas de engenharia reversa em cada plataforma é essencial para
prover respostas adequadas aos ataques que estas sofrem.
Contudo, apesar dos impactos da infecção por malware na plataforma Linux
serem reais e das técnicas de engenharia reversa poderem auxiliar no combate à este
ataques, a literatura acadêmica tem dado pouca atenção a plataforma Linux e focado na
plataforma Windows, dada sua concentração de mercado historicamente grande, até a
ascensão recente da plataforma Linux. Frente a este cenário de uso crescente e técnicas
de análise pouco difundidas em comparação a plataforma anteriormente dominante, vis-
lumbramos a necessidade de se apresentar os conceitos de engenharia reversa com foco
específico nesta plataforma, fato que motiva o desenvolvimento deste curso.
Objetivos. Este minicurso busca ser uma introdução à engenharia reversa de aplicações
em ambientes Linux, com foco na análise de aplicações maliciosas, em especial as que
implementam técnicas de evasão de procedimentos de análise. Durante o minicurso, os
participantes desenvolverão habilidades básicas de engenharia reversa, como a caracteri-
zação de binários, a identificação das proteções usadas e alguns contornos (bypass) para
tais proteções.
Sobre o curso. Este curso é proposto na modalidade majoritariamente prática, através
de exercícios de análise de binário reais, mas contando com o devido suporte teórico
para embasar as decisões tomadas pelos participantes. O curso ocorrerá no formato de
uma competição capture-the-flag, na qual os participantes serão desafiados a re-
solver alguns desafios que levem à engenharia reversa do binário dado. Desta forma, este
capítulo corresponde a parte teórica do curso, fornecendo subsídios para que os alunos
realizem os desafios.
Audiência. Este curso se destina ao público que pretende iniciar seus estudos na área de
análise de binários. Não são exigidos conhecimentos prévios na área de segurança, apenas
familiaridade com o uso de sistemas GNU/Linux e seu terminal (bash), e conhecimen-
tos básicos em alguma linguagem de programação. Acreditamos que o curso possa ser
de interesse também para quem já possua familiaridade com as soluções de análise da
plataforma Linux, como debuggers, dado que as técnicas de engenharia reversa são dis-
tintas das empregadas comumente na depuração de aplicações convencionais.
Materiais. Todo os binários a serem analisados durante o curso podem ser obtidos através
do repositório: https://github.com/marcusbotacin/Malware.Reverse.
Intro, de modo que os leitores possam acompanhar este capítulo mesmo após a realiza-
ção do curso presencial. Todos os códigos são disponibilizados juntamente com arquivos
de compilação (Makefiles), não requerendo que os participantes tenham conhecimen-
tos avançados, como a compilação de drivers de kernel para executar as tarefas propostas.
Estrutura. Este capítulo é dividido da seguinte forma: Na Seção 4.2, apresentamos a es-
trutura básica dos binários ELF utilizados nas plataformas Linux e ferramentas básicas
para a manipulação destes; Na Seção 4.3, introduzimos os primeiros conceitos de engen-
haria reversa e apresentamos as verificações iniciais a serem realizadas sobre arquivos
binários sem a execução do mesmo (análises estáticas), como a identificação do tipo de
arquivo inspecionado, a presença de bibliotecas, e sinais de ofuscação de código, de modo
a se obter uma compreensão inicial dos possíveis comportamentos exibidos pelo binário;
Na Seção 4.4, estendemos as análise de observações passivas para modificações ativas no
binário (binary patching), de modo a contornar verificações implementadas pelas rotinas
de anti-análise; Na Seção 4.5, estendemos as análises anteriormente descritas através da
execução dos binários desconhecidos em um ambiente controlado (sandbox), permitindo,
assim, a análise de exemplares ofuscados; Na Seção 4.6, tal qual realizado para as técnicas
de análise estática, estendemos as técnicas dinâmicas de observações passivas para inter-
ferências ativas na execução dinâmica de código, permitindo, assim, contornar técnicas
de anti-análise implementadas pelos binários; Apresentamos, também, como os atacantes
se utilizam destas mesmas técnicas para implementar seus comportamentos evasivos, tais
como rootkits; Na Seção 4.7, apresentamos abordagens complementares de análise, com
focos em subsistemas específicos, como a monitoração do subsistema de arquivos para
recuperação de arquivos deletados pelos exemplares maliciosos; Na Seção 4.8, estende-
mos os conceitos e soluções anteriormente apresentadas em modo usuário (userland) para
o modo mais privilegiado (kernel), visando contornar mecanismos de anti-análise mais
sofisticados; Na Seção 4.9, apresentamos conceitos básicos de monitoração de tráfego de
rede; Na Seção 4.10, apresentamos nossas considerações finais.
4.2. Binários ELF: Definição e Manipulação
Diferentes plataformas representam seus aplicativos de diferentes maneiras, de modo que
compreender a representação de um arquivo executável é essencial para a execução de
procedimentos de investigação de binários desconhecidos e suspeitos. Nesta seção, intro-
duzimos o tipo binário utilizado pelas plataformas Linux e ferramentas básicas para a
manipulação destes.
O cabeçalho ELF, definido como mostrado no Código 4.1, é uma estrutura obri-
gatória e está sempre presente no deslocamento (offset) “0” de todo arquivo ELF. Ele ap-
resenta as informações básicas do binário, como seu tipo (e_type)–podendo ser binários
autocontidos ou bibliotecas—, a arquitetura do sistema alvo (e_machine), entre outras
informações essenciais a execução.
1 #define EI_NIDENT 16
2 typedef struct {
3 unsigned char e_ident[EI_NIDENT];
4 uint16_t e_type;
5 uint16_t e_machine;
6 uint32_t e_version;
7 ElfN_Addr e_entry;
8 ElfN_Off e_phoff;
9 ElfN_Off e_shoff;
10 uint32_t e_flags;
11 uint16_t e_ehsize;
12 uint16_t e_phentsize;
13 uint16_t e_phnum;
14 uint16_t e_shentsize;
15 uint16_t e_shnum;
16 uint16_t e_shstrndx;
17 } ElfN_Ehdr;
1 typedef struct {
2 uint32_t p_type;
3 uint32_t p_flags;
4 Elf64_Off p_offset;
5 Elf64_Addr p_vaddr;
6 Elf64_Addr p_paddr;
7 uint64_t p_filesz;
8 uint64_t p_memsz;
9 uint64_t p_align;
10 } Elf64_Phdr;
Código 4.2. Definição do cabeçalho
de programa de arquivo ELF.
Dentre os tipos que um arquivo ELF pode assumir, tal qual apontado pelo cabeçalho
de programa, estão binários autocontidos e arquivos objetos, utilizado para a implemen-
tação de códigos em bibliotecas. A ligação de bibliotecas à binários pode ser realizada
de duas maneiras [Simmonds 2015]: (i) estaticamente, em tempo de compilação (gcc
-static <arquivo>); ou (ii) dinamicamente, em tempo de execução. Cada uma
destas formas de ligação apresenta vantagens e desvantagens: Por um lado, ligações
estáticas, por embutirem no binário todo o código necessário para a execução da apli-
cação, permitem que o binário seja executado em diversos sistemas sem a necessidade
de se instalar qualquer dependência. Por outro lado, estas aumentam significativamente
o tamanho final do binário gerado em comparação com binários ligados à bibliotecas
dinâmicas.
O cabeçalho de seção de um arquivo ELF, como mostrado no Código 4.3, estab-
elece como o conteúdo da aplicação está disposto dentro do binário. Cada tipo de dado
(instruções de máquina, variáveis estáticas, entre outros) é disposta em uma seção difer-
ente, cada uma recebendo um nome (sh_name) e atributos (e.g., sh_flags) próprios.
1 typedef struct {
2 uint32_t sh_name;
3 uint32_t sh_type;
4 uint64_t sh_flags;
5 Elf64_Addr sh_addr;
6 Elf64_Off sh_offset;
7 uint64_t sh_size;
8 uint32_t sh_link;
9 uint32_t sh_info;
10 uint64_t sh_addralign;
11 uint64_t sh_entsize;
12 } Elf64_Shdr;
Código 4.3. Definição do cabeçalho
de seção de um arquivo ELF.
O Código 4.4 exibe as seções de um um binário ELF típico: Instruções de máquina
são armazenadas na seção .text; Variáveis inicializadas com e sem permissão de escrita
são armazenados, respectivamente, nas seções .data e .rodata; Variáveis e outros da-
dos dinâmicos são armazenados nas seções *dyn; Bibliotecas dinâmicas e outros apon-
tadores carregados em tempo de execução são armazenados na região correspondente as
seções do tipo *symbols*.
1 [Nr] Nome
2 [ 1] .interp [ 2] .note.ABI-tag
3 [ 3] .note.gnu.build-i [ 4] .gnu.hash
4 [ 5] .dynsym [ 6] .dynstr
5 [ 7] .gnu.version [ 8] .gnu.version_r
6 [ 9] .rela.dyn [10] .rela.plt
7 [11] .init [12] .plt
8 [13] .plt.got [14] .text
9 [15] .fini [16] .rodata
10 [17] .eh_frame_hdr [18] .eh_frame
11 [19] .init_array [20] .fini_array
12 [21] .jcr [22] .dynamic
13 [23] .got [24] .got.plt
14 [25] .data [26] .bss
15 [27] .comment [28] .shstrtab
16 [29] .symtab [30] .strtab
1 def process_file(filename):
2 with open(filename, ’rb’) as f:
3 elffile = ELFFile(f)
4 for section in elffile.iter_sections():
5 print(section.name)
Código 4.5. Enumeração das seções de um arquivo ELF
através da solução pyelftools.
4.3. Análise Estática
No contexto de engenharia reversa de aplicações maliciosas, referimos a análise estática
como o conjunto de métodos utilizados para obter informações sobre os arquivos binários
suspeitos sem a efetiva execução destes [Sikorski and Honig 2012]. No contexto de
análise forense, este tipo de análise é usualmente a etapa inicial de um conjunto de pro-
cedimentos complexos realizados com o objetivo de se obter informações preliminares
sobre o artefato em análise.
Através dos procedimentos de análise estática, um analista pode identificar o tipo
do arquivo em análise e se bibliotecas de código são ligadas à este, permitindo a classi-
ficação do artefato. Um analista pode também inspecionar se o arquivo apresenta strings
que possam prover informações forenses. Finalmente, um analista pode obter o código
assembly para identificar, preliminarmente, possíveis comportamentos maliciosos ou téc-
nicas de evasão. Apresentamos, a seguir, soluções e procedimentos para realizar estes
passos de análise.
Código 4.8. Comando file em arquivo ELF compilado com ligação estática
Caso o arquivo analisado tenha sido ligado estaticamente, por exemplo, por rotinas
de ofuscação, o comando ldd informará ao analista não ser capaz de identificar nenhuma
biblioteca, como exemplificado pelo Código 4.10.
strings do tipo inteiro (%d), sugere que este exemplar pode ser um scanner [Galante et al.
2018, Cozzi et al. 2018] de rede, realizando tentativas contra todos os hosts possíveis
dentro da sub-rede especificada. Tal hipótese é corroborada pelas demais strings, que
ilustram diversas senhas que podem ser utilizadas em ataques de força bruta [Wang et al.
2018].
1 >$ strings
a9a780c66ec18861e4881430202f62d6ceaba3187626d48ab241522f86a5c254
2 189.96.%d.%d 189.99.%d.%d
3 39.34.%d.%d 59.103.%d.%d
4 191.12.%d.%d 186.117.%d.%d
5 179.170.%d.%d 191.206.%d.%d
6 187.118.%d.%d 179.224.%d.%d
7 admin [31mPhone Cracked
8 [31mUsername [31mPassword
9 [36mDevice Cracked GETLOCALIP
10 My IP: %s BOTKILL
11 Killing Bots NETIS ON | OFF
12 [TELNET] SCANNER ON:%s ICMP
13 HTTP STOP
14 ENDTHEBOTLOL 8.8.8.8
15 /proc/net/route /etc/resolv.conf
Código 4.14. Saída do comando strings em exemplar malicioso indicando
diversas strings suspeitas
Como nos casos anteriores, atacantes previnem-se de exibir suas strings através
de: (i) geração de strings em tempo de execução; e (ii) ofuscação das strings estáticas,
como exemplificado pelo Código 4.15.
1 >$ strings upx-file.bin
2 $Info: This file is packed with the UPX executable packer http://
upx.sf.net $
3 dl%)
4 UPPH
5 q}Nsf
6 x‘TJq&H
7 UPX!
Código 4.15. Saída do comando strings em arquivo empacotado pela solução UPX
4.3.5. O utilitário e comando UPX
Uma das formas mais comuns de se ofuscar códigos maliciosos é através do uso de empa-
cotadores, capazes de embutir o arquivo original em sua estrutura e extraí-los em tempo de
execução e dentre os quais a solução Ultimate Packer for eXecutables (UPX) [M.F.X.J. Ober-
humer 2018] é a mais popular. O Código 4.16 ilustra o empacotamento de um arquivo
com ligação estática via UPX.
1 >$ upx original.bin -o upx-file.bin
2 Ultimate Packer for eXecutables
3 Copyright (C) 1996 - 2013
4 UPX 3.91 Markus Oberhumer, Laszlo Molnar & John Reiser Sep
30th 2013
5
Código 4.16. Empacotamento de um binário com ligação estática pela solução UPX
1 int password()
2 scanf("%[^\n]s",string);
3 if(strcmp(string,PASS)==0)
4 malicious();
5 else
6 exit(0);
Código 4.19. Exemplo de código
de um exemplar que exibe seu
comportamento malicioso apenas
quando a string de inicialização é
corretamente definida.
1 int main()
2 crc32 = Crc32_ComputeBuf(0,
passwd,33);
3 if(crc32!=MYCRC)
4 exit(0);
5 passwd(pass);
Código 4.20. Exemplo de código de
verificação de CRC32 para proteger
a função verificadora de strings.
Para realizar análise do exemplar com verificação de integridade via CRC, deve-
se, agora, realizar binary patching em duas seções do exemplar: (i) na função passwd
para ignorar o resultado da verificação da senha, tal qual no caso anterior; e (ii) na rotina
de verificação de integridade da função passwd via CRC. Através do uso do hte, pode-se
realizar binary patching das duas seções; a primeira tal qual demonstrado anteriormente, e
a segunda tal qual exibido na Figura 4.5, onde a instrução jz foi substituída pela instrução
jnz de modo a se evitar o término da execução mesmo com a falha de verificação de inte-
gridade da função modificada. Resultado semelhante pode ser obtido de forma dinâmica,
como mostrado na Seção 4.6.
Outra técnica de evasão de análise que também afeta o strace é o delay na exe-
cução de chamadas, comumente implementado através de chamada da função sleep por
um tempo suficientemente longo para que a análise termine antes dos comportamentos
maliciosos serem exibidos [Grégio et al. 2012], seja durante uma sessão de depuração ou
durante a execução em um ambiente de análise automatizado limitado por um timeout.
O Código 4.25 ilustra a ocorrência deste tipo de técnica de evasão durante um traço de
execução de um processo malicioso. Nota-se que nenhuma outra chamada de sistema é
reportada após a invocação da função nanosleep dado que esta não retornou dentro do
período de análise deste binário. Um método para mitigar os efeitos deste tipo de técnica
de evasão é discutido na Seção 4.6.2.
1 >$ strace
a4332ab4b8f8e2f04fef7c40c103ab570f42011ba41b3caaa03029b8928cba2e
2 [pid 11046] waitpid(11084, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}],
0) = 11084
3 [pid 11046] munmap(0xf6f0a000, 4096) = 0
4 [pid 11046] ioctl(1, SIOCGIFFLAGS, {ifr_name="ens3", ifr_flags=IFF_UP
|IFF_BROADCAST|IFF_RUNNING|IFF_MULTICAST}) = 0
5 [pid 11046] gettimeofday({312344432895491, -17819621742608320}, NULL)
= 0
6 [pid 11046] nanosleep({429496729600000000, 577756380723720712}, <
unfinished ...>
Código 4.25. Traço de chamadas de sistema de exemplar malicioso que realiza
uma chamada sleep com tempo suficientemente longo para causar o término da
execução em muitos sistemas de análise
1 int main(){
2 if(ptrace(PTRACE_TRACEME)==-1)
3 exit(0);
4 malicious()
Código 4.26. Evasão de análise por
strace através da autoverificação
da presença do framework ptrace.
Caso este código seja executado em strace, a análise será encerrada, como
exemplificado pelo Código 4.27. Contudo, sua execução em ambientes nativos, como as
máquinas das vítimas/usuários, o código executa naturalmente e exibe seus comportamen-
tos maliciosos. Este tipo de técnica de evasão pode ser contornada através da modificação
do fluxo de execução, como descrito na Seção 4.6.
4.5.2. Ltrace
A solução de análise de traço de execução ltrace é o análogo da solução strace para a
obtenção de traços de execução a nível de chamadas de funções (APIs). O traço a nível
de API é útil para determinar comportamentos maliciosos em mais alto nível, uma vez
que diferentes APIs (printf, putc) podem resultar na mesma chamada de sistema
(write). O Código 4.28 exemplifica o traço de um exemplar malicioso que carrega
o exploit DirtyCow [Oster 2019] para escalar privilégios e copiar o arquivo de senhas
passwd.
1 >$ ltrace
b0148c40166b2b6cea71e1f00100a05087d2a492f21e008e30c594cf91ecf9f1.ltr
Tal qual strace, análises baseadas em ltrace devem “seguir” processos fil-
hos (fork) para evitar evasão. Similarmente, ltrace também é vulnerável a evasão
por longos delays e possivelmente por detecção de locks do tipo ptrace. Além disso,
atacantes também exploram outro fator derivado das decisões de projeto para a imple-
mentação de ltrace: dado que ltrace instrumenta as APIs monitoradas através da
alteração da tabela de símbolos, este só pode lidar com binários ligados dinamicamente.
Em caso de binários estáticos, ltrace exibe um erro, como ilustrado no Código 4.29.
1 >$ ltrace ./static-malicious.bin
2 Couldn’t find .dynsym or .dynstr in "/proc/25332/exe"
Código 4.29. Traço de chamadas de funções reportando falha ao analisar um
binário estaticamente ligada via ltrace
4.5.3. Ptrace
Soluções como strace baseiam seu funcionamento no framework ptrace, que fornece uma
interface clara para o monitoramento de aplicações. Através da chamada ptrace, tal
qual mostrada no Código 4.30, um processo (monitor) pode monitorar um outro pro-
cesso (monitorado) especificado através de um Process IDentifier (PID). Em arquite-
turas de monitoramento típicas, tais quais as implementadas por strace e ltrace, o
processo monitor invoca ptrace sobre um processo filho, o binário monitorado.
1 long ptrace(enum __ptrace_request request, pid_t pid, void *addr,
void *data);
4.6.1. Debugging
Uma das soluções mais populares para a depuração (debugging) de código em platafor-
mas Linux é o GDB [Alves et al. 2017], que também pode ser usado para realizar a
engenharia reversa de aplicações, tal qual exemplificado nesta seção. O nosso objetivo
não é esgotar todas as possibilidades de uso da ferramenta, mas apresentar algumas pos-
sibilidades importantes ao leitor, de modo que este possa, futuramente, se aprofundar
no assunto através da literatura especializada em GDB [Matloff and Salzman 2008] ou
engenharia reversa [Wong 2018].
Uma das capacidades do GDB é realizar o disassembly do código binário, como
exemplificado pelo Código 4.32. Embora a solução objdump mostrada na Seção 4.3
também seja capaz de realizar esta tarefa, o código assembly exibido pelo GDB se baseia
na interpretação dos bytes do binário carregados na memória e está sujeito as modificações
de contexto realizadas pelo analista.
Por se tratar de uma solução de inspeção dinâmica, o GDB permite que o analista
suspenda a execução em determinados pontos de interesse, denominados breakpoints ou
pontos de parada, como exemplificado pelo Código 4.33. Este recurso permite que o anal-
ista se foque nos dados ao redor da região de interesse e inspecione o programa no exato
momento em que uma atividade suspeita está sendo executada pelo binário desconhecido.
1 (gdb) b main
2 Ponto de parada 1 at 0x40064a
3 (gdb) r
4 Starting program: /home/sbseg/malware
5 Breakpoint 1, 0x000000000040064a in main ()
Os locais de análise não precisam ser limitado pelos pontos de parada, de modo
que um analista pode avançar a execução de forma granular a partir destes para melhor
inspecionar uma região de interesse. Uma forma típica de se inspecionar uma aplicação
é realizar sua execução passo a passo (step-by-step). O Código 4.35 ilustra a execução
passo a passo a partir do ponto de parada anteriormente estabelecido através do comando
stepi, exibindo a instrução executada em cada etapa através da definição display/i
$pc.
1 LD_PRELOAD=./library.so ./binary.bin
Código 4.39.
Exemplo de chamada LD_PRELOAD na qual
a biblioteca substitui funções originalmente
referenciadas pelo binário
A Figura 4.7, por sua vez, exibe o fluxo de execução alterado devido a injeção de
código via LD_PRELOAD. Neste caso, uma função (trampolim) com a mesma assinatura
da original é invocada previamente e realiza o registro das informações de log. Após o
registro, a execução é direcionada para o endereço original para que a função monitorada
realize a operação requisitada pelo binário.
Figura 4.7. Logging com LD_PRELOAD. Fluxo de execução alterado após a modi-
ficação da tabela de símbolos por LD_PRELOAD para a invocação de uma função
trampolim.
10 orig_puts_f_type orig_puts;
11 orig_puts = (orig_puts_f_type)dlsym(RTLD_NEXT,"puts");
12 return orig_puts(str);
13 }
Código 4.41. Código da função trampolim injetada via LD_PRELOAD para
registrar a invocação da função. Após o registro, deve-se invocar a função
original para garantir a realização da operação
Embora bastante poderoso, a injeção de código por LD_PRELOAD também pode ser
contornada por atacantes, seja pela utilização de ligação estática, gerando, assim, um
binário com tabela de símbolos vazia, impossibilitando a instrumentação, seja pela de-
tecção direta da injeção de código no processo em execução, como exemplificado pelo
Código 4.43. Este código detecta, através de execução (getenv ou /etc), se as bibliotecas
de LD_PRELOAD estão presentes. Como contramedida, analistas podem se utilizar de
instrumentação a nível de kernel, como discutido na Seção 4.8.
1 int main()
2 {
3 if(getenv("LD_PRELOAD"))
4 printf("LD_PRELOAD detected through getenv()\n");
5 else
6 printf("Environment is clean\n");
7 if(open("/etc/ld.so.preload", O_RDONLY) > 0)
8 printf("/etc/ld.so.preload detected through open()\n");
9 else
10 printf("/etc/ld.so.preload is not present\n");
11 return 0;
12 }
1 auditctl -w /etc/passwd -p r
2 auditctl -w /etc/shadow -p r
Código 4.45. Definição de regra do
Audit para monitoração da leitura
dos arquivos passwd e shadow.
De um modo geral, as etapas requiridas para efetuar syscall hooking são as seguintes:
4.10. Conclusão
Nesse minicurso, apresentamos os conceitos básicos da engenharia reversa de aplicações
maliciosas e introduzimos o leitor as características particulares das soluções de análise
para o ambiente Linux e também aos comportamentos maliciosos dos exemplares afe-
tando esta plataforma. Acreditamos que a partir dos conhecimentos obtidos neste curso,
os leitores estarão aptos a realizar procedimentos básicos de análise em artefatos descon-
hecidos e a projetar experimentos de análise de binário. Esperamos, assim, contribuir para
o desenvolvimento das pesquisas dos leitores em análise de binários de maneira geral.
Embora focado na plataforma Linux, acreditamos que os conhecimentos de análise
aqui apresentados possam estimular o desenvolvimento dos leitores quanto a análise de
binários em múltiplas plataformas (Unix-Like). Por fim, recomendamos a leitura dos tra-
balhos referenciados para que o leitor obtenha uma compreensão mais detalhada dos con-
ceitos apresentados neste capítulo. Em especial, recomendamos a leitura da bibliografia
especializada na plataforma Linux [Galante et al. 2018, Cozzi et al. 2018, Damri and
Vidyarthi 2016, Isohara et al. 2010, Duncan and Schreuders 2019] para uma melhor com-
preensão de como as soluções apresentadas podem ser empregadas nas múltiplas tarefas
associadas a engenharia reversa e segurança computacional.
Agradecimentos. Os autores agradecem a: Coordenação de Aperfeiçoamento de Pessoal
de Nível Superior (CAPES), em especial via Projeto FORTE - Forense Digital Tempes-
tiva e Eficiente (Processo: 23038.007604/2014-69 - Edital 24/2014 - Programa Ciências
Forenses); Conselho Nacional de Desenvolvimento Científico e Tecnológico (CNPq), em
especial via Programa de Bolsas de Doutorado (processo número 164745/2017-3) e Pro-
grama de Bolsas de Iniciação Científica (processo número 138239/2017-7).
Referências
[Afonso et al. 2015] Afonso, V. M., de Amorim, M. F., Grégio, A. R. A., Junquera, G. B.,
and de Geus, P. L. (2015). Identifying android malware using dynamically obtained
features. Journal of Computer Virology and Hacking Techniques, 11(1):9–17.
[Alves et al. 2017] Alves, P., Brobecker, J., Evans, D., and Zaretskii, E. (2017). Gdb:
The gnu project debugger. https://www.gnu.org/software/gdb/.
[Beegle 2007] Beegle, L. E. (2007). Rootkits and their effects on information security.
Inf. Sys. Sec., 16(3):164–176.
[Botacin et al. 2018] Botacin, M. F., de Geus, P. L., and Grégio, A. R. A. (2018). The
other guys: automated analysis of marginalized malware. Journal of Computer Virol-
ogy and Hacking Techniques, 14(1):87–98.
[Branco et al. 2012] Branco, R. R., Barbosa, G. N., and Neto, P. D. (2012). Scientific but
not academical overview of malware anti-debugging, anti-disassembly and anti-vm
technologies. https://media.blackhat.com/bh-us-12/Briefings/
Branco/BH_US_12_Branco_Scientific_Academic_WP.pdf.
[Cheng et al. 2018] Cheng, B., Ming, J., Fu, J., Peng, G., Chen, T., Zhang, X., and Mar-
ion, J.-Y. (2018). Towards paving the way for large-scale windows malware analysis:
Generic binary unpacking with orders-of-magnitude performance boost. In Proceed-
ings of the 2018 ACM SIGSAC Conference on Computer and Communications Secu-
rity, CCS ’18, pages 395–411, New York, NY, USA. ACM.
[Combs 2012] Combs, G. (2012). Wireshark Network Analysis (Second Edition): The
Official Wireshark Certified Network Analyst Study Guide. Laura Chappell University.
[Coogan et al. 2009] Coogan, K., Debray, S., Kaochar, T., and Townsend, G. (2009). Au-
tomatic static unpacking of malware binaries. In Proceedings of the 2009 16th Working
Conference on Reverse Engineering, WCRE ’09, pages 167–176, Washington, DC,
USA. IEEE Computer Society.
[Corbet et al. 2005] Corbet, J., Rubini, A., and Kroah-Hartman, G. (2005). Linux Device
Drivers, 3rd Edition. O’Reilly Media, Inc.
[Cozzi et al. 2018] Cozzi, Graziano, Fratantonio, and Balzarotti (2018). Understanding
linux malware. http://www.s3.eurecom.fr/~yanick/publications/
2018_oakland_linuxmalware.pdf.
[Damri and Vidyarthi 2016] Damri, G. and Vidyarthi, D. (2016). Automatic dynamic
malware analysis techniques for linux environment. In 2016 3rd International Confer-
ence on Computing for Sustainable Global Development (INDIACom), pages 825–830.
[Duncan and Schreuders 2019] Duncan, R. and Schreuders, Z. C. (2019). Security impli-
cations of running windows software on a linux system using wine: a malware analysis
study. Journal of Computer Virology and Hacking Techniques, 15(1):39–60.
[eliben 2017] eliben (2017). Parsing elf and dwarf in python. https://github.
com/eliben/pyelftools.
[Fruhlinger 2018] Fruhlinger, J. (2018). The mirai botnet explained: How teen scammers
and cctv cameras almost brought down the internet. https://bit.ly/2Irz5e3.
[Galante et al. 2018] Galante, L., Botacin, M., Grégio, A., and de Geus, P. L. (2018). Ma-
licious linux binaries: A landscape. In Anais Estendidos do XVIII Simpósio Brasileiro
em Segurança da Informação e de Sistemas Computacionais, pages 213–222, Porto
Alegre, RS, Brasil. SBC.
[Gebai and Dagenais 2018] Gebai, M. and Dagenais, M. R. (2018). Survey and analysis
of kernel and userspace tracers on linux: Design, implementation, and overhead. ACM
Comput. Surv., 51(2):26:1–26:33.
[Grégio et al. 2015] Grégio, A. R. A., Afonso, V. M., Filho, D. S. F., Geus, P. L. d., and
Jino, M. (2015). Toward a Taxonomy of Malware Behaviors. The Computer Journal,
58(10):2758–2777.
[Isohara et al. 2010] Isohara, T., Takemori, K., Miyake, Y., Qu, N., and Perrig, A. (2010).
Lsm-based secure system monitoring using kernel protection schemes. In 2010 Inter-
national Conference on Availability, Reliability and Security, pages 591–596.
[Jahoda et al. 2017] Jahoda, M., Krátký, R., Prpič, M., Čapek, T., Wadeley, S., Ruseva,
Y., and Svoboda, M. (2017). A guide to securing red hat enterprise linux: System
auditing. https://access.redhat.com/documentation/en-us/red_
hat_enterprise_linux/6/html/security_guide/chap-system_
auditing.
[Koret and Bachaalany 2015] Koret, J. and Bachaalany, E. (2015). The Antivirus
Hacker’s Handbook. Wiley Publishing, 1st edition.
[Matloff and Salzman 2008] Matloff, N. and Salzman, P. J. (2008). The Art of Debugging
with GDB, DDD, and Eclipse. No Starch Press, San Francisco, CA, USA.
[O’Neill 2016] O’Neill, R. E. (2016). Learning Linux Binary Analysis. Packt Publishing.
[Rossow et al. 2012] Rossow, C., Dietrich, C. J., Grier, C., Kreibich, C., Paxson, V.,
Pohlmann, N., Bos, H., and Steen, M. v. (2012). Prudent practices for designing
malware experiments: Status quo and outlook. In Proceedings of the 2012 IEEE Sym-
posium on Security and Privacy, SP ’12, pages 65–79, Washington, DC, USA. IEEE
Computer Society.
[Sikorski and Honig 2012] Sikorski, M. and Honig, A. (2012). Practical Malware Anal-
ysis: The Hands-On Guide to Dissecting Malicious Software. No Starch Press, San
Francisco, CA, USA, 1st edition.
[Skoudis and Zeltser 2003] Skoudis, E. and Zeltser, L. (2003). Malware: Fighting Mali-
cious Code. Prentice Hall PTR, Upper Saddle River, NJ, USA.
[The Linux Kernel doc. 2017] The Linux Kernel doc. (2017). Linux system calls
implementation. https://linux-kernel-labs.github.io/master/
lectures/syscalls.html.
[Vecchia and Coral 2014] Vecchia, E. D. and Coral, L. (2014). Linux remote evidence
colector – uma ferramenta de coleta de dados utilizando a metodologia live forensics.
Anais do SBSEG 2014, pages 586–597.
[Venezla 2012] Venezla, P. (2012). A world without Linux:
Where would Apache, Microsoft – even Apple be today?
http://www.infoworld.com/article/2616083/data-center/
a-world-without-linux--where-would-apache--microsoft----even-apple-be-today-.
html. Acessado em: Abril/2017.
[Wang et al. 2018] Wang, D., Ming, J., Chen, T., Zhang, X., and Wang, C. (2018). Cracking iot device
user account via brute-force attack to sms authentication code. In Proceedings of the First Workshop on
Radical and Experiential Security, RESEC ’18, pages 57–60, New York, NY, USA. ACM.
[Wong 2018] Wong, R. (2018). Mastering Reverse Engineering: Re-engineer your ethical hacking skills.
Packt.
[Yocom et al. 2004] Yocom, N., Turner, J., and Davis, K. (2004). The Definitive Guide to Linux Network
Programming (Expert’s Voice). Apress.
[Z. Chang 2017] Z. Chang, G. Sison, J. J. (2017). Erebus resurfaces as linux ransomware. https:
//tinyurl.com/y6qwxs3q.