fgets

2013-12-18 6 views
10

मैं बफर अतिप्रवाह के साथ प्रयोग कर रहा हूँ और fgetsfgets

की एक निश्चित इनपुट के साथ ढेर के वापसी पता ओवरराइट करने का प्रयास के साथ एक बफर अतिप्रवाह के कारण इस कोड है सामान्य निष्पादन कार्यक्रम सिर्फ आपके इनपुट देता है। मैं कोड को संशोधित किए बिना foo() आउटपुट करना चाहता हूं।

मेरा विचार buf के बफर को 20 'A' एस दर्ज करके ओवरफ़्लो करना था। यह एक सेगमेंटेशन गलती का काम करता है और कारण बनता है। मेरा अगला विचार foo() का पता लगाना था जो \x4006cd है और इसे 20 'A' एस में संलग्न करें।

मेरी समझ से यह ढेर के वापसी पते को ओवरराइट करना चाहिए और इसे foo पर कूदना चाहिए। लेकिन यह केवल एक segfault का कारण बनता है।

मैं क्या गलत कर रहा हूं?

अद्यतन: असेंबलर उदासीनता मुख्य

Dump of assembler code for function main: 
    0x000000000040073b <+0>: push %rbp 
    0x000000000040073c <+1>: mov %rsp,%rbp 
    0x000000000040073f <+4>: sub $0x10,%rsp 
    0x0000000000400743 <+8>: mov %edi,-0x4(%rbp) 
    0x0000000000400746 <+11>: mov %rsi,-0x10(%rbp) 
    0x000000000040074a <+15>: mov $0x0,%eax 
    0x000000000040074f <+20>: callq 0x4006f1 <bar> 
    0x0000000000400754 <+25>: mov $0x0,%eax 
    0x0000000000400759 <+30>: leaveq 
    0x000000000040075a <+31>: retq 
    End of assembler dump. 

foo

Dump of assembler code for function foo: 
    0x00000000004006cd <+0>: push %rbp 
    0x00000000004006ce <+1>: mov %rsp,%rbp 
    0x00000000004006d1 <+4>: mov 0x200990(%rip),%rax  # 0x601068 <[email protected]@GLIBC_2.2.5> 
    0x00000000004006d8 <+11>: mov %rax,%rcx 
    0x00000000004006db <+14>: mov $0x15,%edx 
    0x00000000004006e0 <+19>: mov $0x1,%esi 
    0x00000000004006e5 <+24>: mov $0x400804,%edi 
    0x00000000004006ea <+29>: callq 0x4005d0 <[email protected]> 
    0x00000000004006ef <+34>: pop %rbp 
    0x00000000004006f0 <+35>: retq 
End of assembler dump. 

बार:

Dump of assembler code for function bar: 
    0x00000000004006f1 <+0>: push %rbp 
    0x00000000004006f2 <+1>: mov %rsp,%rbp 
    0x00000000004006f5 <+4>: sub $0x20,%rsp 
    0x00000000004006f9 <+8>: mov $0x40081a,%edi 
    0x00000000004006fe <+13>: callq 0x400570 <[email protected]> 
    0x0000000000400703 <+18>: mov 0x200956(%rip),%rdx  # 0x601060 <[email protected]@GLIBC_2.2.5> 
    0x000000000040070a <+25>: lea -0x20(%rbp),%rax 
    0x000000000040070e <+29>: mov $0x18,%esi 
    0x0000000000400713 <+34>: mov %rax,%rdi 
    0x0000000000400716 <+37>: callq 0x4005b0 <[email protected]> 
    0x000000000040071b <+42>: lea -0x20(%rbp),%rax 
    0x000000000040071f <+46>: mov %rax,%rdi 
    0x0000000000400722 <+49>: callq 0x400580 <[email protected]> 
    0x0000000000400727 <+54>: mov %rax,%rsi 
    0x000000000040072a <+57>: mov $0x400821,%edi 
    0x000000000040072f <+62>: mov $0x0,%eax 
    0x0000000000400734 <+67>: callq 0x400590 <[email protected]> 
    0x0000000000400739 <+72>: leaveq 
    0x000000000040073a <+73>: retq 
End of assembler dump. 
+0

क्या आपने इस कोड के लिए संबंधित असेंबलर (और इस प्रकार स्टैक लेआउट) देखा है? –

+0

अगर यह केवल इतना आसान था ... –

+0

आपको संबंधित असेंबली को देखना चाहिए। कभी-कभी संकलक 20 से अधिक बाइट करता है जिसे आपने संरेखण के लिए बनाया है। आपको स्टैक के लेआउट को भी देखना चाहिए और रजिस्टरों/सहेजे गए रीट एडर्स कैसे सहेजे जाते हैं और किस क्रम में। आगे बढ़ें और फ़ंक्शन की असीम पोस्ट करें और हम आपकी सहायता कर सकते हैं। असेंबली का विश्लेषण किए बिना –

