2014-05-13 1 views
6

मैं लिनक्स पर कुछ एंटी-डिबगिंग तकनीकों को सीख रहा हूं और जीडीबी में ब्रेकपॉइंट्स का पता लगाने के लिए स्मृति में 0xcc बाइट की जांच के लिए कोड का एक स्निपेट मिला है। यहां वह कोड है:एंटी-डिबगिंग: gdb ब्रेकपॉइंट्स के लिए 0xcc बाइट नहीं लिखता है। कोई विचार क्यों?

 if ((*(volatile unsigned *)((unsigned)foo + 3) & 0xff) == 0xcc) 
    { 
        printf("BREAKPOINT\n"); 
        exit(1); 
     } 

    foo(); 

लेकिन यह काम नहीं करता है। मैंने foo() फ़ंक्शन पर ब्रेकपॉइंट सेट करने की कोशिश की और स्मृति में सामग्री का निरीक्षण किया, लेकिन ब्रेकपॉइंट के लिए लिखे गए 0xcc बाइट को नहीं देखा। यहाँ मैं क्या किया है:

(gdb) b foo 
Breakpoint 1 at 0x804846a: file p4.c, line 8. 
(gdb) x/x 0x804846a 
0x804846a <foo+6>: 0xe02404c7 
(gdb) x/16x 0x8048460 
0x8048460 <frame_dummy+32>: 0x90c3c9d0 0x83e58955 0x04c718ec 0x0485e024 
0x8048470 <foo+12>: 0xfefae808 0xc3c9ffff ..... 

आप देख सकते हैं, वहाँ कोई 0xcc बाइट foo के प्रवेश बिंदु() फ़ंक्शन पर लिखा हो रहा है। क्या किसी को पता है कि क्या हो रहा है या मैं गलत कहां हो सकता हूं? धन्यवाद।

+1

इस विषय पर एक दिलचस्प लेख है 'डीबगर कैसे काम करता है', लेख 'आईएनटी 3 के पीछे जादू' के इस भाग पर एक नज़र डालें: http://www.alexonlinux.com/how-debugger-works # the_magic_behind_int_3 –

उत्तर

8

दूसरा भाग आसानी से समझाया गया है (जैसे फ़्लोरिफाइड सही ढंग से बताया गया है): जीडीबी मूल मेमोरी सामग्री दिखाता है, ब्रेकपॉइंट "बाइट्स" नहीं। डिफॉल्ट मोड में यह वास्तव में ब्रेकपॉइंट्स को हटा देता है जब डीबगर निलंबित हो जाता है और जारी रखने से पहले उन्हें फिर से सम्मिलित करता है। उपयोगकर्ता आमतौर पर ब्रेकपॉइंट्स के लिए उपयोग किए जाने वाले अजीब संशोधित निर्देशों को नहीं देखते हैं।

आपके सी कोड के साथ आप कुछ बाइट्स के लिए ब्रेकपॉइंट चूक गए। जीडीबी function prologue के बाद ब्रेकपॉइंट सेट करता है, क्योंकि फ़ंक्शन प्रस्तावना आम तौर पर जीडीबी उपयोगकर्ता नहीं देखना चाहते हैं।इसलिए, यदि आप foo को तोड़ते हैं, तो वास्तविक ब्रेकपॉइंट आमतौर पर उसके बाद कुछ बाइट्स स्थित होगा (प्रस्तावना कोड पर निर्भर करता है जो फ़ंक्शन पर निर्भर करता है क्योंकि यह स्टैक पॉइंटर, फ्रेम पॉइंटर और अन्य को सहेजने की आवश्यकता नहीं हो सकती है)। लेकिन यह जांचना आसान है।

#include <stdio.h> 
int main() 
{ 
    int i,j; 
    unsigned char *p = (unsigned char*)main; 

    for (j=0; j<4; j++) { 
     printf("%p: ",p); 
     for (i=0; i<16; i++) 
      printf("%.2x ", *p++); 
     printf("\n"); 
    } 
    return 0; 
} 

हम अपने आप में इस कार्यक्रम चलाते हैं यह प्रिंट:

