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

    Recommended Comments



    Join the conversation

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

    Guest
    Add a comment...

    ×   Pasted as rich text.   Paste as plain text instead

      Only 75 emoji are allowed.

    ×   Your link has been automatically embedded.   Display as a link instead

    ×   Your previous content has been restored.   Clear editor

    ×   You cannot paste images directly. Upload or insert images from URL.


  • Similar Content

    • By Fernando Mercês
      Ano passado eu assisti à uma palestra sobre esse novo utilitário da suíte GNU chamado poke. Ele é um editor de dados binários de linha de comando bem diferente dos que costumo usar (HT Editor, Hiew, etc). Hoje decidi testá-lo e curti bastante. Tá em mega beta, então não tá nem perto de ter pacote disponível nos repositórios oficiais das distros Linux, mas consegui compilar e neste artigo vou dar as instruções, que podem variar em cada ambiente, até porque o poke está em constante desenvolvimento. Usei um ambiente Debian testing aqui.
      Instalando as dependências
      A dependência mais chatinha de instalar foi a gettext, porque o pacote pronto dela não foi suficiente. Então tive que clonar e compilar:
      $ sudo apt install perf fp-compiler fp-units-fcl groff build-essential git $ git clone https://git.savannah.gnu.org/git/gettext.git $ cd gettext $ ./gitsub.sh pull $ ./autogen.sh $ ./configure $ make $ sudo make install Com a gettext instalada, agora podemos partir para as demais dependências do poke:
      $ sudo apt install build-essential libgc-dev libreadline-dev flex libnbd-dev help2man texinfo Só então podemos seguir para a compilação do poke.
      Compilando o poke
      $ git clone git://git.savannah.gnu.org/poke.git $ cd poke $ ./bootstrap $ ./configure $ make $ sudo make install Criando links para as bibliotecas
      Como instalei as bibliotecas do poke em /usr/local e o meu sistema não tinha este diretório configurado para que o loader busque as bibliotecas, precisei criar dois links para elas em /usr/lib:
      $ sudo ln -s /usr/local/lib/libpoke.so.0 /usr/lib/libpoke.so.0 $ sudo ln -s /usr/local/lib/libtextstyle.so.0 /usr/lib/libtextstyle.so.0 Sei que há outras maneiras de resolver isso, mas fiz assim pra acelerar, afinal eu queria mexer no poke logo! 🤪
      Abrindo um binário PE no poke
      Baixei o executável do PuTTY para brincar um pouco e abri assim:
      $ poke putty.exe _____ ---' __\_______ ______) GNU poke 0.1-beta __) __) ---._______) Copyright (C) 2019, 2020 Jose E. Marchesi. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Powered by Jitter 0.9.212. Perpetrated by Jose E. Marchesi. hserver listening in port 47209. For help, type ".help". Type ".exit" to leave the program. (poke) Gerenciando os arquivos abertos
      O poke permite trabalhar com múltiplos arquivos de uma vez. Você pode ver a lista de arquivos abertos com o seguinte comando:
      (poke) .info ios Id Mode Size Name * #0 rw 0x0010b990#B ./putty.exe ios signifca "IO Spaces". Não tem nada a ver com o SO da Cisco ou com o da Apple. hehe
      Se quiser abrir outro arquivo, pode usar o comando .file <arquivo> e aí pode selecionar em qual você quer trabalhar com o comando .ios #n onde n é o número que identifica o arquivo, mas vou seguir o artigo com somente um arquivo aberto mesmo, então só teremos a tag #0.
      Dumpando dados
      Um dos principais comandos do poke é o dump (perceba este não começa com um ponto) que basicamente visualiza o conteúdo do arquivo, mas este tem várias opções. Vamos à mais básica:

      A primeira linha na saída acima é só uma régua pra te ajudar a encontrar os bytes.
      Fiz questão de colar uma captura de tela aí acima pra você ver que o poke colore a saída, mas nos exemplos seguintes vou colar a saída em texto pelo bem da sua largura de banda. 🙂
      Por padrão, o dump exibe 128 bytes do arquivo, começando do seu primeiro byte. O número de bytes pode ser alterado na própria linha de comando:
      (poke) dump :size 64#B 76543210 0011 2233 4455 6677 8899 aabb ccdd eeff 0123456789ABCDEF 00000000: 4d5a 7800 0100 0000 0400 0000 0000 0000 MZx............. 00000010: 0000 0000 0000 0000 4000 0000 0000 0000 ........@....... 00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000030: 0000 0000 0000 0000 0000 0000 7800 0000 ............x... A sintaxe pode parecer um pouco estranha no início, mas você acostuma rápido. O sufixo #B diz que a unidade usada é bytes. Você pode testar outros valores como 2#KB ou 1#MB por exemplo.  😉
      Dumpando a partir de posições específicas
      Para dumpar a partir de uma posição específica, podemos usar a opção :from do comando dump:
      (poke) dump :from 0x30#B :size 32#B 76543210 0011 2233 4455 6677 8899 aabb ccdd eeff 0123456789ABCDEF 00000030: 0000 0000 0000 0000 0000 0000 7800 0000 ............x... 00000040: 0e1f ba0e 00b4 09cd 21b8 014c cd21 7468 ........!..L.!th No comando acima eu pedi para o poke me mostrar 32 bytes a partir da posição 0x30. Seria o equivalente a fazer hd -n 32 -s 0x30 <arquivo>.
      O poke mantém um ponteiro de leitura no arquivo, por isso se você comandar somente dump novamente, o dump ocorrerá a partir da última posição lida (no caso, 0x30). Se quiser voltar o ponteiro para a posição zero, é a mesma sintaxe: dump :from 0#B.
      Interpretando dados
      O dump sempre te entrega uma saída em hexadecimal, mas e se quisermos interpretar os dados e exibi-los de maneiras diferentes? Para  isso a gente larga de mão o comando dump e começa a operar com o jeito do poke de ler e interpretar especificamente, assim:
      (poke) byte @ 0#B 77UB O sufixo UB significa Unsigned Byte.
      Se eu quiser a saída em hexa por exemplo, basta eu setar a variável obase (output base):
      (poke) .set obase 16 (poke) byte @ 0#B 0x4dUB Eu poderia querer ler 2 bytes. Tranquilo:
      (poke) byte[2] @ 0#B [0x4dUB,0x5aUB] Posso interpretar o conteúdo como número também:
      (poke) uint16 @ 0#B 0x4d5aUH O prefixo UH significa Unsigned Half (Integer). Perceba que o poke sabe que um uint16 tem 2 bytes e por isso os lê sem a necessidade que especifiquemos o número de bytes a serem lidos.
      À essa altura você já sacou que equivalentes aos tipos padrão da linguagem C (da inttypes.h na real) estão disponíveis para uso né? Fique à vontade pra testar off64, int64, int32, etc.
      Lendo strings
      Além dos tipos numéricos, o poke tem o tipo string, onde ele lê até encontrar um nullbyte:
      (poke) dump 76543210 0011 2233 4455 6677 8899 aabb ccdd eeff 0123456789ABCDEF 00000000: 4d5a 7800 0100 0000 0400 0000 0000 0000 MZx............. 00000010: 0000 0000 0000 0000 4000 0000 0000 0000 ........@....... 00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000030: 0000 0000 0000 0000 0000 0000 7800 0000 ............x... 00000040: 0e1f ba0e 00b4 09cd 21b8 014c cd21 5468 ........!..L.!Th 00000050: 6973 2070 726f 6772 616d 2063 616e 6e6f is program canno 00000060: 7420 6265 2072 756e 2069 6e20 444f 5320 t be run in DOS 00000070: 6d6f 6465 2e24 0000 5045 0000 4c01 0700 mode.$..PE..L... (poke) string @ 0x4d#B "!This program cannot be run in DOS mode.$" Patch simples
      Vamos fazer um patch simples: alterar o "T" desta string acima de maiúsculo para minúsculo. Basicamente é só colocar à esquerda o jeito que acessamos uma determinada posição do arquivo e igualar ao que a gente quer. Sabendo que para converter maiúsculo para minúsculo na tabela ASCII basta somar 32 (0x20), podemos fazer:
      (poke) byte @ 0x4e#B = 0x74 Perceba que fui na posição 0x4e, porque na 0x4d temos o '!' e não o 'T'. Só pra checar se funcionou:
      (poke) string @ 0x4d#B "!this program cannot be run in DOS mode.$" (poke) Legal né? Mas dá pra ficar melhor. O poke suporta char, então podemos meter direto:
      (poke) char @ 0x4e#B = 't' (poke) string @ 0x4d#B "!this program cannot be run in DOS mode.$" Por hora é só. Fica ligado aí que postarei a parte 2 em breve, onde vou mostrar mais recursos do poke que tô achando bem úteis para engenharia reversa. Até lá! 😎
    • By Fernando Mercês
      Comecei a estudar a linguagem Go há alguns dias e fiquei muito impressionado com seus recursos. A facilidade para programação paralela, o fato de ter ponteiros, funções que retornam mais de um valor, código enxuto (se você declarar uma variável e não usar, o programa nem compila!) e outros realmente me encantaram.
      Recentemente precisei disassemblar um trecho de código de um binário PE para um projeto que está escrito em Go. Vi que existem algumas bibliotecas prontas para serem usadas, como gapstone (bindings da Capstone) e go-zydis (bindings da Zydis) mas não encontrei uma nativa.
      No entanto, vi que existe uma ferramenta nativa no toolset da linguagem similar ao objdump do GNU binutils:
      $ go doc cmd/objdump Objdump disassembles executable files. Usage: go tool objdump [-s symregexp] binary Objdump prints a disassembly of all text symbols (code) in the binary. If the -s option is present, objdump only disassembles symbols with names matching the regular expression. Compilei um "hello, world" em Go só pra ver:
      ~/hello $ cat main.go package main import "fmt" func main() { fmt.Println("menteb.in") } ~/hello $ go build E de fato o objdump da Go funciona:
      ~/hello $ go tool objdump hello | head TEXT go.buildid(SB) :-134217728 0x1001000 ff20 JMP 0(AX) :-134217728 0x1001002 476f OUTSD DS:0(SI), DX :-134217728 0x1001004 206275 ANDB AH, 0x75(DX) :-134217728 0x1001007 696c642049443a20 IMULL $0x203a4449, 0x20(SP), BP :-1 0x100100f 226d35 ANDB 0x35(BP), CH :-1 0x1001012 4c6f OUTSD DS:0(SI), DX :-1 0x1001014 6a52 PUSHL $0x52 :-1 0x1001016 436e OUTSB DS:0(SI), DX :-1 0x1001018 4a31794f XORQ DI, 0x4f(CX) Mas ao tentar com o um PE compilado pra 64-bits, descobri que só funciona com binários feito em Go. 😩
      $ go tool objdump putty.exe objdump: disassemble putty.exe: no runtime.pclntab symbol found De qualquer forma, resolvi olhar o código-fonte deste objdump interno da linguagem pra ver qual é dessa mandinga.  Na linha 43 do main.go do objdump tem um import pra uma biblioteca chamada objfile. Pensei: Wow, deve ser uma biblioteca de disassembly, talvez eu possa alterar ! E na hora já criei um projeto tentando usá-la mas fui surpreendido com um errão! kkkk
      ~hello $ cat main.go package main import "fmt" import "cmd/internal/objfile" func main() { fmt.Println("menteb.in") } ~hello $ go build main.go:4:8: use of internal package cmd/internal/objfile not allowed Não pesquisei muito sobre essa história sobre eu não poder usar um pacote interno (por quê o objdump pode e eu não posso?!), mas fui olhar esta objfile e terminei encontrando seu fonte. Para minha alegria, neste arquivos disasm.go vi os seguintes imports:
      "golang.org/x/arch/arm/armasm" "golang.org/x/arch/arm64/arm64asm" "golang.org/x/arch/ppc64/ppc64asm" "golang.org/x/arch/x86/x86asm" Agora sim, carái! É tudo público e posso usar. Desculpe o desabafo.. hehe o artigo na verdade começa aqui mas quis contar como cheguei porque né. 😁
      Cada uma dessas bibliotecas possui uma função Decode() justamente pra decodificar uma instrução (tipo Inst). Testei com um NOP em 64-bits, só pra ver:
      package main import ( "fmt" "log" "golang.org/x/arch/x86/x86asm" ) func main() { dados := []byte{0x90} ins, err := x86asm.Decode(dados, 64) if err != nil { log.Fatalln(err) } fmt.Println(ins) } A saída foi exatamente a esperada:
      $ ./hello NOP Show. Agora é abrir um PE, ler de onde quero e daí disassemblar usado essa x86asm.Decode() num loop, mas vou deixar esse exercício aí pra quem quiser treinar Go. Ou se acharem útil posso postar um aqui mais tarde. Aqui já funcionou mas precisa de uma polida. 🙂
      Perceba também que há bibliotecas para ARM e PowerPC. Achei bem maneiro. Talvez em breve o time da Go adicione suporte a mais arquiteturas. Amém! 🙏 
    • By lucass
      Vou começar agradecendo ao @Fernando Mercês pela oportunidade e por ter sugerido este artigo, que também me motivou bastante a escrevê-lo!
      Introdução
      Não sou conhecido internet a dentro, apenas acompanho alguns canais no Discord (tal como o do Mente Binária). Meu nível de programação e engenharia reversa não é algo admirável ainda. Em um grupo especifico intitulado "Terra do 1337", que é um grupo fechado de amigos com finalidade de estudar engenharia reversa, programação e descontrair, eu surgi com uma idéia de escrever uma ferramenta que iria facilitar a vida de muitos nesta área de engenharia reversa e achei de API Inspector.
      A seguir um spoiler de como foi o início do projeto, para quem se interessar. 😉
      O que é o API Inspector
      É uma ferramenta de código-aberto voltada para área de engenharia reversa, que irá auxiliar na análise de funções correspondentes a certas API's do Windows, retornando informações obtidas dos argumentos caso a função seja chamada pela aplicação.
      O que ele faz
      Ele faz um hook (do Inglês "gancho"), que consiste num desvio na função original da API solicitada para nossa própria função e com isso podemos obter os dados (argumentos/parâmetros) que foram passados para tal função.
      Como ele funciona
      O princípio de um hook é simples: você insere no inicio da função um salto que irá levar para a sua função (que é uma cópia da função original) e depois de efetuar o que quiser, irá retornar para a função original prosseguir.
      Talvez mais fácil visualizar o que expliquei com código:
      //Aqui está a função //ZwWriteVirtualMemory | NtWriteVirtualMemory, originada do binário: ntdll.dll //créditos ao https://undocumented.ntinternals.net/ NTSYSAPI NTSTATUS NTAPI //WINAPI NtWriteVirtualMemory( IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN PVOID Buffer, IN ULONG NumberOfBytesToWrite, OUT PULONG NumberOfBytesWritten OPTIONAL ); //Sua versão assembly 777F2110 mov eax,0x3A 777F2115 mov edx,ntdll.77808D30 777F211A call edx 777F211C ret 0x14 //O que nós vamos fazer é criar uma função similar á ela com o nome que decidirmos //Então vamos inserir um jmp no início da função original para nossa função, ficando assim: 777F2110 jmp api inspector.573523EC 777F2115 mov edx,ntdll.77808D30 777F211A call edx 777F211C ret 0x14 //Usei como exemplo minha próprio ferramenta! //Então quando ocorrer a chamada desta função ela será jogada em nossa função! Depois de nós fazermos que desejar vamos retorna-la, porém para uma região que aloquei onde contém //Um buffer dos bytes que foram sobrescritos da função original: 03610000 mov eax,0x3A 03610005 jmp ntdll.777F2115 //Ela irá retornar depois do jmp que existe na função original e continuar o código.... Vantagens de se utilizar o API Inspector ao invés de um debugger
      Imagine que você está visualizando as chamadas intermodulares (para bibliotecas externas, no caso) que um programa faz, utilizando um debugger (o x64dbg por exemplo) e notou que uma certa função que deseja inspecionar é chamada em diversos pontos do programa. Vejo duas opções neste caso: colocar vários breakpoints, um em cada chamada à função, no código do programa ou colocar um único breakpoint função em si, no código dela, na DLL.
      Em ambos os casos, você vai precisar analisar chamada por chamada, parâmetro por parâmetro. E se a função for chamada 20 vezes consecutivamente? O tempo que você levaria para visualizar apenas o primeiro parâmetro da chamada é o tempo que a ferramenta iria levar para exibir todas as 20 chamadas, com os argumentos formatados bonitinhos ao seu dispor. Entende a vantagem? 🙂
      E as desvantagens?
      Por hora, uma desvantagem é a quantidade de funções e API's suportadas. De fato, a primeira release não possui uma quantidade significativa que vá fazer você utilizar a ferramenta e nem uma quantidade de recursos interessantes na ferramenta. Mas é ai que vem o ponto chave, o fato de deixar ela pública remete ao próprio crescimento da mesma, no primeiro momento é necessário uma orientação da parte de vocês para me ajudar a melhorar o código visual. O segundo passo é eu e vocês começarem a fornecerem mais recursos para ela. Eu irei adicionar todo ou qualquer recurso que seja significativo para a mesma, e para isso eu já tenho mais funcionalidades para implementar na ferramenta que são excelentes.
      Interface gráfica
      Na imagem abaixo, utilizei o API Inspector para hookar a função MessageBoxW() da USER32.DLL. Depois disso, escrevi um texto num novo arquivo no Notepad++ e tentei fechar o programa. Ao fazer isso, o Notepad++ perguntou se eu queria salvar o arquivo e ele faz isso através de uma chamada à MessageBoxW(), que o API Inspector interceptou prontamente.

      Na imagem acima, a janela à esquerda mostra o que está atualmente passando pelas funções hookadas. Na janela a direita, temos um log.
      Como utilizar o API Inspector
      A única coisa que você precisa fazer é anexar a DLL do API Inspector ao processo desejado e para isso existem os softwares chamados "Injetores de DLL" que podem ser achados na internet.
      Você também pode criar o seu próprio injetor. Uma dica é pesquisar sobre injeção com a função LoadLibrary(), mas no exemplo a seguir eu vou mostrar como utilizar o Process Hacker para fazer a injeção.
      1 - Abra o Process Hacker e identifique no mesmo o processo no qual você quer injectar a DLL do API Inspector. No exemplo, usei o processo do Notepad++.

      2 - Clique com o botão direito sobre o processo e escolha Miscellaneous > Inject DLL.

      3 - Selecione a DLL API-Inspector.dll e clique em Abrir.

      4 - Se o Process Hacker possuir privilégios suficientes a ferramenta irá ser carregada, caso contrário, não.

      Após isso você precisa selecionar a API desejada, a função desejada e clicar em GO Hook!
      O step call é uma funcionalidade que vai fazer a ferramenta aguardar o pressionamento da tecla ENTER para retornar para a função original. Pronto, o seu hook está feito e você já poderá inspecionar a função desejada.
      Download e código
      No repositório do API Inspector no Github você pode baixar a versão compilada e ter acesso ao código-fonte também. Contribuições são muito bem vindas!
      Bom, eu nunca tinha escrito um artigo. Se faltou informação ou coloquei informação demais me desculpe. Estou aberto pra ler os comentários. Ah, e participem deste projeto! Eu quero fazer ele crescer muito. Caso precise de referências de como cheguei a este projeto, tem tudo na página inicial do projeto no Github.
      Agradecimentos
      Obrigado novamente ao Fernando Mercês, ao pessoal do Terra 1337 que me incentiva cada vez mais e em especial para o iPower e Luan que são colaboradores do projeto.
      Referências
      Dear ImGui Programming reference for the Win32 API NTAPI Undocumented Functions C++ 3D DirectX Programming
    • By ncaio
      ====== Bem-vindo a bordo ======

      Este é um repositório/espaço aberto/livre de conteúdo referente a hardware hacking em geral. Sinta-se a vontade para contribuir e retirar suas dúvidas. Assim como em outros espaços de conhecimento compartilhado na Internet, este Fórum tem regras. Algumas delas, são:
        * Seja educado(a) e respeitoso(a);
        * Pesquise antes;
        * Seja claro(a) e descritivo(a);
        * Esteja preparado(a) para compartilhar informações relevantes a sua dúvida;
        * Não fuja do foco;
        * Referencie autores;
        * E etc.
×
×
  • Create New...