उत्तर

3

आप स्मृति aligment साथ गिनती नहीं किया। मैंने सही जगह खोजने में आसान बनाने के लिए कोड को थोड़ा सा बदल दिया।

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

int **x; 
int z; 

void foo() 
{ 
    fprintf(stderr, "You did it.\n"); 
} 

void bar() 
{ 
    char buf[2]; 
    //puts("Input:"); 
    //fgets(buf, 70, stdin); 
    x = (int**) buf; 
    for(z=0;z<8;z++) 
      printf("%d X=%x\n", z, *(x+z)); 
    *(x+3) = foo; 
    printf("Your input: %d %s\n", strlen(buf), buf); 
} 


int main(int argc, char **argv) 
{ 
     printf("Foo: %x\n", foo); 
     printf("Main: %x\n", main); 
     bar(); 
     return 0; 
} 
एक छोटे बफर के साथ

, मेरे उदाहरण में 2, मैं 24 बाइट्स दूर वापसी पता पाया (x + 3, 8 बाइट संकेत के लिए; 64 बिट्स, कोई डिबग, कोई अनुकूलन ...) शुरू से ही बफर का। यह स्थिति बफर आकार, वास्तुकला इत्यादि के आधार पर बदल सकती है। इस उदाहरण में, मैं बार के वापसी पते को foo में बदल सकता हूं। वैसे भी आपको foo रिटर्न पर सेगमेंटेशन गलती मिलेगी, क्योंकि यह मुख्य रूप से मुख्य पर वापस जाने के लिए सेट नहीं किया गया था।

मैंने ग्लोबल वर्र्स के रूप में एक्स और जेड को बार के स्टैक आकार को बदलने के लिए नहीं जोड़ा। कोड बफ [0] से शुरू होने वाले मानों की तरह सूचक की एक सरणी प्रदर्शित करेगा। मेरे मामले में, मुझे स्थिति 3 में मुख्य में पता मिला। यही कारण है कि अंतिम कोड में * (x + 3) = foo है। जैसा कि मैंने कहा, यह स्थिति संकलन विकल्पों, मशीन इत्यादि के आधार पर बदल सकती है। सही स्थिति खोजने के लिए, पता सूची पर मुख्य का पता लगाएं (कॉलिंग बार से पहले मुद्रित)।

यह ध्यान रखना महत्वपूर्ण है कि मैंने मुख्य रूप से पता नहीं किया, मुख्य पते का पता नहीं, क्योंकि वापसी के पते को बार में कॉल के बाद लाइन पर सेट किया गया था और मुख्य की शुरुआत में नहीं। तो, मेरे मामले में, यह 0x400668 के बजाय 0x4006af था।

आपके उदाहरण में, 20 बाइट बफर के साथ, जहां तक ​​मुझे पता है, यह 32 बाइट्स (0x20) के साथ गठबंधन किया गया था।

यदि आप fgets के साथ ऐसा करना चाहते हैं, तो आपको यह पता लगाना होगा कि foo का पता कैसे टाइप करें, लेकिन यदि आप x86/x64 मशीन चला रहे हैं, तो इसे थोड़ा अंतराल में जोड़ना याद रखें। आप मूल्य बाइट प्रति बाइट प्रदर्शित करने के लिए कोड बदल सकते हैं, ताकि आप उन्हें सही क्रम में प्राप्त कर सकें और उन्हें ALT + संख्या का उपयोग करके टाइप कर सकें। याद रखें कि ALT धारण करते समय आपके द्वारा टाइप की जाने वाली संख्या दशमलव संख्याएं हैं। कुछ टर्मिनल 0x00 अनुकूल अनुकूल नहीं होंगे।

मेरे उत्पादन लगता है:

$ gcc test.c -o test 
test.c: In function ‘bar’: 
test.c:21: warning: assignment from incompatible pointer type 
$ ./test 
Foo: 400594 
Main: 400668 
0 X=9560e9f0 
1 X=95821188 
2 X=889350f0 
3 X=4006af 
4 X=889351d8 
5 X=0 
6 X=0 
7 X=95a1ed1d 
Your input: 5 ▒▒`▒9 
You did it. 
Segmentation fault 
2
void bar() 
{ 
    char buf[20]; 
    puts("Input:"); 
    fgets(buf, 24, stdin); 
    printf("Your input:.\n", strlen(buf)); 
} 

... यह काम करता है और एक विभाजन गलती का कारण बनता है ...

संकलक शायद एक सुरक्षित संस्करण के साथ fgets को बदल रहा है जिसमें गंतव्य बफर आकार पर एक चेक शामिल है। यदि चेक विफल हो जाता है, तो prgram बिना शर्त रूप से abort() पर कॉल करता है।

इस विशेष मामले में, आपको प्रोग्राम को -U_FORTIFY_SOURCE या -D_FORTIFY_SOURCE=0 के साथ संकलित करना चाहिए।

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