Jump to content

Fernando Mercês

Administrators
  • Posts

    1,570
  • Joined

  • Last visited

  • Days Won

    202

Posts posted by Fernando Mercês

  1. Olá!

    Em 23/09/2024 em 14:00, Cristian Liotto disse:

    Tentei debugar utilizando o rundll32 e passando ela como argumento, mas o processo simplesmente morre, tentei diretamente pelo x64dbg mas também não vai

    Se o código malicioso dela tá na DllMain(), você precisa parar lá. Tem duas alternativas simples: por um breakpoint na LoadLibrary() ao debugar o rundll32.exe (passando sua DLL como argumento) ou setando o EIP na mão para a DllMain() ao abrir a DLL direto no x64dbg.

    Também acho importante ver como o processo chama a DLL. Aï você pode imitar e fazer igual para ver o comportamento malicioso. 🙂 

    Vê se a aula 21 do AMO te ajuda. 😉

    Abraço e boa sorte!

  2. Oi @Jorge Luiz_,

    Construções como if, else, for, while, etc são de alto nível. Em Assembly, elas são implementadas utilizando saltos (em x86, são as instruções começando com "J", de "jump"). Por exemplo, analise o código abaixo:

    cmp eax, 0
    jne exit
    ; código se EAX é zero
    
    exit:
    ;  resto do código

    No exemplo, há uma comparação de EAX com zero. Se não for zero, o programa vai saltar (JNE - Jump If Not Equals) para o rótulo (labelexit. Mas se EAX for zero, o código logo abaixo do salto (JNE) será executado (e depois o que está sob o rótulo exit também).

    O que acontece é que alguns compiladores de Assembly possuem macroinstruções que facilitam este trabalho e funcionam de forma similar às instruções de alto nível. Por exemplo, no fasm você pode fazer:

    .if eax = 0
        ; código se EAX é zero
    .endif
    
    ; resto do código

    Mas no binário compilado, você verá os saltos de qualquer maneira, pois estas são instruções "reais" que o processador entende (enquanto .if só o compilador Assembly entende). Além disso, os rótulos somem pois os destinos da maioria dos saltos são deslocamentos (X bytes para frente ou para trás), o que na prática vira endereços de memória. Veja:

    fasm_if.png

    Dá uma olhada: http://flatassembler.net/docs.php?article=win32#2.2

    Abraço!

    • Agradecer 1
  3. A explicação é complicada (para os meus parâmetros hehe), mas vou tentar. 🙂

    1. *argv[] na main() já é um ponteiro para um array de chars. Mas é uma variável, e tem um endereço de memória (supomos, 0x200).
    2. Para a sum(), ao fazer &argv você passa o endereço de argv, ou seja, 0x200.
    3. Na sum() você recebe esse endereço como um ponteiro para ponteiro para um array de chars: **args[]. O que está certo.
    4. Na sum(), args contém um único elemento (o ponteiro para um array chars e não o array de chars em si).
    5. Com *args[i], sabendo que a precedência de [] é maior que a de *, então vamos analisar o loop:
      1. args[0] é o primeiro (e único) elemento de args. *args[0] o acessa.
      2. args[1] falha, pois args só contém um elemento. Segfault aqui.
    6. Agora, com (*args)[i]:
      1. (*args) é resolvido primeiro em todas as iterações do loop. O resultado é um ponteiro para um array de chars.
      2. (*args)[0] funciona, assim como (*args)[1], (*args)[2], até argc-1.

    Um desenho certamente explicaria melhor, ou talvez com o uso do GDB. Se não entender, avisa aí que eu tento de outra forma. Ou talvez outra pessoa explique melhor. 🙂

    Em tempo, você complicou mais do que precisa. O que eu faria é:
     

    sum(int n, char *args[]) {
    	// código
    	strtol(args[i], ...);
    }
    
    main(int argc, char *argv[]) {
    	// código
    	sum(argc, argv);
    }

    Dessa forma você passa o argv, que já é um ponteiro para um array de char (C strings, neste caso) para sum() e ela acessa por args, que é do mesmo tipo.

    Outras ideias, só por curiosidade:

    Economizando a variável i ao somar do último para o primeiro elemento (ou seja, na ordem reversa):

    int sum(int n, char *args[])
    {
       int result = 0;
       n--;
    
       while (n > 0) {
          result += strtol(args[n], NULL, 10);
          n--;
       }
    
      return result;
    }

    Economizando o uso de argc, já que o último elemento de argv é sempre nulo - ou seja, argv[argc] == NULL:

    int sum(char *args[])
    {
       int result = 0;
    
       while (*args) {
          result += strtol(*args, NULL, 10);
          args++;
       }
    
      return result;
    }

    Ou uma versão menorzinha, aproveitando que ++ é um operador de pós-incremento (primeiro o valor é lido e depois é incrementado):

    int sum(char *args[])
    {
       int result = 0;
    
       while (*args)
          result += strtol(*args++, NULL, 10);
    
      return result;
    }

    Mas aí já entram mais conceitos.. por exemplo *args é o mesmo que fazer *args != NULL. E args++ é aritmética de ponteiros. Não é "mais um" e sim "mais X bytes", onde X é o tamanho do tipo.

    Versão "olha mãe, sem as mãos":

    int sum(char *args[]) {
       return *args ? strtol(*args, NULL, 10) + sum(args + 1) : 0;
    }

    Aqui já entra recursividade (pode esgotar a pilha) e o ternário.

    Fiz essas coisas só para despertar a curiosidade mesmo e provar que C é a linguagem na qual o universo foi escrito. 😄 

    Abraço.

    • Agradecer 1
  4. Não existe um suporte nativo, mas tem gambiarras possíveis:

    ; Opção 1 - Simplesmente um ponto-e-vírgula no início de cada linha (mas essa você já sabe)
    ; linha1
    ; linha2
    ; linha3
    
    ; Opção 2 - Começa com ponto-e-vírtugla e protege o caractere de fim de linha com a contra-barra
    ; linha1\
    linha2\
    linha3
    
    Opção 3 - Testar se uma macro inexistente existe
    %ifdef COMENTARIO ; pode ser qualquer coisa, contanto que não exista - ou seja, não esteja definida
    linha1
    linha2
    linha3
    %endif
      
    Opção 4 - Avaliar uma expressão numérica que retorne falso sempre
    %if 0
    linha1
    linha2
    linha3
    %endif

    Abraço.

  5. Opa,

    Em 04/07/2024 em 13:14, Guilherme23 disse:

    vai informar pelo Youtube também ?

    Sim, por todos os nossos canais. 🙂

    Em 04/07/2024 em 13:14, Guilherme23 disse:

    Será necessário algum conhecimento prévio?

    Sim, os requisitos estão no fim do texto aqui.

    Abraço!

  6. Oi @Guilherme23, tudo em paz e contigo?

    Estamos planejando uma turma do curso A Arte da Engenharia Reversa (pago, online e ao vivo). Em relação aos cursos gratuitos, não lançaremos outros sobre estes tópicos este ano. Segue um resumo do que temos sobre ER e 😄

    Sobre C, temos:

    Há ainda um livro muito legal de dicas de C e Assembly que o autor nos permitiu disponibilizar para download aqui. Chama-se Dicas - C e Assembly para arquitetura x86-64.

    Por hora, isto é tudo. 🙂

    Grande abraço e bons estudos. Qualquer outra dúvida é só falar.

    Abraço!

  7. Em 05/06/2024 em 14:37, rsievering@hotmail.com disse:

    Existe algum certificado que eu possa emitir.???

    Opa, tudo bem? Obrigado por terminar o curso! No momento não emitidos certificados para os cursos livres pois não temos nenhuma maneira automatizada de fazê-lo.

    Um abraço!

  8. Olá!

    Se alguém tiver tempo, pode ser que consiga te ajudar sim, mas se você quiser aprender e fazer você mesmo, ou se unir com alguém da comunidade e fazer junto, recomendo que comece pelos nossos treinamentos gratuitos aqui. Dependendo do quanto você já conhece, pode ser interessante fazer o de C primeiro e depois o CERO. Aí você pode estudar também pelo livro Fundamentos de Engenharia Reversa e o de Assembly, ambos gratuitos. Tá tudo no menu Ensino aqui mesmo no nosso site. 🙂

    Abraço,

    Fernando

  9. Eu nunca usei essas funções da GDI, mas pelo que vi na documentação da LineTo(), ela usa a “caneta” padrão:

    The line is drawn by using the current pen and, if the pen is a geometric pen, the current brush.

    Meus conhecimentos de Paint me dizem que o caminho é alterar a caneta antes de chamar a LineTo(). Pelo que vi, tem que criar a caneta no seu código com a CreatePen():

    HPEN caneta = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));

    No exemplo acima usei uma caneta sólida, de espessura 2 e cor preta. Depois precisa atribuir a caneta à sua tela:

    SelectObject(tela, caneta);

    Se tudo der certo a LineTo vai usar essa caneta ao invés da padrão, mas não testei viu? Tô no celular. hehe

    Abraço!

    • Agradecer 1
  10. Opa, bem vindo @Crystoppher!

    Em algum momento da vida, o x64dbg passou a criar um símbolo exportado (na aba Símbolos/Symbols) chamado OptionalHeader.AddressOfEntryPoint. O nome deste símbolo vem do fato de o endereço do entrypoint ser um campo do cabeçalho chamado Optional Header. No disassembly, se você estiver diante de um endereço de um símbolo, o x64dbg coloca o nome do símbolo do lado. 😉

    Abraço.

    • Agradecer 1
    • Curtir 1
  11. Legais as perguntas! 🙂

    Em 17/10/2023 em 21:39, Nitczi disse:

    Na linha onde está "sar rax,cl" vi que isso é uma operação de bit shifting para a direita, pesquisei em alguns sites para ver como ficaria essa operação e o resultado é sempre 5, mas rodando o programa o resultado é 1, por que?

    O nome é deslocamento aritimético para a direita. Tem o deslocamento lógico também, que é feito pela instrução SHL. 😉

    O que essa instrução faz é, tomando o número em binário, "empurrar" todos os bits para a direita e aí o bit que "sobra" à esquerda é preenchido com zero ou um (caso ele já seja 1). Por exemplo:

    0011 SAR 1 = 0001
    1100 SAR 1 = 1110

    O código faz 0x1122334455667788 SAR 0x3c (60) na primeira iteração do loop. Para entender, você teria que converter 0x1122334455667788 para binário e fazer a operação de deslocamento aritimético para a direita sessenta vezes, entende? Então vamos lá:

    0x1122334455667788 em binário é: 0001 0001 0010 0010 0011 0011 0100 0100 0101 0101 0110 0110 0111 0111 1000 1000 (observe a parte em negrito, que será deslocada para a direita).

    Deslocando somente uma vez para a direita, teremos:

    0000 1000 1001 0001 0001 1001 1010 0010 0010 1010 1011 0011 0011 1011 1100 0100

    O zero foi colocado à esquerda porque o bit original era zero.

    Agora você teria que fazer o processo mais 59 vezes para chegar no resultado 1. 🙂

    Fiz um programa em Python aqui para simular, trabalhando com o número como se fosse uma string. Espero que não confunda mais. 🤣

    rax = '0001000100100010001100110100010001010101011001100111011110001000'
    
    print(f'rax = {rax}')
    
    for i in range(1, 61):
        if rax[0] == '0':
            rax = '0' + rax[:-1]
        else:
            rax = '1' + rax[:-1]
    
        print(f'rax SAR {i:02d} = {rax}')

    A saída é:

    rax = 0001000100100010001100110100010001010101011001100111011110001000
    rax SAR 01 = 0000100010010001000110011010001000101010101100110011101111000100
    rax SAR 02 = 0000010001001000100011001101000100010101010110011001110111100010
    rax SAR 03 = 0000001000100100010001100110100010001010101011001100111011110001
    rax SAR 04 = 0000000100010010001000110011010001000101010101100110011101111000
    rax SAR 05 = 0000000010001001000100011001101000100010101010110011001110111100
    rax SAR 06 = 0000000001000100100010001100110100010001010101011001100111011110
    rax SAR 07 = 0000000000100010010001000110011010001000101010101100110011101111
    rax SAR 08 = 0000000000010001001000100011001101000100010101010110011001110111
    rax SAR 09 = 0000000000001000100100010001100110100010001010101011001100111011
    rax SAR 10 = 0000000000000100010010001000110011010001000101010101100110011101
    rax SAR 11 = 0000000000000010001001000100011001101000100010101010110011001110
    rax SAR 12 = 0000000000000001000100100010001100110100010001010101011001100111
    rax SAR 13 = 0000000000000000100010010001000110011010001000101010101100110011
    rax SAR 14 = 0000000000000000010001001000100011001101000100010101010110011001
    rax SAR 15 = 0000000000000000001000100100010001100110100010001010101011001100
    rax SAR 16 = 0000000000000000000100010010001000110011010001000101010101100110
    rax SAR 17 = 0000000000000000000010001001000100011001101000100010101010110011
    rax SAR 18 = 0000000000000000000001000100100010001100110100010001010101011001
    rax SAR 19 = 0000000000000000000000100010010001000110011010001000101010101100
    rax SAR 20 = 0000000000000000000000010001001000100011001101000100010101010110
    rax SAR 21 = 0000000000000000000000001000100100010001100110100010001010101011
    rax SAR 22 = 0000000000000000000000000100010010001000110011010001000101010101
    rax SAR 23 = 0000000000000000000000000010001001000100011001101000100010101010
    rax SAR 24 = 0000000000000000000000000001000100100010001100110100010001010101
    rax SAR 25 = 0000000000000000000000000000100010010001000110011010001000101010
    rax SAR 26 = 0000000000000000000000000000010001001000100011001101000100010101
    rax SAR 27 = 0000000000000000000000000000001000100100010001100110100010001010
    rax SAR 28 = 0000000000000000000000000000000100010010001000110011010001000101
    rax SAR 29 = 0000000000000000000000000000000010001001000100011001101000100010
    rax SAR 30 = 0000000000000000000000000000000001000100100010001100110100010001
    rax SAR 31 = 0000000000000000000000000000000000100010010001000110011010001000
    rax SAR 32 = 0000000000000000000000000000000000010001001000100011001101000100
    rax SAR 33 = 0000000000000000000000000000000000001000100100010001100110100010
    rax SAR 34 = 0000000000000000000000000000000000000100010010001000110011010001
    rax SAR 35 = 0000000000000000000000000000000000000010001001000100011001101000
    rax SAR 36 = 0000000000000000000000000000000000000001000100100010001100110100
    rax SAR 37 = 0000000000000000000000000000000000000000100010010001000110011010
    rax SAR 38 = 0000000000000000000000000000000000000000010001001000100011001101
    rax SAR 39 = 0000000000000000000000000000000000000000001000100100010001100110
    rax SAR 40 = 0000000000000000000000000000000000000000000100010010001000110011
    rax SAR 41 = 0000000000000000000000000000000000000000000010001001000100011001
    rax SAR 42 = 0000000000000000000000000000000000000000000001000100100010001100
    rax SAR 43 = 0000000000000000000000000000000000000000000000100010010001000110
    rax SAR 44 = 0000000000000000000000000000000000000000000000010001001000100011
    rax SAR 45 = 0000000000000000000000000000000000000000000000001000100100010001
    rax SAR 46 = 0000000000000000000000000000000000000000000000000100010010001000
    rax SAR 47 = 0000000000000000000000000000000000000000000000000010001001000100
    rax SAR 48 = 0000000000000000000000000000000000000000000000000001000100100010
    rax SAR 49 = 0000000000000000000000000000000000000000000000000000100010010001
    rax SAR 50 = 0000000000000000000000000000000000000000000000000000010001001000
    rax SAR 51 = 0000000000000000000000000000000000000000000000000000001000100100
    rax SAR 52 = 0000000000000000000000000000000000000000000000000000000100010010
    rax SAR 53 = 0000000000000000000000000000000000000000000000000000000010001001
    rax SAR 54 = 0000000000000000000000000000000000000000000000000000000001000100
    rax SAR 55 = 0000000000000000000000000000000000000000000000000000000000100010
    rax SAR 56 = 0000000000000000000000000000000000000000000000000000000000010001
    rax SAR 57 = 0000000000000000000000000000000000000000000000000000000000001000
    rax SAR 58 = 0000000000000000000000000000000000000000000000000000000000000100
    rax SAR 59 = 0000000000000000000000000000000000000000000000000000000000000010
    rax SAR 60 = 0000000000000000000000000000000000000000000000000000000000000001

    Com isso você prova que 0x1122334455667788 SAR 60 é igual a 1. Mas na próxima iteração do loop, RAX sofrerá uma operação SAR com 56, que já não é 1, e por aí vai... Ou seja, não é que é sempre 1. 😉

    O objetivo deste programa é você imprimir na tela cada dígito hexa do registrador RAX, não importa o que você coloque lá. Testa com 0xf0f0caf0f0ca2023 por exemplo. 😉

    Abraço!

    • Agradecer 1
×
×
  • Create New...