2012-03-06 5 views
16

मैं सॉफ्टवेयर के एक टुकड़े पर काम कर रहा हूं जो रनटाइम पर असेंबलर कोड उत्पन्न करता है। - इस होना प्रतीत नहीं होता हैमैं रनटाइम पर कोड जनरेशन को सरल कैसे बना सकता हूं?

void genGetCurrentProcess(char *codePtr, FARPROC addressForGetCurrentProcessFunction) 
{ 
#ifdef _WIN64 
    // mov rax, addressForGetCurrentProcessFunction 
    *codePtr++ = 0x48 
    *codePtr++ = 0xB8; 
    *((FARPROC *)codePtr)++ = addressForGetCurrentProcessFunction; 

    // call rax 
    *codePtr++ = 0xFF; 
    *codePtr++ = 0xD0; 
#else 
    // mov eax, addressForGetCurrentProcessfunction 
    *codePtr++ = 0xB8; 
    *((FARPROC *)codePtr)++ = addressForGetCurrentProcessFunction; 

    // call eax 
    *codePtr++ = 0xFF; 
    *codePtr++ = 0xD0; 
#endif 
} 

आमतौर पर मैं इनलाइन कोडांतरक का उपयोग करते हैं, लेकिन अफसोस: उदाहरण के लिए, यहाँ एक बहुत ही सरल समारोह जो (Win64 ABI के लिए) GetCurrentProcess समारोह फोन करने के लिए कोडांतरक कोड उत्पन्न करता है अब 64 बिट एमएसवीसी कंपाइलर्स के साथ संभव है। जबकि मैं इसमें हूं - इस कोड को एमएसवीसी 6 के साथ एमएसवीसी 10 और मिनगब्लू तक भी काम करना चाहिए। genGetCurrentProcess जैसे कई और फ़ंक्शन हैं, वे सभी असेंबलर कोड उत्सर्जित करते हैं और उनमें से कई को फ़ंक्शन पॉइंटर्स मिलते हैं जिन्हें तर्क के रूप में पारित किया जाता है।

इस बारे में कष्टप्रद बात यह है कि इस कोड को संशोधित करने त्रुटियां उत्पन्न हो सकती है और हम स्वयं ABI विशेष बातों का ध्यान रखना मिल गया है (उदाहरण के लिए, आरक्षण 32 बाइट्स रजिस्टर फैलने के लिए कार्य कॉल करने से पहले अंतरिक्ष ढेर) है।

तो मेरा सवाल है - क्या मैं रनटाइम पर असेंबलर कोड उत्पन्न करने के लिए इस कोड को सरल बना सकता हूं? मेरी आशा थी कि मैं किसी भी तरह से असेंबलर कोड सीधे लिख सकता हूं (संभवतः एक बाहरी फाइल में जिसे ml/ml64 का उपयोग करके इकट्ठा किया जाता है) लेकिन यह मुझे स्पष्ट नहीं है कि यह कैसे काम करेगा यदि एकत्रित कोड में कुछ बाइट केवल ज्ञात हैं रनटाइम (उदाहरण के लिए उपरोक्त उदाहरण में addressForGetcurrentProcessFunction मान)। हो सकता है कि कुछ कोड इकट्ठा करना संभव हो लेकिन कोड में कुछ स्थानों पर 'लेबल' असाइन करें ताकि मैं रनटाइम पर कोड को आसानी से संशोधित कर सकूं और फिर इसे अपने बफर में कॉपी कर सकूं?

+2

यह इनलाइन-असेंबली नहीं है, यह इनलाइन मशीन कोड है! –

+0

आपको ऐसा करने की आवश्यकता क्यों है? क्यों न केवल अपने सी कोड से GetCurrentProcess() को कॉल करें? – user9876

+0

@ user9876: मैं एक दूरस्थ (निलंबित) प्रक्रिया में कोड पैच कर रहा हूं; यह प्रोग्राम यूनिक्स सिस्टम पर 'LD_PRELOAD' के रूप में एक समान प्रभाव प्राप्त करता है। –

उत्तर

10

