Ir para conteúdo

Felipe.Silva

Membros
  • Postagens

    88
  • Registro em

  • Última visita

  • Dias Ganhos

    29

Posts postados por Felipe.Silva

  1. Em 27/06/2023 em 18:29, Raphael Silva disse:

    Compreendi a explicação do Fernando, mas quando usar dw, dq...?

    Tenho essa mesma dúvida. Vou usar um trecho que voce (Pedro Otavio) citou:

    ...E caso fosse então dw, ao invés de db, seria despejado na "variável" msg de 2 em 2 bytes?"

    Obrigado amigos!

    Quando você achar que deveria usar. Não existe "o momento certo" para usar, é você que decide isso. Quando você quiser valores de 2 bytes de tamanho, use `dw`. Quando quiser de 4 bytes, use `dd`. Quando quiser de 8 bytes, use `dq` e assim por diante.

    Ninguém pode tomar essa decisão além do próprio programador que está escrevendo o código. Portanto só você sabe quando usar. Quando você vai precisar de valores de 4 bytes de tamanho ao invés de 1 byte só? Ou de 8 bytes? Ou 2 bytes? Você que sabe.

    Veja o exemplo no print abaixo para entender o que essas pseudo-instruções fazem. Elas basicamente despejam os dados exatamente no lugar onde elas foram usadas. O que pode ser visto usando um visualizador hexadecimal como o `hd` (hexdump).

    image.thumb.png.c15b3383aed417575c3d6888f9cdb39b.png

  2. E aí galera. Amanhã (sexta-feira) às 19:00 vou fazer uma apresentação ao vivo no canal Alquymia dando uma introdução sobre baixo nível. Na apresentação vou falar sobre:

    1. Arquitetura x86-64
    2. Código de máquina
    3. Assembly
    4. Compiladores

    Quem tiver interesse de aprender como processadores funcionam não pode perder.

    Link para a live: 

     

    Slides da apresentação:

    https://docs.google.com/presentation/d/1hPzG39uNl_tWji92vojtp0qZRabq12Mw4_y2GYq6YGc/edit?usp=sharing

    • Curtir 1
  3. @Lincoln Arantes que tentativa infantil de se vingar só porque eu provei que o conteúdo de baixa qualidade que você estava compartilhando aqui no fórum foi gerado pelo ChatGPT.

    LincolnArantes1.thumb.png.909a3047ef23bdbfb6161ac42174b564.png

    ---------

    Ah, e teve aquela vez também no Facebook que você afirmou que a linguagem C é código de máquina. As instruções em C estão dentro dos CI né? kkkkkkkkk

    Eu tenho os prints salvos então nem finja que nunca afirmou essa bobagem. Aliás, pior do que isso só se ainda acreditar nessa bobagem. Errar é humano, mas insistir no erro... kkkkkk

    De qualquer forma sua "solução" foi exatamente o que eu falei. No dia que eu escrevi isso daí eu fiz a conversão para ver se tinha mais alguma coisa. Eu verifiquei porque eu não ia afirmar que era "só isso" sem ter certeza que realmente era só isso.

    Só que eu não vou dar a solução de mão beijada, só dei a dica mesmo.

  4. Em 25/03/2023 em 12:26, Emir_Fadul disse:

    Ola devs, tbm estou passando por esse problema, iniciei em Assembly e ainda nao consegui gerar o executavel, tentei as opções do forum e nenhuma deu certo! Fernando um help pfv. Segue abaixo os codigos:

    [assembly.asm]

    bits 64

    global main

    main:

      mov eax, 777

      ret

    =================================

    [main.c]

    #include <stdio.h>

    int assembly(void);

    int main(void){

        printf("Resultado: %d \n", assemby());

        return 0;

    }

    ===============

    Tentei todas as opções!

     

     



     

    Desculpa a demora para responder. Bom, indo direto ao ponto: houve um erro meu e um seu aqui, rsrsrs. Repare que no seu arquivo 'assembly.asm' você definiu o rótulo como `main`, não é como está no código de exemplo passado no livro. Lá o nome do rótulo é `assembly` e não `main`. O nome do rótulo, não coincidentemente, é o mesmo da função invocada no código em C.

    O meu erro é que faltou um `section .text` no código em Assembly, por isso o erro de "undefined reference" no Windows (no Linux esse erro não acontece, sei lá porquê).

    Eu já atualizei as instruções no livro com a correção do código do 'assembly.asm' e adicionei os comandos de como compilar no Windows (só para garantir). O código, após a correção, ficou assim:

    bits 64
    
    section .text
    
    global assembly
    assembly:
      mov eax, 777
      ret

    Se você verificar o livro novamente e seguir as instruções atualizadas, deve funcionar dessa vez.

    Nota: Fiz os testes usando uma máquina virtual do Windows 7, MinGW-w64 versão 12.2.0-rt_v10-rev2 e NASM versão 2.16.01.

    Valeu por me marcar @Fernando Mercês.

  5. Essas diretivas CFI (Call Frame Information) geram informações que são usadas pelo depurador de código. A sigla CFA é de Canonical Frame Address que seria o endereço do stack pointer antes de entrar na função atual.

    A diretiva `.cfi_def_cfa` é usada para definir o valor do CFA. O primeiro parâmetro é um número que identifica um registrador e o segundo um valor numérico sinalizado (offset). O valor do CFA é definido como o valor desse registrador somado ao offset no segundo parâmetro.

    No caso o número 1 identifica o registrador EAX/RAX, o que não faz muito sentido ao meu ver. Essa diretiva foi tirada de um código real?

    Um exemplo real que peguei aqui foi:

    .cfi_def_cfa 7, 8

    Onde o 7 é o registrador RSP. Então essa diretiva está gerando informação para dizer para o depurador: "Nesse exato momento o CFA é RSP+8"

    Você pode desabilitar essas diretivas com a flag -fno-asynchronous-unwind-tables, daí o código fica mais legível. Exemplo:

    $ gcc exemplo.c -o exemplo.s -S -fno-asynchronous-unwind-tables

    Referências

  6. Isso é só um rótulo (label) e não faz absolutamente nada. A sintaxe para declarar um rótulo é igual a sintaxe da linguagem C, colocando o nome do rótulo seguido de dois-pontos.

    Um rótulo é meramente um "nome" que pode ser usado para obter o endereço de memória do byte que está logo em seguida onde o rótulo foi declarado. Repare nesse código aí:

    .LC0:
    	.string "ola"

    Logo após a declaração do rótulo há uma pseudo-instrução .string que recebe uma expressão de string como parâmetro. O que ela faz é simplesmente despejar os bytes da string aonde foi invocada. Portanto o rótulo .LC0 é um "nome" para o endereço da string "ola".

    Repare que no finalzinho do print esse rótulo é utilizado (na penúltima instrução):

    	call	__x86.get_pc_thunk.ax
    	addl	$_GLOBAL_OFFSET_TABLE, %eax
    	subl	$12, %esp
    	leal	.LC0@GOTOFF(%eax), %edx
    	pushl	%edx

    Esse call na primeira instrução é um "truque" que o GCC faz para obter endereços relativos. Para entender isso sugiro que leia isso aqui.

    A instrução leal (penúltima) é usada para obter o endereço daquela string e armazenar no registrador EDX, logo em seguida esse endereço é empilhado.

    ---

    O próprio Mente Binária tem um livro de Assembly que explica algumas coisas à respeito. O capítulo "Programando junto com C" será especialmente útil para você pois ele lida com o GAS e explica como código C funciona após compilado (em Assembly):

    https://mentebinaria.gitbook.io/assembly/programando-junto-com-c

  7. Você copiou e colou o código que te passei ou redigitou tudo?

    Se for o segundo caso, cole seu código aqui para eu ver (por completo). Ah, quando for exibir uma mensagem de erro é melhor mostrar ela por completo. Cada linha e cada letra. Pode até tirar um print do terminal também se quiser.

    Só com essa mensagem aí é impossível eu dizer o que está errado. Eu preciso das duas coisas: A mensagem de erro completa e o código completo que você escreveu.

    Uma dica quando for colar o código aqui, clique nesse botão com o símbolo "<>" que ele formata o texto como código:

    image.thumb.png.57714bfaea376e32950f8275b96be402.png

  8. Nunca usei a API deles mas confira na documentação na parte que fala sobre o POST de notificação. Segundo o que tá lá um PaymentId é enviado na requisição, o que te permite consultar o status da transação. O fluxo seria tipo:

    1. Recebi o POST com PaymentId.
    2. Uso o PaymentId para consultar na API o status da transação.

    Na documentação também diz que é possível cadastrar headers que serão enviados nessa requisição com um valor fixo. Isso pode servir como filtro para ter uma segurança mínima de que foi mesmo a CIELO que enviou o POST. Mas eu não confiaria tanto assim. ?

    image.thumb.png.e5bee66cda584ee4511d4a7c4a5d45d5.png

    • Agradecer 1
    • l33t 1
  9. Cara, você tem que primeiro obter a entrada do usuário e depois fazer o cálculo. Tu tá calculando o valor da variável `imc` antes, impossível obter o resultado correto.

    Mova a atribuição da variável imc para ficar após a leitura das variáveis peso e altura. Exemplo:

    imc = peso/(altura*altura);
    cout << "O seu IMC eh: " << imc << endl;
    return 0;

     

    • Curtir 1
  10. 8 horas atrás, Nicholas F disse:

    Valeu pela resposta, Fernando!

    Eu havia tentado realocar o buffer que eu criei com o mmap mas não encontrei como fazer isso. Dei uma procurada por alocação dinâmica de memória e encontrei pessoas falando sobre o malloc. Tô tentando fazer tudo com syscalls, então não queria usar o malloc.

    O caminho seria com o brk mesmo? Encontrei alguns exemplos em C, mas não ficou muito claro. Ou há alguma maneira de realocar um buffer que tenha sido criado com o mmap, por exemplo?

    Abraço!


    Veja sobre a syscall mremap.

    https://man7.org/linux/man-pages/man2/mremap.2.html

  11. Você parou de atualizar head e tail em myMalloc()... Mas atualizar esses ponteiros é importante para o funcionamento desse sistema aí.
    Por exemplo: O que a função find_block() retorna se head for NULL? Ela só pode retornar NULL... Se você nunca inicializar head para apontar para um bloco, find_block() vai sempre retornar NULL.

    Você pode fazer algo mais ou menos assim:

    void *myMalloc(size_t size)
    {
      t_block b = find_block(size);
      if (b)
      {
        b->free = 0;
      }
      else
      {
        b = extend_heap(size);
        if (!b)
          return NULL;
    
        if (!head)
          head = b;
    
        tail = b;
      }
      return (b + 1);
    }

    Repare como eu inicializo head quando extend_heap() é chamado pela primeira vez. E repare que sempre é necessário chamá-lo eu atualizo tail. Entendeu a ideia? Assim head está sempre apontando para o primeiro bloco alocado e tail sempre apontando para o último.

    Não esquece disso também na myFree(). Ela precisa atualizar tail toda vez que liberar um bloco. E lembre-se que existe a possibilidade de myFree() ser usada no bloco apontado por head, neste caso o ponteiro head passaria a apontar para uma memória que já foi liberada.
    Talvez a solução mais simples neste caso seja redefinir head para NULL e "recomeçar". ? 

  12. void *myMalloc(size_t size) {
    // TODO
        t_block b;
        if(head){
           tail = head;
          // ....

    Esse "tail = head" não me parece certo. Pela lógica do código tail deveria ser atualizado para o novo bloco alocado na memória toda vez que a função extend_heap() precisar ser chamada... Do jeito que está tail volta a apontar para head a cada nova chamada de myMalloc() (exceto a primeira chamada onde head ainda será NULL).

    Sugiro atualizar o código para as vezes que precisou chamar "b = extend_heap(size);" atualizar tail para apontar para b.

    Ah, e qual é a lógica do else dentro da função myFree()? Também toma cuidado com a diferença entre = e ==. Dentro do if deveria ser == certo?

    Outra coisa que não entendi é isso: b = tail->next = NULL;

    Você quer modificar b para NULL? Mas logo em seguida você executa brk(b); o que não faria sentido passar NULL para esta função.
    b também não é inicializada caso o valid_addr retorne false, pois você declarou a variável mas só a inicializa dentro do if.

    Essa estrutura s_block foi o professor que passou assim? Pois eu vejo um probleminha ao precisar desalocar memória e atualizar o valor de tail. Como você vai pegar o endereço do penúltimo bloco sem um ponteiro para o bloco anterior?
    Até daria para percorrer a lista para isso, mas seria mais eficiente ter um ponteiro t_block previous na estrutura. ? 

    E uma coisa interessante é se sua myFree() liberasse todos os últimos blocos que estejam marcados como free, e não somente o último. Ou então deixar apenas N blocos no final e liberar o resto, assim poupa tempo pro myMalloc() não precisar de extend_heap() o tempo todo.

    Ah, uma dica: Antes de mais nada sugiro implementar logo a função debugBlockList(). Ela vai te ajudar a "visualizar" a lista e assim ficará mais fácil entender o que está funcionando conforme deveria e o que não está.

  13. 11 horas atrás, seculodigital disse:

    Como faço para atribuir uma letra a este mapeamento para que no Linux seja apresentado como uma unidade (igual como ocorre no Windows) ?

    Esse conceito de "unidade de armazenamento" associado à uma letra "só" existe no *Windows. No Linux (e outros UNIX-Like) os volumes são montados em diretórios.

    * "Só" porque MS-DOS e ReactOS também usam esse conceito. Se bobear pode haver algum sistema operacional desconhecido que faz isso também.

  14. O próprio Wine tem um debugger (winedbg) que você pode utilizar para depurar um .exe, dá para usar ele como gdb's server com a opção --gdb, caso você saiba usar o gdb...

    Porém o que o edb (e outros debuggers) faz é depurar processos e não arquivos executáveis. Se você pode iniciar um processo para o .exe então você pode depurá-lo. O passo-a-passo fica:

    1. Execute o .exe com o Wine.
    2. Abra o edb com privilégios root, menu "File" clique em "Attach". Procure pelo processo, dá para pesquisar pelo nome ou pelo PID.

    É necessário executar o edb como root porque é necessário privilégios root para poder fazer esse attach no processo em execução. Ah, um detalhe: É necessário que o processo se mantenha em execução para você poder fazer isso. Se ele finaliza imediatamente após iniciar você não vai conseguir fazer o attach.

    • Curtir 2
  15. Na programação orientada a objetos existe o conceito de encapsulamento, que resumidamente é o conceito de não alterar uma variável diretamente mas sim usando uma função. Isso faz com que a variável fique "encapsulada" dentro do objeto e permite que qualquer lógica seja aplicada na alteração daquela variável.

    E é exatamente o que você quer fazer... Toda vez que as variáveis A e B são alteradas existe uma certa lógica ocorrendo com elas, não é? Então eu sugeriria você colocar tudo dentro de uma struct e implementar funções para modificar os valores de A e B. Tipo assim:
     

    struct var {
    	bool mode; // A
      	int value; // B
      	int counter;
    };
    
    void var_mode(struct var *variable, bool mode)
    {
      // etc...
    }
    
    void var_value(struct var *variable, int value)
    {
      // etc...
    }

     

    • l33t 1
  16. Não sou lá um especialista no assunto, mas enquanto não aparece uma pessoa mais qualificada você vai ter que se contentar com o que eu sei. rsrsrs :P 
    Antes de mais nada esse método é para atacar redes WPA2-PSK, que é um dos métodos de autenticação que uma rede WPA2 suporta.
    Geralmente esse método de autenticação mais simples é usado em residências. Empresas usam o outro método porque é mais seguro. (não sei como o outro método funciona, nem pergunte.)

    O "método tradicional" para quebrar uma senha de uma rede WPA2 segue três passos simples:
    1) Monitorar o tráfego no canal em que se encontra a rede alvo.
    2) Esperar pacientemente que alguém se conecte a rede. Quando o handshake é capturado é o "sinal" que alguém tentou se conectar a rede.
    3) Quebrar a senha por força bruta. (se você pegou o handshake de uma conexão falha vai perder tempo :P )

    Obs.: O passo dois pode ser acelerado forçando a desautenticação de algum dispositivo forjando pacotes. Mas isso não é importante para o assunto.

    Como eu disse eu não entendo muita coisa, mas o ataque de força bruta acontece no pacote de comunicação do 4-Way Handshake.
    Basicamente ele tenta "simular" a criação desse pacote usando uma chave X como se fosse a senha de autenticação.
    Se o resumo do pacote bater com o resumo do handshake capturado, então quer quiser que a senha é a correta.

    O novo método apresentado no artigo elimina a necessidade de capturar o handshake. (essa é a parte mais problemática)
    Isso porque ele descobriu que esse tal de PMKID é gerado usando o algoritmo HMAC-SHA1. Onde é usado como chave o PMK* e como dado a concatenação da string "PMK Name", o MAC do AP(o roteador neste caso) e o MAC do dispositivo que está se comunicando com o roteador.
    Ou seja: "PMK Name" + MAC_DO_ROTEADOR + MAC_DO_DISPOSITIVO

    Tudo isso concatenado é "hasheado" usando algoritmo HMAC-SHA1 e usando como chave o PMK. Onde o "PMK" nada mais é que a senha configurada para a rede WiFi.
    O MAC do roteador e do dispositivo pode ser capturado facilmente monitorando a rede... Percebeu onde se encontra a vulnerabilidade do sistema?
    Dessa forma dá para descobrir facilmente o dado, só o que não temos é a chave utilizada. (a senha da rede WiFi)

    Ou seja, isso abre uma porta para fazer força bruta... É só usar o algoritmo HMAC-SHA1 no dado com senhas diferentes...
    Se conseguir o mesmo PMKID significa que usou a mesma chave... Logo, você conseguiu senha da rede. ^-^

    • Curtir 1
×
×
  • Criar Novo...