Jump to content
  • Estude binários de Windows com o novo pev

       (0 reviews)

    Fernando Mercês

    Desde 2013 que estamos trabalhando duro numa nova versão do pev, nosso toolkit para análise de binários PE (Portable Executable), o formato utilizado pelos executáveis (EXE, DLL, OCX, etc) do Windows.

    O pev é um projeto em que me sinto muito feliz de fazer parte e o principal motivo é que existe algo de muito forte e especial nele: colaboração.  Quase 30 pessoas contribuíram com o projeto de alguma forma (código, testes, empacotamento, etc) e hoje ele está presente nos repositórios das principais distribuições Linux, inclusive as focadas em segurança de alguma forma.

    Outro ponto importante é que ele começou como um projeto de faculdade lá em 2010, junto com outros alunos. Como a faculdade nem laboratório de pesquisa tinha, fizemos o nosso próprio grupo, batizado de Coding 40°, em homenagem ao calor da nossa cidade.

    O projeto atraiu muitos colaboradores, incluindo um que já commitou mais que eu no repositório e redefiniu, de forma muito profissional, toda a infraestrutura por trás do pev e da libpe. Foi o Jardel Weyrich. Sério, dá pra detectar que um projeto teve sucesso quando aparece alguém que já contribuiu com mais código para ele do que você!:)

    Por último, mas não menos importante: o pev é livre. E na boa, até agradeço as centenas de programadores que fizeram analisadores de PE proprietários, porque me motivaram a iniciar o pev. Era preciso um analisador de binários PE de código aberto, que permitisse estudantes e curiosos entender como um PE é parseado, que campos são importantes, por que a análise estática é tão poderosa, etc. Hoje, mesmo com todos os bugs que ainda hão de surgir (fora os que já surgiram e ainda não conseguimos corrigir!).

    Quero agradecer, de forma permanente, a todos que se envolvem ou se envolveram de alguma forma com o pev: usando, avisando-nos sobre bugs, contribuindo com código, ideias, testes, tudo importa! Obrigado, de coração.

    Emoções à parte, vamos partir para a análise de binários e falar das novidades do pev 0.80, lançado hoje!

    Acontece que um binário PE pode esconder muitas informações importantes antes mesmo de ser executado. Por exemplo, com a ferramenta readpe, do pev, você vai descobrir que um executável PE é dividido em cabeçalhos e seções e eles armazenam várias informações interessantes, por exemplo:

    $ readpe arquivo.exe
    DOS Header
        Magic number:                    0x5a4d (MZ)
        Bytes in last page:              144
        Pages in file:                   3
        Relocations:                     0
        Size of header in paragraphs:    4
        Minimum extra paragraphs:        0
        Maximum extra paragraphs:        65535
        Initial (relative) SS value:     0
        Initial SP value:                0xb8
        Initial IP value:                0
        Initial (relative) CS value:     0
        Address of relocation table:     0x40
        Overlay number:                  0
        OEM identifier:                  0
        OEM information:                 0
        PE header offset:                0x80
    COFF/File header
        Machine:                         0x14c IMAGE_FILE_MACHINE_I386
        Number of sections:              3
        Date/time stamp:                 1425562907 (Thu, 05 Mar 2015 13:41:47 UTC)
        Symbol Table offset:             0
        Number of symbols:               0
        Size of optional header:         0xe0
        Characteristics:                 0x102
        Characteristics names
                                             IMAGE_FILE_EXECUTABLE_IMAGE
                                             IMAGE_FILE_32BIT_MACHINE
    Optional/Image header
        Magic number:                    0x10b (PE32)
        Linker major version:            11
        Linker minor version:            0
        Size of .text section:           0x2a800
        Size of .data section:           0x3400
        Size of .bss section:            0
        Entrypoint:                      0x2c78e
        Address of .text section:        0x2000
        Address of .data section:        0x2e000
        ImageBase:                       0x400000
        Alignment of sections:           0x2000
        Alignment factor:                0x200
        Major version of required OS:    4
        Minor version of required OS:    0
        Major version of image:          0
        Minor version of image:          0
        Major version of subsystem:      4
        Minor version of subsystem:      0
        Size of image:                   0x34000
        Size of headers:                 0x200
        Checksum:                        0
        Subsystem required:              0x2 (IMAGE_SUBSYSTEM_WINDOWS_GUI)
        DLL characteristics:             0x8540
        DLL characteristics names
                                             IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
                                             IMAGE_DLLCHARACTERISTICS_NX_COMPAT
                                             IMAGE_DLLCHARACTERISTICS_NO_SEH
                                             IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
        Size of stack to reserve:        0x100000
        Size of stack to commit:         0x1000
        Size of heap space to reserve:   0x100000
        Size of heap space to commit:    0x1000
    Data directories
        Directory
            IMAGE_DIRECTORY_ENTRY_IMPORT:    0x2c738 (83 bytes)
        Directory
            IMAGE_DIRECTORY_ENTRY_RESOURCE:  0x2e000 (12728 bytes)
        Directory
            IMAGE_DIRECTORY_ENTRY_BASERELOC: 0x32000 (12 bytes)
        Directory
            IMAGE_DIRECTORY_ENTRY_IAT:       0x2000 (8 bytes)
        Directory
            IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR:    0x2008 (72 bytes)
    Imported functions
        Library
            Name:                            mscoree.dll
            Functions
                Function
                    Name:                            _CorExeMain
    export directory not found
    Sections
        Section
            Name:                            .text
            Virtual Address:                 0x2000
            Physical Address:                0x2a794
            Size:                            0x2a800 (174080 bytes)
            Pointer To Data:                 0x200
            Relocations:                     0
            Characteristics:                 0x60000020
            Characteristic Names
                                                 IMAGE_SCN_CNT_CODE
                                                 IMAGE_SCN_MEM_EXECUTE
                                                 IMAGE_SCN_MEM_READ
        Section
            Name:                            .rsrc
            Virtual Address:                 0x2e000
            Physical Address:                0x31b8
            Size:                            0x3200 (12800 bytes)
            Pointer To Data:                 0x2aa00
            Relocations:                     0
            Characteristics:                 0x40000040
            Characteristic Names
                                                 IMAGE_SCN_CNT_INITIALIZED_DATA
                                                 IMAGE_SCN_MEM_READ
        Section
            Name:                            .reloc
            Virtual Address:                 0x32000
            Physical Address:                0xc
            Size:                            0x200 (512 bytes)
            Pointer To Data:                 0x2dc00
            Relocations:                     0
            Characteristics:                 0x42000040
            Characteristic Names
                                                 IMAGE_SCN_CNT_INITIALIZED_DATA
                                                 IMAGE_SCN_MEM_DISCARDABLE
                                                 IMAGE_SCN_MEM_READ

    Só olhando para este cabeçalho, já dá pra dizer muita coisa sobre esse binário. Por exemplo, é possível inferir que ele foi compilado em 5 de março de 2015, é um executável de janelas (GUI – Graphical User Interface) e na Import Table dele tem apenas uma entrada, uma função chamada _CorExeMain importada da biblioteca mscoree.dll. Isso já dá a dica que esse é binário foi compilado em .NET. Como eu sei disso? É que eu já vi vários binários em .NET e todos eles importam somente essa função. Não se preocupe, com o tempo você também pega os macetes!;)

    Claro que, para estudar os binários de forma eficiente é legal ler também outros tutoriais sobre o assunto. O que mais gosto em Português é O formato PE, da Vovó Vicky, isso mesmo, uma simpática senhora, médica, do Sul do país que adora arquivos PE. ❤️

    Voltando ao nosso binário, vamos dar uma olhada nas strings presentes nele com o pestr:

    $ pestr -so arquivo.exe
    0x2d81e .rsrc FileDescription
    0x2d840 .rsrc Gynx
    0x2d852 .rsrc FileVersion
    0x2d86c .rsrc 1.0.0.0
    0x2d882 .rsrc InternalName
    0x2d89c .rsrc Gynx.exe
    0x2d8b6 .rsrc LegalCopyright
    0x2d8d4 .rsrc Copyright
    0x2d8ea .rsrc   2015
    0x2d8fe .rsrc OriginalFilename

    A lista de strings completa é bem maior, mas eu cortei só para mostrar algumas.

    Primeira pergunta que pode surgir aqui é: por que fizemos um programa pestr se já existe o programa strings? Bem, você pode notar pela saída que dizemos muito mais que a string (texto) em si. Sabemos em que seção ela está e o offset (posição) no arquivo. Além disso, o pestr imprime strings ASCII e Unicode.

    No meio das strings tem outra informação de data, que reforça o ano da data de compilação. Tem também o nome original do arquivo (quando o programador compilou). Se você pesquisar no Google pelo nome do arquivo, já vai encontrar muita coisa!

    Continuando nossa análise, vamos ver com o pescan se tem algo estranho neste arquivo:

    $ pescan -v ~/dotnet
    file entropy:                    5.252392 (normal)
    fpu anti-disassembly:            no
    imagebase:                       normal - 0x400000
    entrypoint:                      normal - va: 0x2c78e - raw: 0x2a98e
    DOS stub:                        normal
    TLS directory:                   not found
    timestamp:                       normal - Thu, 05 Mar 2015 13:41:47 UTC
    section count:                   3
    sections
        section
            .text:                           normal
        section
            .rsrc:                           normal
        section
            .reloc:                          small length

    A baixa entropia sugere que o binário não está comprimido (packed) e tudo parece estar normal. Isso significa que o binário não está protegido, não que seu código não seja malicioso.;)

    Agora, já entrando nos novos recursos, que tal saber os hashes deste arquivo? Buscando por eles no Google também é possível encontrar algumas informações. Ao invés de calcular um por um, utilizando vários programas, o pev conta com o pehash, que faz tudo pra você:

    $ pehash -a arquivo.exe
    file
        filepath:                        /home/user/arquivo.exe
        md5:                             1f4c40ff46297bdc5a595cd574e0db64
        sha1:                            2bc6fa6558988d628dd4b95d0741405685c1c232
        sha256:                          b823a04f49463e410c9f823baade182eb283ba073b40c6d8cc443a570a9a1df6
        ssdeep:                          3072:yLYmWbfXGKJy7DFR9KwHS+MASjB5jL0S9Q0VwuUcu:AYmWbfX3y7DFR9KwHS+MAS/js0VhU
        imphash:                         f34d5f2d4577ed6d9ceec516c1f5a744
    headers
        header
            header_name:                     IMAGE_DOS_HEADER
            md5:                             919f1c12cf0d1cd93d7f1077f13ac374
            sha1:                            3d43712e5606b4640b85f5f0e25e9db8ed552074
            sha256:                          c46a3fc444808f3b86a7e757e5202d16f8ea9bf1c6aff2cabc593e7d0f2c9ad2
            ssdeep:                          3:WlWUqt/vllnln:idqP
        header
            header_name:                     IMAGE_COFF_HEADER
            md5:                             15174f39bbe557d104f169053af5c7a2
            sha1:                            21f9311fa5e1a7c8724c657db39ef2fbb1b896ce
            sha256:                          7430166bd1b2d5c400f2f5fb60c90393b50388b97e877aa7cf0c3057a413a85f
            ssdeep:                          3:HHJl/fkn:HHJlkn
        header
            header_name:                     IMAGE_OPTIONAL_HEADER
            md5:                             3b079fa2a88b6901db907bc47dee2d67
            sha1:                            21c1c517743170c94d1ade608ff7d2746fd7e3ea
            sha256:                          0fec7657e9361e8262af5872bf3784a7647b6978f3d0e35a419d2f410c8654a0
            ssdeep:                          3:6FZ//llAlFlllXNB//llrllel/dglPt1l9tllH:pfGwlN
    sections
        section
            section_name:                    .text
            md5:                             973d11759194c14071aa6963de8f55c7
            sha1:                            1934e0085c8776e3243bf658e95b8943d4f91bc9
            sha256:                          e68349bfcb04b20c11973ce27770570ebb22c8c7750133d073f15f7ec9eeda38
            ssdeep:                          3072:XLYmWbfXGKJy7DFR9KwHS+MASjB5jL0S9Q0VwuUc:bYmWbfX3y7DFR9KwHS+MAS/js0VhU
        section
            section_name:                    .rsrc
            md5:                             9d498bee08b1cf075d8aca022f1e16e9
            sha1:                            f938a8c23185b023bb5dd12082013c2a628bc0d3
            sha256:                          eb7454309df90fea2d01c887b0040e8237353919efc06a7081a7abb15091283a
            ssdeep:                          24:3A5t/ug9GXBEiViKZWIDDOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO:weg90VWIDZ6Kp+l4BhDqFWSfbNtm
        section
            section_name:                    .reloc
            md5:                             37ab911460a0b274ffa9f4e388ec933b
            sha1:                            7c9eac3b843c9a7ab8ef08aac5c14e4c51b2c703
            sha256:                          fb50df3b064d126999295b35f1a151f8fbe7e3593e306a9255a534999843f5b2
            ssdeep:                          3:LlQl:S

    Achou que teria os hashes do arquivo somente? Pois é, o pev surpreende mesmo! O pehash calcula MD5, SHA1, SHA-256 e ssdeep (uma técnica de fuzzy hash que vale a pena pesquisar sobre!) para cada cabeçalho e seção. Além disso, a partir das funções importadas do binário o pehash calcula o imphash, que já expliquei no artigo Entendendo o imphash.

    Tanto o imphash quanto o ssdeep podem ser utilizados, de maneiras diferentes, para saber se um arquivo é parecido com outro, se são variantes do mesmo código-fonte, mas neste caso o imphash não ajuda por ser um binário .NET (todos eles importam aquela mesma função única que comentei acima).

    Também é possível, com o peres (criação do Marcelo Fleury),  extrair os recursos e checar, por exemplo, o manifesto em XML dos arquivo:

    $ peres -x arquivo.exe
    Save On:                         resources/icons/2.ico
    Save On:                         resources/icons/3.ico
    Save On:                         resources/icons/4.ico
    Save On:                         resources/icons/5.ico
    Save On:                         resources/icons/6.ico
    Save On:                         resources/icons/7.ico
    Save On:                         resources/icons/8.ico
    Save On:                         resources/groupicons/32512.ico
    Save On:                         resources/versions/1.rc
    Save On:                         resources/manifests/1.xml
    
    $ cat resources/manifests/1.xml
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
      <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
      <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
        <security>
          <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
            <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
          </requestedPrivileges>
        </security>
      </trustInfo>
    </assembly>

    O ícone utilizado também é extraído (groupicons) mas ele é quebrado em várias imagens (icons) e precisam ser reconstruídos se você precisar do ícone original do arquivo. De qualquer forma, você pode calcular o hash deles e comparar com os dos ícones de outros arquivos, se for essa a intenção.;)

    Uma outra novidade é o programa cpload, para analisar arquivos .cpl (Control Panel Applets). Ele é presente somente na versão do pev para Windows, pois serve para analisar binários dinamicamente. Este formato é um pouco diferente do EXE convencional (na verdade um CPL é uma “DLL que executa com dois cliques”). Na época o formato desses arquivos era muito pouco conhecido e até escrevi um artigo para a Wikipédia em Português sobre. Com o cpload, é possível enviar para a função presente no arquivo .cpl todas as mensagens que ela deve reconhecer. Assim o analista pode ver qual delas dispara o código. No exemplo abaixo, a mensagem CPL_DBLCLK (clique duplo) foi enviada para um .cpl presente no Windows chamado joy.cpl. Veja que o programa executa e mostra uma janela:

    cpload-dblclk.png.dfb36d4c9774706bb34bb51e508fa6fa.png

    Adicionalmente, se você fizer isso no contexto de um debugger, passando os argumentos como na imagem abaixo:

    cpload-olly-arguments.png.bca94ef0b9f9f98024681d5596aeaa2f.png

    O cpload força um software breakpoint antes do carregamento do arquivo .cpl pela função LoadLibrary() e antes da entrada na CPLApplet(), que é a função principal de um arquivo .cpl, o que permite ao analista enxergar o trecho exato de código dele, sem precisar debugar processos do sistema como o rundll32.exe.

    cpload-olly-bp.png.7b9a1b51fa499534a2a27d1416bfde17.png

    E ainda sobre o pev, os plugins de formato de saída estão dando um show (ideia do Jan Seidl e portada para plugins pelo Jardel). Olha só como fica a saída se você pedir ao pedis, nosso disassembler, para disassemblar o entrypoint  de um binário PE em JSON:

    $ pedis --format json --entrypoint PUTTY.EXE
    {
        "54eb0": "6a 60                           push 0x60",
        "54eb2": "68 70 7b 47 00                  push 0x477b70",
        "54eb7": "e8 08 21 00 00                  call 0x456fc4",
        "54ebc": "bf 94 00 00 00                  mov edi, 0x94",
        "54ec1": "8b c7                           mov eax, edi",
        "54ec3": "e8 b8 fa ff ff                  call 0x454980",
        "54ec8": "89 65 e8                        mov [ebp-0x18], esp",
        "54ecb": "8b f4                           mov esi, esp",
        "54ecd": "89 3e                           mov [esi], edi",
        "54ecf": "56                              push esi",
        "54ed0": "ff 15 e0 d2 45 00               call dword [0x45d2e0]",
        "54ed6": "8b 4e 10                        mov ecx, [esi+0x10]",
        "54ed9": "89 0d 48 e1 47 00               mov [0x47e148], ecx",
        "54edf": "8b 46 04                        mov eax, [esi+0x4]",
        "54ee2": "a3 54 e1 47 00                  mov [0x47e154], eax",
        "54ee7": "8b 56 08                        mov edx, [esi+0x8]",
        "54eea": "89 15 58 e1 47 00               mov [0x47e158], edx",
        "54ef0": "8b 76 0c                        mov esi, [esi+0xc]",
        "54ef3": "81 e6 ff 7f 00 00               and esi, 0x7fff",
        "54ef9": "89 35 4c e1 47 00               mov [0x47e14c], esi",
        "54eff": "83 f9 02                        cmp ecx, 0x2",
        "54f02": "74 0c                           jz 0x454f10",
        "54f04": "81 ce 00 80 00 00               or esi, 0x8000",
        "54f0a": "89 35 4c e1 47 00               mov [0x47e14c], esi",
        "54f10": "c1 e0 08                        shl eax, 0x8",
        "54f13": "03 c2                           add eax, edx",
        "54f15": "a3 50 e1 47 00                  mov [0x47e150], eax",
        "54f1a": "33 f6                           xor esi, esi",
        "54f1c": "56                              push esi",
        "54f1d": "8b 3d d8 d2 45 00               mov edi, [0x45d2d8]",
        "54f23": "ff d7                           call edi0x454f25",
        "54f25": "66 81 38 4d 5a                  cmp word [eax], 0x5a4d",
        "54f2a": "75 1f                           jnz 0x454f4b",
        "54f2c": "8b 48 3c                        mov ecx, [eax+0x3c]",
        "54f2f": "03 c8                           add ecx, eax",
        "54f31": "81 39 50 45 00 00               cmp dword [ecx], 0x4550",
        "54f37": "75 12                           jnz 0x454f4b",
        "54f39": "0f b7 41 18                     movzx eax, word [ecx+0x18]",
        "54f3d": "3d 0b 01 00 00                  cmp eax, 0x10b",
        "54f42": "74 1f                           jz 0x454f63",
        "54f44": "3d 0b 02 00 00                  cmp eax, 0x20b",
        "54f49": "74 05                           jz 0x454f50",
        "54f4b": "89 75 e4                        mov [ebp-0x1c], esi",
        "54f4e": "eb 27                           jmp 0x454f77",
        "54f50": "83 b9 84 00 00 00 0e            cmp dword [ecx+0x84], 0xe",
        "54f57": "76 f2                           jbe 0x45504b",
        "54f59": "33 c0                           xor eax, eax",
        "54f5b": "39 b1 f8 00 00 00               cmp [ecx+0xf8], esi",
        "54f61": "eb 0e                           jmp 0x454f71",
        "54f63": "83 79 74 0e                     cmp dword [ecx+0x74], 0xe",
        "54f67": "76 e2                           jbe 0x45504b",
        "54f69": "33 c0                           xor eax, eax",
        "54f6b": "39 b1 e8 00 00 00               cmp [ecx+0xe8], esi",
        "54f71": "0f 95 c0                        setnz al",
        "54f74": "89 45 e4                        mov [ebp-0x1c], eax",
        "54f77": "56                              push esi",
        "54f78": "e8 b4 28 00 00                  call 0x457831",
        "54f7d": "59                              pop ecx",
        "54f7e": "85 c0                           test eax, eax",
        "54f80": "75 21                           jnz 0x454fa3",
        "54f82": "83 3d 94 e1 47 00 01            cmp dword [0x47e194], 0x1",
        "54f89": "75 05                           jnz 0x454f90",
        "54f8b": "e8 56 44 00 00                  call 0x4593e6",
        "54f90": "6a 1c                           push 0x1c",
        "54f92": "e8 d8 42 00 00                  call 0x45926f",
        "54f97": "68 ff 00 00 00                  push 0xff",
        "54f9c": "e8 be fb ff ff                  call 0x454b5f",
        "54fa1": "59                              pop ecx",
        "54fa2": "59                              pop ecx",
        "54fa3": "e8 65 47 00 00                  call 0x45970d",
        "54fa8": "89 75 fc                        mov [ebp-0x4], esi",
        "54fab": "e8 e9 25 00 00                  call 0x457599",
        "54fb0": "85 c0                           test eax, eax",
        "54fb2": "7d 08                           jge 0x454fbc",
        "54fb4": "6a 1b                           push 0x1b",
        "54fb6": "e8 d0 fe ff ff                  call 0x454e8b",
        "54fbb": "59                              pop ecx",
        "54fbc": "ff 15 a8 d1 45 00               call dword [0x45d1a8]",
        "54fc2": "a3 00 e9 47 00                  mov [0x47e900], eax",
        "54fc7": "e8 af 4d 00 00                  call 0x459d7b",
        "54fcc": "a3 8c e1 47 00                  mov [0x47e18c], eax",
        "54fd1": "e8 03 4d 00 00                  call 0x459cd9",
        "54fd6": "85 c0                           test eax, eax",
        "54fd8": "7d 08                           jge 0x454fe2",
        "54fda": "6a 08                           push 0x8",
        "54fdc": "e8 aa fe ff ff                  call 0x454e8b",
        "54fe1": "59                              pop ecx",
        "54fe2": "e8 bf 4a 00 00                  call 0x459aa6",
        "54fe7": "85 c0                           test eax, eax",
        "54fe9": "7d 08                           jge 0x454ff3",
        "54feb": "6a 09                           push 0x9",
        "54fed": "e8 99 fe ff ff                  call 0x454e8b",
        "54ff2": "59                              pop ecx",
        "54ff3": "6a 01                           push 0x1",
        "54ff5": "e8 95 fb ff ff                  call 0x454b8f",
        "54ffa": "59                              pop ecx",
        "54ffb": "89 45 d8                        mov [ebp-0x28], eax",
        "54ffe": "3b c6                           cmp eax, esi",
        "55000": "74 07                           jz 0x455009",
        "55002": "50                              push eax",
        "55003": "e8 83 fe ff ff                  call 0x454e8b",
        "55008": "59                              pop ecx",
        "55009": "89 75 bc                        mov [ebp-0x44], esi",
        "5500c": "8d 45 90                        lea eax, [ebp-0x70]",
        "5500f": "50                              push eax",
        "55010": "ff 15 ac d1 45 00               call dword [0x45d1ac]",
        "55016": "e8 2e 4a 00 00                  call 0x459a49",
        "5501b": "89 45 e0                        mov [ebp-0x20], eax",
        "5501e": "f6 45 bc 01                     test byte [ebp-0x44], 0x1",
        "55022": "74 06                           jz 0x45502a",
        "55024": "0f b7 45 c0                     movzx eax, word [ebp-0x40]",
        "55028": "eb 03                           jmp 0x45502d",
        "5502a": "6a 0a                           push 0xa",
        "5502c": "58                              pop eax",
        "5502d": "50                              push eax",
        "5502e": "ff 75 e0                        push dword [ebp-0x20]",
        "55031": "56                              push esi",
        "55032": "56                              push esi",
        "55033": "ff d7                           call edi0x455035",
        "55035": "50                              push eax",
        "55036": "e8 93 3b ff ff                  call 0x448bce",
        "5503b": "8b f8                           mov edi, eax",
        "5503d": "89 7d d4                        mov [ebp-0x2c], edi",
        "55040": "39 75 e4                        cmp [ebp-0x1c], esi",
        "55043": "75 06                           jnz 0x45504b",
        "55045": "57                              push edi",
        "55046": "e8 6f fc ff ff                  call 0x454cba",
        "5504b": "e8 8c fc ff ff                  call 0x454cdc",
        "55050": "eb 2b                           jmp 0x45507d",
        "55052": "8b 45 ec                        mov eax, [ebp-0x14]",
        "55055": "8b 08                           mov ecx, [eax]",
        "55057": "8b 09                           mov ecx, [ecx]",
        "55059": "89 4d dc                        mov [ebp-0x24], ecx",
        "5505c": "50                              push eax",
        "5505d": "51                              push ecx",
        "5505e": "e8 75 48 00 00                  call 0x4598d8",
        "55063": "59                              pop ecx",
        "55064": "59                              pop ecx",
        "55065": "c3                              ret"

    Os formatos de saída suportados por todos os programas do toolkit incluem JSON, XML, CSV e o padrão, texto. Assim o pev se faz útil para quem quer automatizar o processo de análise estática de binários PE, para salvar em um banco de dados para consulta posterior, por exemplo.

    A documentação para a versão 0.80 está pronta e recomendo fortemente que você a leia se quiser aproveitar o máximo do toolkit. O changelog completo também está disponível. Despeço-me com a certeza de que fizemos um bom trabalho e de que o software livre é viável, funciona e é, principalmente, algo prazeroso de se manter, que pode ajudar pessoas e empresas a atingirem seus objetivos, sem custo.:)

    Confere lá: https://github.com/merces/pev



    User Feedback

    Join the conversation

    You can post now and register later. If you have an account, sign in now to post with your account.

    Guest

  • Similar Content

    • By Vira
      Bom dia Galera,
       
      Sou bem novo aqui no Fórum, procurei as regras mas não encontrei. Então usarei apenas do bom senso! 🙂
       
      Eu estou a mais ou menos dois meses cutucando um CTF do hack the box, minha experiência com reversing não é muito grande, mas estou procurando aprimora-la cada vez mais. Terminei semana passada o CERO que o Fernando ministrou no Papo Binário, consegui certos progressos mas ainda assim não consigo retornar a flag.
       
      Segue o enunciado do CTF:
      Find the secret flag and get the name of the creators of this challenge!
      o arquivo do CTF esta em anexo, mas tambem pode ser baixado em https://www.hackthebox.eu/home/challenges/Reversing na opção Find The Secret Flag
      Senha do arquivo ZIP: hackthebox
       
      Identifiquei alguns pontos sobre o desafio:
      As 4 primeiras strings ascii são parte do programa normal, e não são produtivas pra nada, pelo que eu vi, as duas ultimas dentro do data são stirngs encodadas:

      Mesmo sabendo das strings, não encontrei referencias dela em nenhuma parte do código.
      A unica referencia a string encodada é na função sub.printf_400a5b, e o fluxo do código tabém não cai na área dela por padrão

       
      Eu fiz todo os tipos de direcionamentos que aprendi, procurei fazer com que as entradas do que as funções necessitam fossem sempre válidas, mas sempre que entro nestas funções recebo um seg fault, ou uma saida aleatória que não é útil pra  nada.
      As funções que destaquei abaixo são as que não identifiquei como sendo chamadas de forma nennhuma na execução do binário.

       
      Alguém mais experiente poderia me auxiliar com este desafio? Honestamente estou a tanto tempo nele que nem estou mais preocupado com a pontuação em si, mas quero entender que pontos estou errando para melhorar minhas habilidades. tenho certeza que isso me ajudará a reverter strings ofuscadas em malwares!!
       
      Obrigado desde já!
       
       

      secret_flag.zip
    • By kassane
      Olá pessoal, tudo bem?
      Creio que a maioria já sabem sobre  software reverse engineering(SRE) publicado pelo NSA's Research Directorate.
      Pois já existe uma comunidade voltada para esta ferramenta específica com um crescimento massivo, inclusive até mesmos curiosos desconfiados.
      Fontes de informações disponíveis:
      Ghidra -Download Release Notes Installation Guide Issues Tracker Community Collection Cheat Sheet - PDF API Documentation Decompiler Documentation Online Courses Getting Started Scripts Wiki  
    • By Candeer
      Olá! No artigo anterior falamos sobre Signals, que é de suma importância para a comunicação entre processos, mas para construir o nosso debugger precisamos muito mais do que apenas isso, precisamos de fato ter total controle sobre um dado processo e se possível controlar até o seu própio início.
      Neste artigo será explicado o que são forks e seu uso em desenvolvimento de aplicações em sistemas UNIX. Sem mais delongas, vamos prosseguir!!!😀
      Resumidamente a syscall fork é usada para a duplicação e criação de um processo. Quando um dado processo chama a função fork(), é criada uma cópia idêntinca de seus dados. Note que apenas uma cópia é feita, o processo filho não compartilha o mesmo espaço de memória do pai.
      A syscall fork retorna um PID que é usado para indetificar em qual processos estamos e também dar acesso ao ID do processo filho. Caso o PID seja 0 estamos executando no filho, caso seja qualquer outro somos o processo pai, isso ocorre pois o pai precisa saber o PID do filho, mas o filho não necessariamente precisa saber o seu própio (da mesma maneira que o seu processo não sabe o própio PID ao menos que o mesmo peça).
      Algo interessante de se notar é que os Init System usados para subir e gerenciar serviços de sua máquina trabalham dessa mesma maneira, você pode checar sua árvore de processo usando comando pstree:
      $ pstree Dessa maneira você tem uma representação bem visual de como está dividida a sua estrutura de processos 😀. Note que todos os processos são filhos do seu Init system (seja ele SystemV, Systemd, etc). Aconselho você explorar o comando pstree para uma visão bem mais detalhada do seu sistema! Outra abordagem é usar o própio comando ps:
      $ ps -ef Rode o comando acima (dependendo da quantidade de processos use um pipe para o less 😉) e com ele teremos uma visão mais detalhada. A coluna PID representa o ID do processo em si e a coluna PPID representa o "Parent Process ID", que nada mais é que o ID do processo pai. Note que o PID 1 é o seu Init System e os seus processos rodam como filho dele!

      Vale notar que o processo Pai do própio init é o PID 0, que é conhecido como "swapper" ou "scheduler", que é o processo responsavel para realização de paging. Paging é o sistema de gerenciamento de memória que salva os dados da RAM em uma memória secundária (HD, SSD e etc) e recupera em formato de páginas (outros PID também são filhos do propio PID 0 como PID 2 que gerencia todas as threads que rodam em Kernel Land(KThread) etc).
       
      Programando Forks
      A syscall fork está na lib  <unistd.h> (Unix Standard library) e tem a seguinte construção:
      #include <sys/types.h> #include <unistd.h> pid_t fork(void); Precisamos incluir a lib <sys/types.h> para que seja possivel acessar o tipo pid_t. A função fork não espera nenhum parâmetro para a sua construção e o código abaixo demonstra o quão simples é cria um fork.
      #include <stdio.h> // Acesso a syscall #include <unistd.h> // Acesso ao tipo variavel pid_t #include <sys/types.h> int main(void) { int x; printf("Processo normal...\n"); printf("Forking...\n"); sleep(5); pid_t pid = fork(); x = 40; if (pid == 0) { printf("Eu sou o processo filho meu PID: %d\n", pid); } else { printf("Eu sou o processo pai de %d\n", pid); } sleep(5); return 0; } Compile o código acima da seguinte forma:
      $ gcc -o fork fork.c $ ./fork Note que o código se "divide" a partir da chamada fork e um if  é usado para saber se estamos executando no pai ou no filho, note também que o pai sabe o PID e o filho não.
      Para melhor visualização o código acima roda por 10 segundos (por conta da chamada ao sleep com esse tempo de espera). Abra um outro terminal e rode o comando:
      $ watch -n1 pstree O comando acima vai executar o pstree a cada 1 segundo, desta forma você verá o exato momento da criação do fork.

      Comunicando-se com o processo fork
      Agora imagine que um  processo precisa esperar o seu filho terminar algum trabalho e dependendo do seu sinal o processo pai realiza alguma ação. A comunicação entre o processo pai e o filho se da por signals. O pai pode saber exatamente o estado do seu processo filho usando a syscall wait e waitpid, ambas na lib <sys/wait.h>:
      #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int options); A syscall wait espera que ao menos 1 de seus processos filho troque de estado, já a waitpid espera por um processo específico. Como sabemos exatamente qual processo queremos rastrear iremos usar esta call 😀:
      #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> int main(void) { printf("Spliting work...\n"); pid_t pid = fork(); if (!pid) { int a = 0; for(int i = 0; i < 100000000; i++ ) { a += i*2 + 10 *i; } return 9; } int status; int signal; printf("Waiting child finish work...\n"); waitpid(pid, &status, 0); if (WIFEXITED(status)) { signal = WEXITSTATUS(status); printf("Child exited, status = %s\n", strsignal(signal)); } return 1; } Compile o código acima e execute:
      $ gcc -o work work.c $ ./work Spliting work... Waiting child finish work... Child exited, status = Killed Veja que após a chamada de fork nosso processo filho executa várias iterações e realiza um cálculo (um cálculo totalmente randômico) e após isso retorna 9. Este retorno em questão é apenas por motivos educativos (no artigo anterior falamos de sinais e como eles funcionam). O processo pai usa a syscall waitpid para esperar que qualquer signal seja enviada do pid especificado. Após receber um status é verificado se o fork saiu (WIFEXITED) e se sim, pegamos o signal enviado usando WEXITSTATUS(status da saída) e usamos a chamada strsignal(provida pela string.h) para recuperar uma versão em texto do signal. Nesse caso iremos recuperar o signal "KILLED", pois colocamos 9 apenas por razões educativas.
      Normalmente se tudo ocorreu bem colocamos 0 (inclusive é dessa maneira que sua shell avalia se o programa rodou certo).
      $./work && echo "Filho saiu com 0, tudo certo..." || echo "Filho saiu com 1, algo errado..." No caso acima a nossa shell irá criar um fork do nosso work, executar o nosso programa (que por sua vez também executa um fork mas não entra em questão aqui) e se o signal retornado pelo fork for 0 ele imprime uma mensagem, caso contrario ele imprime uma mensagem de erro, dessa maneira você pode orquestrar um shell scripting usando o própio retorno do processo 😉
      Tente mudar o retorno do fork acima e verifique seu status usando funções providas pela <sys/wait.h>. No exemplo acima usamos apenas a call WIFEXITED e WEXITSTATUS, mas existem várias outras.
      Forks são de extrema importância para criação e gerenciamento de processos e iremos usar forks para que seja possível executar o programa que queremos debugar, dessa maneira o software em questão vai ser filho do nosso debugger, o que nós da total controle sobre o mesmo.
      Comentarios são todos bem vindos e todos os códigos usados estão disponíveis no github! 😀

      Links úteis:
          Process Control
          fork
          wait
          Process State
          Fork Bomb - Cuidado com isso
    • By Candeer
      Olá, neste artigo compartilharei um pouco da minha pesquisa no desenvolvimento de debuggers. No momento estou trabalhando em um protótipo de debugger para Linux, mas nada tão avançado quanto um gdb ou radare (muitas coisas são necessárias para chegar neste nível de maturidade de software).
      O desenvolvimento de debuggers é uma atividade muito interessante, já que, em sua forma mais básica, pode ser resumido em uma série de chamadas de sistema (syscalls) para que seja possível o controle do processo a ser depurado (muitas vezes chamado de debuggee) e de seus recursos, mas não vamos colocar a carroça na frente dos cavalos e vamos em partes.
      Antes de começarmos a discutir detalhes mais específicos acerca da depuração de processos, é necessário um entendimento básico de como os mesmos se comunicam na plataforma que vamos desenvolver o tal debugger, no nosso caso, UNIX-like.
      Inter-process communication (IPC)
      IPC é uma forma que processos podem utilizar para se comunicar dentro de um sistema operacional. Existem diversas maneiras de comunicação: via sinais (signals), sockets, etc, mas para a criação de um debugger é apenas necessário usar sinais para a execução.
      Sinais funcionam como uma notificação que pode ser enviada à um processo específico para avisar que algum evento ocorreu.
      É possível também programar um processo para reagir aos sinais de maneira não padrão. Se você já teve um uso razoável de Linux, você provavelmente já enviou sinais à um processo. Por exemplo, quando você aperta Ctrl+C para interromper a execução de um processo, é enviado um sinal do tipo SIGINT, que nada mais é que uma abreviação para Signal Interruption. Se o processo em questão não está preparado para reagir a este sinal, o mesmo é terminado. Por exemplo, considere o seguinte código:
      #include <stdio.h> int main(void) { while(1) printf("hi\n"); return 0; } Ao compilar e executar o código acima e apertar Ctrl+C, o mesmo encerra como esperado, porém podemos verificar que um SIGINT foi enviado usando a ferramenta ltrace, que além de listar chamadas a bibliotecas também mostra os sinais enviados ao processo:
      $ gcc -o hello hello.c $ ltrace ./hello Rode o comando acima e aperte Ctrl+C para verificar o sinal enviado!
      Programando reações a sinais
      A capacidade de enviar sinais a um processo nos dá a possibilidade de saber o que esta acontecendo com algum processo específico que estejamos depurando.
      Para programar reações a algum tipo de sinal, podemos incluir a biblioteca signal, para que possamos usar a função e estrutura (struct) sigaction:
      struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); };  
      int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); A struct sigaction nos permite adicionar handlers (tratadores) para nossos sinais, enviando o endereço de nossa função que realiza algum tipo de ação baseada no sinal enviado para o campo sa_handler(sigaction handler).
      Um handler neste contexto nada mais é que uma função que sempre vai ser chamada quando um dado sinal for enviado, dessa maneira podemos executar alguma ação quando recebermos um sinal.
      Já a função sigaction recebe o número do sinal, porém uma série de macros já são pré-definidas e podemos passar como argumento apenas o nome do sinal, como SIGINT por exemplo. A função recebe também a referência da struct previamente definida (struct sigaction) e, caso precise trocar um handler por outro, também recebe no último argumento (oldact) o handler anterior, para que possa ser feita a troca pelo novo. Como não é o nosso caso, vamos passar NULL neste último argumento.
      O código abaixo simula um uso de handlers de sinais, que imprime uma mensagem quando um sinal é enviado:
      #include <stdio.h> #include <signal.h> #include <unistd.h> // sleep void simple_handler(int sig) { printf("Hello SIGINT\n"); } int main() { struct sigaction sig_handler = { simple_handler }; sigaction(SIGINT, &sig_handler, NULL); sleep(1000); return 0; } Ao executar o código acima, aperte Ctrl+C e veja que será imprimido a mensagem do nosso handler!
      O manual da signal contém uma tabela com todos os sinais usados por sistemas POSIX.
      Para enviarmos sinais facilmente em sistemas UNIX podemos usar o comando kill:
      $ kill -l O comando acima mostra todos os sinais e seus respectivos números, com isso podemos fazer algo interessante. Por exemplo, rode o código acima em um terminal separado e use o kill para se comunicar com o seu processo, assim:
      $ ps ax | grep simple_signal $ kill -2 <pid> Primeiro buscamos o PID do nosso processo então usamos o kill que espera como primeiro argumento numero do sinal (listado em kill -l) e o segundo o PID do processo alvo.
      Ao enviar o sinal, podemos ver que o nosso código reage aos sinais que foram associados a um handler especifico! Tente criar handlers para vários sinais e teste usando o comando kill. 😃
      Abaixo um código para demonstrar um uso real de um software que escreve dados aleatórios nos arquivos temporários e antes de uma finalização abrupta, é deletado o que foi usado:
      #include <stdio.h> #include <signal.h> #include <unistd.h> // Log errors void fatal(const char* err_msg) { fprintf(stderr, "Error: %s\n", err_msg); } // Escreve algo random em um arquivo void random_work() { FILE* temp_files = fopen("/tmp/foo", "w"); if (!temp_files) { fatal("Cant open foo!"); } else { fprintf(temp_files, "%s", "Random random random!\n"); fclose(temp_files); } } // Handler para deleta arquivos criados void handler_termination(int sig) { // Verifica se existe usando a function access // Caso existe usa a syscall unlink para remover o arquivo if (access("/tmp/foo", R_OK) < 0) return; unlink("/tmp/foo"); printf("All clean! closing...\n"); } int main() { //struct sigaction que recebe a function handler_termination como valor do seu handler struct sigaction interruption_handler; interruption_handler.sa_handler = handler_termination; // Syscall sigaction que associa o nosso handler para um sinal especifico // O ultimo campo NULL, espera o handler anterior para que posso tornar o novo handler o default sigaction(SIGINT, &interruption_handler, NULL); random_work(); sleep(1000); handler_termination(0); return 0; } Dica: Dê uma olhada na tabela de sinais e crie handlers para o mesmo código acima!
      Para a construção do nosso debugger iremos focar mais no signal SIGTRAP, para que seja possível detectar se o nosso processo sofreu uma "trap" da CPU. Uma trap ocorre quando acontece alguma interrupção síncrona na execução, que faz o processo ficar parado até que o sistema operacional execute alguma ação. Isto será usado para implementar e interpretar breakpoints. Veremos tudo isso com mais detalhes em breve!
      Sinta-se livre para comentar e sugerir correções e melhorias. Até o próximo artigo!
      Links úteis:
      Syscall IPC CERO 11 – Linux Syscalls Syscalls, Kernel mode vs User mode Programação em C
    • By R3n4to
      Olá,
      Gostaria de sugestões de tema para TCC na área segurança. Segurança da informação me atrai bastante, mas estou muito sem ideia em relação ao tema para TCC. O que vocês podem me sugerir? Com o que dá para fazer um bom trabalho?  Muito obrigado!
       
×
×
  • Create New...