日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

malloc 结构体_二进制安全之堆溢出(系列)——堆基础 amp; 结构(二)

發(fā)布時間:2024/7/23 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 malloc 结构体_二进制安全之堆溢出(系列)——堆基础 amp; 结构(二) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

哈嘍啊

這里是二進制安全之堆溢出(系列)第二期“堆基礎(chǔ) & 結(jié)構(gòu)”第二節(jié)!!

話不多說,直接上干貨!

微觀結(jié)構(gòu)

函數(shù)執(zhí)行流程

void *malloc (size_t bytes) void *__libc_malloc (size_t bytes) //對于_int_malloc做簡單封裝__malloc_hook //類似于虛函數(shù),派生接口,指定一個malloc的方式 _int_malloc(mstate av, size_t bytes) //申請內(nèi)存塊的核心

main_arena

  • 集中管理bins鏈的結(jié)構(gòu)體,使用含fd和bk的bin頭一對一管理各個free的chunk
  • 分釋放配堆塊是基于main_arena來尋址的,首先找的是fastbin,其次再找bins
  • main_arena存儲在libc上,用以管理所有bins的頭和尾,每個bins鏈頭的fd和尾的b與之連接
struct malloc_state {/* Serialize access. */__libc_lock_define (, mutex);//定義了一個0x4字節(jié)的lock/* Flags (formerly in max_fast). */int flags;//0x4/* Set if the fastbin chunks contain recently inserted free blocks. *//* Note this is a bool but not all targets support atomics on booleans. */int have_fastchunks;//0x4/* Fastbins */mfastbinptr fastbinsY[NFASTBINS]; //fastbin鏈的管理頭,總共10個, 每個0x10字節(jié)/* Base of the topmost chunk -- not otherwise kept in a bin */mchunkptr top;//0x4 到此為止總共0x96字節(jié)/* The remainder from the most recent split of a small request */mchunkptr last_remainder; //切割后剩下的chunk鏈接到last_remainder/* Normal bins packed as described above */mchunkptr bins[NBINS * 2 - 2]; // 每個bin頭有fd和bk兩個指針/* Bitmap of bins */unsigned int binmap[BINMAPSIZE]; //位圖,用32bit來分別表示當前bin哪個鏈上有chunk,通過按位與的方式/* Linked list */struct malloc_state *next;/* Linked list for free arenas. Access to this field is serializedby free_list_lock in arena.c. */struct malloc_state *next_free;/* Number of threads attached to this arena. 0 if the arena is onthe free list. Access to this field is serialized byfree_list_lock in arena.c. */INTERNAL_SIZE_T attached_threads;/* Memory allocated from the system in this arena. */INTERNAL_SIZE_T system_mem;INTERNAL_SIZE_T max_system_mem; }
  • main_arena:用來管理整個bin鏈的結(jié)構(gòu)體,總共128個bin,10個fastbin
  • 每個bin頭可以簡化為fd和bk兩個前后項指針
  • glibc ---> main_arena ---> 對應(yīng)的bins頭的fd和bk ---> 遍歷找到對應(yīng)free的chunk
  • main_arena存放在libc中,其中存放的是每一個bin鏈的頭尾
tips:如果我們能打印一個非fastbin鏈中的fd,bk,那我們就可以計算出libc的基地址libc.addr = libc_on - libc.sysbols["main_arena"] - 88

main_chunk

