2016-12-18 13 views
5

मैं समझने की कोशिश कर रहा हूं कि glibc में malloc कार्यान्वयन कैसे काम कर रहा है। मॉलोक के स्रोत कोड के अनुसार (glibc 2.23 में malloc.c) मुफ्त मेमोरी भागों में निम्न संरचना है।उबंटू 16.04 - मॉलोक कार्यान्वयन। अगले खंड में सूचक कहाँ है?

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       | 
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

आम तौर पर हम इस संरचना को gnu डीबगर (gdb) में भी देख सकते हैं। तो मैंने निम्नलिखित कार्यक्रम लिखा था। कार्यक्रम 64 बाइट के आकार के साथ 6 मेमोरी भाग आवंटित करता है। प्रत्येक खंड यादृच्छिक से भरा होता है, इसलिए हम बाद में gdb में अनुसार खंड को आसानी से देख सकते हैं। चूंकि भाग 1,3 और 6 मुक्त हैं क्योंकि उनके ऊपर उल्लिखित संरचना होनी चाहिए। चूंकि बीच में आवंटित भाग हैं, इसलिए मुक्त भाग को समेकित नहीं किया जा सकता है और नतीजतन वे एक दोगुनी लिंक्ड सूची में व्यवस्थित होते हैं जो प्रत्येक खंड में पॉइंटर्स को घुमाते हैं।

#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"); 
} 

जब मैं gdb भीतर कार्यक्रम शुरू करने और एक ब्रेकपाइंट लाइन strcpy(b4, argv[1]); में हम देखते हैं कि मुक्त कर दिया हिस्सा एक डबल लिंक्ड सूची में आयोजन किया जाता है सक्षम होना चाहिए निर्धारित किया है। हालांकि gdb उत्पादन इस प्रकार है:

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 

इस उत्पादन हम मुक्त कर दिया मात्रा और पिछले मुक्त कर दिया हिस्सा वापस करने के लिए सूचक देख सकते में (उत्पादन से सही पक्ष पर टिप्पणी देखें)। लेकिन आगे के पॉइंटर्स और पिछले खंड का आकार कहां है?

उत्तर

3

पार तैनात security.stackexchange

हिस्सा के आकार के आधार से मुक्त होने के लिए, मात्रा डिब्बे के विभिन्न प्रकार (लिंक किए गए सूचियों) में आयोजित की जाती हैं:

  • क्रमित किए बिना डिब्बे
  • छोटे डिब्बे
  • बड़े डिब्बे

यदि आपको यह जानने में रुचि है कि इन डिब्बे को कैसे बनाए रखा जाता है तो आपको स्रोत कोड देखने का सुझाव दिया जाता है। लेकिन इन सभी डिब्बे के बीच कुछ आम बात यह है कि सूचियां दोगुनी से जुड़े हैं। तो आपको लगता है कि आप मिल गया है चाहिए अपने धारणा में सही थे दोनों एक आगे और मुक्त कर दिया मात्रा में एक पिछड़े सूचक (और यह भी शायद पिछले आकार क्षेत्र)

हालांकि, वहाँ विशेष का एक और प्रकार है बिन फास्टबिन के रूप में जाना जाता है। एक बहुत छोटे आकार के टुकड़े (आमतौर पर 16 और 80 बाइट्स के बीच, लेकिन यह संस्करणों में थोड़ा भिन्न हो सकता है) इन फास्टबिन्स में रखा जाता है। आपके नियमित डिब्बे के विपरीत, ये सिंगल-लिंक्ड हैं। उन्हें अपने आकार के आधार पर उचित फास्टबिन में रखा जाता है (प्रत्येक बिन में एक ही आकार के भाग होते हैं)। सूची को पार करने के बजाय, प्रदर्शन को तेज करने के लिए, LIFO क्रम में भाग को जोड़ा और हटाया जा सकता है। नियमित हिस्सों के विपरीत, आसन्न फास्टबिन-टुकड़े समेकित नहीं होते हैं (जो निश्चित रूप से विखंडन में परिणाम देते हैं, लेकिन तेजी से तेज़ी से बनाते हैं)। इसका मतलब यह भी है कि आपको पिछले खंड के आकार की आवश्यकता नहीं है।

आपके कार्यक्रम में भाग शायद इन फास्टबिन्स में से एक का हिस्सा भी हैं। इसलिए यह देखने के लिए कि आप क्या उम्मीद कर रहे हैं, बड़े आकार की स्मृति आवंटित करने और मुक्त करने का प्रयास करें।

संबंधित मुद्दे