Ir para conteúdo
  • Cadastre-se
  • Entre para seguir isso  

    Entendendo o imphash

       (0 análises)

    Fernando Mercês

    No início de 2014, a Mandiant publicou que estava calculando o hash MD5 das funções importadas por binários PE para buscar variantes de malware [1]. Eles também fizeram um patch na biblioteca pefile [2] para suportar o novo cálculo. A ideia colou e até o Virus Total passou a utilizar [3]. Eu mesmo utilizei um tempo sem entender direito até que um dia decidi estudá-lo para implementar no pev [4] (que ainda não fiz) e hoje decidi escrever sobre.:)

    Todo binário PE que se preze usa funções de bibliotecas. Assim sendo, desde os primórdios da especificação PE, há o que é conhecido por IT – Import Table, que é uma tabela contendo uma lista de cada módulo (DLL) que o binário utiliza (importa) com suas respectivas funções. Por exemplo, vamos analisar o programa no estilo “Hello, world” abaixo:

    #include <stdio.h>
     
    int main(void)
    {
    	puts("Quem avisa chato eh!");
    	return 0;
    }

    Ao compilar usando o Dev-Cpp [5] no Windows 7, podemos checar quais funções são importadas por ele:

    C:\> readpe --imports hello.exe
     
    Imported functions
        Library
            Name:                            KERNEL32.dll
            Functions
                Function
                    Name:                            DeleteCriticalSection
                Function
                    Name:                            EnterCriticalSection
                Function
                    Name:                            GetCurrentProcess
                Function
                    Name:                            GetCurrentProcessId
                Function
                    Name:                            GetCurrentThreadId
                Function
                    Name:                            GetLastError
                Function
                    Name:                            GetStartupInfoA
                Function
                    Name:                            GetSystemTimeAsFileTime
                Function
                    Name:                            GetTickCount
                Function
                    Name:                            InitializeCriticalSection
                Function
                    Name:                            LeaveCriticalSection
                Function
                    Name:                            QueryPerformanceCounter
                Function
                    Name:                            RtlAddFunctionTable
                Function
                    Name:                            RtlCaptureContext
                Function
                    Name:                            RtlLookupFunctionEntry
                Function
                    Name:                            RtlVirtualUnwind
                Function
                    Name:                            SetUnhandledExceptionFilter
                Function
                    Name:                            Sleep
                Function
                    Name:                            TerminateProcess
                Function
                    Name:                            TlsGetValue
                Function
                    Name:                            UnhandledExceptionFilter
                Function
                    Name:                            VirtualProtect
                Function
                    Name:                            VirtualQuery
        Library
            Name:                            msvcrt.dll
            Functions
                Function
                    Name:                            __C_specific_handler
                Function
                    Name:                            __dllonexit
                Function
                    Name:                            __getmainargs
                Function
                    Name:                            __initenv
                Function
                    Name:                            __iob_func
                Function
                    Name:                            __lconv_init
                Function
                    Name:                            __set_app_type
                Function
                    Name:                            __setusermatherr
                Function
                    Name:                            _acmdln
                Function
                    Name:                            _amsg_exit
                Function
                    Name:                            _cexit
                Function
                    Name:                            _fmode
                Function
                    Name:                            _initterm
                Function
                    Name:                            _lock
                Function
                    Name:                            _onexit
                Function
                    Name:                            _unlock
                Function
                    Name:                            abort
                Function
                    Name:                            calloc
                Function
                    Name:                            exit
                Function
                    Name:                            fprintf
                Function
                    Name:                            free
                Function
                    Name:                            fwrite
                Function
                    Name:                            malloc
                Function
                    Name:                            memcpy
                Function
                    Name:                            puts
                Function
                    Name:                            signal
                Function
                    Name:                            strlen
                Function
                    Name:                            strncmp
                Function
                    Name:                            vfprintf
    

    Pois é, apesar de eu ter chamado apenas a função puts(), o binário precisa de muito mais para funcionar.:)

    Agora um segundo exemplo, com um recurso a mais, mas sem chamar nenhuma outra função da mesma biblioteca:

    #include <stdio.h>
     
    char *superfuncaonova(int n)
    {
      if (n >= 666)
        return "arre, porra!";
      else
        return "eu quero eh rock, diabo!";
    }
     
    int main(void)
    {
      puts("Quem avisa chato eh!");
      puts(superfuncaonova(1));
      
      return 0;
    }

    Após compilar e listar os imports deste hello2.exe, você vai confirmar que é exatamente a mesma lista do primeiro hello.exe. Isto porque, apesar de ter uma função interna nova, não utiliza outra função de biblioteca nova, o que não altera a IAT. Isso é comum em variantes de uma mesma família de malware já que as funcionalidades estão prontas e o que difere de uma variante para outra normalmente são informações como servidor de comando e controle, algumas strings, etc. Sendo assim, é inteligente utilizar essa lista para buscar famílias. Parabéns para quem pensou nisso.:)

    E como o imphash foi implementado?

    Comparar cada item da lista não seria prático então alguém teve a ideia de tirar o hash MD5 da lista, obedecendo o seguinte padrão:

    Varrendo a import table (IT), na ordem em que aparecem os imports:

    1. Prefixar cada função com o nome do módulo sem extensão (mas mantendo o ponto) da qual ela é importada. Por exemplo, se o binário importa DeleteCriticalSection() da KERNEL32.DLL, esse import reescrito ficaria KERNEL32.EnterCriticalSection.
    2. Caso não haja nome da função, tentar resolver e, caso não consiga, utilizar seu número ordinal.
    3. Converter tudo para minúsculo.
    4. Criar uma string com os imports no padrão acima, separados por vírgula.
    5. Calcular o hash MD5 da string acima.

    Eu salvei a saída do readpe para um arquivo de texto e, usando expressões regulares, o editei até que ficasse no padrão definido acima:

    $ cat hello.imports
    kernel32.deletecriticalsection,kernel32.entercriticalsection,kernel32.getcurrentprocess,kernel32.getcurrentprocessid,kernel32.getcurrentthreadid,kernel32.getlasterror,kernel32.getstartupinfoa,kernel32.getsystemtimeasfiletime,kernel32.gettickcount,kernel32.initializecriticalsection,kernel32.leavecriticalsection,kernel32.queryperformancecounter,kernel32.rtladdfunctiontable,kernel32.rtlcapturecontext,kernel32.rtllookupfunctionentry,kernel32.rtlvirtualunwind,kernel32.setunhandledexceptionfilter,kernel32.sleep,kernel32.terminateprocess,kernel32.tlsgetvalue,kernel32.unhandledexceptionfilter,kernel32.virtualprotect,kernel32.virtualquery,msvcrt.__c_specific_handler,msvcrt.__dllonexit,msvcrt.__getmainargs,msvcrt.__initenv,msvcrt.__iob_func,msvcrt.__lconv_init,msvcrt.__set_app_type,msvcrt.__setusermatherr,msvcrt._acmdln,msvcrt._amsg_exit,msvcrt._cexit,msvcrt._fmode,msvcrt._initterm,msvcrt._lock,msvcrt._onexit,msvcrt._unlock,msvcrt.abort,msvcrt.calloc,msvcrt.exit,msvcrt.fprintf,msvcrt.free,msvcrt.fwrite,msvcrt.malloc,msvcrt.memcpy,msvcrt.puts, msvcrt.signal,msvcrt.strlen,msvcrt.strncmp,msvcrt.vfprintf

    NOTA: O arquivo tem somente uma linha, sendo que não há um caractere de nova linha (\n ) no final dela, veja:

    $ hdump hello.imports | tail
    000003c0  74 2e 65 78 69 74 2c 6d  73 76 63 72 74 2e 66 70  |t.exit,msvcrt.fp|
    000003d0  72 69 6e 74 66 2c 6d 73  76 63 72 74 2e 66 72 65  |rintf,msvcrt.fre|
    000003e0  65 2c 6d 73 76 63 72 74  2e 66 77 72 69 74 65 2c  |e,msvcrt.fwrite,|
    000003f0  6d 73 76 63 72 74 2e 6d  61 6c 6c 6f 63 2c 6d 73  |msvcrt.malloc,ms|
    00000400  76 63 72 74 2e 6d 65 6d  63 70 79 2c 6d 73 76 63  |vcrt.memcpy,msvc|
    00000410  72 74 2e 70 75 74 73 2c  6d 73 76 63 72 74 2e 73  |rt.puts,msvcrt.s|
    00000420  69 67 6e 61 6c 2c 6d 73  76 63 72 74 2e 73 74 72  |ignal,msvcrt.str|
    00000430  6c 65 6e 2c 6d 73 76 63  72 74 2e 73 74 72 6e 63  |len,msvcrt.strnc|
    00000440  6d 70 2c 6d 73 76 63 72  74 2e 76 66 70 72 69 6e  |mp,msvcrt.vfprin|
    00000450  74 66                                             |tf|
    

    O imphash deste arquivo então deve ser o hash MD5 do conteúdo de hello.imports. Vamos ver?

    $ python imphash.py hello.exe # usando a pefile
    3856e6eb1020e4f12c9b8f75c966a09c
    
    $ md5 hello.imports
    MD5 (hello.imports) = 3856e6eb1020e4f12c9b8f75c966a09c

    Legal! Agora que sabemos como calcular o imphash de binários PE, podemos implementar em qualquer software, certo? Mais ou menos. Você percebeu que ignoramos o passo 2? Pois é, no próximo artigo sobre o assunto vou explicar o motivo pelo qual o imphash está quebrado. Até lá. o/

     

    Referências

    [1] https://www.fireeye.com/blog/threat-research/2014/01/tracking-malware-import-hashing.html
    [2] https://github.com/erocarrera/pefile
    [3] http://blog.virustotal.com/2014/02/virustotal-imphash.html
    [4] https://github.com/merces/pev
    [5] https://sourceforge.net/projects/orwelldevcpp/

    Entre para seguir isso  


    Feedback do Usuário

    Join the conversation

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

    Visitante

  • Conteúdo Similar

    • Por 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  
    • Por 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
    • Por 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
    • Por 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!
       
    • Por Fabiano Furtado
      Pessoal,
      bom dia. Estou estudando algumas técnicas de proteção de binários, me baseando no video do Fernando Mercês do Roadsec 2017 https://www.youtube.com/watch?v=cpU9U0sqzh4
      Mais especificamente, em 27'29", o Fernando mostra como substituir algumas instruções por outras equivalentes, para dificultar a análise do binário.
      Fiz exatamente isso, mas o programa da um Segmentation Fault após a alteração, e eu não tenho idéia do que pode ser. Alguma ajuda?
      Segue o programa exemplo em C que fiz para alterar o JMP:
      #include <stdio.h>
      int main(void) {
        int c = 0;
        c++;
        
        if ( c == 1 ) {
          __asm__("nop");
          __asm__("nop");
          __asm__("nop");
          __asm__("nop");
          goto end;
        }
        do {
          puts("Dentro do while");
          goto end;    
        } while (1);
        puts("antes do Fim");
        
      end:
        puts("Fim");
        
        return 0;
      }
      Compilei ele com: gcc -Wall -m32 -O0 salto.c -o salto
      Seguem as linhas originais:
          11b5:       83 7d f4 01             cmp    DWORD PTR [ebp-0xc],0x1                                                    
          11b9:       75 06                   jne    11c1 <main+0x34>                                                           
          11bb:       90                      nop                                                                               
          11bc:       90                      nop                                                                               
          11bd:       90                      nop                                                                               
          11be:       90                      nop                                                                               
          11bf:       eb 13                   jmp    11d4 <main+0x47>                                                           
          11c1:       83 ec 0c                sub    esp,0xc                                                                    
          11c4:       8d 83 08 e0 ff ff       lea    eax,[ebx-0x1ff8]                                                           
          11ca:       50                      push   eax                                                                        
          11cb:       e8 60 fe ff ff          call   1030 <puts@plt>                                                            
          11d0:       83 c4 10                add    esp,0x10                                                                   
          11d3:       90                      nop                                                                               
          11d4:       83 ec 0c                sub    esp,0xc                                                                    
          11d7:       8d 83 18 e0 ff ff       lea    eax,[ebx-0x1fe8]
      Seguem as linhas alteradas:
          11b9:       75 06                   jne    11c1 <main+0x34>                                                           
          11bb:       68 d4 11 00 00          push   0x11d4                                                                     
          11c0:       c3                      ret                                                                               
          11c1:       83 ec 0c                sub    esp,0xc                                                                    
          11c4:       8d 83 08 e0 ff ff       lea    eax,[ebx-0x1ff8]                                                           
          11ca:       50                      push   eax                                                                        
          11cb:       e8 60 fe ff ff          call   1030 <puts@plt>                                                            
          11d0:       83 c4 10                add    esp,0x10                                                                   
          11d3:       90                      nop                                                                               
          11d4:       83 ec 0c                sub    esp,0xc                                                                    
          11d7:       8d 83 18 e0 ff ff       lea    eax,[ebx-0x1fe8]
      Alguma ajuda?
      Desde já, agradeço.
×
×
  • Criar Novo...