# Bins & Alocaรงรตes de Memรณria {% hint style="success" %} Aprenda e pratique Hacking AWS:[**Treinamento HackTricks AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ Aprenda e pratique Hacking GCP: [**Treinamento HackTricks GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
Apoie o HackTricks * Verifique os [**planos de assinatura**](https://github.com/sponsors/carlospolop)! * **Junte-se ao** ๐Ÿ’ฌ [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** ๐Ÿฆ [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.** * **Compartilhe truques de hacking enviando PRs para os repositรณrios** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
{% endhint %} ## Informaรงรตes Bรกsicas Para melhorar a eficiรชncia de como os pedaรงos sรฃo armazenados, cada pedaรงo nรฃo estรก apenas em uma lista encadeada, mas existem vรกrios tipos. Estes sรฃo os bins e existem 5 tipos de bins: [62](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l1407) small bins, 63 large bins, 1 unsorted bin, 10 fast bins e 64 tcache bins por thread. O endereรงo inicial para cada bin desordenado, pequeno e grande estรก dentro do mesmo array. O รญndice 0 nรฃo รฉ usado, 1 รฉ o bin desordenado, os bins 2-64 sรฃo os bins pequenos e os bins 65-127 sรฃo os bins grandes. ### Bins Tcache (Cache por Thread) Mesmo que as threads tentem ter seu prรณprio heap (veja [Arenas](bins-and-memory-allocations.md#arenas) e [Subheaps](bins-and-memory-allocations.md#subheaps)), hรก a possibilidade de que um processo com muitas threads (como um servidor web) **acabe compartilhando o heap com outras threads**. Nesse caso, a soluรงรฃo principal รฉ o uso de **lockers**, que podem **desacelerar significativamente as threads**. Portanto, um tcache รฉ semelhante a um bin rรกpido por thread no sentido de que รฉ uma **lista encadeada simples** que nรฃo mescla pedaรงos. Cada thread tem **64 bins tcache encadeados simples**. Cada bin pode ter um mรกximo de [7 pedaรงos do mesmo tamanho](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l323) variando de [24 a 1032B em sistemas de 64 bits e 12 a 516B em sistemas de 32 bits](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l315). Quando um thread libera um pedaรงo, se nรฃo for muito grande para ser alocado no tcache e o bin tcache respectivo **nรฃo estiver cheio** (jรก com 7 pedaรงos), ele serรก alocado lรก. Se nรฃo puder ir para o tcache, precisarรก esperar pelo bloqueio do heap para poder realizar a operaรงรฃo de liberaรงรฃo globalmente. Quando um **pedaรงo รฉ alocado**, se houver um pedaรงo livre do tamanho necessรกrio no **Tcache, ele o usarรก**, caso contrรกrio, precisarรก esperar pelo bloqueio do heap para poder encontrar um nos bins globais ou criar um novo.\ Hรก tambรฉm uma otimizaรงรฃo, nesse caso, enquanto tiver o bloqueio do heap, o thread **preencherรก seu Tcache com pedaรงos do heap (7) do tamanho solicitado**, para que, caso precise de mais, os encontre no Tcache.
Adicionar um exemplo de pedaรงo tcache ```c #include #include int main(void) { char *chunk; chunk = malloc(24); printf("Address of the chunk: %p\n", (void *)chunk); gets(chunk); free(chunk); return 0; } ``` Compile-o e depure-o com um breakpoint no opcode ret da funรงรฃo main. entรฃo com o gef vocรช pode ver o tcache bin em uso: ```bash gefโžค heap bins โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Tcachebins for thread 1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Tcachebins[idx=0, size=0x20, count=1] โ† Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) ```
#### Estruturas e Funรงรตes do Tcache No cรณdigo a seguir, รฉ possรญvel ver o **nรบmero mรกximo de bins** e **chunks por รญndice**, a struct **`tcache_entry`** criada para evitar frees duplos e **`tcache_perthread_struct`**, uma struct que cada thread usa para armazenar os endereรงos de cada รญndice do bin.
tcache_entry e tcache_perthread_struct ```c // From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c /* We want 64 entries. This is an arbitrary limit, which tunables can reduce. */ # define TCACHE_MAX_BINS 64 # define MAX_TCACHE_SIZE tidx2usize (TCACHE_MAX_BINS-1) /* Only used to pre-fill the tunables. */ # define tidx2usize(idx) (((size_t) idx) * MALLOC_ALIGNMENT + MINSIZE - SIZE_SZ) /* When "x" is from chunksize(). */ # define csize2tidx(x) (((x) - MINSIZE + MALLOC_ALIGNMENT - 1) / MALLOC_ALIGNMENT) /* When "x" is a user-provided size. */ # define usize2tidx(x) csize2tidx (request2size (x)) /* With rounding and alignment, the bins are... idx 0 bytes 0..24 (64-bit) or 0..12 (32-bit) idx 1 bytes 25..40 or 13..20 idx 2 bytes 41..56 or 21..28 etc. */ /* This is another arbitrary limit, which tunables can change. Each tcache bin will hold at most this number of chunks. */ # define TCACHE_FILL_COUNT 7 /* Maximum chunks in tcache bins for tunables. This value must fit the range of tcache->counts[] entries, else they may overflow. */ # define MAX_TCACHE_COUNT UINT16_MAX [...] typedef struct tcache_entry { struct tcache_entry *next; /* This field exists to detect double frees. */ uintptr_t key; } tcache_entry; /* There is one of these for each thread, which contains the per-thread cache (hence "tcache_perthread_struct"). Keeping overall size low is mildly important. Note that COUNTS and ENTRIES are redundant (we could have just counted the linked list each time), this is for performance reasons. */ typedef struct tcache_perthread_struct { uint16_t counts[TCACHE_MAX_BINS]; tcache_entry *entries[TCACHE_MAX_BINS]; } tcache_perthread_struct; ```
A funรงรฃo `__tcache_init` รฉ a funรงรฃo que cria e aloca o espaรงo para o objeto `tcache_perthread_struct` ```c // From https://github.com/bminor/glibc/blob/f942a732d37a96217ef828116ebe64a644db18d7/malloc/malloc.c#L3241C1-L3274C2 static void tcache_init(void) { mstate ar_ptr; void *victim = 0; const size_t bytes = sizeof (tcache_perthread_struct); if (tcache_shutting_down) return; arena_get (ar_ptr, bytes); victim = _int_malloc (ar_ptr, bytes); if (!victim && ar_ptr != NULL) { ar_ptr = arena_get_retry (ar_ptr, bytes); victim = _int_malloc (ar_ptr, bytes); } if (ar_ptr != NULL) __libc_lock_unlock (ar_ptr->mutex); /* In a low memory situation, we may not be able to allocate memory - in which case, we just keep trying later. However, we typically do this very early, so either there is sufficient memory, or there isn't enough memory to do non-trivial allocations anyway. */ if (victim) { tcache = (tcache_perthread_struct *) victim; memset (tcache, 0, sizeof (tcache_perthread_struct)); } } ``` #### รndices Tcache O tcache possui vรกrios bins dependendo do tamanho e os ponteiros iniciais para o **primeiro chunk de cada รญndice e a quantidade de chunks por รญndice estรฃo localizados dentro de um chunk**. Isso significa que ao localizar o chunk com essas informaรงรตes (geralmente o primeiro), รฉ possรญvel encontrar todos os pontos iniciais do tcache e a quantidade de chunks do Tcache. ### Bins Rรกpidos Os bins rรกpidos sรฃo projetados para **acelerar a alocaรงรฃo de memรณria para pequenos chunks** mantendo chunks recentemente liberados em uma estrutura de acesso rรกpido. Esses bins usam uma abordagem Last-In, First-Out (LIFO), o que significa que o **chunk mais recentemente liberado รฉ o primeiro** a ser reutilizado quando hรก uma nova solicitaรงรฃo de alocaรงรฃo. Esse comportamento รฉ vantajoso para a velocidade, pois รฉ mais rรกpido inserir e remover do topo de uma pilha (LIFO) em comparaรงรฃo com uma fila (FIFO). Alรฉm disso, **os bins rรกpidos usam listas encadeadas simples**, nรฃo duplamente encadeadas, o que melhora ainda mais a velocidade. Como os chunks nos bins rรกpidos nรฃo sรฃo mesclados com vizinhos, nรฃo hรก necessidade de uma estrutura complexa que permita a remoรงรฃo do meio. Uma lista encadeada simples รฉ mais simples e rรกpida para essas operaรงรตes. Basicamente, o que acontece aqui รฉ que o cabeรงalho (o ponteiro para o primeiro chunk a ser verificado) estรก sempre apontando para o chunk liberado mais recentemente desse tamanho. Entรฃo: * Quando um novo chunk รฉ alocado desse tamanho, o cabeรงalho estรก apontando para um chunk livre para usar. Como esse chunk livre estรก apontando para o prรณximo a ser usado, esse endereรงo รฉ armazenado no cabeรงalho para que a prรณxima alocaรงรฃo saiba onde obter um chunk disponรญvel. * Quando um chunk รฉ liberado, o chunk livre salvarรก o endereรงo para o chunk disponรญvel atual e o endereรงo para esse novo chunk liberado serรก colocado no cabeรงalho. O tamanho mรกximo de uma lista encadeada รฉ `0x80` e elas sรฃo organizadas de modo que um chunk de tamanho `0x20` estarรก no รญndice `0`, um chunk de tamanho `0x30` estarรก no รญndice `1`... {% hint style="danger" %} Chunks nos bins rรกpidos nรฃo sรฃo definidos como disponรญveis, entรฃo eles sรฃo mantidos como chunks de bin rรกpido por algum tempo em vez de poderem ser mesclados com outros chunks livres ao redor deles. {% endhint %} ```c // From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711 /* Fastbins An array of lists holding recently freed small chunks. Fastbins are not doubly linked. It is faster to single-link them, and since chunks are never removed from the middles of these lists, double linking is not necessary. Also, unlike regular bins, they are not even processed in FIFO order (they use faster LIFO) since ordering doesn't much matter in the transient contexts in which fastbins are normally used. Chunks in fastbins keep their inuse bit set, so they cannot be consolidated with other free chunks. malloc_consolidate releases all chunks in fastbins and consolidates them with other free chunks. */ typedef struct malloc_chunk *mfastbinptr; #define fastbin(ar_ptr, idx) ((ar_ptr)->fastbinsY[idx]) /* offset 2 to use otherwise unindexable first 2 bins */ #define fastbin_index(sz) \ ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2) /* The maximum fastbin request size we support */ #define MAX_FAST_SIZE (80 * SIZE_SZ / 4) #define NFASTBINS (fastbin_index (request2size (MAX_FAST_SIZE)) + 1) ```
Adicionar um exemplo de chunk fastbin ```c #include #include int main(void) { char *chunks[8]; int i; // Loop to allocate memory 8 times for (i = 0; i < 8; i++) { chunks[i] = malloc(24); if (chunks[i] == NULL) { // Check if malloc failed fprintf(stderr, "Memory allocation failed at iteration %d\n", i); return 1; } printf("Address of chunk %d: %p\n", i, (void *)chunks[i]); } // Loop to free the allocated memory for (i = 0; i < 8; i++) { free(chunks[i]); } return 0; } ``` Observe como alocamos e liberamos 8 pedaรงos do mesmo tamanho para que preencham o tcache e o oitavo seja armazenado no fast chunk. Compile e depure com um breakpoint no opcode `ret` da funรงรฃo `main`. Em seguida, com o `gef`, vocรช pode ver que o bin tcache estรก cheio e um pedaรงo estรก no fast bin: ```bash gefโžค heap bins โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Tcachebins for thread 1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Tcachebins[idx=0, size=0x20, count=7] โ† Chunk(addr=0xaaaaaaac1770, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac1750, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac1730, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac1710, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac16f0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac16d0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Fastbins for arena at 0xfffff7f90b00 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Fastbins[idx=0, size=0x20] โ† Chunk(addr=0xaaaaaaac1790, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) Fastbins[idx=1, size=0x30] 0x00 ```
### Bin nรฃo ordenado O bin nรฃo ordenado รฉ um **cache** usado pelo gerenciador de heap para tornar a alocaรงรฃo de memรณria mais rรกpida. Veja como funciona: Quando um programa libera um pedaรงo de memรณria e se esse pedaรงo nรฃo pode ser alocado em um tcache ou fast bin e nรฃo estรก colidindo com o chunk superior, o gerenciador de heap nรฃo o coloca imediatamente em um bin especรญfico pequeno ou grande. Em vez disso, ele primeiro tenta **fundir com quaisquer chunks livres vizinhos** para criar um bloco maior de memรณria livre. Em seguida, ele coloca esse novo chunk em um bin geral chamado "bin nรฃo ordenado". Quando um programa **solicita memรณria**, o gerenciador de heap **verifica o bin nรฃo ordenado** para ver se hรก um chunk de tamanho suficiente. Se encontrar, ele o utiliza imediatamente. Se nรฃo encontrar um chunk adequado no bin nรฃo ordenado, ele move todos os chunks nesta lista para seus bins correspondentes, seja pequeno ou grande, com base em seu tamanho. Observe que se um chunk maior for dividido em 2 metades e o restante for maior que MINSIZE, ele serรก colocado de volta no bin nรฃo ordenado. Portanto, o bin nรฃo ordenado รฉ uma maneira de acelerar a alocaรงรฃo de memรณria reutilizando rapidamente a memรณria liberada recentemente e reduzindo a necessidade de pesquisas e fusรตes demoradas. {% hint style="danger" %} Observe que mesmo que os chunks sejam de categorias diferentes, se um chunk disponรญvel estiver colidindo com outro chunk disponรญvel (mesmo que originalmente pertenรงam a bins diferentes), eles serรฃo fundidos. {% endhint %}
Adicionar um exemplo de chunk nรฃo ordenado ```c #include #include int main(void) { char *chunks[9]; int i; // Loop to allocate memory 8 times for (i = 0; i < 9; i++) { chunks[i] = malloc(0x100); if (chunks[i] == NULL) { // Check if malloc failed fprintf(stderr, "Memory allocation failed at iteration %d\n", i); return 1; } printf("Address of chunk %d: %p\n", i, (void *)chunks[i]); } // Loop to free the allocated memory for (i = 0; i < 8; i++) { free(chunks[i]); } return 0; } ``` Observe como alocamos e liberamos 9 pedaรงos do mesmo tamanho para que **preencham o tcache** e o oitavo seja armazenado no unsorted bin porque รฉ **muito grande para o fastbin** e o nono nรฃo รฉ liberado, entรฃo o nono e o oitavo **nรฃo sรฃo mesclados com o top chunk**. Compile e depure com um breakpoint no opcode `ret` da funรงรฃo `main`. Em seguida, com o `gef`, vocรช pode ver que o bin tcache estรก cheio e um pedaรงo estรก no unsorted bin: ```bash gefโžค heap bins โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Tcachebins for thread 1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Tcachebins[idx=15, size=0x110, count=7] โ† Chunk(addr=0xaaaaaaac1d10, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac1c00, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac1af0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac19e0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac18d0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac17c0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac12a0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Fastbins for arena at 0xfffff7f90b00 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Fastbins[idx=0, size=0x20] 0x00 Fastbins[idx=1, size=0x30] 0x00 Fastbins[idx=2, size=0x40] 0x00 Fastbins[idx=3, size=0x50] 0x00 Fastbins[idx=4, size=0x60] 0x00 Fastbins[idx=5, size=0x70] 0x00 Fastbins[idx=6, size=0x80] 0x00 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Unsorted Bin for arena at 0xfffff7f90b00 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ [+] unsorted_bins[0]: fw=0xaaaaaaac1e10, bk=0xaaaaaaac1e10 โ†’ Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) [+] Found 1 chunks in unsorted bin. ```
### Bins Pequenos Os bins pequenos sรฃo mais rรกpidos do que os bins grandes, mas mais lentos do que os bins rรกpidos. Cada bin dos 62 terรก **pedaรงos do mesmo tamanho**: 16, 24, ... (com um tamanho mรกximo de 504 bytes em 32 bits e 1024 em 64 bits). Isso ajuda na velocidade de encontrar o bin onde um espaรงo deve ser alocado e na inserรงรฃo e remoรงรฃo de entradas nessas listas. Assim รฉ calculado o tamanho do bin pequeno de acordo com o รญndice do bin: * Menor tamanho: 2\*4\*รญndice (por exemplo, รญndice 5 -> 40) * Maior tamanho: 2\*8\*รญndice (por exemplo, รญndice 5 -> 80) ```c // From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711 #define NSMALLBINS 64 #define SMALLBIN_WIDTH MALLOC_ALIGNMENT #define SMALLBIN_CORRECTION (MALLOC_ALIGNMENT > CHUNK_HDR_SZ) #define MIN_LARGE_SIZE ((NSMALLBINS - SMALLBIN_CORRECTION) * SMALLBIN_WIDTH) #define in_smallbin_range(sz) \ ((unsigned long) (sz) < (unsigned long) MIN_LARGE_SIZE) #define smallbin_index(sz) \ ((SMALLBIN_WIDTH == 16 ? (((unsigned) (sz)) >> 4) : (((unsigned) (sz)) >> 3))\ + SMALLBIN_CORRECTION) ``` Funรงรฃo para escolher entre bins pequenos e grandes: ```c #define bin_index(sz) \ ((in_smallbin_range (sz)) ? smallbin_index (sz) : largebin_index (sz)) ```
Adicionar um exemplo de pequeno chunk ```c #include #include int main(void) { char *chunks[10]; int i; // Loop to allocate memory 8 times for (i = 0; i < 9; i++) { chunks[i] = malloc(0x100); if (chunks[i] == NULL) { // Check if malloc failed fprintf(stderr, "Memory allocation failed at iteration %d\n", i); return 1; } printf("Address of chunk %d: %p\n", i, (void *)chunks[i]); } // Loop to free the allocated memory for (i = 0; i < 8; i++) { free(chunks[i]); } chunks[9] = malloc(0x110); return 0; } ``` Observe como alocamos e liberamos 9 pedaรงos do mesmo tamanho para que **preencham o tcache** e o oitavo seja armazenado no unsorted bin porque รฉ **muito grande para o fastbin** e o nono nรฃo รฉ liberado, entรฃo o nono e o oitavo **nรฃo sรฃo mesclados com o top chunk**. Em seguida, alocamos um pedaรงo maior de 0x110, o que faz com que **o pedaรงo no unsorted bin vรก para o small bin**. Compile e depure com um breakpoint no opcode `ret` da funรงรฃo `main`. Em seguida, com o `gef`, vocรช pode ver que o bin tcache estรก cheio e um pedaรงo estรก no small bin: ```bash gefโžค heap bins โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Tcachebins for thread 1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Tcachebins[idx=15, size=0x110, count=7] โ† Chunk(addr=0xaaaaaaac1d10, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac1c00, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac1af0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac19e0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac18d0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac17c0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† Chunk(addr=0xaaaaaaac12a0, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Fastbins for arena at 0xfffff7f90b00 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Fastbins[idx=0, size=0x20] 0x00 Fastbins[idx=1, size=0x30] 0x00 Fastbins[idx=2, size=0x40] 0x00 Fastbins[idx=3, size=0x50] 0x00 Fastbins[idx=4, size=0x60] 0x00 Fastbins[idx=5, size=0x70] 0x00 Fastbins[idx=6, size=0x80] 0x00 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Unsorted Bin for arena at 0xfffff7f90b00 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ [+] Found 0 chunks in unsorted bin. โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Small Bins for arena at 0xfffff7f90b00 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ [+] small_bins[16]: fw=0xaaaaaaac1e10, bk=0xaaaaaaac1e10 โ†’ Chunk(addr=0xaaaaaaac1e20, size=0x110, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) [+] Found 1 chunks in 1 small non-empty bins. ```
### Bins grandes Ao contrรกrio dos bins pequenos, que gerenciam pedaรงos de tamanhos fixos, cada **bin grande lida com uma faixa de tamanhos de pedaรงos**. Isso รฉ mais flexรญvel, permitindo que o sistema acomode **vรกrios tamanhos** sem precisar de um bin separado para cada tamanho. Em um alocador de memรณria, os bins grandes comeรงam onde os bins pequenos terminam. As faixas para os bins grandes crescem progressivamente, o que significa que o primeiro bin pode abranger pedaรงos de 512 a 576 bytes, enquanto o prรณximo abrange de 576 a 640 bytes. Esse padrรฃo continua, com o bin maior contendo todos os pedaรงos acima de 1MB. Os bins grandes sรฃo mais lentos de operar em comparaรงรฃo com os bins pequenos porque eles precisam **ordenar e pesquisar em uma lista de tamanhos de pedaรงos variados para encontrar o melhor encaixe** para uma alocaรงรฃo. Quando um pedaรงo รฉ inserido em um bin grande, ele precisa ser ordenado, e quando a memรณria รฉ alocada, o sistema deve encontrar o pedaรงo certo. Esse trabalho extra os torna **mais lentos**, mas como alocaรงรตes grandes sรฃo menos comuns do que as pequenas, รฉ uma troca aceitรกvel. Existem: * 32 bins de 64B de faixa (colidem com os bins pequenos) * 16 bins de 512B de faixa (colidem com os bins pequenos) * 8 bins de 4096B de faixa (parte colide com os bins pequenos) * 4 bins de 32768B de faixa * 2 bins de 262144B de faixa * 1 bin para tamanhos restantes
Cรณdigo dos tamanhos dos bins grandes ```c // From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711 #define largebin_index_32(sz) \ (((((unsigned long) (sz)) >> 6) <= 38) ? 56 + (((unsigned long) (sz)) >> 6) :\ ((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\ ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\ ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\ ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\ 126) #define largebin_index_32_big(sz) \ (((((unsigned long) (sz)) >> 6) <= 45) ? 49 + (((unsigned long) (sz)) >> 6) :\ ((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\ ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\ ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\ ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\ 126) // XXX It remains to be seen whether it is good to keep the widths of // XXX the buckets the same or whether it should be scaled by a factor // XXX of two as well. #define largebin_index_64(sz) \ (((((unsigned long) (sz)) >> 6) <= 48) ? 48 + (((unsigned long) (sz)) >> 6) :\ ((((unsigned long) (sz)) >> 9) <= 20) ? 91 + (((unsigned long) (sz)) >> 9) :\ ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\ ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\ ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\ 126) #define largebin_index(sz) \ (SIZE_SZ == 8 ? largebin_index_64 (sz) \ : MALLOC_ALIGNMENT == 16 ? largebin_index_32_big (sz) \ : largebin_index_32 (sz)) ```
Adicione um exemplo de grande bloco ```c #include #include int main(void) { char *chunks[2]; chunks[0] = malloc(0x1500); chunks[1] = malloc(0x1500); free(chunks[0]); chunks[0] = malloc(0x2000); return 0; } ``` Duas grandes alocaรงรตes sรฃo realizadas, em seguida uma รฉ liberada (colocando-a no bin nรฃo ordenado) e uma alocaรงรฃo maior รฉ feita (movendo a liberada do bin nรฃo ordenado para o bin grande). Compile e depure com um breakpoint no opcode `ret` da funรงรฃo `main`. Entรฃo com `gef` vocรช pode ver que o bin tcache estรก cheio e um chunk estรก no bin grande: ```bash gefโžค heap bin โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Tcachebins for thread 1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ All tcachebins are empty โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Fastbins for arena at 0xfffff7f90b00 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Fastbins[idx=0, size=0x20] 0x00 Fastbins[idx=1, size=0x30] 0x00 Fastbins[idx=2, size=0x40] 0x00 Fastbins[idx=3, size=0x50] 0x00 Fastbins[idx=4, size=0x60] 0x00 Fastbins[idx=5, size=0x70] 0x00 Fastbins[idx=6, size=0x80] 0x00 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Unsorted Bin for arena at 0xfffff7f90b00 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ [+] Found 0 chunks in unsorted bin. โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Small Bins for arena at 0xfffff7f90b00 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ [+] Found 0 chunks in 0 small non-empty bins. โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Large Bins for arena at 0xfffff7f90b00 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ [+] large_bins[100]: fw=0xaaaaaaac1290, bk=0xaaaaaaac1290 โ†’ Chunk(addr=0xaaaaaaac12a0, size=0x1510, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) [+] Found 1 chunks in 1 large non-empty bins. ```
### Maior Fragmento ```c // From https://github.com/bminor/glibc/blob/a07e000e82cb71238259e674529c37c12dc7d423/malloc/malloc.c#L1711 /* Top The top-most available chunk (i.e., the one bordering the end of available memory) is treated specially. It is never included in any bin, is used only if no other chunk is available, and is released back to the system if it is very large (see M_TRIM_THRESHOLD). Because top initially points to its own bin with initial zero size, thus forcing extension on the first malloc request, we avoid having any special code in malloc to check whether it even exists yet. But we still need to do so when getting memory from system, so we make initial_top treat the bin as a legal but unusable chunk during the interval between initialization and the first call to sysmalloc. (This is somewhat delicate, since it relies on the 2 preceding words to be zero during this interval as well.) */ /* Conveniently, the unsorted bin can be used as dummy top on first call */ #define initial_top(M) (unsorted_chunks (M)) ``` Basicamente, este รฉ um pedaรงo contendo toda a heap atualmente disponรญvel. Quando um malloc รฉ executado, se nรฃo houver nenhum pedaรงo livre disponรญvel para usar, este pedaรงo superior reduzirรก seu tamanho fornecendo o espaรงo necessรกrio. O ponteiro para o Top Chunk รฉ armazenado na estrutura `malloc_state`. Alรฉm disso, no inรญcio, รฉ possรญvel usar o pedaรงo nรฃo ordenado como o pedaรงo superior.
Observe o exemplo do Top Chunk ```c #include #include int main(void) { char *chunk; chunk = malloc(24); printf("Address of the chunk: %p\n", (void *)chunk); gets(chunk); return 0; } ``` Depois de compilar e depurar com um ponto de interrupรงรฃo no opcode `ret` de `main`, vi que o malloc retornou o endereรงo `0xaaaaaaac12a0` e estes sรฃo os chunks: ```bash gefโžค heap chunks Chunk(addr=0xaaaaaaac1010, size=0x290, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) [0x0000aaaaaaac1010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................] Chunk(addr=0xaaaaaaac12a0, size=0x20, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) [0x0000aaaaaaac12a0 41 41 41 41 41 41 41 00 00 00 00 00 00 00 00 00 AAAAAAA.........] Chunk(addr=0xaaaaaaac12c0, size=0x410, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) [0x0000aaaaaaac12c0 41 64 64 72 65 73 73 20 6f 66 20 74 68 65 20 63 Address of the c] Chunk(addr=0xaaaaaaac16d0, size=0x410, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) [0x0000aaaaaaac16d0 41 41 41 41 41 41 41 0a 00 00 00 00 00 00 00 00 AAAAAAA.........] Chunk(addr=0xaaaaaaac1ae0, size=0x20530, flags=PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA) โ† top chunk ``` Onde pode ser visto que o chunk superior estรก no endereรงo `0xaaaaaaac1ae0`. Isso nรฃo รฉ surpresa porque o รบltimo chunk alocado estava em `0xaaaaaaac12a0` com um tamanho de `0x410` e `0xaaaaaaac12a0 + 0x410 = 0xaaaaaaac1ae0`.\ Tambรฉm รฉ possรญvel ver o tamanho do chunk superior no seu cabeรงalho de chunk: ```bash gefโžค x/8wx 0xaaaaaaac1ae0 - 16 0xaaaaaaac1ad0: 0x00000000 0x00000000 0x00020531 0x00000000 0xaaaaaaac1ae0: 0x00000000 0x00000000 0x00000000 0x00000000 ```
### รšltimo Resto Quando o malloc รฉ usado e um chunk รฉ dividido (do unsorted bin ou do top chunk, por exemplo), o chunk criado a partir do restante do chunk dividido รฉ chamado de รšltimo Resto e seu ponteiro รฉ armazenado na estrutura `malloc_state`. ## Fluxo de Alocaรงรฃo Confira: {% content-ref url="heap-memory-functions/malloc-and-sysmalloc.md" %} [malloc-and-sysmalloc.md](heap-memory-functions/malloc-and-sysmalloc.md) {% endcontent-ref %} ## Fluxo de Liberaรงรฃo Confira: {% content-ref url="heap-memory-functions/free.md" %} [free.md](heap-memory-functions/free.md) {% endcontent-ref %} ## Verificaรงรตes de Seguranรงa das Funรงรตes de Heap Verifique as verificaรงรตes de seguranรงa realizadas por funรงรตes amplamente utilizadas no heap em: {% content-ref url="heap-memory-functions/heap-functions-security-checks.md" %} [heap-functions-security-checks.md](heap-memory-functions/heap-functions-security-checks.md) {% endcontent-ref %} ## Referรชncias * [https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/](https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/) * [https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/](https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/) * [https://heap-exploitation.dhavalkapil.com/diving\_into\_glibc\_heap/core\_functions](https://heap-exploitation.dhavalkapil.com/diving\_into\_glibc\_heap/core\_functions) * [https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/implementation/tcache/](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/implementation/tcache/) {% hint style="success" %} Aprenda e pratique Hacking AWS:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ Aprenda e pratique Hacking GCP: [**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
Suporte ao HackTricks * Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)! * **Junte-se ao** ๐Ÿ’ฌ [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** ๐Ÿฆ [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.** * **Compartilhe truques de hacking enviando PRs para os repositรณrios** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
{% endhint %}