0x40057d: 55 48 89 e5 48 83 ec 10 48 c7 45 f8 7d 05 40 00 
0x40058d: c7 45 f4 00 00 00 00 eb 5a 48 8b 45 f8 48 89 c6 
0x40059d: bf 84 06 40 00 b8 00 00 00 00 e8 b4 fe ff ff c7 
0x4005ad: 45 f0 00 00 00 00 eb 27 48 8b 45 f8 48 8d 50 01

अब हम gdb में इसे चलाने (अतः के लिए उत्पादन फिर से प्रारूपित) मैं इस कोड का इस्तेमाल किया।

(gdb) break main 
Breakpoint 1 at 0x400585: file ../bp.c, line 6. 
(gdb) info break 
Num  Type   Disp Enb Address   What 
1  breakpoint  keep y 0x0000000000400585 in main at ../bp.c:6 
(gdb) disas/r main,+32 
Dump of assembler code from 0x40057d to 0x40059d: 
    0x000000000040057d (main+0): 55      push %rbp 
    0x000000000040057e (main+1): 48 89 e5     mov %rsp,%rbp 
    0x0000000000400581 (main+4): 48 83 ec 10    sub $0x10,%rsp 
    0x0000000000400585 (main+8): 48 c7 45 f8 7d 05 40 00 movq $0x40057d,-0x8(%rbp) 
    0x000000000040058d (main+16): c7 45 f4 00 00 00 00  movl $0x0,-0xc(%rbp) 
    0x0000000000400594 (main+23): eb 5a      jmp 0x4005f0 
    0x0000000000400596 (main+25): 48 8b 45 f8    mov -0x8(%rbp),%rax 
    0x000000000040059a (main+29): 48 89 c6     mov %rax,%rsi 
End of assembler dump.
इस हम सत्यापित के साथ

, कि इस कार्यक्रम सही बाइट्स प्रिंट कर रहा है। लेकिन यह भी दिखाता है कि 0x400585 (जो फ़ंक्शन प्रस्तावना के बाद है) पर ब्रेकपॉइंट डाला गया है, फ़ंक्शन के पहले निर्देश पर नहीं। अब हम (रन) के साथ gdb के तहत कार्यक्रम चलाने के लिए और फिर "जारी रखें" के बाद ब्रेकप्वाइंट मारा जाता है, तो हम इस उत्पादन प्राप्त करें:

(gdb) cont 
Continuing. 
0x40057d: 55 48 89 e5 48 83 ec 10 cc c7 45 f8 7d 05 40 00 
0x40058d: c7 45 f4 00 00 00 00 eb 5a 48 8b 45 f8 48 89 c6 
0x40059d: bf 84 06 40 00 b8 00 00 00 00 e8 b4 fe ff ff c7 
0x4005ad: 45 f0 00 00 00 00 eb 27 48 8b 45 f8 48 8d 50 01

यह अब 0xcc से पता चलता पते 9 मुख्य में बाइट्स के लिए मुद्रित किया जा रहा ।

+0

ब्रेकपॉइंट मारा जाने के बाद gdb '0xCC' बाइट को क्यों नहीं हटाया गया? –

+0

यह डिज़ाइन द्वारा है। जीडीबी "मानक" ब्रेकपॉइंट्स को हटा नहीं देता है जिसे वे मारा जाता है। अस्थायी ब्रेकपॉइंट्स (टकराव के साथ डाला गया) को हिट होने के बाद स्थायी रूप से हटा दिया जाता है। – dbrank0

4

यदि आपका हार्डवेयर इसका समर्थन करता है, तो जीडीबी Hardware Breakpoints का उपयोग कर रहा है, जो कोड को पैच नहीं करता है।

मैं किसी भी सरकारी डॉक्स के माध्यम से इस बात की पुष्टि नहीं की है, this page इंगित करता है कि

डिफ़ॉल्ट रूप से, gdb हार्डवेयर की मदद से अलग होने के अंक का उपयोग करने के प्रयास करता है।

