2012-05-03 15 views
6

बस आपको कुछ संदर्भ देने के लिए, मैं यह हासिल करने की कोशिश कर रहा हूं: मैं .so फ़ाइल में वर्जन स्ट्रिंग रखने के लिए किसी साझा ऑब्जेक्ट फ़ाइल में एक कॉन्स char * एम्बेड कर रहा हूं। मैं डेटा विश्लेषण कर रहा हूं और यह स्ट्रिंग मुझे डेटा को यह बताती है कि सॉफ़्टवेयर के किस संस्करण ने इसे बनाया है। यह सब ठीक काम करता है।एनएम प्रतीक मूल्य में ऑफसेट?

मेरे पास जो मुद्दा है, वह है जब मैं सीधे .so लाइब्रेरी से स्ट्रिंग को पढ़ने की कोशिश करता हूं। मैं

nm libSMPselection.so | grep _version_info 

का उपयोग करें और

000000000003d968 D __SMPselection_version_info 

यह सब ठीक है और अपेक्षा के अनुरूप (चार * _SMPselection_version_info कहा जाता है) प्राप्त करने की कोशिश। हालांकि मैं अब फ़ाइल खोलने, 0x3d968 की तलाश करने और मेरी स्ट्रिंग पढ़ने शुरू करने की उम्मीद करता, लेकिन मुझे जो भी मिलता है वह कचरा है।

जब मैं .so फ़ाइल खोलता हूं और केवल स्ट्रिंग की सामग्री (मुझे पता है कि यह कैसे शुरू होता है) की खोज करता है, तो मैं इसे 0x2e0b4 पते पर पा सकता हूं। इस पते पर यह शून्य है और शून्य के रूप में समाप्त हो गया है। (मैं अब इस विधि का उपयोग कर रहा हूं।)

मैं कंप्यूटर वैज्ञानिक नहीं हूं। क्या कोई मुझे बता सकता है कि एनएम द्वारा दिखाए गए प्रतीक मूल्य सही नहीं हैं, या अलग-अलग, प्रतीक मूल्य क्या है यदि यह प्रतीक का पता नहीं है?

उत्तर

2

किसी ने भी सबसे आसान तरीका सुझाया नहीं: एक बाइनरी जो आपके lib को गतिशील रूप से लोड करती है (इसे कमांड लाइन पर नाम दें) और अपने प्रतीक के लिए dlsym() करता है (या इसे कमांड लाइन पर भी प्राप्त कर सकते हैं) इसे कास्ट करें सूचक को स्ट्रिंग करने और इसे stdout करने के लिए प्रिंट करता है।

+1

यह एक अच्छा विचार है। मैं अभी कोशिश कर रहा हूँ। केवल एक समस्या है: जिन पुस्तकालयों का मैं परीक्षण कर रहा हूं उनमें अन्य पुस्तकालयों पर निर्भरता की एक लंबी श्रृंखला है। यदि मैं उन्हें dlopen से लोड करने का प्रयास करता हूं तो मुझे सिग्नल-नहीं-मिली त्रुटियां मिलती हैं। जिस संस्करण स्ट्रिंग में मुझे रूचि है, उसकी कोई निर्भरता नहीं है। मैं निर्भरता को नजरअंदाज कैसे कर सकता हूं? – Simon

+0

मैंने चेक किया है। यह बहुत अच्छा काम करता है अगर मेरे पास सभी निर्भरताएं लोड हों जो मेरे दो उपयोग-मामलों में से एक है। विचार के लिए धन्यवाद। – Simon

1

लिनक्स पर (वैसे मैं साथ OSX 10.7 पर एक मैक काम कर रहा हूँ द्वारा) आप 'तार' कमांड जो मदद से आप बाइनरी से तार निकालने की है।

http://linux.about.com/library/cmd/blcmdl1_strings.htm

HPUX में (और मैं अन्य यूनिक्स की झलक में भी लगता है) वहां भी इसी तरह कमांड 'क्या' कहा जाता है। यह केवल तारों को निकालता है जो "@ (#)" से शुरू होते हैं, लेकिन यदि आप स्ट्रिंग की सामग्री को नियंत्रित करते हैं तो यह कोई समस्या नहीं है।

