Tradutor

quarta-feira, 23 de janeiro de 2013

(Des)construindo Software

“A Engenharia Reversa é o processo de extrair conhecimento ou design de algo feito pelo homem (…) O Software é uma das mais complexas e intrigantes tecnologias dentre nós nos dias de hoje. Sua engenharia reversa se trata de abrir o programa e olhá-lo por dentro. Claro, nós não precisamos de nenhuma chave de fenda nesta jornada. Da mesma forma que a engenharia de software, seu reverso é puramente um processo virtual envolvendo apenas um processador e a mente humana.” Reversing – Secrets of Reverse Engineering – Eldad Eilam

Antes de nos debruçarmos na reversão em si, é importante sabermos como se dá o processo de engendramento do software binário.

Para a sua construção, faz-se necessária (a não ser que vocês sejam masoquistas e queiram construir em código de máquina) uma linguagem de programação. Essa se traduz como um método padronizado para informar instruções a um processador. Cada linguagem detém sua própria padronização assim como seu nível de abstração (baixo, médio e alto).

Na sequência, são destacados os procedimentos demandados para a transformação do código escrito em um bloco de instruções “entendível” aos olhos do computador.


Construção de Software

A construção ou compilação é um processo de vários estágios que envolve várias ferramentas. No nosso caso, as ferramentas usadas serão o front-end gcc (GNU Compiler), o cc1 (C Compiler), o as (GNU Assembler), o collect2 (ld wrapper), e o ld (GNU Linker). O conjunto completo de ferramentas utilizadas no processo de compilação é chamado toolchain, que, quase que por padrão, já vem instalado nas distribuições GNU/Linux. A criação de toolchains específicas são primordiais para o cross-compiling, mas esse assunto fica para um post futuro.

Durante uma invocação do GCC a sequência de comandos executadas percorre os seguintes estágios:

- pré-processamento (expansão de macros)
- compilação (do código fonte para linguagem assembly)
- assembler (de linguagem assembly para código de máquina)
- linking (criação do binário final)


Criemos como exemplo um programa minimalista em C com o famoso Hello World.

# mkdir construindo; cd construindo
# echo -e "#include <stdio.h>\nint main() { printf(\"Hello World\\\n\"); return 0;}" > programa1.c

Para esta compilação, usemos o gcc.

# gcc programa1.c -o programa1

Ao rodar o gcc, as etapas de pré-processamento, compilação, assembly e linking são efetuadas uma após a outra de forma transparente, até que o binário ELF 'programa1' seja criado.

# ./programa1
Hello World

Em seguida, para melhor entendimento, percorreremos cada fase manualmente.


Pré-processamento e Compilação

Pré-processamento

Em versões passadas do gcc, o pré-processamento era feito como um estágio em separado através do cpp (C Preprocessor):

# cpp programa1.c -o programa1.i

A saída era um arquivo com as macros expandidas e declarações de arquivos header incluídas. O pré-processador, em verdade, traduzia a abstração média da linguagem C (na qual programamos) para uma reconhecível à próxima etapa da compilação.

# 1 "programa1.c"
# 1 "<command-line>"
# 1 "programa1.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 28 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
...
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__$
# 940 "/usr/include/stdio.h" 3 4
# 2 "programa1.c" 2
int main(void) { printf("Hello World\n"); return 0;}

Esse primeiro estágio, atualmente, é incorporado pelo compilador cc1 quando usado com opções default; ou seja, geralmente é omitido.

# gcc programa1.c -o programa1 -v
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -quiet -v -imultiarch x86_64-linux-gnu programa1.c -quiet -dumpbase programa1.c -mtune=generic -march=x86-64 -auxbase programa1 -version -fstack-protector -o /tmp/ccZvPRPS.s
...

Como pode ser visto no modo verboso (detalhado), o cc1 efetua o pré-processamento e compilação, gerando diretamente o arquivo assembly. De toda forma podemos fazer com que o cc1 seja invocado duas vezes, com o uso da opção -no-integrated-cpp; primeiramente para o pré-processamento, gerando o arquivo expandido (*.i) e posteriormente para a compilação, gerando o arquivo para montagem (*.s). Tal procedimento é útil quando se pretende utilizar um pré-processador alternativo, por exemplo.

# gcc programa1.c -o programa1 -v -no-integrated-cpp
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu programa1.c -mtune=generic -march=x86-64 -fstack-protector -o /tmp/ccjNwBsL.i
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -fpreprocessed /tmp/ccjNwBsL.i -quiet -dumpbase programa1.c -mtune=generic -march=x86-64 -auxbase programa1 -version -fstack-protector -o /tmp/cc0B4fmf.s
...

