वर्चुअल मशीन के आधार पर रा $ कैल से कीजेनमे विश्लेषण

0. जानकारी


दरार पर KeygenMe पेज
सरल vm के साथ क्रैकमे। मुख्य चेक एल्गोरिथ्म सरल है, इसलिए मुख्य लक्ष्य - vm।
पीसीओडी का मुश्किल शुरू से अंत तक बढ़ रहा है। पहला भाग एमुलेटर की तरह लगता है, लेकिन फिर यह एक अन्य तर्क के साथ मशीन जैसा दिखता है, रजिस्टर, कमांड =)
गुड लक और मज़े करो।
कठिनाई: 4 - विशेष ज्ञान की आवश्यकता है
प्लेटफ़ॉर्म: विंडोज
भाषा: C / C ++

जब हम फ़ॉर्म पर "चेक" बटन पर क्लिक करते हैं, तो हम उस कोड को देखकर अपना शोध शुरू करते हैं। चूंकि CrackMe एक नियमित संवाद बॉक्स पर आधारित है, पहली चीज जो हम देखते हैं, वह इसका पंजीकृत विंडो फ़ंक्शन है।


अंजीर। WM_COMMAND को संसाधित करने के लिए जिम्मेदार डायलॉग विंडो फ़ंक्शन का हिस्सा।

बटन दबाने से एप्लिकेशन को WM_COMMAND संदेश उस तत्व की आईडी के साथ भेजता है जिसकी घटना हुई थी। इस स्थिति में, GetDlgItemTextA API का उपयोग करके इनपुट मान प्राप्त किए जाते हैं, और फिर जो फ़ंक्शन दर्ज किए गए मानों की जांच करता है उसे कहा जाता है।


चित्र 2. विंडो फ़ंक्शन से बुलाए गए फ़ंक्शन की जांच करें।

एनओपी कमांड (403F3E - 4035A9 = 995h) की बड़ी संख्या को देखते हुए, हम मान सकते हैं कि एल्गोरिथ्म का स्रोत कोड, जो आभासी था, मूल रूप से यहां स्थित था, और बाद में इसे ओवरराइट कर दिया गया था।
सब_4017C0 फ़ंक्शन एक वर्चुअल मशीन कॉल पर एक आवरण है, जिसका मुख्य लूप सब_401890 फ़ंक्शन में स्थित है , जिसका छद्म कोड नीचे दिखाया गया है।

sub_401890
चित्र 3. सब_401890 फ़ंक्शन में एक वर्चुअल मशीन का मुख्य लूप।

स्विच / केस के अंदर ये सभी कार्य कमांड के कार्यान्वयन हैं।

वर्चुअलाइज्ड कोड स्वयं .rvmpc सेक्शन में स्टोर होता है, जिसका पता 00407000 है।

1. कमांड प्रारूप


एक आभासी मशीन की संरचना का निर्धारण, इसकी वास्तुकला का निर्धारण, साथ ही साथ इसके द्वारा उपयोग किए जाने वाले आदेशों का प्रारूप, कोड विचलन में पहला और सबसे महत्वपूर्ण कार्य है।
यह वर्चुअल मशीन एक रजिस्टर है; एक स्टैक का उपयोग चर के अस्थायी भंडारण के लिए किया जाता है।
इस वर्चुअल मशीन के लिए कमांड प्रारूप निश्चित लंबाई और काफी निरर्थक नहीं है। सभी प्रकार के कमांडों में निम्नलिखित फॉर्म का एक सामान्य हेडर होता है:
विस्थापनटाइपआकारविवरण
+0शब्द2ऑपरेशन कोड
+2DWORD4टीम आई.डी.
+6बाइट1तर्क का आकार
+7DWORD4अगला कमांड आई.डी.
+ भाDWORD4अज्ञात है

"कमांड आईडी" फ़ील्ड में पूरे बाइटकोड के लिए एक अद्वितीय मूल्य होता है। तदनुसार, अगले कमांड पर जाने के लिए, वर्चुअल मशीन "अगले कमांड के आईडी" फ़ील्ड से मान लेती है और कमांड के लिए पूरे कोड ऐरे में खोज करती है जिसकी आईडी निर्दिष्ट एक से मेल खाती है। फिर, स्विच / केस का उपयोग करते हुए, प्रत्येक कमांड की व्याख्या "ऑपरेशन कोड" फ़ील्ड के मान से होती है।

