2017-01-09 12 views
5

मैं x86_64 सिस्टम पर लिनक्स उपयोगकर्ता स्पेस मेमोरी लेआउट के बारे में सीख रहा हूं और कुछ अनुभागों से कुछ पते प्रिंट करना चाहता हूं।मेरा जंग निष्पादन योग्य 0x400000 के बजाय ऐसे उच्च पते (ढेर के पास) क्यों मैप किया गया है?

fn main() { 
    let x = 3;  // should be stored on stack 
    let s = "hello"; // should be in the .data section 

    println!("stack ≈ {:p}", &x); 
    println!(".text ≈ {:p}", main as *const()); 
    println!(".data ≈ {:p}", s); 


    use std::io; 

    let mut f = std::fs::File::open("/proc/self/maps").unwrap(); 
    let out = io::stdout(); 
    io::copy(&mut f, &mut out.lock()).unwrap(); 
} 

इस कोड को भी stdout के लिए फ़ाइल /proc/self/maps प्रिंट: मैं इस जंग कोड का इस्तेमाल किया। मैंने rustc mem.rs के साथ इस फ़ाइल को mem.rs संकलित किया। यह मुद्रित:

stack ≈ 0x7ffffbf82f2c 
.text ≈ 0x7f45b7c0a2b0 
.data ≈ 0x7f45b7c4d35b 

7f45b6800000-7f45b6c00000 rw-- 00000000 00:00 0 
7f45b6de0000-7f45b6f9a000 r-x- 00000000 00:00 664435    /lib/x86_64-linux-gnu/libc-2.19.so 
7f45b6f9a000-7f45b6fa2000 ---- 001ba000 00:00 664435    /lib/x86_64-linux-gnu/libc-2.19.so 
[ ... more .so files] 
7f45b7a22000-7f45b7a23000 r--- 00022000 00:00 663920    /lib/x86_64-linux-gnu/ld-2.19.so 
7f45b7a23000-7f45b7a24000 rw-- 00023000 00:00 663920    /lib/x86_64-linux-gnu/ld-2.19.so 
7f45b7a24000-7f45b7a25000 rw-- 00000000 00:00 0 
7f45b7aa0000-7f45b7aa2000 rw-- 00000000 00:00 0 
7f45b7ab0000-7f45b7ab2000 rw-- 00000000 00:00 0 
7f45b7ac0000-7f45b7ac1000 rw-- 00000000 00:00 0 
7f45b7ad0000-7f45b7ad1000 rw-- 00000000 00:00 0 
7f45b7ae0000-7f45b7ae2000 rw-- 00000000 00:00 0 
7f45b7c00000-7f45b7c5f000 r-x- 00000000 00:00 1134580   /home/lukas/tmp/mem 
7f45b7e5e000-7f45b7e62000 r--- 0005e000 00:00 1134580   /home/lukas/tmp/mem 
7f45b7e62000-7f45b7e63000 rw-- 00062000 00:00 1134580   /home/lukas/tmp/mem 
7f45b7e63000-7f45b7e64000 rw-- 00000000 00:00 0 
7ffffb784000-7ffffb785000 ---- 00000000 00:00 0     [stack] 
7ffffb785000-7ffffbf84000 rw-- 00000000 00:00 0 
7ffffc263000-7ffffc264000 r-x- 00000000 00:00 0     [vdso] 

कम से कम पतों मैं अपने ही पर छपी मैच के लिए क्या maps कहते लगते हैं।

