mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-22 20:53:37 +00:00
618 lines
47 KiB
Markdown
618 lines
47 KiB
Markdown
# Bins & Εκχωρήσεις Μνήμης
|
||
|
||
{% hint style="success" %}
|
||
Μάθετε & εξασκηθείτε στο AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**Εκπαίδευση HackTricks AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
|
||
Μάθετε & εξασκηθείτε στο GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**Εκπαίδευση HackTricks GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||
|
||
<details>
|
||
|
||
<summary>Υποστηρίξτε το HackTricks</summary>
|
||
|
||
* Ελέγξτε τα [**σχέδια συνδρομής**](https://github.com/sponsors/carlospolop)!
|
||
* **Εγγραφείτε** στην 💬 [**ομάδα Discord**](https://discord.gg/hRep4RUj7f) ή στην [**ομάδα telegram**](https://t.me/peass) ή **ακολουθήστε** μας στο **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
* **Κοινοποιήστε κόλπα χάκερ υποβάλλοντας PRs** στα αποθετήρια [**HackTricks**](https://github.com/carlospolop/hacktricks) και [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) στο GitHub.
|
||
|
||
</details>
|
||
{% endhint %}
|
||
|
||
## Βασικές Πληροφορίες
|
||
|
||
Για να βελτιώσουμε την αποδοτικότητα στον τρόπο αποθήκευσης των κομματιών, κάθε κομμάτι δεν βρίσκεται μόνο σε μία συνδεδεμένη λίστα, αλλά υπάρχουν διάφοροι τύποι. Αυτοί είναι οι bins και υπάρχουν 5 τύποι bins: [62](https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=malloc/malloc.c;h=6e766d11bc85b6480fa5c9f2a76559f8acf9deb5;hb=HEAD#l1407) μικροί bins, 63 μεγάλοι bins, 1 unsorted bin, 10 fast bins και 64 tcache bins ανά thread.
|
||
|
||
Η αρχική διεύθυνση για κάθε unsorted, μικρό και μεγάλο bin βρίσκεται μέσα στον ίδιο πίνακα. Το δείκτης 0 δεν χρησιμοποιείται, το 1 είναι το unsorted bin, τα bins 2-64 είναι μικροί bins και τα bins 65-127 είναι μεγάλοι bins.
|
||
|
||
### Tcache (Αποθήκη Ανά Thread)
|
||
|
||
Ακόμα κι αν τα threads προσπαθούν να έχουν το δικό τους heap (δείτε [Αρένες](bins-and-memory-allocations.md#arenas) και [Υπο-σωροί](bins-and-memory-allocations.md#subheaps)), υπάρχει η πιθανότητα ότι ένας διεργασία με πολλά threads (όπως ένας web server) **θα μοιραστεί το heap με άλλα threads**. Σε αυτήν την περίπτωση, η κύρια λύση είναι η χρήση **κλειδαριών**, οι οποίες μπορεί **να επιβραδύνουν σημαντικά τα threads**.
|
||
|
||
Επομένως, ένα tcache είναι παρόμοιο με ένα fast bin ανά thread στον τρόπο που είναι μια **μονόδρομη συνδεδεμένη λίστα** που δεν ενώνει κομμάτια. Κάθε thread έχει **64 μονόδρομους tcache bins**. Κάθε bin μπορεί να έχει ένα μέγιστο των [7 κομματιών ίδιου μεγέθους](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l323) κυμαίνονται από [24 έως 1032B σε 64-bit συστήματα και 12 έως 516B σε 32-bit συστήματα](https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=2527e2504761744df2bdb1abdc02d936ff907ad2;hb=d5c3fafc4307c9b7a4c7d5cb381fcdbfad340bcc#l315).
|
||
|
||
**Όταν ένα thread απελευθερώνει** ένα κομμάτι, **αν δεν είναι πολύ μεγάλο** για να εκχωρηθεί στο tcache και το αντίστοιχο tcache bin **δεν είναι γεμάτο** (ήδη 7 κομμάτια), **θα εκχωρηθεί εκεί**. Αν δεν μπορεί να πάει στο tcache, θα πρέπει να περιμένει το κλείδωμα του heap για να μπορέσει να εκτελέσει την πράξη απελευθέρωσης παγκοσμίως.
|
||
|
||
Όταν ένα **κομμάτι εκχωρείται**, αν υπάρχει ένα ελεύθερο κομμάτι του απαιτούμενου μεγέθους στο **Tcache θα το χρησιμοποιήσει**, αν όχι, θα πρέπει να περιμένει το κλείδωμα του heap για να βρει ένα στα γενικά bins ή να δημιουργήσει ένα νέο.\
|
||
Υπάρχει επίσης μια βελτιστοποίηση, σε αυτήν την περίπτωση, ενώ έχει το κλείδωμα του heap, το thread **θα γεμίσει το Tcache του με κομμάτια heap (7) του απαιτούμενου μεγέθους**, έτσι ώστε σε περίπτωση που χρειαστεί περισσότερα, θα τα βρει στο Tcache.
|
||
|
||
<details>
|
||
|
||
<summary>Προσθέστε ένα παράδειγμα του tcache chunk</summary>
|
||
```c
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
|
||
int main(void)
|
||
{
|
||
char *chunk;
|
||
chunk = malloc(24);
|
||
printf("Address of the chunk: %p\n", (void *)chunk);
|
||
gets(chunk);
|
||
free(chunk);
|
||
return 0;
|
||
}
|
||
```
|
||
Μεταγλωτίστε το και αποσφαλματώστε το με ένα σημείο ανακοπής στον κωδικό επιστροφής (ret opcode) από την κύρια συνάρτηση (main function). Στη συνέχεια, με το gef μπορείτε να δείτε το tcache bin που χρησιμοποιείται:
|
||
```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)
|
||
```
|
||
#### Δομές & Συναρτήσεις Tcache
|
||
|
||
Στον παρακάτω κώδικα είναι δυνατόν να δούμε τα **max bins** και **chunks ανά index**, τη δομή **`tcache_entry`** που δημιουργήθηκε για να αποφευχθούν οι διπλές απελευθερώσεις και τη **`tcache_perthread_struct`**, μια δομή που κάθε νήμα χρησιμοποιεί για να αποθηκεύσει τις διευθύνσεις σε κάθε index του bin.
|
||
```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;
|
||
```
|
||
</details>
|
||
|
||
Η συνάρτηση `__tcache_init` είναι η συνάρτηση που δημιουργεί και εκχωρεί τον χώρο για το αντικείμενο `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));
|
||
}
|
||
|
||
}
|
||
```
|
||
</details>
|
||
|
||
#### Δείκτες Tcache
|
||
|
||
Το tcache έχει αρκετούς κάδους ανάλογα με το μέγεθος και οι αρχικοί δείκτες προς το **πρώτο κομμάτι κάθε δείκτη και η ποσότητα των κομματιών ανά δείκτη βρίσκονται μέσα σε ένα κομμάτι**. Αυτό σημαίνει ότι εντοπίζοντας το κομμάτι με αυτές τις πληροφορίες (συνήθως το πρώτο), είναι δυνατό να βρεθούν όλοι οι αρχικοί δείκτες tcache και η ποσότητα των κομματιών Tcache.
|
||
|
||
### Γρήγοροι κάδοι
|
||
|
||
Οι γρήγοροι κάδοι σχεδιάστηκαν για να **επιταχύνουν την εκχώρηση μνήμης για μικρά κομμάτια** κρατώντας πρόσφατα ελευθερωμένα κομμάτια σε μια δομή γρήγορης πρόσβασης. Αυτοί οι κάδοι χρησιμοποιούν μια προσέγγιση Τελευταίο Εισερχόμενο, Πρώτο Εξερχόμενο (LIFO), που σημαίνει ότι το **πιο πρόσφατα ελευθερωμένο κομμάτι είναι το πρώτο** που θα χρησιμοποιηθεί όταν υπάρχει αίτηση για νέα εκχώρηση. Αυτή η συμπεριφορά είναι επωφελής για την ταχύτητα, καθώς είναι πιο γρήγορο να εισάγετε και να αφαιρέσετε από την κορυφή ενός στοίβας (LIFO) σε σύγκριση με μια ουρά (FIFO).
|
||
|
||
Επιπλέον, **οι γρήγοροι κάδοι χρησιμοποιούν μονόδεσμες λίστες**, όχι διπλές, οι οποίες βελτιώνουν περαιτέρω την ταχύτητα. Δεδομένου ότι τα κομμάτια στους γρήγορους κάδους δεν συγχωνεύονται με γείτονες, δεν χρειάζεται μια πολύπλοκη δομή που επιτρέπει την αφαίρεση από τη μέση. Μια μονόδεσμη λίστα είναι απλούστερη και ταχύτερη για αυτές τις λειτουργίες.
|
||
|
||
Βασικά, αυτό που συμβαίνει εδώ είναι ότι η κεφαλίδα (ο δείκτης προς το πρώτο κομμάτι για έλεγχο) δείχνει πάντα στο πιο πρόσφατα ελευθερωμένο κομμάτι αυτού του μεγέθους. Έτσι:
|
||
|
||
* Όταν εκχωρηθεί ένα νέο κομμάτι αυτού του μεγέθους, η κεφαλίδα δείχνει σε ένα ελεύθερο κομμάτι για χρήση. Δεδομένου ότι αυτό το ελεύθερο κομμάτι δείχνει στο επόμενο που θα χρησιμοποιηθεί, αυτή η διεύθυνση αποθηκεύεται στην κεφαλίδα ώστε η επόμενη εκχώρηση να ξέρει πού να βρει ένα διαθέσιμο κομμάτι
|
||
* Όταν ένα κομμάτι ελευθερώνεται, το ελεύθερο κομμάτι θα αποθηκεύσει τη διεύθυνση του τρέχοντος διαθέσιμου κομματιού και η διεύθυνση αυτού του νεοελευθερωμένου κομματιού θα τεθεί στην κεφαλίδα
|
||
|
||
Το μέγιστο μέγεθος μιας συνδεδεμένης λίστας είναι `0x80` και οργανώνονται έτσι ώστε ένα κομμάτι μεγέθους `0x20` θα βρίσκεται στον δείκτη `0`, ένα κομμάτι μεγέθους `0x30` θα βρίσκεται στον δείκτη `1`...
|
||
|
||
{% hint style="danger" %}
|
||
Τα κομμάτια στους γρήγορους κάδους δεν ορίζονται ως διαθέσιμα, έτσι διατηρούνται ως κομμάτια γρήγορων κάδων για κάποιο χρονικό διάστημα αντί να είναι σε θέση να συγχωνευτούν με άλλα ελεύθερα κομμάτια που τα περιβάλλουν.
|
||
{% 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)
|
||
```
|
||
<details>
|
||
|
||
<summary>Προσθέστε ένα παράδειγμα γρήγορου κομματιού (fastbin chunk)</summary>
|
||
```c
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
|
||
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;
|
||
}
|
||
```
|
||
Σημειώστε πως εκχωρούμε και απελευθερώνουμε 8 τμήματα με τον ίδιο μέγεθος έτσι ώστε να γεμίσει το tcache και το όγδοο να αποθηκευτεί στο fast chunk.
|
||
|
||
Μεταγλωττίστε το και αποσφαλματώστε το με ένα σημείο αναμονής στον κώδικα `ret` από τη συνάρτηση `main`. Στη συνέχεια, με το `gef` μπορείτε να δείτε ότι το tcache bin είναι γεμάτο και ένα τμήμα βρίσκεται στο 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
|
||
```
|
||
</details>
|
||
|
||
### Μη ταξινομημένος κάδος
|
||
|
||
Ο μη ταξινομημένος κάδος είναι ένας **cache** που χρησιμοποιείται από τον διαχειριστή σωρού για να κάνει την εκχώρηση μνήμης πιο γρήγορη. Έτσι λειτουργεί: Όταν ένα πρόγραμμα απελευθερώνει ένα κομμάτι, και αν αυτό το κομμάτι δεν μπορεί να εκχωρηθεί σε έναν tcache ή fast bin και δεν συγκρούεται με το κομμάτι κορυφής, ο διαχειριστής σωρού δεν το τοποθετεί αμέσως σε ένα συγκεκριμένο μικρό ή μεγάλο κάδο. Αντίθετα, πρώτα προσπαθεί να **συγχωνεύσει το με κάποια γειτονικά ελεύθερα κομμάτια** για να δημιουργήσει ένα μεγαλύτερο τμήμα ελεύθερης μνήμης. Στη συνέχεια, τοποθετεί αυτό το νέο κομμάτι σε ένα γενικό κάδο που ονομάζεται "μη ταξινομημένος κάδος".
|
||
|
||
Όταν ένα πρόγραμμα **ζητά μνήμη**, ο διαχειριστής σωρού **ελέγχει τον μη ταξινομημένο κάδο** για να δει αν υπάρχει ένα κομμάτι αρκετού μεγέθους. Αν βρει ένα, το χρησιμοποιεί αμέσως. Αν δε βρει ένα κατάλληλο κομμάτι στον μη ταξινομημένο κάδο, μεταφέρει όλα τα κομμάτια σε αυτή τη λίστα στους αντίστοιχους τους κάδους, είτε μικρούς είτε μεγάλους, με βάση το μέγεθός τους.
|
||
|
||
Σημειώστε ότι αν ένα μεγαλύτερο κομμάτι χωριστεί σε 2 μισά και το υπόλοιπο είναι μεγαλύτερο από το MINSIZE, θα τοποθετηθεί πίσω στον μη ταξινομημένο κάδο.
|
||
|
||
Έτσι, ο μη ταξινομημένος κάδος είναι ένας τρόπος για ταχεία εκχώρηση μνήμης με την ταχεία επαναχρησιμοποίηση πρόσφατα απελευθερωμένης μνήμης και τη μείωση της ανάγκης για χρονοβόρες αναζητήσεις και συγχωνεύσεις.
|
||
|
||
{% hint style="danger" %}
|
||
Σημειώστε ότι ακόμα κι αν τα κομμάτια ανήκουν σε διαφορετικές κατηγορίες, αν ένα διαθέσιμο κομμάτι συγκρούεται με ένα άλλο διαθέσιμο κομμάτι (ακόμα κι αν αρχικά ανήκουν σε διαφορετικούς κάδους), θα συγχωνευτούν.
|
||
{% endhint %}
|
||
|
||
<details>
|
||
|
||
<summary>Προσθέστε ένα παράδειγμα μη ταξινομημένου κομματιού</summary>
|
||
```c
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
|
||
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;
|
||
}
|
||
```
|
||
Σημειώστε πώς εκχωρούμε και απελευθερώνουμε 9 τμήματα του ίδιου μεγέθους έτσι ώστε **να γεμίσουν το tcache** και το όγδοο να αποθηκευτεί στο unsorted bin επειδή είναι **πολύ μεγάλο για το fastbin** και το ένατο δεν απελευθερώνεται έτσι το ένατο και το όγδοο **δεν συγχωνεύονται με το top chunk**.
|
||
|
||
Μεταγλωττίστε το και αποσφαλματώστε το με ένα σημείο αναμονής στον κώδικα `ret` από τη συνάρτηση `main`. Στη συνέχεια, με το `gef` μπορείτε να δείτε ότι το tcache bin είναι γεμάτο και ένα τμήμα βρίσκεται στο 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.
|
||
```
|
||
</details>
|
||
|
||
### Μικροί Bins
|
||
|
||
Οι μικροί bins είναι ταχύτεροι από τους μεγάλους bins αλλά πιο αργοί από τους γρήγορους bins.
|
||
|
||
Κάθε bin από τα 62 θα έχει **chunks του ίδιου μεγέθους**: 16, 24, ... (με μέγιστο μέγεθος 504 bytes σε 32bits και 1024 σε 64bits). Αυτό βοηθάει στην ταχύτητα εντοπισμού του bin όπου θα πρέπει να γίνει εκχώρηση χώρου και στην εισαγωγή και αφαίρεση καταχωρίσεων σε αυτές τις λίστες.
|
||
|
||
Έτσι υπολογίζεται το μέγεθος του μικρού bin ανάλογα με το δείκτη του bin:
|
||
|
||
* Μικρότερο μέγεθος: 2\*4\*δείκτης (π.χ. δείκτης 5 -> 40)
|
||
* Μεγαλύτερο μέγεθος: 2\*8\*δείκτης (π.χ. δείκτης 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)
|
||
```
|
||
Συνάρτηση για την επιλογή μεταξύ μικρών και μεγάλων κάδων:
|
||
```c
|
||
#define bin_index(sz) \
|
||
((in_smallbin_range (sz)) ? smallbin_index (sz) : largebin_index (sz))
|
||
```
|
||
<details>
|
||
|
||
<summary>Προσθέστε ένα παράδειγμα μικρού κομματιού</summary>
|
||
```c
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
|
||
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;
|
||
}
|
||
```
|
||
Σημειώστε πώς εκχωρούμε και απελευθερώνουμε 9 τμήματα με τον ίδιο μέγεθος έτσι ώστε **να γεμίσει το tcache** και το όγδοο αποθηκεύεται στον unsorted κάδο επειδή είναι **πολύ μεγάλο για το fastbin** και το ένατο δεν είναι ελεύθερο, έτσι το όγδοο και το ένατο **δεν συγχωνεύονται με το top chunk**. Στη συνέχεια εκχωρούμε ένα μεγαλύτερο τμήμα μεγέθους 0x110 το οποίο κάνει **το τμήμα στον unsorted κάδο να πάει στον small κάδο**.
|
||
|
||
Μεταγλωττίστε το και αποσφαλματώστε το με ένα σημείο διακοπής στον κώδικα `ret` από τη συνάρτηση `main`. Στη συνέχεια, με το `gef` μπορείτε να δείτε ότι ο tcache κάδος είναι γεμάτος και ένα τμήμα βρίσκεται στον small κάδο:
|
||
```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.
|
||
```
|
||
</details>
|
||
|
||
### Μεγάλοι κάδοι
|
||
|
||
Αντίθετα με τους μικρούς κάδους, οι οποίοι διαχειρίζονται κομμάτια με σταθερούς μεγέθη, **κάθε μεγάλος κάδος χειρίζεται ένα εύρος μεγεθών κομματιών**. Αυτό είναι πιο ευέλικτο, επιτρέποντας στο σύστημα να φιλοξενεί **διάφορα μεγέθη** χωρίς την ανάγκη για έναν ξεχωριστό κάδο για κάθε μέγεθος.
|
||
|
||
Σε έναν διαχειριστή μνήμης, οι μεγάλοι κάδοι ξεκινούν από το σημείο που τελειώνουν οι μικροί κάδοι. Τα εύρη των μεγάλων κάδων μεγαλώνουν σταδιακά, πράγμα που σημαίνει ότι ο πρώτος κάδος μπορεί να καλύπτει κομμάτια από 512 έως 576 bytes, ενώ ο επόμενος καλύπτει από 576 έως 640 bytes. Αυτό το πρότυπο συνεχίζεται, με τον μεγαλύτερο κάδο να περιέχει όλα τα κομμάτια άνω των 1MB.
|
||
|
||
Οι μεγάλοι κάδοι είναι πιο αργοί στη λειτουργία σε σύγκριση με τους μικρούς κάδους επειδή πρέπει **να ταξινομήσουν και να αναζητήσουν μέσω μιας λίστας με διαφορετικά μεγέθη κομματιών για να βρουν την καλύτερη ταιριάστηκη** για μια δέσμευση. Όταν ένα κομμάτι εισάγεται σε έναν μεγάλο κάδο, πρέπει να ταξινομηθεί, και όταν δεσμεύεται μνήμη, το σύστημα πρέπει να βρει το σωστό κομμάτι. Αυτή η επιπλέον εργασία τους καθιστά **πιο αργούς**, αλλά αφού οι μεγάλες δεσμεύσεις είναι λιγότερο συνηθισμένες από τις μικρές, είναι μια αποδεκτή ανταλλαγή.
|
||
|
||
Υπάρχουν:
|
||
|
||
* 32 κάδοι εύρους 64B (συγκρούονται με τους μικρούς κάδους)
|
||
* 16 κάδοι εύρους 512B (συγκρούονται με τους μικρούς κάδους)
|
||
* 8 κάδοι εύρους 4096B (μέρος συγκρούεται με τους μικρούς κάδους)
|
||
* 4 κάδοι εύρους 32768B
|
||
* 2 κάδοι εύρους 262144B
|
||
* 1 κάδος για τα υπόλοιπα μεγέθη
|
||
|
||
<details>
|
||
|
||
<summary>Κώδικες μεγέθους μεγάλων κάδων</summary>
|
||
```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))
|
||
```
|
||
</details>
|
||
|
||
<details>
|
||
|
||
<summary>Προσθέστε ένα παράδειγμα μεγάλου κομματιού</summary>
|
||
```c
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
|
||
int main(void)
|
||
{
|
||
char *chunks[2];
|
||
|
||
chunks[0] = malloc(0x1500);
|
||
chunks[1] = malloc(0x1500);
|
||
free(chunks[0]);
|
||
chunks[0] = malloc(0x2000);
|
||
|
||
return 0;
|
||
}
|
||
```
|
||
Πραγματοποιούνται 2 μεγάλες δεσμεύσεις μνήμης, στη συνέχεια μια από αυτές απελευθερώνεται (τοποθετώντας τη στον unsorted κάδο) και γίνεται μια μεγαλύτερη δέσμευση μνήμης (μετακινώντας την ελεύθερη στοιχειώδη από τον unsorted κάδο στον μεγάλο κάδο).
|
||
|
||
Μεταγλωττίστε το και αποσφαλματώστε το με ένα σημείο αναμονής στην εντολή `ret` από τη συνάρτηση `main`. Στη συνέχεια, με το `gef` μπορείτε να δείτε ότι ο tcache κάδος είναι γεμάτος και ένα κομμάτι βρίσκεται στον μεγάλο κάδο:
|
||
```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.
|
||
```
|
||
</details>
|
||
|
||
### Κορυφαίο Κομμάτι
|
||
```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))
|
||
```
|
||
Βασικά, αυτό είναι ένα τμήμα που περιέχει όλο το διαθέσιμο σωρό. Όταν γίνεται μια κλήση στη συνάρτηση `malloc`, αν δεν υπάρχει κάποιο διαθέσιμο ελεύθερο τμήμα για χρήση, το τμήμα κορυφής θα μειώνει το μέγεθός του παρέχοντας τον απαραίτητο χώρο.\
|
||
Ο δείκτης προς το Τμήμα Κορυφής αποθηκεύεται στη δομή `malloc_state`.
|
||
|
||
Επιπλέον, στην αρχή, είναι δυνατόν να χρησιμοποιηθεί το τμήμα αταξινόμητων ως τμήμα κορυφής.
|
||
|
||
<details>
|
||
|
||
<summary>Παρατήρηση παραδείγματος Τμήματος Κορυφής</summary>
|
||
```c
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
|
||
int main(void)
|
||
{
|
||
char *chunk;
|
||
chunk = malloc(24);
|
||
printf("Address of the chunk: %p\n", (void *)chunk);
|
||
gets(chunk);
|
||
return 0;
|
||
}
|
||
```
|
||
Μετά τη μεταγλώττιση και αποσφαλμάτωσή του με ένα σημείο διακοπής στον κώδικα `ret` της `main`, είδα ότι το malloc επέστρεψε τη διεύθυνση `0xaaaaaaac12a0` και αυτά είναι τα 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
|
||
```
|
||
Εκεί που μπορεί να φανεί ότι το κορυφαίο κομμάτι βρίσκεται στη διεύθυνση `0xaaaaaaac1ae0`. Αυτό δεν είναι έκπληξη επειδή το τελευταίο εκχωρημένο κομμάτι ήταν στη διεύθυνση `0xaaaaaaac12a0` με μέγεθος `0x410` και `0xaaaaaaac12a0 + 0x410 = 0xaaaaaaac1ae0`.\
|
||
Είναι επίσης δυνατό να δούμε το μήκος του κορυφαίου κομματιού στην κεφαλίδα του κομματιού:
|
||
```bash
|
||
gef➤ x/8wx 0xaaaaaaac1ae0 - 16
|
||
0xaaaaaaac1ad0: 0x00000000 0x00000000 0x00020531 0x00000000
|
||
0xaaaaaaac1ae0: 0x00000000 0x00000000 0x00000000 0x00000000
|
||
```
|
||
</details>
|
||
|
||
### Τελευταίο Υπόλοιπο
|
||
|
||
Όταν χρησιμοποιείται η συνάρτηση malloc και ένα κομμάτι χωρίζεται (από τον unsorted bin ή από το top chunk για παράδειγμα), το κομμάτι που δημιουργείται από το υπόλοιπο του διαιρεμένου κομματιού ονομάζεται Τελευταίο Υπόλοιπο και ο δείκτης του αποθηκεύεται στη δομή `malloc_state`.
|
||
|
||
## Ροή Εκχώρησης
|
||
|
||
Ελέγξτε:
|
||
|
||
{% content-ref url="heap-memory-functions/malloc-and-sysmalloc.md" %}
|
||
[malloc-and-sysmalloc.md](heap-memory-functions/malloc-and-sysmalloc.md)
|
||
{% endcontent-ref %}
|
||
|
||
## Ροή Απελευθέρωσης
|
||
|
||
Ελέγξτε:
|
||
|
||
{% content-ref url="heap-memory-functions/free.md" %}
|
||
[free.md](heap-memory-functions/free.md)
|
||
{% endcontent-ref %}
|
||
|
||
## Έλεγχοι Ασφαλείας Συναρτήσεων Heap
|
||
|
||
Ελέγξτε τους έλεγχους ασφαλείας που πραγματοποιούνται από τις συναρτήσεις που χρησιμοποιούνται εκτενώς στο heap στο:
|
||
|
||
{% 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 %}
|
||
|
||
## Αναφορές
|
||
|
||
* [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" %}
|
||
Μάθετε & εξασκηθείτε στο AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**Εκπαίδευση HackTricks AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
|
||
Μάθετε & εξασκηθείτε στο GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**Εκπαίδευση HackTricks GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||
|
||
<details>
|
||
|
||
<summary>Υποστηρίξτε το HackTricks</summary>
|
||
|
||
* Ελέγξτε τα [**σχέδια συνδρομής**](https://github.com/sponsors/carlospolop)!
|
||
* **Εγγραφείτε** 💬 στην ομάδα [**Discord**](https://discord.gg/hRep4RUj7f) ή στην ομάδα [**telegram**](https://t.me/peass) ή **ακολουθήστε** μας στο **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
* **Μοιραστείτε κόλπα χάκερ υποβάλλοντας PRs στα** [**HackTricks**](https://github.com/carlospolop/hacktricks) και [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) αποθετήρια στο GitHub.
|
||
|
||
</details>
|
||
{% endhint %}
|