2012-05-04 10 views
7

मैं एक (C++) परियोजना है, जिसमें पूरी तरह से गतिशील रूप से आवंटित कार्यों की आवश्यकता है, जो malloc/नई और mprotect का मतलब है पर काम कर रहा है पर नए कार्यों बनाने और उसके बाद करने के लिए मैन्युअल रूप से बफर संशोधित करने के लिए विधानसभा के साथ C++ का उपयोग करते हुए असेंबली कोड इस वजह से मैंने ठीक से सोचा है, मेरे "बफर" में क्या आवश्यक है, क्योंकि यह किसी अन्य _cdecl फ़ंक्शन के को दोहराएं। उदाहरण के लिए:आवंटित और रनटाइम

int ImAcDeclFunc(int a, int b) 
{ 
    return a + b; 
} 

मैं सचमुच इस समारोह का डुप्लिकेट बनाने के लिए चाहते हैं, लेकिन पूरी तरह से गतिशील, कि क्या आवश्यकता होती है (और यह सी ++ इनलाइन विधानसभा के साथ है याद) चाहते हैं? शुरुआत के लिए, मुझे लगता है मैं कुछ इस तरह (या एक समान समाधान) क्या करना है जाएगा:

// My main.... 
byte * ImAcDeclFunc = new byte[memory]; 
mprotect(Align(ImAcDeclFunc), pageSize, PROT_EXEC | PROT_READ | PROT_WRITE); 

इस के बाद मैं ImAcDeclFunc(int a, int b); के लिए विधानसभा कोड पता लगाने के लिए होगा। अब मैं असेंबली में अभी भी लुसी हूं, तो यह कार्य AT & टी वाक्यविन्यास में कैसे होगा? यहाँ मेरी बोल्ड प्रयास है:

push %ebp 
movl %%ebp, %%esp 
movl 8(%ebp), %%eax 
movl 12(%ebp), %%edx 
addl edx, eax 
pop ebp 
ret 

अगर यह कोड सही है (जो मैं अत्यधिक संदेह, कृपया मुझे सही करें) मैं केवल हेक्स में इस कोड के मूल्य खोजने की आवश्यकता होगी अब (उदाहरण के लिए, 'JMP' 0xE9 और है ' inc '0xFE है), और इन मानों का सीधे सी ++ में उपयोग करें? अगर मैं अपने पिछले सी ++ कोड जारी रखने के लिए:

*ImAcDeclFunc = 'hex value for push'; // This is 'push' from the first line 
*(uint)(ImAcDeclFunc + 1) = 'address to push'; // This is %ebp from the first line 
*(ImAcDeclFunc + 5) = 'hex value for movl' // This is movl from the second line 
// and so on... 

मैं पूरी कोड/बफर के लिए ऐसा करने के बाद के बाद, कि एक पूरी तरह से गतिशील _cdecl समारोह के लिए पर्याप्त (यानी मैं सिर्फ एक समारोह सूचक को यह डाली सकता है हो सकता है और int result = ((int (*)(int, int))ImAcDeclFunc)(firstArg, secondArg) करें?)। और मैं बढ़ावा :: समारोह या कुछ समान का प्रयोग करने में कोई दिलचस्पी नहीं हूँ, मैं जरूरत समारोह पूरी तरह से गतिशील, इसलिए मेरी रुचि :)

नोट होने की: यह सवाल मेरे previous one पर एक निरंतरता है, लेकिन साथ बहुत अधिक विशिष्टताएं।

+0

आपको फ़ंक्शन कॉपी करने की आवश्यकता क्यों होगी? मूल एक उतना ही अच्छा है। क्या आप कुछ उच्च स्तरीय प्रतिनिधित्व से पूरी तरह से नया कार्य उत्पन्न करना चाहते हैं? –

+0

@ एनएम। हां, यह सब मेरे लिए समझने के लिए सिर्फ एक उदाहरण था, और आसानी से आपके लिए सबकुछ प्रस्तुत करना था। मुझे आसानी से इनमें से बीस की आवश्यकता होगी। यदि आप मेरा लिंक पढ़ते हैं (मेरे दूसरे प्रश्न के लिए) तो आप वास्तव में समझेंगे कि क्यों :) –

+0

मैंने पहली बार उस प्रश्न को समझने की कोशिश की, बिना किसी सफलता के। –