+1

इससे उन्हें एक विशिष्ट प्रतीक की सामग्री प्राप्त करने में मदद मिलेगी? – PlasmaHH

+0

"क्या" अच्छा है लेकिन मैं वास्तव में चाहता हूं कि मेरी स्ट्रिंग एकाधिक लाइनें हों और न्यूलाइन पर क्या रुक जाए। स्ट्रिंग कमांड मुझे बताए बिना सभी स्ट्रिंग प्रिंट करता है कि मेरी अपनी स्ट्रिंग कहां समाप्त होती है। ऐसा लगता है कि यह पूरी फाइल को सिर्फ पढ़ने के लिए है जो मैं करता हूं। अगर मैं प्रतीक प्रविष्टि पढ़ सकता हूं और स्ट्रिंग पर सीधे कूद सकता हूं तो यह अधिक सुरुचिपूर्ण लगता है। – Simon

5

अपने ईएलएफ या इसी तरह से संरचित बाइनरी मानते हुए, आपको उस पते को ध्यान में रखना होगा जहां सामान लोड किया गया है, जो ईएलएफ हेडर में चीजों से प्रभावित है।

अपनी बाइनरी पर objdump -Fd का उपयोग करके, आप डिस्सेबलर को प्रतीक की सटीक फ़ाइल ऑफसेट भी दिखा सकते हैं।

objdump -x का उपयोग करके आप मानक लोडर निष्पादन योग्य के लिए यह लोडर पता, आमतौर पर 0x400000 पा सकते हैं।

अगली बात आपको सावधान रहना है यह देखने के लिए कि क्या यह एक अप्रत्यक्ष स्ट्रिंग है, यह आप objdump -g का उपयोग कर आसानी से कर सकते हैं। जब स्ट्रिंग को अप्रत्यक्ष स्ट्रिंग के रूप में पाया जाता है, तो objdump -Fd द्वारा स्थिति आउटपुट पर आपको स्ट्रिंग नहीं मिलेगी, लेकिन पता। इससे आपको लोडर पते को फिर से घटाना होगा।

objdump -Fd BIN | grep VersionString 
    45152f:  48 8b 1d 9a df 87 00 mov 0x87df9a(%rip),%rbx  # ccf4d0 <acVersionString> (File Offset: 0x8cf4d0) 

objdump -x BIN 
... 
LOAD off 0x0000000000000000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**12 
... 

तो हम फ़ाइल में 0x8cf4d0 को देखो और hexeditor में मिल:

008C:F4D0 D8 C1 89 00 00 00 00 00 01 00 00 00 FF FF FF FF 

तो हम 0x89C1D8 वहाँ ले, घटाना 0x400000 और मुझे तुम मेरे बाइनरी में से एक के लिए एक उदाहरण दिखा 0x49c1d8 है और जब हम hexeditor में वहाँ देखने के लिए हम पाते हैं:

0049:C1D0 FF FF 7F 7F FF FF 7F FF 74 72 75 6E 6B 5F 38 30 
0049:C1E0 34 33 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

"trunk_8043" इसका मतलब है।

वाईएमएमवी, विशेष रूप से जब यह कुछ अन्य फ़ाइल प्रारूप होता है, लेकिन इन चीजों को कैसे संरचित किया जाता है, यह सामान्य तरीका है, जिसमें कई मामलों और विवरण जो विशेष मामलों के लिए विचलित होते हैं।

+0

ठीक है, धन्यवाद, मुझे लगता है कि आपने इसका जवाब दिया है। मैं जो उम्मीद कर रहा था वह पूरी फ़ाइल स्कैन किए बिना स्ट्रिंग प्राप्त करने में सक्षम था (या इसे डायसम्बल करना)। वैसे, objdump के मेरे संस्करण में -एफ विकल्प नहीं है (मैं जीएनयू objdump 2.17.50.0.6-20.el5 20061020 का उपयोग कर रहा हूँ)। – Simon