Podemos, também, interromper o processo do gcc, invocando o cc1 apenas uma vez com o intuito de gerarmos o arquivo (*.i) pré-processado.

# gcc programa1.c -o programa1.i  -v -E
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu programa1.c -o programa1.i -mtune=generic -march=x86-64 -fstack-protector
...

Para isso utilizamos a opção '-E'.


Compilação

O objetivo principal do uso do cc1, através ou não do arquivo expandido (programa1.i), é gerar o respectivo código assembly, linguagem de baixo nível.

# gcc programa1.i -o programa1.s -v -S
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -fpreprocessed programa1.i -quiet -dumpbase programa1.i -mtune=generic -march=x86-64 -auxbase-strip programa1.s -version -o programa1.s -fstack-protector
...

# gcc programa1.c -o programa1.s -v -S
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 -quiet -v -imultiarch x86_64-linux-gnu programa1.c -quiet -dumpbase programa1.c -mtune=generic -march=x86-64 -auxbase-strip programa1.s -version -o programa1.s -fstack-protector
...

A opção '-S', instrui o gcc a apenas converter o código C, pré-processado ou não, para a linguagem de montagem (programa1.s).

.file "programa1.c"
.section .rodata
.LC0:
.string "Hello World"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %edi
call puts
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2"
.section .note.GNU-stack,"",@progbits

Atenção! O código assembly pode estar diferente do gerado em seu computador. Essa divergência pode ter sido ocasionada por vários motivos: versão do GCC; arquitetura utilizada; flags de compilação.

Para gerar o respectivo código em 32 bits, basta utilizar a opção -m32.

# gcc programa1.i -S -m32

ou

# gcc programa1.c -S -m32

Vejam a diferença:

.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)call puts
movl $0, %eax
leave
.cfi_restore 5
cfi_def_cfa 4, 4ret
.cfi_endproc


Assembler (Montador)

Na montagem, o código assembly é convertido nas suas instruções correlatas em código de máquina. O resultado é um arquivo-objeto (object file).

# gcc programa1.s -o programa1.o -v -c
...
 as -v --64 -o programa1.o programa1.s
...

# gcc programa1.s -o programa1.o -v -m32 -c
...
 as -v --32 -o programa1.o programa1.s
...

A opção '-c' faz com o gcc apenas compile ou monte o arquivo fonte, mas não o linque.

Como visto acima, o as faz a montagem do binário usando o arquivo assembly (programa1.s). Ao rodarmos o file contra o arquivo-objeto construído, podemos verificar a estrutura ELF.

# file programa1.o
programa1.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped

programa1.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

Entretanto, como o processo de compilação ainda não foi finalizado, ao tentarmos executá-lo recebemos a mensagem de que é impossível executar o arquivo binário. Ao usarmos o ltrace (ferramenta de análise de chamadas à bibliotecas) recebemos a mensagem "./programa1.o is not an ELF executable nor shared library.". O assembler construiu o bloco de instruções binárias para a arquitetura, contudo não definiu os endereços referentes às funções externas, assim como não relocou o binário para a correta execução.


Linking

Até então o arquivo-objeto montado não sabe para onde olhar (endereço das funções necessárias ao correto funcionamento). O Linking ou lincagem é, neste caso, o procedimento de aglutinação de arquivos-objeto, resolução de símbolos e relocação das seções e respectivos endereços do binário outrora gerado.

Vejamos.

# gcc programa1.o -o programa1 -v
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/collect2 --sysroot=/ --build-id --no-add-needed --as-needed --eh-frame-hdr -m elf_x86_64 --hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro -o programa1 /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.7 -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../.. programa1.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.7/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crtn.o
...

ou

# gcc programa1.o -o programa1 -v -m32
...
 /usr/lib/gcc/x86_64-linux-gnu/4.7/collect2 --sysroot=/ --build-id --no-add-needed --as-needed --eh-frame-hdr -m elf_i386 --hash-style=gnu -dynamic-linker /lib/ld-linux.so.2 -z relro -o programa1 /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib32/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib32/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.7/32/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.7/32 -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../i386-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib32 -L/lib/i386-linux-gnu -L/lib/../lib32 -L/usr/lib/i386-linux-gnu -L/usr/lib/../lib32 -L/usr/lib/gcc/x86_64-linux-gnu/4.7 -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../i386-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.7/../../.. -L/lib/i386-linux-gnu -L/usr/lib/i386-linux-gnu programa1.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.7/32/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib32/crtn.o
...