  • 在程序的執(zhí)行過程中,我們稱malloc申請的內(nèi)存為chunk。這塊內(nèi)存在ptmalloc內(nèi)部用malloc_chunk結(jié)構(gòu)體來表示。
  • 當程序申請的chunk被free后,會被加入到相應(yīng)的空閑管理列表中。
  • 無論一個chunk的大小如何,處于分配狀態(tài)還是釋放狀態(tài),它們都使用一個統(tǒng)一的結(jié)構(gòu)。但根據(jù)是否被釋放,結(jié)構(gòu)會有所更改。
struct malloc_chunk {INTERNAL_SIZE_T mchunk_prev_size; // 如果前面一個堆塊是空閑的則表示前一個堆塊的大小,否則無意義INTERNAL_SIZE_T mchunk_size; //當前chunk的大小,由于對齊的原因所以低三位作為flag,意義如下:/*A:倒數(shù)第三位表示當前chunk屬于主分配區(qū)(0)還是非主分配區(qū)(1)M:倒數(shù)第二位表示當前chunk是從mmap(1)[多線程]分配的,還是從brk(0)[子線程]分配的P:最低為表示前一塊是否在使用中*//*1.真正的內(nèi)存從這里開始分配2.malloc之后這些指針沒有用,這時存放的是數(shù)據(jù)3.只有在free之后才有效。*/struct malloc_chunk* fd; //當chunk空閑時才有意義,記錄后一個空閑chunk的地址struct malloc_chunk* bk; //同上,記錄前一個空閑chunk的地址/* Only used for large blocks: pointer to next larger size. */struct malloc_chunk* fd_nextsize; //當前chunk為largebin時才有意義,指向比當前chunk大的第一個空閑chunkstruct malloc_chunk* bk_nextsize; //指向比當前chunk小的第一個空閑堆塊 };
  • prev_size
    • malloc(0x18)會分配0x20的內(nèi)存
    • malloc(0x19)分會配0x30的內(nèi)存
    • 如果該chunk的物理相鄰的前一地址chunk(兩個指針的地址差值為前一個chunk大小)是空閑的話,那該字段記錄的是前一個chunk的大小
    • 否則用來存儲物理相鄰的前一個chunk的數(shù)據(jù),這里前一個chunk指的是較低地址的chunk。
    • prev_size位可以被共享,當前的chunk, 如果不夠用就會占用下一塊chunk的prev_size
  • size
    • chunk1的數(shù)據(jù)有效區(qū)域覆蓋到chunk2的prev_size位,并且chunk2的size位的prev_inuse被覆蓋為0。系統(tǒng)認為chunk2之前的chunk1已經(jīng)未在使用了。
    • 當free(chunk2)的時候,系統(tǒng)會將chunk2與chunk2中prev_size大小的空間合并到bins。
    • 我們可以通過改變chunk2的prev_size的內(nèi)容,操縱向前合并的大小。
    • 造成的問題:overlap(堆塊重疊),chunk1被釋放了,但是我們可以操縱修改它(堆利用的核心思想),從而修改bins鏈的內(nèi)容,泄露其中的地址。
    • 形成的攻擊:fastbin ---> fd ---> main_arena ---> 分配新的堆塊,我們通過修改chunk1的fd內(nèi)容,達到分配任意內(nèi)存的目的,造成fastbin attack。
    • 記錄前一個chunk是否被分配。
    • 一般來說,堆中第一個被分配的內(nèi)存塊的size字段的P位都會被設(shè)置為1,以便于防止訪問前面的非法內(nèi)存。
    • 當一個chunk的size位的P位為0時,我們能通過prev_size獲取上一個chunk的大小及地址,方便進行空閑堆塊的合并。
    • 對于fastbin的堆塊,不管前面還有沒有被分配的chunk,PREV_INUSE都為1。
    • 64位chunk的size必須是16字節(jié)對齊
    • 32位chunk的size必須是8 字節(jié)對齊
    • 64位 低4位沒用 11110000
    • 32位 低3位沒用 11111000
    • define chunksize(p) (chunk_nomask (p) & ~(SIZE_BITS))
    • define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
    • NON_MAIN_ARENA記錄當前chunk是否是main_arena管理的堆塊,1表示不屬于,0表示屬于
    • IS_MAPPED記錄當前的chunk是否是由mmap分配的。
    • PREV_INUSE
    • 最小堆原則 : malloc(0)會分配0x20的空間,prev_size + size + 數(shù)據(jù)對齊的0x10字節(jié)
    • prev_inuse 漏洞利用

