2015-07-22 10 views
5

का "निकास" कैसे ढूंढें परीक्षण 32-bit x86 लिनक्स पर है।सी प्रोग्राम

तो मूल रूप से मैं असेंबली कोड में उपकरण निर्देशों को सम्मिलित करके निष्पादित मूल ब्लॉक की जानकारी लॉग करने का प्रयास कर रहा हूं।

मेरी रणनीति इस तरह है: एक ग्लोबल सरणी में निष्पादित मूल ब्लॉक की अनुक्रमणिका लिखें, और सरणी पूर्ण होने पर सरणी को डिस्क से डिस्क में फ्लश करें (16 एम)।

यहां मेरी समस्या है। उपकरण की बाइनरी के निष्पादन के दौरान मुझे डिस्क पर सरणी को फ्लश करने की आवश्यकता होती है, भले ही यह 16 एम सीमा तक न पहुंच जाए। हालांकि, मुझे नहीं पता कि assembly प्रोग्राम से बाहर निकलने के लिए कहां खोजें। लक्ष्य विधानसभा कार्यक्रम से

  1. grep exit, और सही call exit अनुदेश से पहले स्मृति फ्लश:

    मैं इस कोशिश की। लेकिन कुछ डीबगिंग अनुभव के अनुसार, लक्ष्य सी प्रोग्राम, md5sum बाइनरी कहता है, जब यह निष्पादन समाप्त होता है तो exit पर कॉल नहीं करता है।

  2. main फ़ंक्शन के अंत में स्मृति को फ्लश करें। हालांकि, असेंबली कोड में, मुझे नहीं पता कि main फ़ंक्शन का सटीक अंत कहां है। मैं एक रूढ़िवादी दृष्टिकोण कर सकता हूं, कह सकता हूं, सभी ret निर्देश की तलाश में, लेकिन मुझे लगता है कि main फ़ंक्शन ret निर्देश के साथ समाप्त नहीं होता है।

तो यहाँ है, मेरे सवाल यह है कि कैसे वहाँ एक assembly code का सही निष्पादन अंत की पहचान करने के लिए, और सम्मिलित कुछ इंस्ट्रूमेंटेशन निर्देश? कुछ लाइब्रेरी कोड हुकिंग मेरे लिए ठीक है। मैं विभिन्न इनपुट के साथ समझता हूं, बाइनरी अलग-अलग स्थिति से बाहर निकल सकता है, इसलिए मुझे लगता है कि मुझे कुछ रूढ़िवादी अनुमान की आवश्यकता है। क्या मैंने स्पष्ट कर दिया है? धन्यवाद!

+0

क्या आपका उपकरण कुछ मुफ्त सॉफ्टवेयर है? मुझे आपके कोड के अंदर देखने में खुशी होगी .... –

+1

मुझे नहीं लगता कि यह हमेशा अच्छी तरह से परिभाषित किया जाता है। एक बार जब ऑप्टिमाइज़र ने अपना काम किया हो, तो हो सकता है कि कार्यों के बीच सीमाएं, या यहां तक ​​कि 'मुख्य()' और libc की सामग्री के बीच भी परिभाषित सीमाएं न हो जाएं (प्रोग्राम का एंट्रीपॉइंट)। एक संभावित सुराग का पता लगाना होगा कि कैसे ढेर का उपयोग किया जा रहा है, लेकिन फिर से, मुझे नहीं लगता कि यह जरूरी है कि प्रोग्राम बाहर निकलने पर स्टैक पूरी तरह से उलट जाएगा। – Havenard

उत्तर

4

मुझे विश्वास है कि आप सामान्य मामले में ऐसा नहीं कर सकते हैं। सबसे पहले, यदि main कुछ कोड लौटा रहा है, तो यह एक निकास कोड है (यदि main में कोई स्पष्ट return नहीं है तो हाल के सी मानकों की आवश्यकता है कि संकलक अंतर्निहितreturn 0;) जोड़ता है। फिर एक फ़ंक्शन कुछ डेटा में exit का पता संग्रहीत कर सकता है (उदा। एक वैश्विक फ़ंक्शन, struct में फ़ील्ड, ...), और कुछ अन्य फ़ंक्शन सही ढंग से फ़ंक्शन पॉइंटर के माध्यम से कॉल कर सकता है। व्यावहारिक रूप से, एक प्रोग्राम dlopen का उपयोग करके कुछ प्लगइन्स लोड कर सकता है और नाम के लिए dlsym का उपयोग कर सकता है, या बस प्लगइन के अंदर exit पर कॉल कर सकता है ... AFAIU उस समस्या को हल करने (वास्तविक exit कॉल, गतिशील अर्थ में) खोजने के लिए पूर्ण सामान्यता में हो सकता है halting problem के बराबर साबित हुआ। Rice's theorem भी देखें।

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

(अस्वीकरण, मैं MELT के मुख्य लेखक हूँ, मुझे और अधिक के लिए संपर्क करने में संकोच ...)

BTW, आप atexit(3) के बारे में पता है? यह आपके फ्लशिंग मुद्दे के लिए सहायक हो सकता है ... और आप LD_PRELOAD चाल का उपयोग भी कर सकते हैं (dynamic linkers के बारे में पढ़ें, ld-linux(8) देखें)।

2