उत्तर

5

तो आप ले इस lala.c:

int ImAcDeclFunc(int a, int b) 
{ 
    return a + b; 
} 

int main(void) 
{ 
    return 0; 
} 

आप इसे gcc -Wall lala.c -o lala साथ संकलन कर सकते हैं। इसके बाद आप objdump -Dslx lala >> lala.txt के साथ निष्पादन योग्य को अलग कर सकते हैं। आप पाएंगे ImAcDeclFunc के लिए इकट्ठा किया जाता है:

00000000004004c4 <ImAcDeclFunc>: 
ImAcDeclFunc(): 
    4004c4: 55      push %rbp 
    4004c5: 48 89 e5    mov %rsp,%rbp 
    4004c8: 89 7d fc    mov %edi,-0x4(%rbp) 
    4004cb: 89 75 f8    mov %esi,-0x8(%rbp) 
    4004ce: 8b 45 f8    mov -0x8(%rbp),%eax 
    4004d1: 8b 55 fc    mov -0x4(%rbp),%edx 
    4004d4: 8d 04 02    lea (%rdx,%rax,1),%eax 
    4004d7: c9      leaveq 
    4004d8: c3      retq 

वास्तव में इस समारोह कहीं और कॉपी करने के लिए अपेक्षाकृत आसान है। इस मामले में, आप यह कहकर पूरी तरह से सही हैं कि आप बाइट्स की प्रतिलिपि बना सकते हैं और यह केवल काम करेगा।

समस्या तब होती है जब आप ओपोड के हिस्से के रूप में रिश्तेदार ऑफसेट का उपयोग करने वाले निर्देशों का उपयोग करना शुरू करते हैं। उदाहरण के लिए, एक सापेक्ष कूद या एक सापेक्ष कॉल। इन मामलों में, आपको को को ठीक से निर्देशित करने की आवश्यकता है जब तक कि आप इसे उसी पते पर कॉपी करने में सक्षम न हों, जहां यह मूल रूप से था।

संक्षेप में, स्थानांतरित करने के लिए, आपको यह पता लगाना होगा कि यह मूल रूप से कहां स्थित था, और उस अंतर की गणना करें जहां आप इसे आधार पर जा रहे हैं और इस ऑफसेट के संबंध में प्रत्येक सापेक्ष निर्देश को स्थानांतरित कर सकते हैं। यह अपने आप में व्यवहार्य है।आपकी वास्तविक कठिनाई अन्य कार्यों में कॉल को संभालने में कामयाब रही है, विशेष रूप से लाइब्रेरीज़ को कॉल करती है। इस मामले में आपको यह गारंटी देने की आवश्यकता होगी कि लाइब्रेरी जुड़ा हुआ है और उसके बाद इसे निष्पादित करने योग्य निष्पादन योग्य प्रारूप द्वारा परिभाषित तरीके से कॉल करें। यह बेहद गैर-तुच्छ है। यदि आप अभी भी रुचि रखते हैं तो मैं आपको इस दिशा में इंगित कर सकता हूं कि आपको इसके लिए कहां पढ़ना चाहिए।


ऊपर अपने सरल मामले में, आप यह कर सकते हैं:

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <malloc.h> 
#include <sys/mman.h> 
#include <unistd.h> 

int main(void) 
{ 
    char func[] = {0x55, 0x48, 0x89, 0xe5, 0x89, 0x7d, 0xfc, 
    0x89, 0x75, 0xf8, 0x8b, 0x45, 0xf8, 
    0x8b, 0x55, 0xfc, 0x8d, 0x04, 0x02, 
    0xc9, 0xc3}; 

    int (* func_copy)(int,int) = mmap(NULL, sizeof(func), 
     PROT_WRITE | PROT_READ | PROT_EXEC, 
     MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 

    memcpy(func_copy, func, sizeof(func)); 
    printf("1 + 2 = %d\n", func_copy(1,2)); 

    munmap(func_copy, sizeof(func)); 
    return EXIT_SUCCESS; 
} 

यह x86-64 पर ठीक काम करता है। यह प्रिंट:

1 + 2 = 3 
+1

यदि आप मुझे एक कामकाजी उदाहरण के साथ आपूर्ति कर सकते हैं तो मैं इसकी सराहना करता हूं। यह मेरे लिए ठोस सोना होगा! सापेक्ष कॉल के बारे में, मुझे पता है कि यह इस तरह है; 'targetAddress - currentAddress -/+ किसी भी ऑफसेट '? 'हैंडलिंग लाइब्रेरी कॉल' के बारे में, क्या यह कोई समस्या होगी, अगर मैं केवल सदस्य कार्यों को कॉल करूंगा? चूंकि मैं जीसीसी का उपयोग करता हूं, यह _exactly_ को cdecl कॉल की तरह है लेकिन एक अतिरिक्त सूचक ('यह' सूचक) के साथ। या यदि मैं सदस्य समारोह से शायद _stdcall के साथ लाइब्रेरी फ़ंक्शन कॉल करता हूं तो यह समस्याएं पैदा करेगा; i.e dynamic_func-> member_func-> library_func? –

+0

ओह, वैसे, mprotect विफल नहीं है क्योंकि आप स्मृति को संरेखित नहीं करते हैं? मैं खुद कोशिश करूँगा :) –