O que o gcc realmente faz é invocar o collect2 (wrapper  para o ld (binutils)) informando todos os arquivos-objeto que devem ser lincados.

É verdade que o ld pode ser utilizado diretamente; de toda sorte, o gcc/collect2 já informa todas as libs necessárias para o linking, o que facilita bastante.

Após terminado o processo, é possível verificar que o executável está devidamente lincado.

# file programa1
programa1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0xa0c...bf73, not stripped

programa1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0xe07...8df3, not stripped

E, finalmente, executá-lo.

# ./programa1
Hello World


Conclusão

Pudemos, neste post, acompanhar de forma breve o processo de construção de um executável ELF, exemplificando os respectivos procedimentos no ambiente GNU/Linux através do GCC. No próximo, iniciaremos uma abordagem prática da engenharia reversa que possibilitará um entendimento objetivo da estrutura ELF, assim como do método e das ferramentas utilizadas na reversão.

Até lá!


Mais Informações

Reversing – Secrets of Reverse Engineering – Eldad Eilam
Reverse Engineering
A Introduction to GCC – Brian Gough
Compiler, Assembler, Linker and Loader: A Brief Story
Basics of GCC compilation process
GNU C Compiler Internals/GNU C Compiler Architecture
GCC front-end Whitepaper - Andi Hellmund
Programming language
List of programming languages by type
C (programming language)
Low-level programming language
Assembly Language
Machine code

terça-feira, 8 de janeiro de 2013

Mas o que diabos é HACKING?

#include <stdio.h>

