2016-12-18 85 views
5

Glibc'deki malloc uygulamasının nasıl çalıştığını anlamaya çalışıyorum. Malloc'un kaynak koduna göre (glogc 2.23'te malloc.c) boş bellek parçaları aşağıdaki yapıya sahiptir.Ubuntu 16.04 - malloc uygulaması. Bir sonraki parçaya işaretçi nerede?

chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
      |    Size of previous chunk       | 
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
    `head:' |    Size of chunk, in bytes       |P| 
     mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
      |    Forward pointer to next chunk in list    | 
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
      |     Back pointer to previous chunk in list  | 
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
      |    Unused space (may be 0 bytes long)    . 
      .                . 
      .                | 
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
    `foot:' |    Size of chunk, in bytes       | 
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

Normalde de gnu hata ayıklayıcı (gdb) bu ​​yapıyı görmek gerekir. Ben de şu programı yazdım. Program, 64 Byte büyüklüğünde 6 bellek parçasını ayırır. Her bir parça memset ile doldurulur, bu yüzden gdb'de daha sonra gelen öbekleri kolayca görebiliriz. 1,3 ve 6 numaralı parçalar serbest bırakıldığı için yukarıda belirtilen yapıya sahip olmalıdır. Arasında serbest bırakılan parçalar bulunduğundan, serbest bırakılan parçalar birleştirilemez ve sonuç olarak her bir dizideki işaretçilerden iki katına bağlı bir listede düzenlenirler.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

void to_jump(); 

int main(int argc, char **argv){ 
    char *b1, *b2, *b3, *b4, *b5, *b6; 

    //allocate 6 chunks of memory 
    b1 = malloc(64); 
    b2 = malloc(64); 
    b3 = malloc(64); 
    b4 = malloc(64); 
    b5 = malloc(64); 
    b6 = malloc(64); 

    memset(b1, 'B', 64); 
    memset(b2, 'C', 64); 
    memset(b3, 'D', 64); 
    memset(b5, 'E', 64); 
    memset(b6, 'F', 64); 
    //free chunks 1,3 and 6 
    free(b1); 
    free(b3); 
    free(b6); 

    strcpy(b4, argv[1]); // <-- set breakpoint here 
    //exploit this line 
    free(b4); 
    free(b5); 
    free(b2); 
} 

void to_jump(){ 
    printf("Exploited"); 
} 

Ben gdb içinde Programı başlatmak ve serbest parçalar bir çift bağlantılı liste halinde organize olduğunu görmek gerekir hat strcpy(b4, argv[1]); bir kesme noktası ayarlamak

. şöyle gdb çıkışı Ancak: Biz serbest parçalar ve önceki serbest yığın geri işaretçisi görebilirsiniz Bu çıktıda

gdb-peda$ p b1 
$11 = 0x602010 "" 
gdb-peda$ x/62xg 0x602000 
0x602000: 0x0000000000000000 0x0000000000000051 
0x602010: 0x0000000000000000 0x4242424242424242 | 
0x602020: 0x4242424242424242 0x4242424242424242 | b1 (freed) 
0x602030: 0x4242424242424242 0x4242424242424242 | 
0x602040: 0x4242424242424242 0x4242424242424242 | 
0x602050: 0x0000000000000000 0x0000000000000051 
0x602060: 0x4343434343434343 0x4343434343434343 | 
0x602070: 0x4343434343434343 0x4343434343434343 | b2 (allocated) 
0x602080: 0x4343434343434343 0x4343434343434343 | 
0x602090: 0x4343434343434343 0x4343434343434343 | 
0x6020a0: 0x0000000000000000 0x0000000000000051 
0x6020b0: 0x0000000000602000 0x4444444444444444 | 0x602000 is pointing to b1 (previous freed block) 
0x6020c0: 0x4444444444444444 0x4444444444444444 | b3 (freed) 
0x6020d0: 0x4444444444444444 0x4444444444444444 | 
0x6020e0: 0x4444444444444444 0x4444444444444444 | 
0x6020f0: 0x0000000000000000 0x0000000000000051 
0x602100: 0x0000000000000000 0x0000000000000000 | 
0x602110: 0x0000000000000000 0x0000000000000000 | b4 (will be filled trough strcpy(b4, argv[1]); 
0x602120: 0x0000000000000000 0x0000000000000000 | 
0x602130: 0x0000000000000000 0x0000000000000000 | 
0x602140: 0x0000000000000000 0x0000000000000051 
0x602150: 0x4545454545454545 0x4545454545454545 | 
0x602160: 0x4545454545454545 0x4545454545454545 | b5 (allocated) 
0x602170: 0x4545454545454545 0x4545454545454545 | 
0x602180: 0x4545454545454545 0x4545454545454545 | 
0x602190: 0x0000000000000000 0x0000000000000051 
0x6021a0: 0x00000000006020a0 0x4646464646464646 | 0x6020a0 is pointing to b3 (previous freed block) 
0x6021b0: 0x4646464646464646 0x4646464646464646 | b6 (freed) 
0x6021c0: 0x4646464646464646 0x4646464646464646 | 
0x6021d0: 0x4646464646464646 0x4646464646464646 | 
0x6021e0: 0x0000000000000000 0x0000000000020e21 

(çıkışından sağ tarafta yorumlar). Ama ileri işaretçiler ve önceki yığınların boyutu nerede?

cevap

3

Çapraz yayınlanan parçalar depo farklı (bağlı listeleri) tutulur, serbest için yığın boyutuna bağlı olarak security.stackexchange

den:

  • Unsorted kutuları
  • Küçük kutuları
  • Büyük kutuları

Bu kutuların nasıl korunacağını bilmek istiyorsanız kaynak kodunu bulmanız önerilir. Ancak tüm bu kutular arasında ortak olan bir şey, listelerin çift bağlantılı olmasıdır. Yani bulduk gerektiğini sizin varsayımı doğru her ikisi ileri ve geriye işaretçi serbest parçalar halinde (ve aynı zamanda belki önceki boyut alanı) Ancak

, özel başka bir tür var fastbin olarak bilinen kutu. Çok küçük boyutlu (genellikle 16 ile 80 bayt arasında değişen, ancak versiyonlar arasında biraz farklılık gösterebilen parçalar) bu fastbinslerde tutulur. Normal kutularınızdan farklı olarak, bunlar tek tek bağlantılı. Boyutlarına göre (aynı boyuttaki parçalar içeren her bir kutu) uygun bir fastbin içinde tutulurlar. Listeyi geçmek zorunda kalmak yerine, parçalar bir LIFO düzeninde eklenebilir ve kaldırılabilir, performansı hızlandırabilir. Ayrıca, normal yığınlardan farklı olarak, bitişik fastbin parçaları birleştirilmez (ki bu da parçalanmaya neden olur, ancak daha hızlı serbest kalır). Bu ayrıca, önceki yığının büyüklüğüne de ihtiyacınız olmadığı anlamına gelir.

Programınızdaki parçalar da muhtemelen bu fastbins öğelerinden birinin bir parçasıdır. Bu nedenle, ne beklediğinizi görmek için, daha büyük bir boyutta bellek ayırmayı ve boşaltmayı deneyin.