+0

@ElliottDarfink: हाँ, मैंने अभी भी संरेखण देखा है। इसे बदलने के बाद भी यह segfaults है तो कुछ और खेलने की आवश्यकता होगी। हां, सापेक्ष ऑफसेट ज्यादातर लक्ष्य एड्रेस और वर्तमान एड्रेस के डेल्टा लेने से काम करते हैं। –

1

आप जीएनयू बिजली की जांच करना चाहेंगे: http://www.gnu.org/software/lightning/। यह आपको जो करने की कोशिश कर रहा है उसके साथ आपकी मदद कर सकता है।

+1

हां, मैंने इसके बारे में पढ़ा है लेकिन मुझे समझ में नहीं आया कि यह कैसे काम करता है। उल्लेख नहीं है कि दस्तावेज कितना पतला है। आप नहीं जानते कि कोई दस्तावेज संसाधन है जो मदद हाथ प्रदान कर सकता है? ऐसा लगता है कि मैं क्या चाहता हूं, मैं सिर्फ _how_ नहीं जानता। –

1

मुझे लगता है कि यह बेहतर विचार के बजाय स्वयं संशोधित प्रोग्राम लिखने के अपने प्रोजेक्ट में कुछ पटकथा भाषा एम्बेड करने के लिए हो जाएगा। इसमें कम समय लगेगा और आपको अधिक लचीलापन मिलेगा।

यदि मैं सचमुच इस फ़ंक्शन का डुप्लिकेट बनाना चाहता हूं, लेकिन पूरी तरह से गतिशील रूप से, इसकी आवश्यकता क्या होगी (और याद रखें कि यह इनलाइन असेंबली के साथ सी ++ है)?

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

+0

'इसे डिस्सेबलर के साथ मानव की आवश्यकता होगी' - यह गलत है। स्वचालित उपकरण हैं जो स्थैतिक विश्लेषण करते हैं जो इस के विपरीत है (जैसे Dyninst)। –

+0

@ माइककवान: कोई विरोधाभास नहीं है, और मैं सही हूं। जबकि स्वचालित उपकरण हैं, वे 100% विश्वसनीय नहीं हैं, उन्हें मानव सहायता की आवश्यकता हो सकती है, और वे अक्सर डीबग जानकारी से सहायक डेटा खींचते हैं। आईडीए प्रो की तरह कुछ फ़ाइल को दिनचर्या में विभाजित करने में कुछ मिनट लगते हैं, और फिर भी उनमें से कई को याद कर सकते हैं। यदि आप सॉफ़्टवेयर का विश्लेषण करने का प्रयास करते हैं तो यह और भी मजाकिया हो जाएगा जो डिससेबलर को भ्रमित करने के लिए अपमानित था। – SigTerm

+0

और आप मानते हैं कि एक ऐसे डिस्सेबलर वाला इंसान ऐसे मामलों में बेहतर कर सकता है? अप्रत्यक्ष शाखाओं के साथ ज्यादातर स्थिर विश्लेषण खत्म हो जाता है। इन मामलों में मानव विश्लेषण बहुत बेहतर नहीं है। आपके उत्तर में भी अधिक त्रुटियां हैं।प्रतीक की मदद से फ़ंक्शन का आकार वास्तव में निर्धारित किया जा सकता है (कम से कम ईएलएफ पर)। –