00400000-0040b000 r-x- 00000000 00:00 107117      /bin/cat 
0060a000-0060b000 r--- 0000a000 00:00 107117      /bin/cat 
0060b000-0060c000 rw-- 0000b000 00:00 107117      /bin/cat 
0071c000-0073d000 rw-- 00000000 00:00 0       [heap] 
7f7deb933000-7f7debc30000 r--- 00000000 00:00 758714    /usr/lib/locale/locale-archive 
7f7debc30000-7f7debdea000 r-x- 00000000 00:00 664435    /lib/x86_64-linux-gnu/libc-2.19.so 
7f7debdea000-7f7debdf2000 ---- 001ba000 00:00 664435    /lib/x86_64-linux-gnu/libc-2.19.so 
[ ... more .so files ...] 
7f7dec222000-7f7dec223000 r--- 00022000 00:00 663920    /lib/x86_64-linux-gnu/ld-2.19.so 
7f7dec223000-7f7dec224000 rw-- 00023000 00:00 663920    /lib/x86_64-linux-gnu/ld-2.19.so 
7f7dec224000-7f7dec225000 rw-- 00000000 00:00 0 
7f7dec250000-7f7dec252000 rw-- 00000000 00:00 0 
7f7dec260000-7f7dec261000 rw-- 00000000 00:00 0 
7f7dec270000-7f7dec272000 rw-- 00000000 00:00 0 
7ffff09e8000-7ffff11e8000 rw-- 00000000 00:00 0     [stack] 
7ffff1689000-7ffff168a000 r-x- 00000000 00:00 0     [vdso] 

बाद परिणाम सब कुछ मैं इस विषय के बारे में पढ़ा मेल खाता है:: निष्पादन से वर्गों वर्चुअल ऐड्रेस स्पेस के निचले सिरे में मैप किया जाता है (शुरुआत लेकिन जब मैं टर्मिनल में cat /proc/self/maps निष्पादित, मैं इस आउटपुट प्राप्त लगभग 0x400000)।

मैंने विंडोज़ के लिए लिनक्स सबसिस्टम (मूल रूप से उबंटू 14.04) में सब कुछ निष्पादित और संकलित किया। मुझे पता है, यह नया और सामान है, लेकिन मुझे पूरा यकीन है कि यह उपप्रणाली के साथ कोई मुद्दा नहीं है (कृपया मुझे बताएं कि यह है, हालांकि!)। जंग 1.14 कि मायने रखती है (मैं इसे शक),

मैं भी यही एक सी कार्यक्रम के साथ करने की कोशिश की है (बहाना मेरी शायद बुरा सी):

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

int main(int argc, char **argv) { 
    FILE *test_file; 
    char buf[4096]; 
    if ((test_file = fopen ("/proc/self/maps", "r")) != NULL) { 
     while (!feof (test_file)) { 
      fgets (buf, sizeof (buf), test_file); 
      puts (buf); 
     } 
    } 

    return 0; 
} 

यह कुछ इसी तरह आउटपुट cat रहे हैं:

00400000-00401000 r-x- 00000000 00:00 1325490     /home/lukas/tmp/a.out 
00600000-00601000 r--- 00000000 00:00 1325490     /home/lukas/tmp/a.out 
00601000-00602000 rw-- 00001000 00:00 1325490     /home/lukas/tmp/a.out 

जंग के निष्पादन योग्य ढेर के पास बड़े पते पर मैप किए गए क्यों हैं?

+2

क्या इसके लायक है, एक उबंटू 16.04 डोकर छवि में अपनी जंग कोड चल रहा है, मैं 'पाने के लिए ढेर ≈ 0x7ffc2a01636c'; '.text ≈ 0x559f58ae4270'; '.डेटा ≈ 0x559f58b2735b'। यह ढेर के करीब नहीं है। – Shepmaster

उत्तर

6

rustc -Z print-link-args addr.rs का उपयोग करके, आप देख सकते हैं कि रस्टर कंपाइलर का उपयोग करने वाला लिंकर आमंत्रण किस प्रकार उपयोग करेगा। चूंकि वर्तमान लिंकर cc होता है, इसलिए हम सीधे सी प्रोग्राम के लिए इन विकल्पों का पुन: उपयोग कर सकते हैं। महत्वहीन तर्क की उपेक्षा और दूसरों एक-एक करके दूर करने, मैं इस संकलक मंगलाचरण के साथ छोड़ दिया गया था:

