2016-12-18 4 views
5

私はglibcのmallocの実装がどのように機能しているかを理解しようとしています。 malloc(glibc 2.23のmalloc.c)のソースコードによれば、空きメモリチャンクは以下の構造を持っています。Ubuntu 16.04 - mallocの実装です。次のチャンクへのポインタはどこにありますか?

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つのメモリチャンクを割り当てます。各チャンクはmemsetで埋められているので、後でgdbのチャンクを簡単に見ることができます。チャンク1,3および6は解放されているので、上記の構造を持つ必要があります。その間に割り当てられたチャンクがあるので、解放されたチャンクは統合できません。その結果、各チャンク内のポインタを介してリンクされたリストの2倍に編成されます。

#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の順序でチャンクを追加したり削除したりすることができ、パフォーマンスが向上します。また、通常のチャンクとは異なり、隣接するファスト・ビン・チャンクは統合されません(断片化につながりますが、高速化は速くなります)。これはまた、前のチャンクのサイズも必要ないことを意味します。

プログラム内のチャンクは、おそらくこれらのファストビーンの1つの一部です。したがって、あなたが期待しているものを見るには、より大きなサイズのメモリを割り当てて解放してみてください。

関連する問題