हुकिंग: Difference between revisions
No edit summary |
No edit summary |
||
Line 3: | Line 3: | ||
{{distinguish|हुकिंग}} | {{distinguish|हुकिंग}} | ||
[[कंप्यूटर प्रोग्रामिंग]] में '''हुकिंग''' शब्द | [[कंप्यूटर प्रोग्रामिंग]] में '''हुकिंग''' शब्द [[मॉड्यूलर प्रोग्रामिंग]] के बीच [[फ़ंक्शन कॉल|कॉल फ़ंक्शन]] या [[ घटना (कंप्यूटिंग) |इवेंट (कंप्यूटिंग)]] को इंटरसेप्ट करके [[ऑपरेटिंग सिस्टम]], [[अनुप्रयोग प्रक्रिया सामग्री|एप्लिकेशन]] या अन्य सॉफ़्टवेयर कॉम्पोनेन्ट के प्रोग्राम को परिवर्तित या इंटरसेप्ट करने के लिए उपयोग की जाने वाली तकनीकों की एक तालिका सम्मिलित होती है। ऐसे कोड जो इंटरसेप्टेड कॉल फ़ंक्शन, ईवेंट या संदेशों को सुरक्षित रखते हैं उन्हे हुक कहा जाता है। | ||
हुकिंग का उपयोग कई उद्देश्यों के लिए किया जाता है, जिसमें [[डिबगिंग]] और | हुकिंग का उपयोग कई उद्देश्यों के लिए किया जाता है, जिसमें [[डिबगिंग]] और फंक्शन का विस्तार सम्मिलित है। उदाहरणों में किसी एप्लिकेशन के लिए कीबोर्ड या माउस ईवेंट संदेशों को इंटरसेप्ट करना या किसी एप्लिकेशन के अन्य कॉम्पोनेन्ट के फ़ंक्शन को संशोधित करने के लिए ऑपरेटिंग सिस्टम कॉल को इंटरसेप्ट करना सम्मिलित हो सकता है। इसका व्यापक रूप से बेंचमार्किंग प्रोग्राम में भी उपयोग किया जाता है। उदाहरण के लिए 3डी गेम में [[फ्रेम रेट|फ्रेम दर]] मापने के लिए जहां आउटपुट और इनपुट हुकिंग के माध्यम से प्राप्त किया जाता है। | ||
हुकिंग का उपयोग | हुकिंग का उपयोग मॉलिसियस कोड द्वारा भी किया जा सकता है। उदाहरण के लिए [[रूटकिट]] सॉफ़्टवेयर के [[एपीआई]] कॉल के '''आउटपुट द्वारा स्वयं को अदृश्य बनाने की कोशिश करते हैं जो अ'''न्यथा उनके अस्तित्व को प्रकट कर सकते हैं प्रायः हुकिंग तकनीकों का उपयोग करते हैं। | ||
== प्रकार == | == प्रकार == | ||
सामान्यतः हुक तब | सामान्यतः हुक को तब प्रयुक्त किया जाता है जब सॉफ़्टवेयर पहले से ही सक्रिय हो, क्योकि हुकिंग एक ऐसा फ़ंक्शन है जिसे एप्लिकेशन प्रारम्भ होने से पहले भी प्रयुक्त किया जा सकता है। इन दोनों तकनीकों का निम्नलिखित रूप से वर्णन किया गया है। | ||
=== सोर्स कोड संशोधन === | === सोर्स कोड संशोधन === | ||
किसी एप्लिकेशन के | किसी एप्लिकेशन के प्रारम्भ होने से पहले [[रिवर्स इंजीनियरिंग]] की तकनीकों के माध्यम से [[निष्पादन|संचालित कोड]] या [[ पुस्तकालय (कंप्यूटिंग) |लाइब्रेरी]] के सोर्स कोड को संशोधित करके हुकिंग प्राप्त की '''जा सकती है। इसका उपयोग सामान्य'''तः कॉल फ़ंक्शन को मॉनिटर करने या उन्हें पूरी तरह से परिवर्तित करने के लिए इंटरसेप्ट करने के लिए किया जाता है। | ||
उदाहरण के लिए एक डिस्सेबलर का उपयोग करके मॉड्यूल के भीतर किसी फ़ंक्शन का प्रवेश बिंदु पाया जा सकता है। इसके बाद इसे किसी अन्य लाइब्रेरी मॉड्यूल को गतिशील रूप से लोड करने के लिए परिवर्तित किया जा सकता है और फिर उस लोड की गई लाइब्रेरी के भीतर वांछित तरीकों को निष्पादित किया जा सकता है। यदि लागू हो, तो एक अन्य संबंधित दृष्टिकोण जिसके द्वारा हुकिंग प्राप्त की जा सकती है वह निष्पादन योग्य की आयात तालिका को बदलकर है। इस तालिका को किसी भी अतिरिक्त लाइब्रेरी मॉड्यूल को लोड करने के लिए संशोधित किया जा सकता है और साथ ही यह भी परिवर्तित किया जा सकता है कि जब एप्लिकेशन द्वारा किसी फ़ंक्शन को कॉल किया जाता है तो कौन सा बाहरी कोड लागू होता है। | उदाहरण के लिए एक डिस्सेबलर का उपयोग करके मॉड्यूल के भीतर किसी फ़ंक्शन का प्रवेश बिंदु पाया जा सकता है। इसके बाद इसे किसी अन्य लाइब्रेरी मॉड्यूल को गतिशील रूप से लोड करने के लिए परिवर्तित किया जा सकता है और फिर उस लोड की गई लाइब्रेरी के भीतर वांछित तरीकों को निष्पादित किया जा सकता है। यदि लागू हो, तो एक अन्य संबंधित दृष्टिकोण जिसके द्वारा हुकिंग प्राप्त की जा सकती है वह निष्पादन योग्य की आयात तालिका को बदलकर है। इस तालिका को किसी भी अतिरिक्त लाइब्रेरी मॉड्यूल को लोड करने के लिए संशोधित किया जा सकता है और साथ ही यह भी परिवर्तित किया जा सकता है कि जब एप्लिकेशन द्वारा किसी फ़ंक्शन को कॉल किया जाता है तो कौन सा बाहरी कोड लागू होता है। | ||
फ़ंक्शन हुकिंग प्राप्त करने का एक वैकल्पिक तरीका [[रैपर लाइब्रेरी]] के माध्यम से फ़ंक्शन | फ़ंक्शन हुकिंग प्राप्त करने का एक वैकल्पिक तरीका [[रैपर लाइब्रेरी]] के माध्यम से कॉल फ़ंक्शन को इंटरसेप्ट करना है। रैपर एक लाइब्रेरी का एक संस्करण है जिसे एक एप्लिकेशन लोड करता है, जिसमें मूल लाइब्रेरी की सभी समान कार्यक्षमता होती है जिसे वह प्रतिस्थापित करेगा। अर्थात्, सभी फ़ंक्शन जो पहुंच योग्य हैं, मूल और प्रतिस्थापन के बीच अनिवार्य रूप से समान हैं। इस रैपर लाइब्रेरी को मूल लाइब्रेरी से किसी भी कार्यक्षमता को कॉल करने के लिए डिज़ाइन किया जा सकता है, या इसे तर्क के एक बिल्कुल नए सेट के साथ प्रतिस्थापित किया जा सकता है। | ||
=== रनटाइम संशोधन === | === रनटाइम संशोधन === | ||
ऑपरेटिंग सिस्टम और सॉफ़्टवेयर रनटाइम पर आसानी से इवेंट हुक डालने के साधन प्रदान कर सकते हैं। यह उपलब्ध है बशर्ते कि हुक डालने की प्रक्रिया को ऐसा करने के लिए पर्याप्त अनुमति दी गई हो। उदाहरण के लिए, माइक्रोसॉफ्ट विंडोज़, उपयोगकर्ताओं को हुक डालने की अनुमति देता है जिसका उपयोग सिस्टम इवेंट और [[ संवाद बकस |डायलॉग]], [[ स्क्रॉल बार |स्क्रॉल बार]] और [[मेनू (कंप्यूटिंग)|मेनू]] के साथ-साथ अन्य आइटम के लिए एप्लिकेशन इवेंट को संसाधित या संशोधित करने के लिए किया जा सकता है। यह हुक को [[कीबोर्ड (कंप्यूटिंग)|कीबोर्ड]] और [[माउस (कंप्यूटिंग)]] इवेंट को सम्मिलित करने, हटाने, संसाधित करने या संशोधित करने की भी अनुमति देता है। लिनक्स एक और उदाहरण प्रदान करता है जहां [[ नेटफ़िल्टर |नेटफ़िल्टर]] के माध्यम से [[कर्नेल (ऑपरेटिंग सिस्टम)]] के भीतर नेटवर्क घटनाओं को संसाधित करने के लिए हुक का उपयोग समान तरीके से किया जा सकता है। | ऑपरेटिंग सिस्टम और सॉफ़्टवेयर रनटाइम पर आसानी से इवेंट हुक डालने के साधन प्रदान कर सकते हैं। यह उपलब्ध है बशर्ते कि हुक डालने की प्रक्रिया को ऐसा करने के लिए पर्याप्त अनुमति दी गई हो। उदाहरण के लिए, माइक्रोसॉफ्ट विंडोज़, उपयोगकर्ताओं को हुक डालने की अनुमति देता है जिसका उपयोग सिस्टम इवेंट और [[ संवाद बकस |डायलॉग]], [[ स्क्रॉल बार |स्क्रॉल बार]] और [[मेनू (कंप्यूटिंग)|मेनू]] के साथ-साथ अन्य आइटम के लिए एप्लिकेशन इवेंट को संसाधित या संशोधित करने के लिए किया जा सकता है। यह हुक को [[कीबोर्ड (कंप्यूटिंग)|कीबोर्ड]] और [[माउस (कंप्यूटिंग)]] इवेंट को सम्मिलित करने, हटाने, संसाधित करने या संशोधित करने की भी अनुमति देता है। लिनक्स एक और उदाहरण प्रदान करता है जहां [[ नेटफ़िल्टर |नेटफ़िल्टर]] के माध्यम से [[कर्नेल (ऑपरेटिंग सिस्टम)]] के भीतर नेटवर्क घटनाओं को संसाधित करने के लिए हुक का उपयोग समान तरीके से किया जा सकता है। | ||
जब ऐसी कार्यक्षमता प्रदान नहीं की जाती है, तो हुकिंग का एक विशेष रूप एक प्रक्रिया द्वारा किए गए लाइब्रेरी फ़ंक्शन | जब ऐसी कार्यक्षमता प्रदान नहीं की जाती है, तो हुकिंग का एक विशेष रूप एक प्रक्रिया द्वारा किए गए लाइब्रेरी कॉल फ़ंक्शन को इंटरसेप्ट करने का काम करता है। फ़ंक्शन हुकिंग को एक इंजेक्टेड कोड पर जाने के लिए लक्ष्य फ़ंक्शन के पहले कुछ कोड इंस्ट्रक्शन को बदलकर कार्यान्वित किया जाता है। वैकल्पिक रूप से साझा लाइब्रेरी अवधारणा का उपयोग करने वाले सिस्टम पर, [[इंटरप्ट वेक्टर]] तालिका या आयात डिस्क्रिप्टर तालिका को मेमोरी में संशोधित किया जा सकता है। अनिवार्य रूप से ये युक्तियाँ सोर्स कोड संशोधन के समान विचारों को नियोजित करती हैं, लेकिन इसके अतिरिक्त किसी प्रक्रिया के पहले से चलने के बाद उसकी मेमोरी में स्थित इंस्ट्रक्शन और संरचनाओं को बदल देती हैं। | ||
== सैंपल कोड == | == सैंपल कोड == |
Revision as of 19:51, 22 November 2023
कंप्यूटर प्रोग्रामिंग में हुकिंग शब्द मॉड्यूलर प्रोग्रामिंग के बीच कॉल फ़ंक्शन या इवेंट (कंप्यूटिंग) को इंटरसेप्ट करके ऑपरेटिंग सिस्टम, एप्लिकेशन या अन्य सॉफ़्टवेयर कॉम्पोनेन्ट के प्रोग्राम को परिवर्तित या इंटरसेप्ट करने के लिए उपयोग की जाने वाली तकनीकों की एक तालिका सम्मिलित होती है। ऐसे कोड जो इंटरसेप्टेड कॉल फ़ंक्शन, ईवेंट या संदेशों को सुरक्षित रखते हैं उन्हे हुक कहा जाता है।
हुकिंग का उपयोग कई उद्देश्यों के लिए किया जाता है, जिसमें डिबगिंग और फंक्शन का विस्तार सम्मिलित है। उदाहरणों में किसी एप्लिकेशन के लिए कीबोर्ड या माउस ईवेंट संदेशों को इंटरसेप्ट करना या किसी एप्लिकेशन के अन्य कॉम्पोनेन्ट के फ़ंक्शन को संशोधित करने के लिए ऑपरेटिंग सिस्टम कॉल को इंटरसेप्ट करना सम्मिलित हो सकता है। इसका व्यापक रूप से बेंचमार्किंग प्रोग्राम में भी उपयोग किया जाता है। उदाहरण के लिए 3डी गेम में फ्रेम दर मापने के लिए जहां आउटपुट और इनपुट हुकिंग के माध्यम से प्राप्त किया जाता है।
हुकिंग का उपयोग मॉलिसियस कोड द्वारा भी किया जा सकता है। उदाहरण के लिए रूटकिट सॉफ़्टवेयर के एपीआई कॉल के आउटपुट द्वारा स्वयं को अदृश्य बनाने की कोशिश करते हैं जो अन्यथा उनके अस्तित्व को प्रकट कर सकते हैं प्रायः हुकिंग तकनीकों का उपयोग करते हैं।
प्रकार
सामान्यतः हुक को तब प्रयुक्त किया जाता है जब सॉफ़्टवेयर पहले से ही सक्रिय हो, क्योकि हुकिंग एक ऐसा फ़ंक्शन है जिसे एप्लिकेशन प्रारम्भ होने से पहले भी प्रयुक्त किया जा सकता है। इन दोनों तकनीकों का निम्नलिखित रूप से वर्णन किया गया है।
सोर्स कोड संशोधन
किसी एप्लिकेशन के प्रारम्भ होने से पहले रिवर्स इंजीनियरिंग की तकनीकों के माध्यम से संचालित कोड या लाइब्रेरी के सोर्स कोड को संशोधित करके हुकिंग प्राप्त की जा सकती है। इसका उपयोग सामान्यतः कॉल फ़ंक्शन को मॉनिटर करने या उन्हें पूरी तरह से परिवर्तित करने के लिए इंटरसेप्ट करने के लिए किया जाता है।
उदाहरण के लिए एक डिस्सेबलर का उपयोग करके मॉड्यूल के भीतर किसी फ़ंक्शन का प्रवेश बिंदु पाया जा सकता है। इसके बाद इसे किसी अन्य लाइब्रेरी मॉड्यूल को गतिशील रूप से लोड करने के लिए परिवर्तित किया जा सकता है और फिर उस लोड की गई लाइब्रेरी के भीतर वांछित तरीकों को निष्पादित किया जा सकता है। यदि लागू हो, तो एक अन्य संबंधित दृष्टिकोण जिसके द्वारा हुकिंग प्राप्त की जा सकती है वह निष्पादन योग्य की आयात तालिका को बदलकर है। इस तालिका को किसी भी अतिरिक्त लाइब्रेरी मॉड्यूल को लोड करने के लिए संशोधित किया जा सकता है और साथ ही यह भी परिवर्तित किया जा सकता है कि जब एप्लिकेशन द्वारा किसी फ़ंक्शन को कॉल किया जाता है तो कौन सा बाहरी कोड लागू होता है।
फ़ंक्शन हुकिंग प्राप्त करने का एक वैकल्पिक तरीका रैपर लाइब्रेरी के माध्यम से कॉल फ़ंक्शन को इंटरसेप्ट करना है। रैपर एक लाइब्रेरी का एक संस्करण है जिसे एक एप्लिकेशन लोड करता है, जिसमें मूल लाइब्रेरी की सभी समान कार्यक्षमता होती है जिसे वह प्रतिस्थापित करेगा। अर्थात्, सभी फ़ंक्शन जो पहुंच योग्य हैं, मूल और प्रतिस्थापन के बीच अनिवार्य रूप से समान हैं। इस रैपर लाइब्रेरी को मूल लाइब्रेरी से किसी भी कार्यक्षमता को कॉल करने के लिए डिज़ाइन किया जा सकता है, या इसे तर्क के एक बिल्कुल नए सेट के साथ प्रतिस्थापित किया जा सकता है।
रनटाइम संशोधन
ऑपरेटिंग सिस्टम और सॉफ़्टवेयर रनटाइम पर आसानी से इवेंट हुक डालने के साधन प्रदान कर सकते हैं। यह उपलब्ध है बशर्ते कि हुक डालने की प्रक्रिया को ऐसा करने के लिए पर्याप्त अनुमति दी गई हो। उदाहरण के लिए, माइक्रोसॉफ्ट विंडोज़, उपयोगकर्ताओं को हुक डालने की अनुमति देता है जिसका उपयोग सिस्टम इवेंट और डायलॉग, स्क्रॉल बार और मेनू के साथ-साथ अन्य आइटम के लिए एप्लिकेशन इवेंट को संसाधित या संशोधित करने के लिए किया जा सकता है। यह हुक को कीबोर्ड और माउस (कंप्यूटिंग) इवेंट को सम्मिलित करने, हटाने, संसाधित करने या संशोधित करने की भी अनुमति देता है। लिनक्स एक और उदाहरण प्रदान करता है जहां नेटफ़िल्टर के माध्यम से कर्नेल (ऑपरेटिंग सिस्टम) के भीतर नेटवर्क घटनाओं को संसाधित करने के लिए हुक का उपयोग समान तरीके से किया जा सकता है।
जब ऐसी कार्यक्षमता प्रदान नहीं की जाती है, तो हुकिंग का एक विशेष रूप एक प्रक्रिया द्वारा किए गए लाइब्रेरी कॉल फ़ंक्शन को इंटरसेप्ट करने का काम करता है। फ़ंक्शन हुकिंग को एक इंजेक्टेड कोड पर जाने के लिए लक्ष्य फ़ंक्शन के पहले कुछ कोड इंस्ट्रक्शन को बदलकर कार्यान्वित किया जाता है। वैकल्पिक रूप से साझा लाइब्रेरी अवधारणा का उपयोग करने वाले सिस्टम पर, इंटरप्ट वेक्टर तालिका या आयात डिस्क्रिप्टर तालिका को मेमोरी में संशोधित किया जा सकता है। अनिवार्य रूप से ये युक्तियाँ सोर्स कोड संशोधन के समान विचारों को नियोजित करती हैं, लेकिन इसके अतिरिक्त किसी प्रक्रिया के पहले से चलने के बाद उसकी मेमोरी में स्थित इंस्ट्रक्शन और संरचनाओं को बदल देती हैं।
सैंपल कोड
वर्चुअल टेबल हुकिंग विधि
जब भी कोई क्लास किसी वर्चुअल फ़ंक्शन (या मेथड) को परिभाषित/इनहेरिट करता है, तो कंपाइलर क्लास में एक छिपा हुआ सदस्य वेरिएबल जोड़ते हैं जो वर्चुअल मेथड टेबल (वीएमटी या वीटेबल) की ओर इशारा करता है। अधिकांश कंपाइलर कक्षा के प्रत्येक उदाहरण के पहले 4 बाइट्स पर छिपे हुए वीएमटी पॉइंटर को रखते हैं। वीएमटी मूल रूप से सभी वर्चुअल फ़ंक्शन के लिए पॉइंटर्स की एक सरणी है जिसे क्लास के इंस्टेंस कॉल कर सकते हैं। रनटाइम पर ये पॉइंटर्स सही फ़ंक्शन को इंगित करने के लिए सेट किए जाते हैं, क्योंकि संकलन समय पर, यह अभी तक ज्ञात नहीं है कि क्या बेस फ़ंक्शन को कॉल किया जाना है या यदि किसी व्युत्पन्न वर्ग से फ़ंक्शन का ओवरराइड संस्करण कॉल किया जाना है (जिससे अनुमति मिलती है) बहुरूपता के लिए)। इसलिए, वर्चुअल फ़ंक्शन को किसी भी वीएमटी के भीतर पॉइंटर्स को प्रतिस्थापित करके हुक किया जा सकता है जो वे दिखाई देते हैं। नीचे दिया गया कोड माइक्रोसॉफ़्ट विंडोज़ में एक विशिष्ट वीएमटी हुक का एक उदाहरण दिखाता है, जो C++ में लिखा गया है।[1]
#include <iostream>
#include "windows.h"
using namespace std;
class VirtualClass
{
public:
int number;
virtual void VirtualFn1() //This is the virtual function that will be hooked.
{
cout << "VirtualFn1 called " << number++ << "\n\n";
}
};
using VirtualFn1_t = void(__thiscall*)(void* thisptr);
VirtualFn1_t orig_VirtualFn1;
void __fastcall hkVirtualFn1(void* thisptr, int edx) //This is our hook function which we will cause the program to call instead of the original VirtualFn1 function after hooking is done.
{
cout << "Hook function called" << "\n";
orig_VirtualFn1(thisptr); //Call the original function.
}
int main()
{
VirtualClass* myClass = new VirtualClass(); //Create a pointer to a dynamically allocated instance of VirtualClass.
void** vTablePtr = *reinterpret_cast<void***>(myClass); //Find the address that points to the base of VirtualClass' VMT (which then points to VirtualFn1) and store it in vTablePtr.
DWORD oldProtection;
VirtualProtect(vTablePtr, 4, PAGE_EXECUTE_READWRITE, &oldProtection); //Removes page protection at the start of the VMT so we can overwrite its first pointer.
orig_VirtualFn1 = reinterpret_cast<VirtualFn1_t>(*vTablePtr); //Stores the pointer to VirtualFn1 from the VMT in a global variable so that it can be accessed again later after its entry in the VMT has been
//overwritten with our hook function.
*vTablePtr = &hkVirtualFn1; //Overwrite the pointer to VirtualFn1 within the virtual table to a pointer to our hook function (hkVirtualFn1).
VirtualProtect(vTablePtr, 4, oldProtection, 0); //Restore old page protection.
myClass->VirtualFn1(); //Call the virtual function from our class instance. Because it is now hooked, this will actually call our hook function (hkVirtualFn1).
myClass->VirtualFn1();
myClass->VirtualFn1();
delete myClass;
return 0;
}
यह ध्यान रखना महत्वपूर्ण है कि सभी वर्चुअल फ़ंक्शन क्लास सदस्य फ़ंक्शन होने चाहिए, और सभी (गैर स्थैतिक) क्लास सदस्य फ़ंक्शन को _thiscall
कॉलिंग कन्वेंशन के साथ कॉल किया जाता है (जब तक कि सदस्य फ़ंक्शन तर्कों की एक चर संख्या नहीं लेता है, जिस स्थिति में इसे कहा जाता है) _cdecl
के साथ)_thiscall
कॉलिंग कन्वेंशन ईसीएक्स रजिस्टर (x86 आर्किटेक्चर पर) के माध्यम से कॉलिंग क्लास इंस्टेंस (सामान्यतः "इस" पॉइंटर के रूप में संदर्भित) के लिए एक पॉइंटर पास करता है। इसलिए, हुक फ़ंक्शन द्वारा पारित किए गए "इस" पॉइंटर को ठीक से इंटरसेप्ट करने और इसे एक तर्क के रूप में लेने के लिए, इसे ईसीएक्स रजिस्टर में देखना होगा। उपरोक्त उदाहरण में, यह _fastcall
कॉलिंग कन्वेंशन का उपयोग करने के लिए हुक फ़ंक्शन (hkVirtualFn1)
को सेट करके किया जाता है, जो हुक फ़ंक्शन को उसके एक तर्क के लिए ईसीएक्स रजिस्टर में देखने का कारण बनता है।
यह भी ध्यान दें कि, उपरोक्त उदाहरण में, हुक फ़ंक्शन (hkVirtualFn1)
स्वयं एक सदस्य फ़ंक्शन नहीं है, इसलिए यह _thiscall
कॉलिंग कन्वेंशन का उपयोग नहीं कर सकता है। इसके अतिरिक्त _fastcall
का उपयोग करना होगा क्योंकि यह एकमात्र अन्य कॉलिंग कन्वेंशन है जो किसी तर्क के लिए ईसीएक्स रजिस्टर को देखता है। hkVirtualFn1
सी# कीबोर्ड इवेंट हुक
निम्न उदाहरण माइक्रोसॉफ्ट नेट फ्रेमवर्क का उपयोग करके माइक्रोसॉफ़्ट विंडोज़ में कीबोर्ड ईवेंट से जुड़ जाएगा।
using System.Runtime.InteropServices;
namespace Hooks;
public class KeyHook
{
/* Member variables */
protected static int Hook;
protected static LowLevelKeyboardDelegate Delegate;
protected static readonly object Lock = new object();
protected static bool IsRegistered = false;
/* DLL imports */
[DllImport("user32")]
private static extern int SetWindowsHookEx(int idHook, LowLevelKeyboardDelegate lpfn,
int hmod, int dwThreadId);
[DllImport("user32")]
private static extern int CallNextHookEx(int hHook, int nCode, int wParam, KBDLLHOOKSTRUCT lParam);
[DllImport("user32")]
private static extern int UnhookWindowsHookEx(int hHook);
/* Types & constants */
protected delegate int LowLevelKeyboardDelegate(int nCode, int wParam, ref KBDLLHOOKSTRUCT lParam);
private const int HC_ACTION = 0;
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
private const int WH_KEYBOARD_LL = 13;
[StructLayout(LayoutKind.Sequential)]
public struct KBDLLHOOKSTRUCT
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
/* Methods */
static private int LowLevelKeyboardHandler(int nCode, int wParam, ref KBDLLHOOKSTRUCT lParam)
{
if (nCode == HC_ACTION)
{
if (wParam == WM_KEYDOWN)
System.Console.Out.WriteLine("Key Down: " + lParam.vkCode);
else if (wParam == WM_KEYUP)
System.Console.Out.WriteLine("Key Up: " + lParam.vkCode);
}
return CallNextHookEx(Hook, nCode, wParam, lParam);
}
public static bool RegisterHook()
{
lock (Lock)
{
if (IsRegistered)
return true;
Delegate = LowLevelKeyboardHandler;
Hook = SetWindowsHookEx(
WH_KEYBOARD_LL, Delegate,
Marshal.GetHINSTANCE(
System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]
).ToInt32(), 0
);
if (Hook != 0)
return IsRegistered = true;
Delegate = null;
return false;
}
}
public static bool UnregisterHook()
{
lock (Lock)
{
return IsRegistered = (UnhookWindowsHookEx(Hook) != 0);
}
}
}
एपीआई/फ़ंक्शन हुकिंग/इंटरसेप्शन जेएमपी अनुदेश उर्फ स्प्लिसिंग का उपयोग करके
निम्नलिखित सोर्स कोड कोड एक एपीआई/फ़ंक्शन हुकिंग विधि का एक उदाहरण है जो एक गंतव्य फ़ंक्शन के पहले छह बाइट्स को जेएमपी (x86 इंस्ट्रक्शन) के साथ एक नए फ़ंक्शन पर ओवरराइट करके हुक करता है। कोड को एक डायनामिक-लिंक लाइब्रेरी फ़ाइल में संकलित किया जाता है और फिर डायनामिक-लिंक लाइब्रेरी इंजेक्शन की किसी भी विधि का उपयोग करके लक्ष्य प्रक्रिया में लोड किया जाता है। मूल फ़ंक्शन के बैकअप का उपयोग करके पहले छह बाइट्स को फिर से पुनर्स्थापित किया जा सकता है ताकि कॉल बाधित न हो। इस उदाहरण में Win32 API फ़ंक्शन MessageBoxW जुड़ा हुआ है।[2]
/*
This idea is based on chrom-lib approach, Distributed under GNU LGPL License.
Source chrom-lib: https://github.com/linuxexp/chrom-lib
Copyright (C) 2011 Raja Jamwal
*/
#include <windows.h>
#define SIZE 6
typedef int (WINAPI *pMessageBoxW)(HWND, LPCWSTR, LPCWSTR, UINT); // Messagebox prototype
int WINAPI MyMessageBoxW(HWND, LPCWSTR, LPCWSTR, UINT); // Our detour
void BeginRedirect(LPVOID);
pMessageBoxW pOrigMBAddress = NULL; // address of original
BYTE oldBytes[SIZE] = {0}; // backup
BYTE JMP[SIZE] = {0}; // 6 byte JMP instruction
DWORD oldProtect, myProtect = PAGE_EXECUTE_READWRITE;
INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
{
switch (Reason)
{
case DLL_PROCESS_ATTACH: // if attached
pOrigMBAddress = (pMessageBoxW)
GetProcAddress(GetModuleHandleA("user32.dll"), // get address of original
"MessageBoxW");
if (pOrigMBAddress != NULL)
BeginRedirect(MyMessageBoxW); // start detouring
break;
case DLL_PROCESS_DETACH:
VirtualProtect((LPVOID)pOrigMBAddress, SIZE, myProtect, &oldProtect); // assign read write protection
memcpy(pOrigMBAddress, oldBytes, SIZE); // restore backup
VirtualProtect((LPVOID)pOrigMBAddress, SIZE, oldProtect, &myProtect); // reset protection
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
void BeginRedirect(LPVOID newFunction)
{
BYTE tempJMP[SIZE] = {0xE9, 0x90, 0x90, 0x90, 0x90, 0xC3}; // 0xE9 = JMP 0x90 = NOP 0xC3 = RET
memcpy(JMP, tempJMP, SIZE); // store jmp instruction to JMP
DWORD JMPSize = ((DWORD)newFunction - (DWORD)pOrigMBAddress - 5); // calculate jump distance
VirtualProtect((LPVOID)pOrigMBAddress, SIZE, // assign read write protection
PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(oldBytes, pOrigMBAddress, SIZE); // make backup
memcpy(&JMP[1], &JMPSize, 4); // fill the nop's with the jump distance (JMP,distance(4bytes),RET)
memcpy(pOrigMBAddress, JMP, SIZE); // set jump instruction at the beginning of the original function
VirtualProtect((LPVOID)pOrigMBAddress, SIZE, oldProtect, &myProtect); // reset protection
}
int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uiType)
{
VirtualProtect((LPVOID)pOrigMBAddress, SIZE, myProtect, &oldProtect); // assign read write protection
memcpy(pOrigMBAddress, oldBytes, SIZE); // restore backup
int retValue = MessageBoxW(hWnd, lpText, lpCaption, uiType); // get return value of original function
memcpy(pOrigMBAddress, JMP, SIZE); // set the jump instruction again
VirtualProtect((LPVOID)pOrigMBAddress, SIZE, oldProtect, &myProtect); // reset protection
return retValue; // return original return value
}
नेटफ़िल्टर हुक
यह उदाहरण दिखाता है कि नेटफिल्टर का उपयोग करके लिनक्स कर्नेल में नेटवर्क ट्रैफ़िक को परिवर्तित के लिए हुकिंग का उपयोग कैसे करें।
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/in.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
/* Port we want to drop packets on */
static const uint16_t port = 25;
/* This is the hook function itself */
static unsigned int hook_func(unsigned int hooknum,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct iphdr *iph = ip_hdr(*pskb);
struct tcphdr *tcph, tcpbuf;
if (iph->protocol != IPPROTO_TCP)
return NF_ACCEPT;
tcph = skb_header_pointer(*pskb, ip_hdrlen(*pskb), sizeof(*tcph), &tcpbuf);
if (tcph == NULL)
return NF_ACCEPT;
return (tcph->dest == port) ? NF_DROP : NF_ACCEPT;
}
/* Used to register our hook function */
static struct nf_hook_ops nfho = {
.hook = hook_func,
.hooknum = NF_IP_PRE_ROUTING,
.pf = NFPROTO_IPV4,
.priority = NF_IP_PRI_FIRST,
};
static __init int my_init(void)
{
return nf_register_hook(&nfho);
}
static __exit void my_exit(void)
{
nf_unregister_hook(&nfho);
}
module_init(my_init);
module_exit(my_exit);
आंतरिक आईएटी हुकिंग
निम्नलिखित कोड दर्शाता है कि किसी अन्य मॉड्यूल से आयातित फ़ंक्शन को कैसे हुक किया जाए। इसका उपयोग कॉलिंग प्रक्रिया से भिन्न प्रक्रिया में फ़ंक्शन को हुक करने के लिए किया जा सकता है। इसके लिए कोड को एक डायनामिक-लिंक लाइब्रेरी फ़ाइल में संकलित किया जाना चाहिए और फिर डायनामिक-लिंक लाइब्रेरी इंजेक्शन की किसी भी विधि का उपयोग करके लक्ष्य प्रक्रिया में लोड किया जाना चाहिए। इस पद्धति का लाभ यह है कि यह एंटीवायरस सॉफ्टवेयर या एंटी-चीट सॉफ़्टवेयर द्वारा कम पता लगाया जा सकता है, कोई इसे बाहरी हुक में बना सकता है जो किसी भी दुर्भावनापूर्ण कॉल का उपयोग नहीं करता है। पोर्टेबल एक्ज़ीक्यूटेबल हेडर में आयात पता तालिका (आईएटी) सम्मिलित है, जिसे नीचे सोर्स कोड में दिखाए अनुसार हेरफेर किया जा सकता है। नीचे दिया गया सोर्स कोड माइक्रोसॉफ़्ट विंडोज़ के अंतर्गत चलता है।
#include <windows.h>
typedef int(__stdcall *pMessageBoxA) (HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType); //This is the 'type' of the MessageBoxA call.
pMessageBoxA RealMessageBoxA; //This will store a pointer to the original function.
void DetourIATptr(const char* function, void* newfunction, HMODULE module);
int __stdcall NewMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) { //Our fake function
printf("The String Sent to MessageBoxA Was : %s\n", lpText);
return RealMessageBoxA(hWnd, lpText, lpCaption, uType); //Call the real function
}
int main(int argc, CHAR *argv[]) {
DetourIATptr("MessageBoxA",(void*)NewMessageBoxA,0); //Hook the function
MessageBoxA(NULL, "Just A MessageBox", "Just A MessageBox", 0); //Call the function -- this will invoke our fake hook.
return 0;
}
void **IATfind(const char *function, HMODULE module) { //Find the IAT (Import Address Table) entry specific to the given function.
int ip = 0;
if (module == 0)
module = GetModuleHandle(0);
PIMAGE_DOS_HEADER pImgDosHeaders = (PIMAGE_DOS_HEADER)module;
PIMAGE_NT_HEADERS pImgNTHeaders = (PIMAGE_NT_HEADERS)((LPBYTE)pImgDosHeaders + pImgDosHeaders->e_lfanew);
PIMAGE_IMPORT_DESCRIPTOR pImgImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((LPBYTE)pImgDosHeaders + pImgNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
if (pImgDosHeaders->e_magic != IMAGE_DOS_SIGNATURE)
printf("libPE Error : e_magic is no valid DOS signature\n");
for (IMAGE_IMPORT_DESCRIPTOR *iid = pImgImportDesc; iid->Name != NULL; iid++) {
for (int funcIdx = 0; *(funcIdx + (LPVOID*)(iid->FirstThunk + (SIZE_T)module)) != NULL; funcIdx++) {
char *modFuncName = (char*)(*(funcIdx + (SIZE_T*)(iid->OriginalFirstThunk + (SIZE_T)module)) + (SIZE_T)module + 2);
const uintptr_t nModFuncName = (uintptr_t)modFuncName;
bool isString = !(nModFuncName & (sizeof(nModFuncName) == 4 ? 0x80000000 : 0x8000000000000000));
if (isString) {
if (!_stricmp(function, modFuncName))
return funcIdx + (LPVOID*)(iid->FirstThunk + (SIZE_T)module);
}
}
}
return 0;
}
void DetourIATptr(const char *function, void *newfunction, HMODULE module) {
void **funcptr = IATfind(function, module);
if (*funcptr == newfunction)
return;
DWORD oldrights, newrights = PAGE_READWRITE;
//Update the protection to READWRITE
VirtualProtect(funcptr, sizeof(LPVOID), newrights, &oldrights);
RealMessageBoxA = (pMessageBoxA)*funcptr; //Some compilers require the cast (like "MinGW"), not sure about MSVC though
*funcptr = newfunction;
//Restore the old memory protection flags.
VirtualProtect(funcptr, sizeof(LPVOID), oldrights, &newrights);
}
यह भी देखें
- कॉलबैक (कंप्यूटर विज्ञान)
- डेलीगेशन (प्रोग्रामिंग)
- टर्मिनेट स्टेरेजिडेंट प्रोग्राम
- यूसर एग्जिट प्रोग्राम
- विंडोज़ एपीआई ओवरराइड 32
संदर्भ
- ↑ psyfl, [1]
- ↑ For more information, see http://ntvalk.blogspot.nl/2013/11/hooking-explained-detouring-library.html
- Jonathan Daniel (2013-11-27). "Hooking explained: detouring library calls and vtable patching in Windows/Linux/MAC-OSX". Retrieved 2014-01-01.
- Binh Nguyen (2004-08-16). "Hacking-Lexicon / Linux Dictionary V 0.16". Retrieved 2008-02-23.
Hook
- [2012-06-29: Link appears to be dead] Author: Holy Father (2002-06-10). "Hooking Windows API - Technics of hooking API functions on Windows 1.1 english" (PDF). Archived from the original (PDF) on 2009-12-29. Retrieved 2008-02-21.
{{cite web}}
:|author=
has generic name (help)
बाहरी संबंध
विंडोज़
- आयात पता तालिका फ़ंक्शन हुकिंग पर जानकारी।
- हुकिंग पर माइक्रोसॉफ्ट से जानकारी
- x86 हुकिंग के संबंध में जानकारी और विभिन्न तकनीकें।
- APISpy32 एक एप्लिकेशन है जिसका उपयोग Win32 API को हुक करने के लिए किया जाता है।
- Detours माइक्रोसॉफ्ट रिसर्च द्वारा बनाई गई एक सामान्य प्रयोजन फ़ंक्शन हुकिंग लाइब्रेरी है जो C/C++ में काम करती है।
- [2] किसी अन्य प्रक्रिया में कोड डालने के तीन तरीके।
- HookTool SDK (ACF SDK) एपीआई हुकिंग और कोड इंजेक्शन पर एक व्यापक अवलोकन प्रदान करता है। एक व्यावसायिक उत्पाद भी उपलब्ध है.
- [3] C++ और डेल्फ़ी के लिए एक व्यावसायिक x86 और x64 API हुकिंग और डायनामिक-लिंक लाइब्रेरी इंजेक्शन लाइब्रेरी है।
- EasyHook एक ओपन सोर्स हुकिंग इंजन है जो विंडोज़ में उपयोगकर्ता और कर्नेल भूमि दोनों में x86 और x64 का समर्थन करता है।
- SpyStudio एप्लिकेशन ट्रेस SpyStudio एक एप्लिकेशन ट्रेसर है जो कॉल को हुक करता है, परिणामों को संरचित तरीके से प्रदर्शित करता है।
- rohitab.com एपीआई मॉनिटर एक फ्रीवेयर एप्लिकेशन है जो 32-बिट और 64-बिट एप्लिकेशन और सेवाओं में 10,000+ विंडोज एपीआई और COM इंटरफेस को हुक और प्रदर्शित कर सकता है।
- डेविएरे एपीआई हुक डेविएरे एक फ्रीवेयर इंटर-प्रोसेस हुक फ्रेमवर्क है जिसका उपयोग अन्य प्रक्रियाओं के एपीआई कॉल को इंटरसेप्ट करने और पूर्ण दिखाने के लिए किया जा सकता है। पैरामीटर जानकारी या एपीआई मॉनिटर बनाएं।
- WinAPIOverride WinAPIOverride गैर व्यावसायिक उपयोग के लिए एक फ्रीवेयर है। यह Win32 API, COM, OLE, ActiveX, .NET को 32-बिट और 64-बिट प्रक्रियाओं में हुक कर सकता है। इसमें पोस्ट विश्लेषण टूल की निगरानी सम्मिलित है।
- urmem मेमोरी (हुक, पैच, पॉइंटर रैपर, सिग्नेचर स्कैनर आदि) के साथ काम करने के लिए C++11 क्रॉस-प्लेटफॉर्म लाइब्रेरी (x86)
लिनक्स
- [4] एक छात्र अनुसंधान परियोजना जो उपयोग करती है हुकिंग.
- [5] कार्यक्षमता जो सॉफ़्टवेयर के एक टुकड़े को किसी अन्य प्रक्रिया के निष्पादन को देखने और नियंत्रित करने की अनुमति देती है .
- [6] साझा लाइब्रेरी कॉल को हुक करने के लिए LD_PRELOAD का उपयोग।
Emacs
- Emacs Hooks Emacs के अनुकूलन के लिए हुक एक महत्वपूर्ण तंत्र हैं। हुक एक लिस्प वैरिएबल है जिसमें कुछ अच्छी तरह से परिभाषित अवसरों पर बुलाए जाने वाले कार्यों की एक सूची होती है। (इसे हुक चलाना कहते हैं।)
ओएस एक्स और आईओएस
- Cydia Substrate जेलब्रेक किए गए iOS उपकरणों के लिए एक ढांचा है जो डेवलपर्स को किसी अन्य ढांचे या एप्लिकेशन से जुड़ने की अनुमति देता है।
- harpoon रनटाइम फ़ंक्शन हुकिंग के लिए एक OS
गहराई में एपीआई हुकिंग
- x86 API Hooking Demystified x86 आर्किटेक्चर के लिए विभिन्न एपीआई हुकिंग विधियों पर लेख।
श्रेणी:प्रवाह नियंत्रित करें
श्रेणी:डीएलएल इंजेक्शन
श्रेणी:उदाहरण कोड वाले लेख