gcc -fPIC -pie addr.c -o addr-c 

सी कोड संकलन की तरह इस समान पते का उत्पादन के रूप में जंग संकलित निष्पादन योग्य, यह दर्शाता है कि उनमें से एक या दोनों विकल्प एक संभावित अपराधी है। यह सवाल है कि "-fPIC और/या -pie ऐसे उच्च पते पर नक्शा क्यों करता है?"

PIE द्विआधारी सिर्फ एक साझा पुस्तकालय के रूप में जुड़ा हुआ है, और इसलिए उसके डिफ़ॉल्ट लोड पते (प्रथम LOAD खंड के .p_vaddr) है:

मैं एक और सवाल and answer कि उस पर प्रकाश डाला जा रहा है पाया शून्य। उम्मीद है कि कुछ इस बाइनरी को शून्य पृष्ठ से दूर स्थानांतरित कर देगा, और इसे कुछ यादृच्छिक पते पर लोड करेगा।

जंग निष्पादन पर readelf -e का उपयोग करना, हम देख सकते हैं कि पहली LOAD खंड शून्य का एक आभासी पता है:

Program Headers: 
    Type   Offset    VirtAddr   PhysAddr 
       FileSiz   MemSiz    Flags Align 
    LOAD   0x0000000000000000 0x0000000000000000 0x0000000000000000 
       0x000000000005e6b4 0x000000000005e6b4 R E 200000 
    LOAD   0x000000000005ead0 0x000000000025ead0 0x000000000025ead0 
       0x00000000000039d1 0x00000000000049e8 RW  200000 

मुझे लगता है कि यह तो सवाल का "क्यों इन यादृच्छिक हैं बदलता है पते चुने गए ", लेकिन मुझे उस उत्तर का यकीन नहीं है।^_^ए हंच मुझे बताता है कि एएसएलआर खेल में आता है। यह other answer कि सहन करने के लिए बाहर लगता है:

पाई निष्पादन योग्य फ़ाइलों में ASLR समर्थन करने के लिए है।

एएसएलआर कुछ प्रकार के हमलों के खिलाफ कार्यक्रमों को सख्त करने में मदद करने के लिए एक सुरक्षा तकनीक है, इसलिए यह समझ में आता है कि जंग, इसकी सुरक्षा-दिमागी दृष्टिकोण के साथ, डिफ़ॉल्ट रूप से इस तरह कुछ सक्षम करने का प्रयास करेगा। दरअसल, पतों एक छोटा-सा प्रत्येक मंगलाचरण बदलने के लिए:

[email protected]:/# ./addr | grep 'r-xp' | grep 'addr' 
5587cea9d000-5587ceafc000 r-xp 00000000 00:21 206      /addr 
561d8aae2000-561d8ab41000 r-xp 00000000 00:21 206      /addr 
555c30ffd000-555c3105c000 r-xp 00000000 00:21 206      /addr 
55db249d5000-55db24a34000 r-xp 00000000 00:21 206      /addr 
55e988572000-55e9885d1000 r-xp 00000000 00:21 206      /addr 
560400e1b000-560400e7a000 r-xp 00000000 00:21 206      /addr 
+0

एएसएलआर प्रत्येक निष्पादन का एक अलग पता नहीं देगा? –

+0

@MaththieuM। मैं एएसएलआर के दायरे के बारे में सोच रहा हूं। मुझे हर बार थोड़ा अलग पता मिलता है, लेकिन मेरी मशीन पर यह हमेशा 0x7f के साथ शुरू होता है (ऊपर कभी शेम्पास्टर की टिप्पणी में 0x55 की तरह कुछ नहीं)। वैसे भी महान जवाब, Shepmaster! –

+0

@MaththieuM। मुझे प्रत्येक निष्पादन के साथ अलग-अलग पते मिलते हैं, जिन्हें मैंने अपडेट किया है। – Shepmaster

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