2009-07-29 12 views
26

के बीच स्मृति साझा करना क्योंकि मुझे कोई जवाब नहीं मिला है to the question asked previously here मैं एक अलग दृष्टिकोण की कोशिश कर रहा हूं।दो प्रक्रियाओं (सी, विंडोज)

क्या दो प्रक्रियाओं के बीच स्मृति साझा करने का कोई तरीका है?

दूसरी प्रक्रिया इंजेक्शन से जानकारी प्राप्त करती है क्योंकि यह एक विरासत कार्यक्रम है जिसे अब समर्थित नहीं किया जा रहा है।

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

क्या यह संभव है? कैसे?

कोड की सराहना की जाती है।

संपादित करें:

मुझे लगता है कि यह स्पष्ट नहीं है तो मैं स्पष्ट करना होगा। मुझे पता है कि इंजेक्ट कैसे करें। मैं इसे पहले से कर रहा हूँ। यहां मुद्दा इंजेक्शन के लिए गतिशील डेटा पास करना है।

+0

किस प्रकार का कार्यक्रम? विंडोज़, जीयूआई, कंसोल? –

+0

उनमें से सभी। मैं एक सेवा, या एक जीयूआई या कंसोल से चला सकता हूं – wonderer

+0

पीओसीओ प्रोजेक्ट में मेमोरी मैप की गई फ़ाइलों के लिए सी ++ रैपर का उपयोग करना बहुत आसान है। http://pocoproject.org/download/index.html मुझे बार-बार दर्दनाक रूप से बूस्ट सामान का उपयोग करने की कोशिश करने के बाद यह पाया गया, जो अन्य लोगों को उपयोग करने में आसान हो सकता है, लेकिन मुझे सही तरीके से उपयोग करने में क्रूरता से मुश्किल लग गई। –

उत्तर

9

आप memory-mapped file को आजमा सकते हैं।

This थोड़ा और कदम-दर-चरण विवरण देता है।

+0

यदि आप रॉ Win32 कॉल पर सभी तरह से नीचे नहीं जाना चाहते हैं, तो मैं पीओसीओ प्रोजेक्ट के पूर्व-निर्मित परीक्षण रैपर वर्गों का सुझाव देता हूं। http://pocoproject.org/download/index.html बूस्ट से कहीं अधिक हल्के और पठनीय। –

24

हालांकि खिड़कियां इसकी file mapping API के माध्यम से साझा स्मृति का समर्थन करता है, आप आसानी से एक साझा स्मृति मानचित्रण किसी अन्य प्रक्रिया में सीधे इंजेक्षन नहीं कर सकते हैं, के रूप में MapViewOfFileEx एक प्रक्रिया तर्क नहीं लेता है।

हालांकि, आप VirtualAllocEx और WriteProcessMemory का उपयोग कर किसी अन्य प्रक्रिया में स्मृति आवंटित करके कुछ डेटा इंजेक्ट कर सकते हैं। यदि आप DuplicateHandle का उपयोग करके हैंडल में कॉपी करना चाहते हैं, तो MapViewOfFileEx पर कॉल करने वाले स्टब को इंजेक्ट करें, तो आप किसी अन्य प्रक्रिया में साझा मेमोरी मैपिंग स्थापित कर सकते हैं। चूंकि ऐसा लगता है कि आप वैसे भी कोड इंजेक्शन देंगे, यह आपके लिए अच्छा काम करना चाहिए।

संक्षेप में, आप की आवश्यकता होगी:

  • lpName के लिए hFile के लिए INVALID_HANDLE_VALUE और शून्य के साथ CreateFileMapping को फोन करके एक गुमनाम साझा स्मृति खंड संभाल बनाएँ।
  • कॉपी DuplicateHandle
  • के साथ लक्ष्य की प्रक्रिया में इस संभाल, VirtualAllocEx उपयोग करने के साथ flAllocationType = MEM_COMMIT कोड के लिए कुछ स्मृति आवंटित | MEM_RESERVE और flProtect = PAGE_EXECUTE_READWRITE
  • WriteProcessMemory का उपयोग करके इस मेमोरी में अपना स्टब कोड लिखें। इस स्टब को असेंबलर में लिखा जाना चाहिए। डुप्लिकेट हैंडल से हैंडल को यहां कहीं लिखकर पास करें।
  • CreateRemoteThread का उपयोग करके अपने स्टब निष्पादित करें। स्टब को MapViewOfFileEx पर कॉल करने के लिए प्राप्त हैंडल का उपयोग करना चाहिए। प्रक्रियाओं के बाद एक साझा साझा स्मृति खंड होगा।