विचाराधीन वर्चुअल मशीन के आदेशों का सेट इसे आंतरिक रजिस्टरों, देशी प्रोसेसर रजिस्टरों और देशी कोड के साथ संचालित करने की अनुमति देता है।

opcodeप्रभाव
0x00कॉल
0x01कॉल
0x02सशर्त कूद
0x03धक्का देना
0x04उप / ईएसपी जोड़ें
0x05धक्का देना
0x06mov [esp], dword
0x07jmp आईडी
0x08मूव [एबप +?], डॉर्ड
0x09देशी
0x0Aदेशी
0x0B-
0x0Cआंतरिक ध्वज का संशोधन dw4052AC
0x0D-
0x0E-
0x0F-
0x10Mov REGn, dword-reg / mov REGn, dword [reg + X]
0x11mov डॉर्ड [Addr], (reg / dword) / मूव डॉर्ड [REGn], (reg / dword)
0x12विभिन्न अग्रेषण कमांड mov
0x13विभिन्न अग्रेषण कमांड mov
0x14MOV _32 [A], अनपैक (REGn)
0x15MOV REGn, पैक (_32 [A])
0x16XOR _32 [A] [i], _32 [B] [j]
0x17Mov [REGn], reg / mov reg, [REGn]
0x18XOR _32 [A] [c: d], _32 [B] [e: f]
0x19MOV _32 [ए], 0
0x14 - 0x19 कमांड अतिरिक्त मेमोरी क्षेत्र के साथ काम करते हैं, जो 32-बिट नंबरों पर बिटवाइज़ ऑपरेशन करने की अनुमति देता है।

2. वीएम कोड डिसाइड करना


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

बीस्वाइन लाइब्रेरी (+ exe) का उपयोग करके डिस्सेम्बलर स्रोत
आदेशों की असंतुष्ट सूची मेरे लिए 961 लाइनें थी।

3. भक्ति


यह चरण आवश्यक नहीं है यदि वर्चुअल कोड छोटा है और आप एल्गोरिथ्म को मूल कोड में पुन: कोड किए बिना समझ सकते हैं। जैसा कि ऊपर उल्लेख किया गया है, विचलन की प्रक्रिया में वर्चुअल मशीन के लिए कोड को देशी प्रोसेसर के लिए कोड में ट्रांसकोड करना शामिल है। ऐसा करने के लिए, वर्चुअल मशीन mnemonics के बजाय, disassembler को एक या अधिक मूल प्रोसेसर mnemonics जारी करना होगा। फिर आपको परिणामी कोड को संकलित करना चाहिए। यह ऑपरेशन मौजूदा उपकरणों के लिए समर्थन प्रदान करेगा - डिबगर, डीकॉम्पोलर, आदि।

सिद्धांत रूप में, मैंने एक डिस्सेम्बलर लिस्टिंग द्वारा सबसे अधिक भाग के लिए एल्गोरिथ्म को डिसाइड किया, लेकिन मुझे आश्चर्य हुआ कि अगर हमने देशी x86 कोड में लिस्टिंग एकत्र की तो HexRays कैसे व्यवहार करेगी। ऐसा करने के लिए, मुझे किसी भी आंतरिक रजिस्टर से कमांड mnemonics में छुटकारा मिला, बिट मानों के साथ काम करने वाले कोड का हिस्सा फिर से लिखा, और exe में सब कुछ संकलित किया। मैंने पूर्ण व्यवहार प्राप्त नहीं किया, इसलिए नीचे विघटित कोड में कुछ तार्किक त्रुटियां हैं।

X86 asm पर परिणामी स्रोत
स्रोत कोड FASM का उपयोग करके एकत्र किया जाता है।

तो उदाहरण के लिए टीमों के एक जोड़े
MOV REGn, EBP-x MOV reg, [REGn] 
एक में बदल जाते हैं
 MOV reg, [EBP-x] 

और पिछड़े आंदोलन के आदेश
 MOV REGn, EBP-x MOV [REGn], reg 
में बदल जाते हैं
 MOV [EBP-x], reg 