जब से तुम 0xCC बाइट्स की उम्मीद से संकेत मिलता है, मैं यह सोचते करती हूं कि आप, x86 हार्डवेयर पर चला रहे हैं के रूप में int3 opcode 0xCC है। x86 प्रोसेसर के पास debug registersDR0 - DR3 का एक सेट है, जहां आप ब्रेकपॉइंट अपवाद के कारण डेटा के पते को प्रोग्राम कर सकते हैं। DR7 एक बिटफील्ड है जो ब्रेकपॉइंट्स के व्यवहार को नियंत्रित करता है, और DR6 स्थिति इंगित करता है।

डीबग रजिस्टरों को केवल रिंग 0 (कर्नेल मोड) से पढ़ा/लिखा जा सकता है। इसका मतलब यह है कि कर्नेल आपके लिए इन रजिस्टरों का प्रबंधन करता है (ptrace एपीआई के माध्यम से, मुझे विश्वास है।)

हालांकि, एंटी-डिबगिंग के लिए, सभी आशा खो नहीं जाती है! विंडोज़ पर, GetThreadContext एपीआई आपको (रोक) थ्रेड के लिए CONTEXT की (प्रतिलिपि) प्राप्त करने की अनुमति देता है। इस संरचना में DRx रजिस्टरों की सामग्री शामिल है। This question लिनक्स पर इसे कैसे कार्यान्वित करने के बारे में है।

+0

मुझे लगता है कि आप गलत कहने पर गलत हैं: 'हालांकि मैंने किसी भी आधिकारिक दस्तावेज़ के माध्यम से इसकी पुष्टि नहीं की है, यह पृष्ठ इंगित करता है कि'। यह पृष्ठ इसे दृष्टिकोण के लिए इंगित करता है, ब्रेकपॉइंट्स नहीं। इसके विपरीत उपयोगकर्ता 172611 9 ब्रेकपॉइंट्स के बारे में पूछता है। वैसे, जीडीबी का आधिकारिक डॉक्टर यह भी वॉचपॉइंट्स के बारे में कहता है: 'जीडीबी यदि संभव हो तो हार्डवेयर घड़ी को सेट करता है।' Http://sourceware.org/gdb/current/onlinedocs/gdb/Set-Watchpoints.html#Set-Watchpoints –

2

यह एक श्वेत झूठ भी हो सकता है कि जीडीबी आपको बता रहा है ... रैम में ब्रेकपॉइंट हो सकता है लेकिन जीडीबी ने ध्यान दिया है कि पहले क्या था (इसलिए यह बाद में इसे बहाल कर सकता है) और आपको यह दिखा रहा है राम की सच्ची सामग्री का।

बेशक, यह हार्डवेयर ब्रेकपॉइंट्स का उपयोग भी कर सकता है, जो कुछ प्रोसेसर पर उपलब्ध एक सुविधा है। एच/डब्ल्यू ब्रेकपॉइंट्स सेट करना प्रोसेसर को उस पते को बताकर किया जाता है जिसके लिए उसे देखना चाहिए (और कोड निष्पादित करते समय प्रोग्राम काउंटर द्वारा हिट होने पर ब्रेकपॉइंट इंटरप्ट ट्रिगर करें)।

+1

जबकि आपका पहला पैराग्राफ जीडीबी के माध्यम से स्मृति को देखते हुए देखे गए व्यवहार को समझा सकता है (* मैंने इसे भी पहले, पहले * पर सोचा था), यह प्रोग्राम को स्वयं को देखकर समझाता नहीं है। –

+0

नहीं, मूल प्रश्न ** ** ** नहीं कहा कि उन्होंने कभी भी ब्रेकपॉइंट सेट ** के साथ जीडीबी के तहत कार्यक्रम चलाया और ** यह स्वयं ही देख रहा था। प्रश्न एक प्रोग्राम लिखने का वर्णन करता है जो स्वयं को देखता है, और उसके बाद जीडीबी में ब्रेकपॉइंट सेट करता है और फिर ** स्मृति में ब्रेकपॉइंट देखने के लिए जीडीबी ** का उपयोग कर **। केवल। – Flortify

+0

@ dbrank0 ने सबसे अच्छा जवाब दिया, जिसमें एक प्रोग्राम दिखा रहा है ** ** ** जीडीबी ** के तहत चल रहा ** ** ब्रेकपॉइंट सेट के साथ। – Flortify

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