+0

@ सिमॉन: यह ओबजडम्प का एक सुंदर प्राचीन संस्करण है (मैं अब भी याद नहीं कर सकता कि 2006 कैसा था)। आप '0x4f000d0' से उसी' 0x400000' ऑफ़सेट को घटाकर अपने आप फ़ाइलफ्रेट को अपने आप प्राप्त कर सकते हैं। शायद एक उपकरण भी है जो आपके लिए उन सभी चीजों को करता है, या आप स्वयं को एक छोटी लिपि लिख सकते हैं .. – PlasmaHH

1

nm द्वारा ऑफसेट को .so फ़ाइल में ऑफ़सेट होने की अपेक्षा क्यों की जाएगी? .so फ़ाइलें केवल स्मृति छवियां नहीं हैं; उनमें कई अन्य जानकारी भी शामिल है, और इसमें कम या कम जटिल प्रारूप है। यूनिक्स के तहत (कम से कम अधिकांश इकाइयों के तहत), साझा ऑब्जेक्ट्स एल्फ प्रारूप का उपयोग करते हैं। जानकारी खोजने के लिए, आपको फ़ाइल में विभिन्न फ़ील्ड को समझना होगा, यह जानने के लिए कि आप जिस प्रतीक को चाहते हैं वह स्थित है, जिसमें सेगमेंट, और वह सेगमेंट फ़ाइल में कहां से शुरू होता है। , इसके अलावा (आप शायद एक पुस्तकालय जो उन्हें पढ़ को सरल बनाएगा पा सकते हैं।)

अगर आप कह रही है कि आप एम्बेडेड गया है में सही कर रहे हैं एक char const*, यानी कि अपने कोड की तरह कुछ निहित:

char const* version = "..."; 

तो version का पता या ऑफसेट पॉइंटर का पता या ऑफसेट है, न कि स्ट्रिंग डेटा की ओर इशारा किया गया है। इसे परिभाषित करना:

char const version[] = "..."; 

इसे हल करेगा।

अंत में, सबसे आसान समाधान यह सुनिश्चित करना है कि स्ट्रिंग में कुछ अत्यधिक पहचान योग्य पैटर्न हैं, और पूरी फ़ाइल रैखिक रूप से इस पैटर्न की तलाश में स्कैन करें।

+0

पूरी फाइल स्कैनिंग ठीक वही है जो मैं करता हूं। यह बस कम सुरुचिपूर्ण लगता है और मैं कुछ सीखना चाहता हूं, इसलिए मैंने इस सवाल से पूछा। पॉइंटर बनाता है के बजाय सरणी घोषित करना एनएम प्रदर्शित करता है कि प्रतीकों की सूची से गायब हो जाता है। – Simon

+1

@ सिमोन वेल, यह सही ढंग से फ़ाइल को पार्स करने के लिए _is_ अधिक सुरुचिपूर्ण है, लेकिन यह भी बहुत अधिक काम है। एक सूचक के बजाय सरणी घोषित करने के लिए, कारण गायब होने का कारण सी ++ की सूक्ष्मता के कारण होता है: एक कॉन्स ऑब्जेक्ट में डिफ़ॉल्ट रूप से आंतरिक संबंध होता है। यदि आप इसे 'बाहरी char const संस्करण [] = "..." "घोषित करते हैं, तो ऐसा नहीं होगा; 'बाहरी' बाहरी संबंध को मजबूर करता है और प्रारंभिकरण इसे परिभाषा बनाता है, न कि घोषणा। –

+0

धन्यवाद, निश्चित रूप से मैं जुड़ाव भूल गया! 'बाहरी 'कीवर्ड का उपयोग करना स्ट्रिंग अब प्रतीक तालिका में दिखाई देता है और मुझे पता है कि' एनएम 'से प्राप्त पता वास्तव में स्टिंग के स्थान से मेल खाता है, यह अब काम करता है। मैं 'एनएम' से प्राप्त पते की तलाश करके स्ट्रिंग प्राप्त करने में सक्षम हूं! – Simon