Bins & Memory Allocations
Reading time: 22 minutes
tip
Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za udukuzi kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
Basic Information
Ili kuboresha ufanisi wa jinsi vipande vinavyohifadhiwa, kila kipande hakiko tu katika orodha moja iliyo na uhusiano, bali kuna aina kadhaa. Hizi ni bins na kuna aina 5 za bins: 62 bins ndogo, 63 bins kubwa, 1 bin isiyo na mpangilio, 10 bins za haraka na 64 bins za tcache kwa kila thread.
Anwani ya awali kwa kila bin isiyo na mpangilio, ndogo na kubwa iko ndani ya array moja. Index 0 haitumiki, 1 ni bin isiyo na mpangilio, bins 2-64 ni bins ndogo na bins 65-127 ni bins kubwa.
Tcache (Per-Thread Cache) Bins
Ingawa nyuzi zinajaribu kuwa na heap zao (ona Arenas na Subheaps), kuna uwezekano kwamba mchakato wenye nyuzi nyingi (kama seva ya wavuti) utashiriki heap na nyuzi nyingine. Katika kesi hii, suluhisho kuu ni matumizi ya lockers, ambayo yanaweza kuchelewesha sana nyuzi.
Kwa hivyo, tcache ni sawa na bin ya haraka kwa kila thread kwa njia kwamba ni orodha moja iliyo na uhusiano ambayo haiunganishi vipande. Kila thread ina bins 64 za tcache zenye uhusiano mmoja. Kila bin inaweza kuwa na kiwango cha juu cha 7 vipande vya saizi sawa vinavyotofautiana kutoka 24 hadi 1032B kwenye mifumo ya 64-bit na 12 hadi 516B kwenye mifumo ya 32-bit.
Wakati thread inachomoa kipande, ikiwa si kikubwa sana kuweza kutengwa katika tcache na bin husika ya tcache haiwezi kuwa kamili (tayari kuna vipande 7), itawekwa hapo. Ikiwa haiwezi kuingia kwenye tcache, itahitaji kusubiri kufungwa kwa heap ili iweze kufanya operesheni ya kuachia kwa kiwango cha kimataifa.
Wakati kipande kinapowekwa, ikiwa kuna kipande kilichochomolewa cha saizi inayohitajika katika Tcache itakitumia, ikiwa sivyo, itahitaji kusubiri kufungwa kwa heap ili iweze kupata moja katika bins za kimataifa au kuunda mpya.
Pia kuna uboreshaji, katika kesi hii, wakati wa kuwa na kufungwa kwa heap, thread itajaza Tcache yake na vipande vya heap (7) vya saizi iliyohitajika, hivyo ikiwa inahitaji zaidi, itavipata katika Tcache.
Add a tcache chunk example
#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;
}
Kusanya na kukarabati na breakpoint katika opcode ya ret kutoka kwa kazi ya main. Kisha kwa gef unaweza kuona tcache bin inatumika:
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 Structs & Functions
Katika msimbo ufuatao inawezekana kuona max bins na chunks per index, muundo wa tcache_entry
ulioandaliwa ili kuepuka uhuru mara mbili na tcache_perthread_struct
, muundo ambao kila thread inatumia kuhifadhi anwani za kila index ya bin.
tcache_entry
na tcache_perthread_struct
// 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;
Kazi ya __tcache_init
ni kazi inayounda na kugawa nafasi kwa ajili ya tcache_perthread_struct
obj
tcache_init code
// 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));
}
}
Tcache Indexes
Tcache ina bins kadhaa kulingana na saizi na viashiria vya awali kwa chunk ya kwanza ya kila index na idadi ya chunks kwa index ziko ndani ya chunk. Hii inamaanisha kwamba kutafuta chunk na habari hii (kawaida ya kwanza), inawezekana kupata viashiria vyote vya tcache na idadi ya Tcache chunks.
Fast bins
Fast bins zimeundwa ili kuharakisha ugawaji wa kumbukumbu kwa chunks ndogo kwa kuweka chunks zilizofutwa hivi karibuni katika muundo wa upatikanaji wa haraka. Bins hizi hutumia mbinu ya Last-In, First-Out (LIFO), ambayo inamaanisha kwamba chunk iliyofutwa hivi karibuni ndiyo ya kwanza kutumika tena wakati kuna ombi jipya la ugawaji. Tabia hii ni ya faida kwa kasi, kwani ni haraka zaidi kuingiza na kuondoa kutoka juu ya stack (LIFO) ikilinganishwa na foleni (FIFO).
Zaidi ya hayo, fast bins hutumia orodha zilizounganishwa kwa njia moja, si mbili, ambayo inaboresha zaidi kasi. Kwa kuwa chunks katika fast bins hazijachanganywa na majirani, hakuna haja ya muundo mgumu unaoruhusu kuondoa kutoka katikati. Orodha iliyo na uhusiano mmoja ni rahisi na haraka kwa shughuli hizi.
Kimsingi, kinachotokea hapa ni kwamba kichwa (kiashiria kwa chunk ya kwanza ya kuangalia) daima kinaelekeza kwa chunk iliyofutwa hivi karibuni ya saizi hiyo. Hivyo:
- Wakati chunk mpya inatolewa ya saizi hiyo, kichwa kinaelekeza kwa chunk ya bure ya kutumia. Kwa kuwa chunk hii ya bure inaelekeza kwa chunk inayofuata ya kutumia, anwani hii inahifadhiwa katika kichwa ili ugawaji ujao ujue wapi kupata chunk inayopatikana
- Wakati chunk inafutwa, chunk ya bure itahifadhi anwani ya chunk inayopatikana kwa sasa na anwani ya chunk hii iliyofutwa hivi karibuni itawekwa katika kichwa
Saizi ya juu ya orodha iliyo na uhusiano ni 0x80
na zimeandaliwa hivyo chunk ya saizi 0x20
itakuwa katika index 0
, chunk ya saizi 0x30
itakuwa katika index 1
...
caution
Chunks katika fast bins hazijapangwa kama zinazopatikana hivyo zinahifadhiwa kama chunks za fast bin kwa muda badala ya kuwa na uwezo wa kuchanganya na chunks nyingine za bure zinazozizunguka.
// 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)
Ongeza mfano wa kipande cha fastbin
#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;
}
Kumbuka jinsi tunavyopanga na kuachilia vipande 8 vya saizi sawa ili kujaza tcache na kipande cha nane kinahifadhiwa katika fast chunk.
Kusanya na kufanyia debug na breakpoint katika opcode ya ret
kutoka kwa kazi ya main
. kisha kwa kutumia gef
unaweza kuona kwamba tcache bin imejaa na kipande kimoja kiko katika fast bin:
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 isiyo na mpangilio
Bin isiyo na mpangilio ni cache inayotumiwa na meneja wa heap kufanya ugawaji wa kumbukumbu kuwa wa haraka zaidi. Hivi ndivyo inavyofanya kazi: Wakati programu inapoachilia kipande, na ikiwa kipande hiki hakiwezi kugawanywa katika tcache au fast bin na hakigongani na kipande cha juu, meneja wa heap haweka mara moja katika bin ndogo au kubwa maalum. Badala yake, kwanza hujaribu kuunganisha na kipande chochote cha jirani kilichopatikana ili kuunda block kubwa ya kumbukumbu isiyopatikana. Kisha, huweka kipande hiki kipya katika bin ya jumla inayoitwa "bin isiyo na mpangilio."
Wakati programu inapohitaji kumbukumbu, meneja wa heap anachunguza bin isiyo na mpangilio kuona kama kuna kipande cha ukubwa wa kutosha. Ikiwa anakipata, anakitumia mara moja. Ikiwa hakupata kipande kinachofaa katika bin isiyo na mpangilio, anahamisha vipande vyote katika orodha hii kwenye bins zao zinazofaa, ama ndogo au kubwa, kulingana na ukubwa wao.
Kumbuka kwamba ikiwa kipande kikubwa kinagawanywa katika nusu 2 na kilichobaki ni kikubwa kuliko MINSIZE, kitawekwa tena katika bin isiyo na mpangilio.
Hivyo, bin isiyo na mpangilio ni njia ya kuongeza kasi ya ugawaji wa kumbukumbu kwa kurudi haraka kutumia kumbukumbu iliyokuwa imeachiliwa hivi karibuni na kupunguza hitaji la utafutaji na kuunganishwa kwa muda mrefu.
caution
Kumbuka kwamba hata kama vipande ni vya makundi tofauti, ikiwa kipande kinachopatikana kinagongana na kipande kingine kinachopatikana (hata kama vilikuwa na asili tofauti katika bins tofauti), vitaundwa pamoja.
Ongeza mfano wa kipande kisichopangwa
#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;
}
Kumbuka jinsi tunavyopanga na kuachilia vipande 9 vya saizi sawa ili kujaa tcache na ile ya nane inahifadhiwa katika bin isiyo na mpangilio kwa sababu ni kubwa sana kwa fastbin na ile ya tisa haijaachiliwa hivyo ile ya tisa na ya nane hazijachanganywa na kipande cha juu.
Jumuisha na urekebishe na breakpoint katika opcode ya ret
kutoka kwa kazi ya main
. Kisha kwa kutumia gef
unaweza kuona kwamba bin ya tcache imejaa na kipande kimoja kiko katika bin isiyo na mpangilio:
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.
Small Bins
Small bins ni haraka zaidi kuliko large bins lakini polepole zaidi kuliko fast bins.
Kila bin ya 62 itakuwa na chunks za saizi sawa: 16, 24, ... (ikiwa na saizi ya juu ya 504 bytes katika 32bits na 1024 katika 64bits). Hii inasaidia katika kasi ya kutafuta bin ambapo nafasi inapaswa kutolewa na kuingiza na kuondoa entries kwenye orodha hizi.
Hii ndiyo jinsi saizi ya small bin inavyokadiriwa kulingana na index ya bin:
- Saizi ndogo zaidi: 2*4*index (mfano: index 5 -> 40)
- Saizi kubwa zaidi: 2*8*index (mfano: index 5 -> 80)
// 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)
Function ya kuchagua kati ya bins ndogo na kubwa:
#define bin_index(sz) \
((in_smallbin_range (sz)) ? smallbin_index (sz) : largebin_index (sz))
Ongeza mfano wa kipande kidogo
#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;
}
Kumbuka jinsi tunavyopanga na kuachilia vipande 9 vya saizi sawa ili kujaa tcache na ile ya nane inahifadhiwa katika bin isiyo na mpangilio kwa sababu ni kubwa sana kwa fastbin na ile ya tisa haijaachiliwa hivyo ile ya tisa na ya nane hazijachanganywa na kipande cha juu. Kisha tunapanga kipande kikubwa cha 0x110 ambacho kinafanya kipande kilichoko katika bin isiyo na mpangilio kiende kwenye bin ndogo.
Kusanya na kufanyia debug na breakpoint katika opcode ya ret
kutoka kwa kazi ya main
. Kisha kwa kutumia gef
unaweza kuona kwamba bin ya tcache imejaa na kipande kimoja kiko katika bin ndogo:
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.
Large bins
Kinyume na bins ndogo, ambazo husimamia vipande vya ukubwa thabiti, kila large bin inashughulikia anuwai ya ukubwa wa vipande. Hii ni rahisi zaidi, ikiruhusu mfumo kubeba ukubwa mbalimbali bila kuhitaji bin tofauti kwa kila ukubwa.
Katika mtoa huduma wa kumbukumbu, large bins huanza pale bins ndogo zinapomalizika. Mipaka ya large bins inakuwa kubwa zaidi kwa hatua, ikimaanisha bin ya kwanza inaweza kufunika vipande kutoka 512 hadi 576 bytes, wakati inayofuata inafunika 576 hadi 640 bytes. Mwelekeo huu unaendelea, huku bin kubwa zaidi ikijumuisha vipande vyote vya juu ya 1MB.
Large bins ni polepole kufanya kazi ikilinganishwa na bins ndogo kwa sababu lazima zipange na kutafuta kupitia orodha ya ukubwa wa vipande vinavyobadilika ili kupata bora zaidi kwa ajili ya ugawaji. Wakati kipande kinapowekwa kwenye large bin, kinapaswa kupangwa, na wakati kumbukumbu inatolewa, mfumo lazima upate kipande sahihi. Kazi hii ya ziada inawafanya kuwa polepole, lakini kwa kuwa ugawaji mkubwa ni nadra zaidi kuliko mdogo, ni kubadilishana kukubalika.
Kuna:
- 32 bins za 64B anuwai (zinagongana na bins ndogo)
- 16 bins za 512B anuwai (zinagongana na bins ndogo)
- 8 bins za 4096B anuwai (sehemu zinagongana na bins ndogo)
- 4 bins za 32768B anuwai
- 2 bins za 262144B anuwai
- 1 bin kwa ukubwa uliobaki
Large bin sizes code
// 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))
Ongeza mfano wa kipande kikubwa
#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 allocations kubwa zinafanywa, kisha moja inachukuliwa (ikiweka katika bin isiyo na mpangilio) na allocation kubwa zaidi inafanywa (ikihamasisha ile iliyochukuliwa kutoka bin isiyo na mpangilio hadi bin kubwa).
Ili kuunda na ku-debug, weka breakpoint katika opcode ya ret
kutoka kwa kazi ya main
. Kisha kwa kutumia gef
unaweza kuona kwamba bin ya tcache imejaa na kipande kimoja kiko katika bin kubwa:
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.
Sehemu Kuu
// 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))
Kimsingi, hii ni sehemu inayojumuisha kila kipande kilichopo kwenye heap kwa sasa. Wakati malloc inafanywa, ikiwa hakuna kipande chochote cha bure kinachopatikana kutumia, kipande hiki cha juu kitapunguza ukubwa wake kutoa nafasi inayohitajika.
Pointer kwa Top Chunk inahifadhiwa katika muundo wa malloc_state
.
Zaidi ya hayo, mwanzoni, inawezekana kutumia kipande kisichopangwa kama Top Chunk.
Angalia mfano wa Top Chunk
#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;
}
Baada ya kukusanya na kufanyia debug na alama ya kuvunja katika opcode ya ret
ya main
niliona kwamba malloc ilirudisha anwani 0xaaaaaaac12a0
na hizi ndizo chunks:
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
Inaweza kuonekana kwamba kipande cha juu kiko kwenye anwani 0xaaaaaaac1ae0
. Hii si ajabu kwa sababu kipande cha mwisho kilichotolewa kilikuwa kwenye 0xaaaaaaac12a0
chenye ukubwa wa 0x410
na 0xaaaaaaac12a0 + 0x410 = 0xaaaaaaac1ae0
.
Pia inawezekana kuona urefu wa kipande cha Juu kwenye kichwa chake:
gef➤ x/8wx 0xaaaaaaac1ae0 - 16
0xaaaaaaac1ad0: 0x00000000 0x00000000 0x00020531 0x00000000
0xaaaaaaac1ae0: 0x00000000 0x00000000 0x00000000 0x00000000
Kumbukumbu ya Mwisho
Wakati malloc inatumika na kipande kinagawanywa (kutoka kwenye bin isiyo na mpangilio au kutoka kwenye kipande cha juu kwa mfano), kipande kilichoundwa kutoka kwa sehemu iliyogawanywa kinaitwa Kumbukumbu ya Mwisho na kiashiria chake kinahifadhiwa katika muundo wa malloc_state
.
Mchakato wa Ugawaji
Angalia:
{{#ref}} heap-memory-functions/malloc-and-sysmalloc.md {{#endref}}
Mchakato wa Kuachilia
Angalia:
{{#ref}} heap-memory-functions/free.md {{#endref}}
Ukaguzi wa Usalama wa Fungsi za Heap
Angalia ukaguzi wa usalama unaofanywa na fungsi zinazotumika sana katika heap katika:
{{#ref}} heap-memory-functions/heap-functions-security-checks.md {{#endref}}
Marejeleo
- 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://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/core_functions
- https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/implementation/tcache/
tip
Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za udukuzi kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.