  • fd / bk
    • 釋放到bins鏈有效
    • fd指向下一個(非物理相鄰)空閑的chunk
    • bk指向上一個(非物理相鄰)空閑的chunk
    • 通過fd和bk可以將空閑的chunk塊加入到空閑的chunk鏈表進行統(tǒng)一管理。
  • fd_nextsize / bk_nextsize
    • 釋放到bins鏈有效,不過其用于較大的chunk(large chunk)
    • fd_nextsize指向前一個與當前chunk大小不同的第一個空閑塊,不包含bin的頭指針
    • bk_nextsize指向后一個與當前chunk大小不同的第一個空閑塊,不包含bin的頭指針
    • 一般空閑的largechunk在fd的遍歷順序中,按照從大到小的順序排列,可以避免在尋找合適的chunk時挨個遍歷。

__libc_malloc

void *__libc_malloc (size_t bytes) {mstate ar_ptr;void *victim;void *(*hook) (size_t, const void *)= atomic_forced_read (__malloc_hook);if (__builtin_expect (hook != NULL, 0))return (*hook)(bytes, RETURN_ADDRESS (0)); #if USE_TCACHE/* int_free also calls request2size, be careful to not pad twice. */size_t tbytes;checked_request2size (bytes, tbytes); //注意:用戶申請的字節(jié)一旦進入申請內(nèi)存函數(shù)被轉(zhuǎn)化為了無符號整數(shù)size_t tc_idx = csize2tidx (tbytes);MAYBE_INIT_TCACHE ();DIAG_PUSH_NEEDS_COMMENT;if (tc_idx < mp_.tcache_bins/*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */&& tcache&& tcache->entries[tc_idx] != NULL){return tcache_get (tc_idx);}DIAG_POP_NEEDS_COMMENT; #endifif (SINGLE_THREAD_P){victim = _int_malloc (&main_arena, bytes);assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||&main_arena == arena_for_chunk (mem2chunk (victim)));return victim;}arena_get (ar_ptr, bytes);victim = _int_malloc (ar_ptr, bytes);/* Retry with another arena only if we were able to find a usable arenabefore. */if (!victim && ar_ptr != NULL){LIBC_PROBE (memory_malloc_retry, 1, bytes);ar_ptr = arena_get_retry (ar_ptr, bytes);victim = _int_malloc (ar_ptr, bytes);}if (ar_ptr != NULL)__libc_lock_unlock (ar_ptr->mutex);assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||ar_ptr == arena_for_chunk (mem2chunk (victim)));return victim; }
  • 該函數(shù)會首先檢查是否有內(nèi)存分配函數(shù)的鉤子函數(shù)(__malloc_hook),這個主要用于用戶自定義的堆分配函數(shù)。
  • 這就造成了一個利用點:將__malloc_hook指針指向的內(nèi)容改為one_gadget的地址,再次malloc的時候就會直接啟動shell。__malloc_hook -> one_gadget(直接起shell的地址)這時不能將其修改為system的地址,因為system的參數(shù)為字符型,而malloc_hook的參數(shù)為無符號整數(shù)。
  • 接著會尋找一個arena來試圖分配內(nèi)存,然后調(diào)用__int_malloc函數(shù)去申請對應(yīng)的內(nèi)存
  • 如果分配失敗的話,ptmalloc會試圖再去尋找一個可用的arena,并分配內(nèi)存如果申請到了arena,那么在退出之前還得解鎖(__libc_lock_lock)
  • 判斷目前的狀態(tài)是否滿足以下條件
    • 要么沒有申請到內(nèi)存
    • 要么是mmap的內(nèi)存
    • 要么申請的的內(nèi)存必須在其所分配的arena中
    • assert
    最后返回內(nèi)存,進入__int_malloc

    __int_malloc

    __int_malloc是內(nèi)存分配的核心函數(shù),其核心思路為:

    它根據(jù)用戶申請的內(nèi)存塊大小以及相應(yīng)大小chunk通常使用的頻度,依次實現(xiàn)了不同的分配方法它由小大到大依次檢查不同的bin中是否有相應(yīng)的空閑塊可以滿足用戶請求的內(nèi)存當所有空閑的chunk都無法滿足時,他會考慮top_chunk當top_chunk也無法滿足時,堆分配器才會進行內(nèi)存塊申請

    1. 定義變量

    2. 判斷有沒有可用的arena

    如果沒有可用的arena,則返回系統(tǒng)調(diào)用mmap去申請一塊內(nèi)存

    3. 判斷是否在fastbin范圍

    如果申請的chunk的大小正好位于fastbin的范圍,則從fastbin的頭節(jié)點開始取chunk。需要注意的是,這里比較的是無符號整數(shù)調(diào)用remove_fb取出,并返回得到的fastbin的頭

    4. 判斷是否在smallbin

    如果獲取的內(nèi)存塊的范圍為smallbin的范圍,執(zhí)行以下流程找到其大小對應(yīng)的下標,判斷其鏈表是否為空,不為空則取最后一個

    注意,為了防止一個堆塊能夠正常free且不前向后并,需要修改當前堆塊的物理相鄰的緊接著的2個堆塊的inuse位為1。

    5.調(diào)用consolidate

    當fastbin,small bin中的chunk都不能滿足要求時,就會考慮是不是largebin,在此之前先調(diào)用malloc_consolidate處理fastbin中的chunk

    將有可能合并的chunk先進行合并后放到unsorted bin中,不能合并的就直接放到unsorted bin中,然后再進入大循環(huán),以減少堆中的碎片。只有在分配一個size在largebin范圍內(nèi)的堆塊,才能觸發(fā)malloc_consolidate

    6. 小總結(jié)

    在fastbin范圍內(nèi),先判斷對應(yīng)鏈表是否為空,不為空則取剛放入的chunk在smallbin范圍內(nèi),先判斷對應(yīng)鏈表是否為空,不為空則取第一個放入的chunk這兩者都無法匹配用戶申請的chunk時,就會進入大循環(huán)

    7. 進入大循環(huán)

    a. 嘗試從unsorted bin中分配用戶需要的內(nèi)存b. 嘗試從large bin中分配用戶需要的內(nèi)存b. 嘗試從top_chunk中分配用戶需要的內(nèi)存

    8. 從unsorted bin中分配nb

    如果申請的size小于unsorted bin中符合要求的chunk的size,會對其進行切割,剩下的進入last_remainder(由unsorted bin管理)如果unsorted bin中沒有滿足要求的chunk時,會先place in order整理,然后再去large bin中尋找

    9. 從large bin中分配nb

    注意,large bin中的堆塊不會split,不滿足的話就從top_chunk中切割

    10. 大循環(huán)之對于unsorted bin的check

    對于size的check:檢查當前size是否滿足對齊的 要求對于fd和bk的check:bck -> fd != victim對于double free的check:next->prev_inuse = 0

    11. 大循環(huán)之切割unsorted bin

    如果用戶請求為small bin chunk,那么我們首先考慮last_remainder如果last_remainder分割后還夠可以作為一個chunk,則使用set_head,set_foot設(shè)置標志位,將last_remainder放入原來unsorted bin的位置

    12. 大循環(huán)之取出unsorted bin

    首先將unsorted bin取出,如果其size和我們的nb(need bytes)一樣則直接放回這個unsorted bin

    13. 大循環(huán)之放入對應(yīng)的bin

    根據(jù)取出的size來判斷應(yīng)該放入哪個bin,放入small bin的時候則雙向鏈表插入在else if中處理large bin的邏輯,包括大小排序以及fd_nextsize和bk_nextsize

    14. 大循環(huán)總結(jié)

    整個過程迭代了10000次

    __int_malloc的大循環(huán)主要用來處理unsorted bin如果整個循環(huán)沒有找到合適的bin,說明所有的unsorted bin的大小都不滿足要求如果經(jīng)過了10000次的循環(huán),所有的unsorted bin中的bin都被放入了對應(yīng)的bin中,即small bin放入對應(yīng)的index中,large bin排好序后放入對應(yīng)的index中

    15. 大循環(huán)之large bin

    如果請求的chunk在large bin范圍內(nèi),就在對應(yīng)的bin中從小到大依次掃描,直到找到第一個合適的,并不一定精確


    切割后的remainder會被放入到unsorted bin中,同時設(shè)置標志位等信息

    16. 尋找較大的chunk

    如果走到了這里,說明對于用戶所需的chunk,不能直接從其對應(yīng)的合適的bin中獲取chunk,需要掃描所有的bin,查找比當前bin更大的fast bin或small bin 以及l(fā)arge bin

    17. 找到一個合適的map

    18. 取出chunk

    切割之后還是一樣,放入到unsorted bin

    19. 使用top_chunk

    如果所有的bin中的chunk都沒有辦法直接滿足要求(即不合并),或者沒有空閑的chunk時,就只能使用top_chunk了

    20. top_chunk不夠用

    > 如果top_chunk不夠用的時候并不是直接申請內(nèi)存,而是先調(diào)用consolidate合并空閑的fastbin > > 然后等待下次循環(huán)再去判斷是否夠用,不夠用才會調(diào)用sysmalloc申請內(nèi)存 > > ![](https://ws1.sinaimg.cn/large/006nFhrCly1g47vckz6b7j30gn0cmgnb.jpg)

    _int_malloc總結(jié)

    • malloc尋找堆塊的順序
  • 在fastbin中尋找有沒有對應(yīng)的chunk
  • 請求大小為small bin范圍,在small bin中尋找有沒有對應(yīng)的chunk
  • 請求大小為large bin范圍,僅調(diào)用malloc_consolidate合并fastbin
  • 在unsorted bin中尋找有沒有合適的chunk
  • 在large bin中尋找有沒有合適的chunk
  • 尋找較大的bin鏈中有沒有合適的chunk
  • 尋找top_chunk
  • top_chunk不夠用,調(diào)用malloc_consolidate合并fastbin
  • top_chunk不夠用,系統(tǒng)調(diào)用再次申請內(nèi)存
  • 總結(jié)

    以上是生活随笔為你收集整理的malloc 结构体_二进制安全之堆溢出(系列)——堆基础 amp; 结构(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。