सबसे अधिक, डिजाइन कम हो गया है:
 MOV REG9, DWORD PTR [ebp-E0] MOV eax, DWORD PTR [REG9] MOV [REG2], eax MOV _32[1], 0 MOV _32[0], unpack(REG2) XOR _32[0][0:7], _32[1][18:1F] XOR _32[0][8:F], _32[1][10:17] XOR _32[0][10:17], _32[1][8:F] XOR _32[0][18:1F], _32[1][0:7] MOV REG2, pack(_32[1]) MOV eax, [REG2] MOV REG9, DWORD PTR [ebp-E0] MOV DWORD PTR [REG9], eax 
X86 कोडांतरक पर, यह इस तरह दिखेगा:
 MOV eax, DWORD PTR [ebp-E0] BSWAP eax MOV DWORD PTR [ebp-E0], eax 

फिर मैंने संकलित EXE पर हेक्स-रेज प्लगइन सेट किया और मुझे नीचे दिए गए चित्र में जैसा स्रोत मिला:

विघटित कोड
चित्र 4. x86 आर्किटेक्चर के लिए डिकॉम्पेल्ड कोड का पुनर्निर्माण किया गया।

4. एल्गोरिथ्म का उलटा


यह अध्ययन का सबसे सुस्त हिस्सा है, क्योंकि एल्गोरिथ्म कुछ भी दिलचस्प नहीं है और XOR और चक्रीय बदलावों पर आधारित है।

कुंजी इस प्रकार है:
SSSS-11111111HHHHHHH22222222 - ???
कहां:
एसएसएसएस - एक दशमलव संख्या प्रणाली में एक संख्यात्मक मान;
11111111, 22222222, HHHHHHHH - एक हेक्साडेसिमल संख्या प्रणाली में मूल्य;
??? - मनमाना मूल्य, मनमानी लंबाई

एल्गोरिथ्म:
  1. हम प्रविष्ट नाम के वर्णों का योग मानते हैं
     for ( i = 0; i < nLenName; i++ ) dwNameSum += name[i] 
  2. कुंजी के पहले ब्लॉक के साथ प्राप्त मूल्य की तुलना करें;
  3. कंप्यूटर की ओर से हैश पढ़ें
     for ( j = 0; j < nCompNameLen; j++ ) { dwHashCompName ^= j ^ szCompName[j]; dwHashCompName = __ROL__(dwHashCompName, 3); } 
  4. 11111111, 22222222 और HHHHHHH से हम द्विआधारी प्रतिनिधित्व (हेक्साडेक) से प्राप्त करते हैं - dwHash1, dwHash2, dwHash3 का एक एनालॉग।
  5. प्रत्येक मान के लिए, हम ऑपरेशन करते हैं:
    dwHashN = dwHashN xor dwHashCompName xor htonl(dwHashCompName)
  6. प्रमुख हैश की गणना निम्न प्रकार से की जाती है:
    dwHashSerial = dwHash3 xor dwHash1 xor htonl(dwHash1) xor dwHash2 xor htonl(dwHash2) xor dwHashCompName xor htonl(dwHashCompName)
  7. हैश की गणना एल्गोरिथम द्वारा की जाती है:
     for ( idx = 0; idx < nLenName; idx++ ) { if ( idx % 2 ) dwHashName ^= 0x4F620AEC ^ (idx + dwHash1) ^ szName [idx]; else dwHashName ^= 0x4F620AEC ^ (dwHash2 - idx) ^ szName[idx]; dwHashName = __ROL__(dwHashName, idx); } 

हमें केवल ब्लॉक 1 और 2 के लिए यादृच्छिक रूप से 2 मान उत्पन्न करने की आवश्यकता है। उसके बाद हम dwHashName और dwHashSerial पर विचार करते हैं, dwHash3 को 0. के बराबर लेते हैं और सभी अवशेष फॉर्मूला dwHash3 = dwHashName ^ dwHashSerial का उपयोग करके लापता मान की गणना करते हैं।

और निश्चित रूप से, पूरे अध्ययन का परिणाम:



EXE और keygen स्रोतों को डाउनलोड करें

पीएस यांडेक्स किसी तरह सीधे लिंक से लड़ता है, इसलिए यदि यह 404 दिखाता है, तो लिंक को एक नए टैब में खोलें।

Source: https://habr.com/ru/post/In164437/


All Articles