asmjit पर एक नज़र डालें। यह रनटाइम कोड-पीढ़ी के लिए एक सी ++ लाइब्रेरी है। X64 का समर्थन करता है और शायद मौजूदा एक्सटेंशन (एफपीयू, एमएमएक्स, 3 डीएनओ, एसएसई, एसएसई 2, एसएसई 3, एसएसई 4) का समर्थन करता है। इसका इंटरफ़ेस असेंबली सिंटैक्स जैसा दिखता है और यह आपके लिए निर्देशों को सही ढंग से एन्कोड करता है।

+0

+1 - asmjit दिलचस्प लग रहा है, और मुझे अभी तक इसके बारे में पता नहीं था! इसका जिक्र करने के लिए धन्यवाद। –

0

आप कुछ सहायक एन्कोडिंग को दूर कर सकते हैं, कुछ सहायक कार्यों और मैक्रोज़ लिखकर सम्मेलन और सीपीयू-मोड से संबंधित विवरणों को बुला सकते हैं।

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

UINT32 blah[] = 
{ 
    mov_, ebx_, dwordPtr_, edi_, plus_, eax_, times8_, plus_, const_, 0xFEDCBA98, 
    call_, dwordPtr_, ebx_, 
}; 

लेकिन यह करने और सही करने के लिए यह बहुत काम है। कुछ आसान के लिए, केवल सहायक काम/मैक्रोज़ बनाएं, अनिवार्य रूप से जो आपने पहले ही किया है, लेकिन उपयोगकर्ता से कुछ ग़लत विवरण छुपाएं।

+3

दुर्भाग्य से कोडांतरक बयान है कि जैसे बाइट्स के लिए नक्शे नहीं है (और एक 'UINT32' सरणी का उपयोग कर निश्चित रूप से सही नहीं है, यह होना चाहिए' UINT8' या समान)। –

+0

क्या आपको उन्हें मानचित्रण से रोकता है? बस इसमें कुछ सौ तत्वों के साथ एक गणना परिभाषित करें। इसमें कोई संदेह नहीं है कि परिणामस्वरूप enum स्थिरांक को प्रति बिट 8 बिट से अधिक की आवश्यकता होगी यदि आपके पास 256 से अधिक हैं, लेकिन UINT32s की सरणी में उन्हें संग्रहीत करने में कुछ भी गलत नहीं होगा, क्या वहां होगा? Uint32 काम के बाद से यह आप स्थिरांक एम्बेड करने देता है ('mov eax में की तरह, -123' और' mov बाइट ptr [EBX + 0x123] में, 'a'') आसानी से -123, 0x123, के रूप में' एक '। आप शायद इस बिंदु को याद कर चुके हैं। इस सरणी में निष्पादन के लिए तैयार निर्देश नहीं होंगे, इसमें सामान को अतिरिक्त कोड द्वारा पार्स और संकलित किया जाएगा। –

+1

@ एलेक्स, उनका मुद्दा यह था कि x86/x64 असेंबलर निर्देश आकार और एन्कोडिंग प्रारूप में काफी भिन्न होते हैं। यह आपके मानचित्र में सरल मानचित्रण और एम्बेडिंग कॉन्स का विषय नहीं है, उद्देश्य को हरा देता है। –

2

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

यदि आपकी आवश्यकताओं अपेक्षाकृत सरल हैं, तो यह अधिक हो सकता है। मैं GeneratePrologue, GenerateEpilogue, InstructionPointerRelativeAddress और ऐसे कुछ सहायक कार्यों के साथ-साथ आपको आवश्यक नीमोनिक्स का समर्थन करने वाला सी ++ असेंबलर क्लास करने पर विचार करता हूं। यह आपको छद्म-असेंबली लिखने की अनुमति देगा, और सहायक कार्यकर्ताओं को 32/64 बिट मुद्दों का ख्याल रखना होगा।

+0

मशीन कोड को एक समर्पित असेंबलर फ़ाइल में फैक्टर करना और फिर एक वास्तविक असेंबलर को अनुवाद करना मेरा पसंदीदा समाधान होगा। हालांकि, ध्यान दें कि मेरा मशीन कोड स्थैतिक नहीं है - रजिस्टरों में रखे गए मान केवल रनटाइम पर ही ज्ञात हैं, इसलिए मुझे मूल्यों को ठीक करने के लिए रनटाइम पर असेंबलर द्वारा जेनरेट किए गए कोड को "पैच" करने में सक्षम होना चाहिए। क्या ऐसा करने का कोई अच्छा तरीका है? –