आप इसे थोड़ा आसान अपने ठूंठ एक बाहरी पुस्तकालय लोड करता है, तो मिल सकता है - जो है, यह बस फोन LoadLibrary (खोजने LoadLibrary का पता पाठक के लिए एक व्यायाम के रूप में छोड़ दिया जाता है) और से अपना काम करते हैं पुस्तकालय के dllmain प्रवेश बिंदु। इस मामले में नामित साझा मेमोरी का उपयोग डुप्लिकेट हैंडल के साथ चारों ओर futzing से आसान होने की संभावना है।अधिक जानकारी के लिए CreateFileMapping पर एमएसडीएन आलेख देखें, लेकिन, अनिवार्य रूप से, HFile के लिए INVALID_HANDLE_VALUE और lpName के लिए नाम पास करें।

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

  1. परिवर्तनीय आकार की साझा स्मृति का उपयोग करें। आपके स्टब को आकार और या तो साझा स्मृति में या हैंडल का नाम मिलता है। यह उचित है यदि आपको केवल एक बार डेटा का आदान-प्रदान करने की आवश्यकता है। नोट करें कि साझा मेमोरी सेगमेंट का आकार सृजन के बाद आसानी से बदला नहीं जा सकता है।
  2. named pipe का उपयोग करें। आपके स्टब को पाइप के नाम या हैंडल मिल जाता है। फिर आप परिवर्तनीय आकार के ब्लॉक का आदान-प्रदान करने के लिए उपयुक्त प्रोटोकॉल का उपयोग कर सकते हैं - उदाहरण के लिए, वास्तविक संदेश के बाद लंबाई के लिए size_t लिखें। या PIPE_TYPE_MESSAGE और PIPE_READMODE_MESSAGE का उपयोग करें, और यह निर्धारित करने के लिए ERROR_MORE_DATA के लिए देखें कि संदेश कहां समाप्त होते हैं। यह उचित है यदि आपको डेटा को कई बार एक्सचेंज करने की आवश्यकता है।

संपादित 2: यहाँ कैसे आप अपने ठूंठ के लिए हैंडल या सूचक भंडारण लागू हो सकता है की एक संक्षिप्त वर्णन है:

.db B8   ;; mov eax, imm32 
.dl handle_value ;; fill this in (located at the start of the image + one byte) 
;; handle value is now in eax, do with it as you will 
;; more code follows... 

आप, साथ ही एक निश्चित नाम है, जो शायद आसान है इस्तेमाल कर सकते हैं।

+0

एक गैर-खिड़कियों वाले व्यक्ति के रूप में, जो यहां क्या हो रहा है, इसके बारे में केवल एक विचारधारात्मक विचार है, क्या मुझे यह थोड़ा सा पता होना चाहिए कि यह संभव है? क्या ऐसा करने के लिए एक तुलनीय यूनिक्स प्रक्रिया है? –

+0

हां, यह यूनिक्स में किया जा सकता है। अज्ञात mmap कॉल के लिए रजिस्टरों को frobACE_POKEUSER का उपयोग करें। कॉल पूर्ण होने के बाद, कोड लिखने के लिए PTRACE_POKEDATA या mmapping/proc/pid/mem का उपयोग करें। फिर कोड को जो कुछ भी करें। – bdonlan

+0

स्पष्टीकरण के लिए, ऊपर लिनक्स के लिए था। अन्य यूनिक्सों की संभावना कुछ समान होगी। यदि आप अपना खुद का धागा चाहते हैं, तो अपने इंजेक्शन स्टब से libpthread को कॉल करें। – bdonlan

3

आप साझा मेमोरी

+0

साझा मेमोरी _is_ मेमोरी मैप की गई फ़ाइलों में हैंडल करने के बजाए एक निश्चित नाम का उपयोग करें। तुम क्या करने की कोशिश कर रहे हो? – bdonlan

+0

क्षमा करें मेरा मतलब पाइप था। मुझे टिप्पणी के लिए धन्यवाद – wonderer

1

उपयोग कर सकते हैं जब आप Windows के बारे में बात कर रहे हैं, मुख्य अवरोध कि प्रक्रियाओं को एक अपने स्वयं के आभासी पता स्थान में रहते है। दुर्भाग्य से आप प्रक्रिया से प्रक्रिया के आसपास सामान्य स्मृति पते को पारित नहीं कर सकते हैं और परिणाम प्राप्त कर सकते हैं। (दूसरी ओर, थ्रेड, एक ही पता स्थान में रहते हैं, यही कारण है कि थ्रेड उसी तरह मेमोरी देख सकते हैं।)