int main()
{
    char post[] =
    {
        "Hello World!\n\n"

        "Sejam bem vindos ao Hacking bits. Apenas mais um repositório\n"
        "sobre hacking, perdido nesta vastidão de elétrons.\n\n"

        "Mas o que diabos é HACKING?\n\n"

        "Ih! Já estou vendo os partidários dos jargões de olho no que\n"
        "vem  a seguir! Ainda bem que a minha intenção não é  a de me\n"
        "aprofundar  na etimologia e  no  neologismo, mas a de apenas\n" 
        "transmitir um extrato que sirva de intróito.\n\n"

        "'To hack' é, em uma de suas acepções, fazer  uma  gambiarra,\n"
        "seja  ela de  qualidade ou  não. Quem de  vocês nunca fez um\n"
        "hack  como cortar  uns fios  na  instalação  elétrica   para\n"
        "adicionar  outra  tomada, ou substituir o pé de  uma cadeira\n"
        "quebrada  por  qualquer objeto  que ali  sirva, ou até mesmo\n"
        "colocar  cachaça ou  álcool tubarão no  tanque do carro para\n"
        "sair do prego? Nesse sentido, tudo isso é  hacking... seja a\n"
        "área qual  for. Entretanto, é importante ressaltar que  essa\n"
        "significação,  apesar de  se parecer genérica  está longe de\n"
        "exaurir ou condensar as demais.\n"

        "Os  conservadores defendem que o termo  'hacker' não deveria\n"
        "ser usado como  sinônimo dos  novos conceitos  que maculam a\n"
        "sua   ideia   original.  Exemplos  desses  usos   estão  nas\n"
        "divulgações  da mídia ao  descrever simploriamente um hacker\n"
        "como um criminoso do ciberespaço e  nas autoproclamações sem\n"
        "sentido que vemos aos montes.\n\n"

        "Em  1959, o TMRC  (Tech Model Railroad Club), do MIT, cunhou\n"
        "os sinônimos para Hack e Hacking no seu  TMRC  Dictionary. É\n"
        "importante  frisar que  os termos já existiam, todavia, eram\n"
        "utilizados  em contextos diferentes. E  é neste ponto que se\n"
        "observa certamente  um exemplo do  poder mutante da  língua,\n"
        "ao ser capaz de se adaptar ao zeitgeist.\n\n"

        "A despeito dos sinônimos já existentes, o TMRC usava, em seu\n"
        "meio, significados  distintos. Esses, ainda novos, não  eram\n" 
        "de  conhecimento da grande  massa e pelos  motivos a seguir,\n"
        "não tiveram  a menor chance, até  hoje, de competirem com os\n"
        "demais.\n\n"

        "Qual  é  mesmo um dos  maiores  poderes em ação na sociedade\n"
        "global?\n\n"

        "Acertou quem disse: a MÍDIA.\n"
        "E a mídia de massa vive de puro sensacionalismo! Fato.\n\n"

        "A  mais  antiga  referência  ao  termo  hacker,  vinculado a\n"
        "computadores,  é,  ironicamente,  do jornal   'The Tech'  do\n" 
        "próprio  MIT  (MIT student newspaper de 20/09/1963).  Quando\n"
        "digo  ironicamente,  refiro-me  ao  fato de  o  próprio MIT,\n" 
        "apesar   de   não    ter    sido   o  TMRC,  ter   dado   um\n"
        "'DELETE TMRCDICTIONARYTOMASS.DAT.-I', ao vincular os  termos\n"
        "hacker e  hacking a uma  prática,  digamos,  ilícita;  muito\n"
        "embora não tenha sido o intuito.\n"

        "Porém... tudo  indica que a notícia não se  propagou a  bons\n"
        "olhos, e a mídia fez a festa, iniciando mais uma mutação  na\n"
        "denotação  dos termos.  Melhor  dizendo, atribuindo-lhes uma\n"
        "nova acepção,  assim como o tinha  feito  o próprio TMRC  ao\n"
        "criar o seu jargão.\n\n"

        "Considerando-se  as   neologias  ou  usos  diacrônicos   dos\n"
        "referidos   vocábulos,  uma  coisa  é  certa:  um   hacker é\n"
        "um hacker e ponto; seja ele criminoso ou não. Da mesma forma\n"
        "que  um  arrombador de cofres  pode  ser  um mocinho  ou  um\n"
        "bandido,  bastando  apenas  optar  por  trabalhar  para  uma\n"
        "empresa  da área ou  sair explodindo  bancos.  E, seguindo a\n"
        "mesma  linha,  qualquer  que  seja  o  indivíduo  detido por\n"
        "estar usando o metasploit para  criar payloads comprometendo\n"
        "governos, e/ou por usar phishing para obter senhas de contas\n"
        "bancárias,  pode ser chamado de  hacker.  No  entanto, saber\n"
        "se estava a fazer o hacking no entendimento do TMRC, aí, são\n"
        "mais quinhentos... poderia, quem sabe, estar  fazendo  na 3a\n"
        "acepção   do  Michaelis (derivando  o verbo do   substantivo
\n"
       
"
hack) O_o\n\n"

        "Em verdade,  todos os sinônimos  registrados estão corretos,\n"
        "nenhum deixando de existir por conta da formulação de novos.\n"
        "O que  acontece é  que  em  um  determinado  período  sempre\n"
        "haverá algum que esteja mais em voga, ofuscando seus 'primos\n"
        "significantes'.  Eles  servem  apenas  para   diferenciarmos\n"
        "ações ou coisas num  dado  espaço  e  tempo. De  toda sorte,\n"
        "será  que  o que realmente importa  não é  sabermos, de  nós\n"
        "mesmos, o que 'diabos' somos e fazemos?!\n\n"

        "Sim!  O   que diabos é HACKING para vocês? Comentem! E até a\n"
        "próxima.\n\n"

        "Agradeço ao Luiz Vieira  'Hack Proofing Labs' e  ao  Alberto\n"
        "Fabiano 'SciTech::Inno::Blog' pelo grande apoio na confecção\n"
        "deste escrito.\n\n"

        "Mais Informações\n\n"

        "* TMRC Dictionary - 1959 - 1st Edition\n"

        "* First Recorded Usage of 'Hacker' - Gustavo Duarte\n"
        "* The Jargon File - Eric Steven Raymond - v4.4.7, 29/12/2003\n"
        "* How to Become a Hacker - Eric  S Raymond - Rev 1.44,  2012\n"
        "* Hackers   and  crackers:  a lesson in  etymology and clear\n"
        "  communication - Chad Perrin - 16/08/2010\n"
        "* The Origin of 'Hacker' - Imran Ghory - 01/04/2008\n"
        "* Uma Breve Folksonomia dos Hackers - Adriano Cansian -  You\n"
        "  Sh0t the Sheriff - Edição 2\n"
        "* The Hacker Manifesto - The Mentor - 08/01/1986\n"
        "* De onde vêm as palavras? - Cláudio Moreno - 03/12/2011\n"
        "* A logomarca e o ornitorrinco - Cláudio Moreno\n"
        "* A logomarca e o ornitorrinco - conclusão - Cláudio  Moreno\n"

        "* Online Etymology Dictionary - 'hack'\n"
        "* Online Etymology Dictionary - 'hacker'\n"
        "* Dicionário Michaelis Online - 'hack'\n"  // INSTIGANTE
        "* iDicionário Aulete - 'gambiarra'\n"      // 3° SIGNIFICADO
        "* Como dizer ‘gambiarra’ em inglês? - Denilson de Lima\n"
    };

    printf("%s", post);

    return 0;
}


# gcc helloworld.c -o helloworld
Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Brazil License.