atexit() सही ढंग से 95 +% कार्यक्रमों को संभालेगा। आप या तो पंजीकृत हैंडलरों की अपनी श्रृंखला को संशोधित कर सकते हैं, या इसे अन्य ब्लॉक के रूप में उपकरण बना सकते हैं। हालांकि, कुछ प्रोग्राम _exit() के उपयोग से समाप्त हो सकते हैं जो अटेक्साइट हैंडलर का आह्वान नहीं करता है। संभावित रूप से उपकरण _exit डेटा फ्लशिंग और एएसएक्सिट (या on_exit() बीएसडी-जैसी प्रोग्रामों पर) स्थापित करने के लिए हैंडलर को लगभग 100% कार्यक्रमों को कवर करना चाहिए।


परिशिष्ट: ध्यान दें कि लिनक्स बेस विशिष्टताsays कि सी पुस्तकालय स्टार्टअप करेगा:

कॉल प्रारंभकर्ता समारोह (* init)()।
उचित तर्क के साथ मुख्य() पर कॉल करें।
मुख्य() से वापसी मूल्य के साथ बाहर निकलें()।

+0

यह निर्भर करता है कि प्रोग्राम को डीबग किया जा रहा है, नियमित विकास उपकरण श्रृंखला का उपयोग करके लिखा गया है या नहीं: असेंबलर (सीखने के उद्देश्यों के लिए) में लिखे गए अधिकांश कार्यक्रम सीधे "बाहर निकलें" सिस्टम कॉल को कॉल करते हैं जिसका अर्थ है कि "on_exit" या "atexit" फ़ंक्शन नहीं हैं संभाला। जब एक कार्यक्रम "मार" से बाधित होता है तो यह भी मामला है। –

+0

@ मार्टिनरोसेनौ: लिनक्स पर कितने गैर-छात्र असेंबली कार्यक्रम हो सकते हैं? – wallyk

0

एक विधि जो हर समय काम करनी चाहिए, वहां आपके डेटा को संग्रहीत करने के लिए साझा स्मृति अनुभाग बनाना होगा।

आप एक बाल प्रक्रिया भी तैयार करते हैं जो प्रक्रिया को समाप्त करने के लिए डीबग होने की प्रतीक्षा कर रहा है।

जैसे ही प्रक्रिया डीबग हो गई है, बाल प्रक्रिया समाप्त हो गई है, साझा की गई स्मृति में मौजूद डेटा का उपयोग करके लेखन संचालन को अंतिम रूप दिया जाएगा।

यह बाहर निकलने के सभी रूपों, प्रक्रिया बाधाओं (जैसे Ctrl + C, टर्मिनल विंडो बंद करना, ...) पर काम करना चाहिए या भले ही प्रक्रिया "मार" का उपयोग करके मार डाला गया हो।

-1

आप इस कोशिश कर सकते:

int main() 
bool keepGoing = true; 
{ 
    while(keepGoing) { 
     string x; 
     cin >> x; 
     if(x == "stop") { 
      keepGoing = false; 
     } 
    } 
} 

भले ही यह आदिम है ... मैं शायद कोडिंग butchered लेकिन यह सिर्फ एक अवधारणा है।

+0

यह गलत है (आप 'main()' और ब्रेस के बीच एक चर, 'keepGoing' घोषित कर रहे हैं!) और इसे काम करने के लिए उपयोगकर्ता इंटरैक्शन ('cin') की आवश्यकता होती है। मुझे नहीं लगता कि आप सवाल समझ गए हैं। –

0

लेकिन कुछ डीबगिंग अनुभव के अनुसार, लक्ष्य सी प्रोग्राम, एक एमडी 5 एसयूएम बाइनरी कहता है, जब यह निष्पादन समाप्त होता है तो बाहर निकलने पर कॉल नहीं करता है।

disassembly (objdump -d /usr/bin/md5sum) में हम इस राशि:

के एक i686 जीएनयू/लिनक्स सिस्टम पर एक md5sum द्विआधारी पर एक नज़र डालते हैं

Disassembly of section .text: 

08048f50 <.text>: 
8048f50:  55      push %ebp 
8048f51:  89 e5     mov %esp,%ebp 
8048f53:  57      push %edi 
8048f54:  56      push %esi 
8048f55:  53      push %ebx 
8048f56:  83 e4 f0    and $0xfffffff0,%esp 
8048f59:  81 ec c0 00 00 00  sub $0xc0,%esp 
8048f5f:  8b 7d 0c    mov 0xc(%ebp),%edi 

[ ... ] 

8049e8f:  68 b0 d6 04 08   push $0x804d6b0 
8049e94:  68 40 d6 04 08   push $0x804d640 
8049e99:  51      push %ecx 
8049e9a:  56      push %esi 
8049e9b:  68 50 8f 04 08   push $0x8048f50 
8049ea0:  e8 4b ef ff ff   call 8048df0 <[email protected]> 
8049ea5:  f4      hlt  

यह सब स्टार्टअप बॉयलरप्लेट कोड है। __libc_start_main कॉल के अंदर वास्तविक प्रोग्राम का main कॉल लागू किया गया है। यदि कार्यक्रम उस से वापस आता है, तो, हे देखो, hlt निर्देश है। यह आपका लक्ष्य है।उस hlt निर्देश और उपकरण की तलाश करें जो कार्यक्रम के अंत में है।

+0

तकनीकी रूप से '__libc_start_main()' कभी वापस नहीं आना चाहिए। 'एचएलटी' कभी नहीं पहुंचा जाना चाहिए। '__libc_start_main' एक बिंदु पर बाहर निकलने वाले कार्यों में से एक को आमंत्रित करेगा जो उपयोगकर्ता प्रोग्राम को समाप्त करने के लिए 'sys_exit' सिस्टम कॉल करेगा। –

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