विंडोज़, हालांकि, साझा स्मृति स्थान है जो आपको बहुत सावधान रहना है सही ढंग से प्रबंधन करने के लिए। साझा मेमोरी स्पेस में स्थान आवंटित करने वाली कोई भी प्रक्रिया उस स्मृति को स्पष्ट रूप से मुक्त करने के लिए ज़िम्मेदार है। यह स्थानीय स्मृति के विपरीत है, जो प्रक्रिया मरने पर कम या ज्यादा गायब हो जाती है।

कुछ विचारों के लिए this MSDN sample article देखें कि आप दुनिया भर में साझा स्मृति स्थान का उपयोग कैसे कर सकते हैं। एर, विरासत सॉफ्टवेयर के साथ इंटरफ़ेस। या जो कुछ भी :) शुभकामनाएं जो भी आप कर रहे हैं!

+0

धन्यवाद। वे स्थिति को थोड़ा और स्पष्ट करते हैं। वह लेख वास्तव में यह नहीं बताता कि किस तरह के एपीआई या पद्धतियों का उपयोग करना है। – wonderer

+3

वैश्विक ढेर Win32 में प्रक्रिया-स्थानीय है। साझा स्मृति के लिए इसका उपयोग कम से कम एनटी आधारित (एक्सपी और दोस्तों) पर काम नहीं करेगा। – bdonlan

+0

@bdonlan - ?? शायद हम यहां एक ही बात के बारे में बात नहीं कर रहे हैं। वैश्विक ढेर वैश्विक स्मृति में रहता है, जिसे सभी प्रक्रियाओं में साझा किया जाता है। सभी आवंटन हैंडल आधारित हैं, पॉइंटर आधारित नहीं हैं। मुझे लगता है कि अगर हम बात कर रहे थे तो आप सही हो सकते हैं .NET - मुझे याद नहीं है कि प्रबंधित सीएलआर शब्दावली में "वैश्विक" का अर्थ कुछ और है। Bdonlan, क्या आप अपनी टिप्पणी का विस्तार कर सकते हैं? मैं यह सुनिश्चित करना चाहता हूं कि मैं समझता हूं कि मैं किस बारे में बात कर रहा हूं :) – Mike

0

आप दो प्रक्रियाओं के बीच संवाद करने के लिए Boost.Interprocess का उपयोग करने का प्रयास कर सकते हैं। लेकिन पहले से मौजूद, समर्थित सॉफ्टवेयर में कोड इंजेक्ट करने के लिए, आपको शायद WriteProcessMemory का उपयोग करके @ bdonlan के तरीके का उपयोग करना होगा।

+0

धन्यवाद। क्या आप विस्तार से समझा सकते हैं? मुझे पता है कि कैसे इंजेक्ट करना है, यह मुद्दा नहीं है। – wonderer

+0

मैं writeprocessmemory का उपयोग कर रहा हूँ। मुझे केवल उस जानकारी को पास करने की आवश्यकता है जो कभी-कभी आकार बदलती है – wonderer

1

क्या आपने पाइप (स्मृति के लिए) या यहां तक ​​कि क्रमबद्धता (आपके ऑब्जेक्ट्स के लिए) का उपयोग करने का प्रयास किया था? आप प्रक्रियाओं के बीच स्मृति का प्रबंधन करने के लिए फ़ाइलों का उपयोग कर सकते हैं। प्रक्रियाओं के बीच संचार प्राप्त करने के लिए सॉकेट भी अच्छे हैं।

0

मेमोरी मैपिंग जाने का तरीका है, आपको स्थायी मेमोरी स्पेस बनाने की भी आवश्यकता नहीं है, मेमोरी सेक्टर स्कोप से बाहर हो जाता है जब सभी प्रक्रियाएं इसे बंद कर देती हैं। अन्य तरीके भी हैं। एक सी ऐप से दूसरे डेटा में डेटा पास करने का एक त्वरित और गंदा तरीका सिर्फ ओएस का उपयोग करना है। कमांड लाइन प्रकार app1 | app2 पर। इससे ऐप 2 ऐप 1 का आउटपुट गंतव्य हो सकता है या iow से printf कमांड ऐप 2 को भेज देगा (इसे पाइपिंग कहा जाता है)।

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