2011-11-13 15 views
5

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

सी स्रोत दिया:

int arith(int x, int y, int z) 
{ 
    int t1 = x+y; 
    int t2 = z+t1; 
    int t3 = x+4; 
    int t4 = y * 48; 
    int t5 = t3 + t4; 
    int rval = t2 * t5; 
    return rval; 
} 

विधानसभा दिया:

arith: 
pushl %ebp 
movl %esp,%ebp 

movl 8(%ebp),%eax 
movl 12(%ebp),%edx 
leal (%edx,%eax),%ecx 
leal (%edx,%edx,2),%edx 
sall $4,%edx 
addl 16(%ebp),%ecx 
leal 4(%edx,%eax),%eax 
imull %ecx,%eax 

movl %ebp,%esp 
popl %ebp 
ret 

मैं सिर्फ मैं कैसे उदाहरण के लिए विचार करने के लिए सक्षम होने के लिए चाहिए के रूप में उलझन में हूँ कि z + t1 के जोड़ने (z + x + y) असेंबली में y * 48 के बाद असेंबली कोड में दूसरी पंक्ति (स्रोत में) पर सूचीबद्ध होता है या उदाहरण के लिए x + 4 तीसरी पंक्ति है जब असेंबली में यह एक पंक्ति में भी नहीं है, इसकी पिछले leal कथन के साथ मिश्रित प्रकार। जब मेरे पास स्रोत होता है तो यह मुझे समझ में आता है लेकिन मुझे एक परीक्षण के लिए स्रोत को पुन: पेश करने में सक्षम होना चाहिए और मैं समझता हूं कि संकलक चीजों को अनुकूलित करता है लेकिन अगर किसी के पास रिवर्स इंजीनियरिंग के बारे में सोचने का कोई तरीका है जो मेरी मदद कर सकता है अगर वे मुझे अपनी विचार प्रक्रिया के माध्यम से चल सकते हैं तो मैं इसकी बहुत सराहना करता हूं।

धन्यवाद।

+0

क्या अनुकूलन स्तर आप उपयोग कर रहे हैं जब आप संकलन कर रहे हैं? यदि आप लाइन-दर-लाइन रूपांतरण चाहते हैं, तो -00 का उपयोग करें, अन्यथा, आपको अनुकूलन को ध्यान में रखना होगा। – Maz

+1

... और मूल सी कथन आदेश पर अनुकूलित कोड को वापस करने का पूरी तरह से संभव नहीं है। –

+0

क्या आप वाकई एक बेवकूफ संकलन है? ऐसा लगता है कि यह कुछ हद तक अनुकूलित है। बीजगणितीय अभिव्यक्ति लिखें कि फ़ंक्शन गणना करता है और देखता है कि क्या आप इसे खोज सकते हैं। –

उत्तर

9

मैंने आपके लिए यह दिखाने के लिए अलग-अलग हिस्सों को तोड़ दिया है कि सी स्रोत से असेंबली कैसे बनाई गई थी।

8(%ebp) = x, 12(%ebp) = y, 16(%ebp) = z

arith: 

स्टैक फ्रेम बनाएँ:

pushl %ebp 
movl %esp,%ebp 


ले जाएँ x eax में, y edx में:

movl 8(%ebp),%eax 
movl 12(%ebp),%edx 


t1 = x + yleal (लोड प्रभावी पता) edx और eax, और t1 जोड़ देगा ecx में होगा:

leal (%edx,%eax),%ecx 


int t4 = y * 48; नीचे दो चरणों में, 3 से गुणा करें, तो 16 से t4 अंततः edx में होगा :

edx गुणा करके 2, और परिणाम के लिए edx जोड़ें, यानी। edx = edx * 3:

leal (%edx,%edx,2),%edx 

शिफ्ट 4 बिट्स, यानी छोड़ दिया गया। 16 से गुणा करें:

sall $4,%edx 