+0

क्या आपको जेनरेट कोड को उसी प्रक्रिया से चलाने की आवश्यकता है जो इसे उत्पन्न करता है, या आपको किसी अन्य प्रक्रिया (शेलकोड इंजेक्शन, जो भी हो) के लिए आउटपुट तैयार करने की आवश्यकता है? – snemarch

+0

वहाँ है। उन स्थानों के ऑफ़सेट स्टोर करें जिन्हें किसी तालिका में पैचिंग की आवश्यकता होती है (आपके जेनरेट एएसएम स्रोत कोड की शुरुआत या अंत में), ऐसे निर्देश हैं जिन्हें पैचिंग को कुछ डमी मानों का उपयोग करने की आवश्यकता होती है। फिर उस तालिका का उपयोग कर परिणामी बाइनरी पैच करें। या फिर बेहतर है कि उन रनटाइम मानों को एक टेबल में रखें और अपना एएसएम कोड उन्हें उस तालिका से लाएं। –

0

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

ObjectCodeEmitMovRegister32ScaledRegister32OffsetRegister32(EAX,EDX,4,-LowerBound*4,ESP); 

आप बता सकते हैं मैं लंबे समय के नाम की तरह:

फिर एक MOV अनुदेश उत्पन्न करने के लिए, आप कोड ऐसा दिखता है जैसे लिख सकते हैं। (कम से कम मैं वे क्या करते हैं कभी नहीं भूल सकता।)

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

#define Register32T enum Register32Type 
enum Register32Type {EAX=0,ECX=1,EDX=2,EBX=3,ESP=4,EBP=5,ESI=6,EDI=7}; 

inline 
byte ObjectCodeEmitModRM32Register32(Register32T Register32,Register32T BaseRegister32) 
// Send ModRM32Bytes for register-register mode to object file 
{ byte ModRM32Byte=0xC0+Register32*0x8+BaseRegister32; 
    ObjectCodeEmitByte(ModRM32Byte); 
    return ModRM32Byte; 
} 

inline 
byte ObjectCodeEmitModRM32Direct(Register32T Register32) 
// Send ModRM32Bytes for direct address mode to object file 
{ byte ModRM32Byte=Register32*0x8+0x05; 
    ObjectCodeEmitByte(ModRM32Byte); 
    return ModRM32Byte; 
} 

inline 
void ObjectCodeEmitSIB(Register32T ScaledRegister32, 
      natural Scale, 
      Register32T BaseRegister32) 
// send SIB byte to object file 
// Note: Use ESP for ScaledRegister32 to disable scaling; only useful when using ESP for BASE. 
{ if (ScaledRegister32==ESP && BaseRegister32!=ESP) CompilerFault(31); 
    if  (Scale==1) ObjectCodeEmitByte((byte)(0x00+ScaledRegister32*0x8+BaseRegister32)); 
    else if (Scale==2) ObjectCodeEmitByte((byte)(0x40+ScaledRegister32*0x8+BaseRegister32)); 
    else if (Scale==4) ObjectCodeEmitByte((byte)(0x80+ScaledRegister32*0x8+BaseRegister32)); 
    else if (Scale==8) ObjectCodeEmitByte((byte)(0xC0+ScaledRegister32*0x8+BaseRegister32)); 
    else CompilerFault(32); 
} 

inline 
byte ObjectCodeEmitModRM32OffsetRegister32(Register32T Register32, 
         integer Offset, 
         Register32T BaseRegister32) 
