मुझे लगता है कि अंततः मुझे टिप्पणियों में सुझाए गए डीएक्सआईवी के समान तरीके से एक विधि का उपयोग कर मिला। एक डमी डीएलएल का उपयोग करने के बजाय, मैं एक मूल निष्पादन योग्य बनाता हूं जो /FIXED
और /BASE
कंपाइलर झंडे का उपयोग करके मेरे आरक्षित क्षेत्र की शुरुआत में लोड होता है। निष्पादन के लिए कोड एक गैर-आरंभिकृत सरणी सुनिश्चित करता है कि छवि स्मृति में की जरूरत पतों को शामिल किया गया है, लेकिन नहीं फ़ाइल में किसी भी अतिरिक्त स्थान ले करता है:
unsigned char Reserved[4194304]; // 4MB
रनटाइम पर, एक नया करने के लिए निष्पादन योग्य प्रतियां ही मेमोरी में स्थान और प्रक्रिया पर्यावरण ब्लॉक में कुछ फ़ील्ड अपडेट करने के लिए इसे इंगित करता है। फ़ील्ड अपडेट किए बिना, FormatMessage
जैसे कुछ फ़ंक्शंस को कॉल करना एक क्रैश का कारण बनता है।
#include <intrin.h>
#include <windows.h>
#include <winternl.h>
#pragma intrinsic(__movsb)
void Relocate() {
void *Base, *NewBase;
ULONG SizeOfImage;
PEB *Peb;
LIST_ENTRY *ModuleList, *NextEntry;
/* Get info about the PE image. */
Base = GetModuleHandleW(NULL);
SizeOfImage = ((IMAGE_NT_HEADERS *)(((ULONG_PTR)Base) +
((IMAGE_DOS_HEADER *)Base)->e_lfanew))->OptionalHeader.SizeOfImage;
/* Allocate memory to hold a copy of the PE image. */
NewBase = VirtualAlloc(NULL, SizeOfImage, MEM_COMMIT, PAGE_READWRITE);
if (!NewBase) {
ExitProcess(GetLastError());
}
/* Copy the PE image to the new location using __movsb since we don't have
a C library. */
__movsb(NewBase, Base, SizeOfImage);
/* Locate the Process Environment Block. */
Peb = (PEB *)__readfsdword(0x30);
/* Update the ImageBaseAddress field of the PEB. */
*((PVOID *)((ULONG_PTR)Peb + 0x08)) = NewBase;
/* Update the base address in the PEB's loader data table. */
ModuleList = &Peb->Ldr->InMemoryOrderModuleList;
NextEntry = ModuleList->Flink;
while (NextEntry != ModuleList) {
LDR_DATA_TABLE_ENTRY *LdrEntry = CONTAINING_RECORD(
NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
if (LdrEntry->DllBase == Base) {
LdrEntry->DllBase = NewBase;
break;
}
NextEntry = NextEntry->Flink;
}
}
मैं /NODEFAULTLIB
के साथ निष्पादन योग्य बनाया बस इसके आकार और रनटाइम पर लोड DLLs की संख्या है, इसलिए __movsb
आंतरिक का प्रयोग कम करें। यदि आप __movsb
memcpy
के साथ __movsb
को प्रतिस्थापित करना चाहते हैं तो आप शायद एमएसवीसीआरटी से जुड़ने के साथ दूर हो सकते हैं। आप ntdll.dll
से memcpy
आयात भी कर सकते हैं या अपना खुद का लिख सकते हैं।
एक बार निष्पादन योग्य तरीके से बाहर हो जाने के बाद, मैं एक डीएलएल में एक फ़ंक्शन को कॉल करता हूं जिसमें मेरा शेष कोड होता है। मूल पीई छवि से छुटकारा पाने के लिए डीएलएल UnmapViewOfFile
का उपयोग करता है, जो मुझे काम करने के लिए स्मृति का एक अच्छा 4 एमबी + हिस्सा देता है, गारंटीकृत फ़ाइलों, धागे के ढेर या ढेर को शामिल करने की गारंटी नहीं देता है।
कुछ बातें इस तकनीक के साथ ध्यान में रखना:
- यह एक बहुत बड़ा हैक है। मुझे गंदा लेखन हुआ और यह विंडोज के भविष्य के संस्करणों में बहुत अच्छी तरह से गिर सकता है।
मैंने विंडोज 7 के अलावा किसी भी अन्य चीज़ पर इसका परीक्षण नहीं किया है। यह कोड कम से कम विंडोज 7 और विंडोज 10 पर काम करता है।
- चूंकि निष्पादन योग्य
/FIXED /BASE
के साथ बनाया गया है, इसलिए इसका कोड स्थिति-स्वतंत्र नहीं है और आप केवल स्थानांतरित निष्पादन योग्य पर नहीं जा सकते हैं।
- यदि DL12 फ़ंक्शन जो
UnmapViewOfFile
रिटर्न देता है, तो प्रोग्राम क्रैश हो जाएगा क्योंकि कोड कोड जिसे हम से बुलाया गया है अब मौजूद नहीं है। यह सुनिश्चित करने के लिए कि समारोह कभी वापस नहीं आता है, मैं ExitProcess
का उपयोग करता हूं।
- कुछ भौतिक स्मृति को मुक्त करने के लिए
VirtualFree
का उपयोग करके स्थानांतरित पीई छवि में कुछ अनुभागों को रिलीज़ किया जा सकता है।
- मेरा कोड लोडर डेटा तालिका प्रविष्टियों को फिर से क्रमबद्ध करने से परेशान नहीं करता है। ऐसा लगता है कि इस तरह से ठीक काम करता है, लेकिन अगर छवि पता द्वारा आदेशित प्रविष्टियों पर कुछ निर्भर होना है तो यह तोड़ सकता है।
- कुछ एंटी-वायरस प्रोग्राम इस सामान के बारे में संदिग्ध हो सकते हैं। माइक्रोसॉफ्ट सुरक्षा अनिवार्यता कम से कम शिकायत नहीं की थी।
हिंडसाइट में, dxiv की डमी डीएलएल विधि आसान हो सकती है, क्योंकि मुझे पीईबी के साथ गड़बड़ करने की आवश्यकता नहीं होगी। लेकिन मैं इस तकनीक से फंस गया क्योंकि निष्पादन योग्य अपने इच्छित आधार पते पर लोड होने की अधिक संभावना है। डमी डीएलएल विधि मेरे लिए काम नहीं करती थी। डीएलएल को एनटीएल द्वारा लोड किया जाता है जब विंडोज़ पहले ही मेमोरी के क्षेत्र आरक्षित कर चुका है।
स्रोत
2016-03-22 02:09:31
आप संकलन समय पर स्मृति को "आरक्षित" नहीं कर सकते हैं और फिर यह उपलब्ध होने की उम्मीद कर सकते हैं। यदि आप स्मृति चाहते हैं, तो आपको गतिशील रूप से आवंटित करना होगा। –
जीसीसी का उपयोग करना संभव लगता है, शायद यह मदद कर सकता है: http://stackoverflow.com/questions/22457446/gcc-linker-description-file-force-symbol-to-be-at-specific-address – SHR
तो आप चाहते हैं अपने प्रोग्राम लोड से पहले मेमोरी क्षेत्र आरक्षित करें? भले ही यह नहीं चल रहा है? ऐसे मेमोरी क्षेत्र (आईपीसी) का उपयोग क्या होगा? – dvhh