int t2 = z+t1;ecx शुरू में t1 रखती है, z, 16(%ebp) पर है अनुदेश ecx के अंत में t2 लेंगे:

addl 16(%ebp),%ecx 


int t5 = t3 + t4;t3 बस x + 4 था, और t3 की गणना और भंडारण के बजाय, t3 की अभिव्यक्ति इनलाइन रखी गई है। यह निर्देश आवश्यक है (x+4) + t4, जो t3 + t4 जैसा ही है। यह edx ( t4) और eax ( x) जोड़ता है, और उस परिणाम को प्राप्त करने के लिए ऑफसेट के रूप में 4 जोड़ता है।

leal 4(%edx,%eax),%eax 

int rval = t2 * t5; काफी इस सीधी-सपाट एक; ecxt2 और eax का प्रतिनिधित्व करता है t5 का प्रतिनिधित्व करता है। वापसी मूल्य eax के माध्यम से कॉलर को वापस भेज दिया जाता है।

imull %ecx,%eax 


स्टैक फ्रेम को नष्ट और esp और ebp बहाल: दिनचर्या से

movl %ebp,%esp 
popl %ebp 


वापसी:

ret 


इस उदाहरण से आप देख सकते हैं कि रेसुल टी एक जैसा है, लेकिन संरचना थोड़ा अलग है। सबसे अधिक संभावना है कि इस कोड को किसी प्रकार के अनुकूलन के साथ संकलित किया गया था या किसी ने इसे स्वयं को एक बिंदु प्रदर्शित करने के लिए लिखा था।

जैसा कि अन्य ने कहा है, आप पूरी तरह से अलग-अलग हिस्सों से स्रोत पर नहीं जा सकते हैं। समकक्ष सी कोड के साथ आने के लिए असेंबली पढ़ने वाले व्यक्ति की व्याख्या पर निर्भर है।

gcc -c -g arith.c 
:

डिबग जानकारी ( -g) है, जो स्रोत एम्बेड कर देंगे साथ

संकलित:


सीखने विधानसभा और अपने सी कार्यक्रमों के disassembly को समझने के साथ मदद करने के लिए आप लिनक्स पर निम्न कर सकते हैं

यदि आप 64-बिट मशीन पर हैं, तो आप -m32 ध्वज के साथ 32-बिट बाइनरी बनाने के लिए कंपाइलर को बता सकते हैं (मैंने नीचे दिए गए उदाहरण के लिए ऐसा किया था)।


उपयोग objdump वस्तु फ़ाइल डंप करने के लिए यह स्रोत interleaved के साथ:

objdump -d -S arith.o 

-d = disassembly, -S = प्रदर्शन स्रोत। यदि आप एटी & टी सिंटैक्स पर अपना उदाहरण उपयोग करते हैं तो आप इंटेल एएसएम सिंटैक्स का उपयोग करने के लिए -M intel-mnemonic जोड़ सकते हैं।

आउटपुट:

arith.o:  file format elf32-i386 


Disassembly of section .text: 