// Send ModRM32Bytes for indexed address mode to object file 
// Returns 1st byte of ModRM32 for possible use in EmittedPushRM32 peephole optimization 
{ byte ModRM32Byte; 
    if (Offset==0 && BaseRegister32!=EBP) 
{ ModRM32Byte=0x00+Register32*0x8+BaseRegister32; 
    ObjectCodeEmitByte(ModRM32Byte); 
    if (BaseRegister32==ESP) ObjectCodeEmitSIB(ESP,1,ESP); 
} 
    else if (Offset>=-128 && Offset<=127) 
     { ModRM32Byte=0x40+Register32*0x8+BaseRegister32; 
    ObjectCodeEmitByte(ModRM32Byte); 
    if (BaseRegister32==ESP) ObjectCodeEmitSIB(ESP,1,ESP); 
    ObjectCodeEmitByte((byte)Offset); 
     } 
    else { // large offset 
    ModRM32Byte=0x80+Register32*0x8+BaseRegister32; 
    ObjectCodeEmitByte(ModRM32Byte); 
    if (BaseRegister32==ESP) ObjectCodeEmitSIB(ESP,1,ESP); 
    ObjectCodeEmitDword(Offset); 
    } 
    return ModRM32Byte; 
} 

inline 
byte ObjectCodeEmitModRM32OffsetScaledRegister32(Register32T Register32, 
         integer Offset, 
         Register32T ScaledRegister32, 
         natural Scale) 
// Send ModRM32Bytes for indexing by a scaled register with no base register to object file 
// Returns 1st byte of ModRM32 for possible use in EmittedPushRM32 peephole optimization 
{ byte ModRM32Byte=0x00+Register32*0x8+ESP; 
    ObjectCodeEmitByte(ModRM32Byte); // MOD=00 --> SIB does disp32[index] 
    ObjectCodeEmitSIB(ScaledRegister32,Scale,EBP); 
    ObjectCodeEmitDword(Offset); 
    return ModRM32Byte; 
} 

inline 
byte ObjectCodeEmitModRM32ScaledRegister32OffsetRegister32(Register32T Register32, 
           Register32T ScaledRegister32, 
           natural Scale, 
           integer Offset, 
           Register32T BaseRegister32) 
// Send ModRM32Bytes for indexed address mode to object file 
// Returns 1st byte of ModRM32 for possible use in EmittedPushRM32 peephole optimization 
// If Scale==0, leave scale and scaled register out of the computation 
{ byte ModRM32Byte; 
    if (Scale==0) ObjectCodeEmitModRM32OffsetRegister32(Register32,Offset,BaseRegister32); 
    else if (Offset==0 && BaseRegister32!=EBP) 
{ ModRM32Byte=0x00+Register32*0x8+ESP; 
    ObjectCodeEmitByte(ModRM32Byte); 
    ObjectCodeEmitSIB(ScaledRegister32,Scale,BaseRegister32); 
} 
    else if (Offset>=-128 && Offset<=127) 
     { ModRM32Byte=0x40+Register32*0x8+ESP; 
    ObjectCodeEmitByte(ModRM32Byte); 
    ObjectCodeEmitSIB(ScaledRegister32,Scale,BaseRegister32); 
    ObjectCodeEmitByte((byte)Offset); 
     } 
    else { // large offset 
    ModRM32Byte=0x80+Register32*0x8+ESP; 
    ObjectCodeEmitByte(ModRM32Byte); 
    ObjectCodeEmitSIB(ScaledRegister32,Scale,BaseRegister32); 
    ObjectCodeEmitDword(Offset); 
    } 
    return ModRM32Byte; 
} 

inline 
void ObjectCodeEmitLeaRegister32OffsetRegister32ScaledPlusBase32(
       Register32T Register32Destination, 
          integer Offset, 
          Register32T Register32Source, 
       natural Scale, // 1,2,4 or 8 
       Register32T Base) 
// send "LEA Register32,offset[Register32*Scale+Base]" to object file 
{ ObjectCodeEmitLeaOpcode(); 
    ObjectCodeEmitModRM32ScaledRegister32OffsetRegister32(
    Register32Destination,Register32Source,Scale,Offset,Base); 
} 

inline 
void ObjectCodeEmitMovRegister32ScaledRegister32OffsetRegister32(Register32T DestinationRegister32, 
           Register32T ScaledRegister32, 
           natural Scale, 
           integer Offset, 
           Register32T BaseRegister32) 
// Emit Mov R32 using scaled index addressing 
{ ObjectCodeEmitMovRegister32Opcode(); 
    ObjectCodeEmitModRM32ScaledRegister32OffsetRegister32(DestinationRegister32, 
          ScaledRegister32, 
          Scale, 
          Offset, 
          BaseRegister32); 
} 
संबंधित मुद्दे

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