-
Posts
89 -
Joined
-
Last visited
-
Days Won
30
Felipe.Silva last won the day on May 14
Felipe.Silva had the most liked content!
Recent Profile Visitors
5,392 profile views
Felipe.Silva's Achievements
70
Reputation
-
Falha de segmentação (imagem do núcleo gravada)
Felipe.Silva replied to Jorge Luiz Gouveia Sousa's topic in Assembly
Não é assim que se invoca syscalls em 64 bits. Tente alterar a linha de comando para compilação assim: $ nasm -f elf32 hello.asm $ ld -m elf_i386 -s -o hello hello.o E verá que vai funcionar, porque o código que tu escreveu é para 32 bits mas você tá compilando para 64 bits. -
thamiresbrr started following Felipe.Silva
-
Gabrielle Alves started following Felipe.Silva
-
RodrixTeer started following Felipe.Silva
-
Dúvidas sobre alocação de memória e diretivas DB, DW, DD, DQ,...
Felipe.Silva replied to Pedro Otavio's topic in Assembly
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). -
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: Arquitetura x86-64 Código de máquina Assembly 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
-
- 1
-
@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. --------- 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.
-
Não tem o que ser decifrado, mano. Isso é uma sequência de bytes em hexadecimal, apenas converta de volta para bytes e veja no que deu.
-
Problema em gerar executável no Windows - PoC Aprendendo Assembly
Felipe.Silva replied to Paulo Ferr's topic in Assembly
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. -
Sugiro ver os cursos da GoHacking (o "Ethical Hacking Modern Web Exploitation" por exemplo) e o HackTheBox. https://gohacking.com.br/cursos https://www.hackthebox.com/
-
SpaceHoll0w started following Felipe.Silva
-
Thailsson Baumstark started following Felipe.Silva
-
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 7.12 CFI directives - AS documentations CFI directives in assembly files - ImperialViolet
-
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
-
Robson123321 started following Felipe.Silva
-
RetroGamerCX started following Felipe.Silva
-
cabraljrjoas started following Felipe.Silva
-
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:
-
A linha `global_assembly:` deveria ser global seguido de assembly. Onde global é uma diretiva que será explicada posteriormente, e assembly seria o nome do rótulo logo abaixo (será explicado também). bits 64 global assembly assembly: mov eax, 777 ret
-
Spectre e Meltdown - Entendendo vulnerabilidades de processadores
Felipe.Silva reviewed esoj's artigo in Tudo
Muito bom.-
- segurança
- arquitetura
-
(and 5 more)
Tagged with:
-
-
- 1
-
- assembly
- programação
-
(and 1 more)
Tagged with:
-
A heap é uma estrutura especial de memória usada pelo processo. O que tem de especial nela é o fato de seu tamanho ser variável, já que sua memória pode ser alocada ou desalocada dinamicamente pelo processo. Isso pode ser feito usando syscalls do sistema operacional e o mesmo é responsável por alocar mais páginas de memória para a seção caso seja necessário. No Linux o segmento de dados pode ser aumentado ou diminuído usando a syscall brk, e é esse espaço de memória que os programas normalmente usam para a heap. Em C nós normalmente não usamos a heap diretamente e, ao invés disso, usamos a função malloc() e semelhantes para lidar com a alocação dinâmica de memória. O que alguns não sabem é que na verdade chamadas para a função malloc() ou free() não necessariamente irão resultar na alocação ou desalocação de memória para o processo. Isso se dá porque é a libc quem de fato gerencia a heap e nós não estamos diretamente solicitando ou liberando memória para o sistema operacional. *libc é a biblioteca padrão da linguagem C que contém funções essenciais para tarefas básicas como: Manipulação de strings e arquivos, entrada e saída de dados, funções básicas de matemática etc. A função malloc(), de acordo com a implementação da glibc, usa o segmento de dados, o dividindo em uma ou mais regiões de memória que eles chamam de “arenas”. A arena principal corresponde à heap original do processo, porém outras arenas também podem ser alocadas para o processo. Inicialmente cada thread criada no processo tem uma arena individual até atingir um certo limite pré-definido de arenas que podem ser alocadas no processo. Atingindo esse limite, as threads posteriores passam a compartilhar a mesma arena. Em cada arena de memória existem divisões da memória que são chamadas de maneira homônima de heap, e são nessas heaps que a função malloc() de fato aloca memória para o usuário da libc. Cada bloco de memória que malloc() aloca na heap é chamado de chunk, e cada chunk contém metadados usados pelo sistema interno de malloc para organizar a heap como uma lista duplamente encadeada. Para fins de ilustração, abaixo está a estrutura de um chunk, usada na glibc: struct malloc_chunk { INTERNAL_SIZE_T mchunk_prev_size; INTERNAL_SIZE_T mchunk_size; struct malloc_chunk* fd; struct malloc_chunk* bk; /* Only used for large blocks: pointer to next larger size. */ struct malloc_chunk* fd_nextsize; struct malloc_chunk* bk_nextsize; O valor mchunk_prev_size seria o tamanho do chunk anterior e mchunk_size o tamanho do chunk atual. Os ponteiros *fd e *bk são usados somente quando o chunk está livre, e seriam ponteiros usados para a lista circular duplamente encadeada de chunks que apontam para o chunk posterior e anterior, respectivamente. No entanto, essa estrutura não representa muito claramente como o chunk é de fato usado pelo sistema de malloc, na figura abaixo isso é ilustrado com mais precisão. O ponteiro que malloc() retorna não aponta para o início do chunk mas sim para o início do espaço de memória que pode ser usado pelo usuário. O tamanho do espaço de memória de um chunk é alinhado pelo tamanho de um double word na arquitetura. Caso malloc() seja chamado passando um tamanho desalinhado como argumento, um espaço extra é alocado para manter o alinhamento. Por exemplo, se o alinhamento está sendo feito para 8 bytes e malloc é chamada com 9 como argumento, malloc irá te devolver um chunk com 16 bytes de espaço de memória usável. Além do alinhamento no tamanho do chunk, também existe um alinhamento no endereço de memória retornado por malloc() que é sempre alinhado para o tamanho de uma word. Isso é feito porque em algumas arquiteturas esse alinhamento de memória é necessário para se evitar uma exceção. Em outras arquiteturas (x86, por exemplo) o alinhamento melhora a performance do processador no acesso à memória. Como existe esse alinhamento no tamanho de um chunk isso garante que os três bits menos significativos de mchunk_size não sejam necessários para definir o tamanho do chunk. Se aproveitando disso, os três últimos bits são usados como flags para determinar alguns metadados usados pelo sistema de chunks. O bit M indica que o chunk não pertence a nenhuma arena e, ao invés disso, foi alocado dinamicamente em uma memória mapeada. Caso este bit esteja ligado, os outros dois são ignorados. No contexto de um chunk livre este bit está sempre desligado, tendo em vista que a lista encadeada de chunks livres somente se aplica a chunks que estão em alguma arena. Os chunks diretamente mapeados na memória (com bit M ligado) são criados para chunks muito grandes. Esses chunks quando liberados com a função free() são imediatamente liberados da memória. Por outro lado, usar free() em um chunk comum não necessariamente irá liberar memória para o sistema operacional. O que free() faz nesse caso é marcar o chunk como livre o adicionando de volta à lista de chunks livres. Assim como é indicado nesse trecho da glibc: /* Mark the chunk as belonging to the library again. */ (void)tag_region (chunk2mem (p), memsize (p)); Repare como o comentário descreve a ação como “marcar o chunk como pertencente à biblioteca novamente”, e é efetivamente isso que a função free() faz, não sendo necessariamente uma liberação de memória para o sistema operacional. Inclusive um recurso de otimização que a glibc usa é o que eles chamam de tcache (Thread Local Cache), que se trata de uma lista de chunks existente em cada thread individualmente. Quando você aloca um novo chunk na thread e posteriormente o libera, ele é adicionado ao tcache daquela thread e pode ser reutilizado em uma nova alocação posterior. Um adendo que a função free() pode efetivamente liberar memória para o sistema operacional se houver vários chunks livres no topo do segmento de dados (o que raramente acontece). Ela faz isso chamando a função interna systrim(), que por sua vez (no Linux) usa a syscall brk para diminuir novamente o segmento de dados. Um detalhe interessante que vale citar aqui é que na glibc (no Linux) existem as funções brk e sbrk que servem como wrappers para aumentar/diminuir o segmento de dados. O sistema de liberação de memória do systrim() espera que essas funções não sejam utilizadas diretamente para poder fazer a liberação de memória apropriadamente. Se você usá-las em seu código por algum motivo, irá “quebrar” o sistema de liberação de memória automático do free(), o fazendo não mais liberar memória quando é usado em chunks de arenas. Logo, não é recomendável que você use essas funções diretamente a menos que você esteja implementando seu próprio sistema de gerenciamento de memória dinâmica. O código abaixo é um experimento a fim de vermos na prática os metadados do chunk no Linux: // gcc test.c -o test #include <stdio.h> #include <stdlib.h> int main(void) { size_t *content = malloc(8); size_t chunk_size = content[-1] & ~0b111; size_t chunk_flags = content[-1] & 0b111; printf("size: %zu\nflags: %zu\n", chunk_size, chunk_flags); return 0; } No meu Linux é retornado 32 como tamanho do chunk e 1 como flag, indicando que somente o bit P está ligado. Sugiro ao leitor variar o tamanho passado para malloc a fim de comprovar que o alinhamento do tamanho do chunk de fato ocorre. Também sugiro passar um número grande para malloc() a fim de ver a partir de qual tamanho malloc() irá deixar de usar uma arena e irá alocar o chunk com mmap(). Caso isso ocorra o bit M será ligado e o número 2 (decimal) será indicado como flags. Nota: Esse código propositalmente não utiliza free() antes de finalizar o programa. É redundante e desnecessário usá-la quando o programa é finalizado, tendo em vista que todas as páginas de memória usadas pelo processo serão liberadas pelo sistema operacional. Referências https://man7.org/linux/man-pages/man2/brk.2.html https://sourceware.org/glibc/wiki/MallocInternals https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=e2d7b1b58396906375ba0e953a20ac57f0904378;hb=refs/heads/master http://c-faq.com/malloc/freeb4exit.html