00000000 <arith>: 
int arith(int x, int y, int z) 
{ 
    0: 55      push %ebp 
    1: 89 e5     mov %esp,%ebp 
    3: 83 ec 20    sub $0x20,%esp 
    int t1 = x+y; 
    6: 8b 45 0c    mov 0xc(%ebp),%eax 
    9: 8b 55 08    mov 0x8(%ebp),%edx 
    c: 01 d0     add %edx,%eax 
    e: 89 45 fc    mov %eax,-0x4(%ebp) 
    int t2 = z+t1; 
    11: 8b 45 fc    mov -0x4(%ebp),%eax 
    14: 8b 55 10    mov 0x10(%ebp),%edx 
    17: 01 d0     add %edx,%eax 
    19: 89 45 f8    mov %eax,-0x8(%ebp) 
    int t3 = x+4; 
    1c: 8b 45 08    mov 0x8(%ebp),%eax 
    1f: 83 c0 04    add $0x4,%eax 
    22: 89 45 f4    mov %eax,-0xc(%ebp) 
    int t4 = y * 48; 
    25: 8b 55 0c    mov 0xc(%ebp),%edx 
    28: 89 d0     mov %edx,%eax 
    2a: 01 c0     add %eax,%eax 
    2c: 01 d0     add %edx,%eax 
    2e: c1 e0 04    shl $0x4,%eax 
    31: 89 45 f0    mov %eax,-0x10(%ebp) 
    int t5 = t3 + t4; 
    34: 8b 45 f0    mov -0x10(%ebp),%eax 
    37: 8b 55 f4    mov -0xc(%ebp),%edx 
    3a: 01 d0     add %edx,%eax 
    3c: 89 45 ec    mov %eax,-0x14(%ebp) 
    int rval = t2 * t5; 
    3f: 8b 45 f8    mov -0x8(%ebp),%eax 
    42: 0f af 45 ec    imul -0x14(%ebp),%eax 
    46: 89 45 e8    mov %eax,-0x18(%ebp) 
    return rval; 
    49: 8b 45 e8    mov -0x18(%ebp),%eax 
} 
    4c: c9      leave 
    4d: c3      ret 

आप देख सकते हैं, अनुकूलन के बिना संकलक उदाहरण आपके पास तुलना में एक बड़ा बाइनरी पैदा करता है। आप इसके साथ खेल सकते हैं और संकलन करते समय एक कंपाइलर अनुकूलन ध्वज जोड़ सकते हैं (यानी -O1, -O2, -O3)। ऑप्टिमाइज़ेशन स्तर जितना ऊंचा होगा, उतना ही अमूर्त प्रतीत होता है।

उदाहरण के लिए, बस स्तर 1 अनुकूलन (gcc -c -g -O1 -m32 arith.c1), उत्पादन विधानसभा कोड के साथ एक बहुत कम है:

00000000 <arith>: 
int arith(int x, int y, int z) 
{ 
    0: 8b 4c 24 04    mov 0x4(%esp),%ecx 
    4: 8b 54 24 08    mov 0x8(%esp),%edx 
    int t1 = x+y; 
    8: 8d 04 11    lea (%ecx,%edx,1),%eax 
    int t2 = z+t1; 
    b: 03 44 24 0c    add 0xc(%esp),%eax 
    int t3 = x+4; 
    int t4 = y * 48; 
    f: 8d 14 52    lea (%edx,%edx,2),%edx 
    12: c1 e2 04    shl $0x4,%edx 
    int t5 = t3 + t4; 
    15: 8d 54 11 04    lea 0x4(%ecx,%edx,1),%edx 
    int rval = t2 * t5; 
    19: 0f af c2    imul %edx,%eax 
    return rval; 
} 
    1c: c3      ret 
6

आप मूल स्रोत को पुन: पेश नहीं कर सकते हैं, आप केवल समकक्ष स्रोत को पुन: पेश कर सकते हैं।

आपके मामले में t2 की गणना t1 और retval से पहले कहीं भी दिखाई दे सकती है।

स्रोत एक भी अभिव्यक्ति गया हो सकता है:

return (x+y+z) * ((x+4) + (y * 48)); 
1

Decompilation पूरी तरह से प्राप्त नहीं है: कुछ ज्ञान नुकसान होता है जब स्रोत कोड (जहां & नाम आप मूल की एक सुराग दे दी है टिप्पणी से जा रहा प्रोग्रामर का इरादा) बाइनरी मशीन कोड (जहां प्रोसेसर द्वारा निर्देशों को निष्पादित किया जाना है)।

5

जब रिवर्स इंजीनियरिंग, आपको लाइन द्वारा मूल स्रोत कोड लाइन की परवाह नहीं है, तो आप इसकी परवाह करते हैं कि यह क्या करता है। एक साइड इफेक्ट यह है कि आप देखते हैं कि कोड क्या करता है, न कि प्रोग्रामर ने कोड को क्या करना है।

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