1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 // disable warnings about pointer <-> DWORD conversions
7 # pragma warning(disable : 4311 4312)
11 # define POINTER_TYPE ULONGLONG
13 # define POINTER_TYPE DWORD
23 #include "nsWindowsHelpers.h"
25 typedef const unsigned char* FileView
;
28 class nsAutoRefTraits
<FileView
> {
30 typedef FileView RawRef
;
31 static FileView
Void() { return nullptr; }
33 static void Release(RawRef aView
) {
34 if (nullptr != aView
) UnmapViewOfFile(aView
);
38 #ifndef IMAGE_SIZEOF_BASE_RELOCATION
39 // Vista SDKs no longer define IMAGE_SIZEOF_BASE_RELOCATION!?
40 # define IMAGE_SIZEOF_BASE_RELOCATION (sizeof(IMAGE_BASE_RELOCATION))
43 #include "LoadLibraryRemote.h"
46 PIMAGE_NT_HEADERS headers
;
47 unsigned char* localCodeBase
;
48 unsigned char* remoteCodeBase
;
51 } MEMORYMODULE
, *PMEMORYMODULE
;
53 typedef BOOL(WINAPI
* DllEntryProc
)(HINSTANCE hinstDLL
, DWORD fdwReason
,
56 #define GET_HEADER_DICTIONARY(module, idx) \
57 &(module)->headers->OptionalHeader.DataDirectory[idx]
60 static void OutputLastError(const char* msg
) {
63 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
64 FORMAT_MESSAGE_IGNORE_INSERTS
,
65 nullptr, GetLastError(),
66 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), (LPSTR
)&tmp
, 0,
68 tmpmsg
= (char*)LocalAlloc(LPTR
, strlen(msg
) + strlen(tmp
) + 3);
69 sprintf(tmpmsg
, "%s: %s", msg
, tmp
);
70 OutputDebugStringA(tmpmsg
);
76 static void CopySections(const unsigned char* data
,
77 PIMAGE_NT_HEADERS old_headers
, PMEMORYMODULE module
) {
79 unsigned char* codeBase
= module
->localCodeBase
;
81 PIMAGE_SECTION_HEADER section
= IMAGE_FIRST_SECTION(module
->headers
);
82 for (i
= 0; i
< module
->headers
->FileHeader
.NumberOfSections
;
84 dest
= codeBase
+ section
->VirtualAddress
;
85 memset(dest
, 0, section
->Misc
.VirtualSize
);
86 if (section
->SizeOfRawData
) {
87 memcpy(dest
, data
+ section
->PointerToRawData
, section
->SizeOfRawData
);
89 // section->Misc.PhysicalAddress = (POINTER_TYPE) module->remoteCodeBase +
90 // section->VirtualAddress;
94 static bool CopyRegion(HANDLE hRemoteProcess
, void* remoteAddress
,
95 void* localAddress
, DWORD size
, DWORD protect
) {
97 // Copy the data from local->remote and set the memory protection
98 if (!VirtualAllocEx(hRemoteProcess
, remoteAddress
, size
, MEM_COMMIT
,
102 if (!WriteProcessMemory(hRemoteProcess
, remoteAddress
, localAddress
, size
,
105 OutputLastError("Error writing remote memory.\n");
111 if (VirtualProtectEx(hRemoteProcess
, remoteAddress
, size
, protect
,
114 OutputLastError("Error protecting memory page");
121 // Protection flags for memory pages (Executable, Readable, Writeable)
122 static int ProtectionFlags
[2][2][2] = {
125 {PAGE_NOACCESS
, PAGE_WRITECOPY
},
126 {PAGE_READONLY
, PAGE_READWRITE
},
130 {PAGE_EXECUTE
, PAGE_EXECUTE_WRITECOPY
},
131 {PAGE_EXECUTE_READ
, PAGE_EXECUTE_READWRITE
},
135 static bool FinalizeSections(PMEMORYMODULE module
, HANDLE hRemoteProcess
) {
137 fprintf(stderr
, "Finalizing sections: local base %p, remote base %p\n",
138 module
->localCodeBase
, module
->remoteCodeBase
);
142 int numSections
= module
->headers
->FileHeader
.NumberOfSections
;
144 if (numSections
< 1) return false;
146 PIMAGE_SECTION_HEADER section
= IMAGE_FIRST_SECTION(module
->headers
);
148 // Copy any data before the first section (i.e. the image header)
149 if (!CopyRegion(hRemoteProcess
, module
->remoteCodeBase
, module
->localCodeBase
,
150 section
->VirtualAddress
, PAGE_READONLY
))
153 // loop through all sections and change access flags
154 for (i
= 0; i
< numSections
; i
++, section
++) {
156 int executable
= (section
->Characteristics
& IMAGE_SCN_MEM_EXECUTE
) != 0;
157 int readable
= (section
->Characteristics
& IMAGE_SCN_MEM_READ
) != 0;
158 int writeable
= (section
->Characteristics
& IMAGE_SCN_MEM_WRITE
) != 0;
160 // determine protection flags based on characteristics
161 protect
= ProtectionFlags
[executable
][readable
][writeable
];
162 if (section
->Characteristics
& IMAGE_SCN_MEM_NOT_CACHED
) {
163 protect
|= PAGE_NOCACHE
;
166 void* remoteAddress
= module
->remoteCodeBase
+ section
->VirtualAddress
;
167 void* localAddress
= module
->localCodeBase
+ section
->VirtualAddress
;
169 // determine size of region
170 size
= section
->Misc
.VirtualSize
;
173 "Copying section %s to %p, size %x, executable %i readable %i "
175 section
->Name
, remoteAddress
, size
, executable
, readable
,
178 if (!CopyRegion(hRemoteProcess
, remoteAddress
, localAddress
, size
, protect
))
184 static void PerformBaseRelocation(PMEMORYMODULE module
, SIZE_T delta
) {
186 unsigned char* codeBase
= module
->localCodeBase
;
188 PIMAGE_DATA_DIRECTORY directory
=
189 GET_HEADER_DICTIONARY(module
, IMAGE_DIRECTORY_ENTRY_BASERELOC
);
190 if (directory
->Size
> 0) {
191 PIMAGE_BASE_RELOCATION relocation
=
192 (PIMAGE_BASE_RELOCATION
)(codeBase
+ directory
->VirtualAddress
);
193 for (; relocation
->VirtualAddress
> 0;) {
194 unsigned char* dest
= codeBase
+ relocation
->VirtualAddress
;
195 unsigned short* relInfo
= (unsigned short*)((unsigned char*)relocation
+
196 IMAGE_SIZEOF_BASE_RELOCATION
);
198 i
< ((relocation
->SizeOfBlock
- IMAGE_SIZEOF_BASE_RELOCATION
) / 2);
202 ULONGLONG
* patchAddr64
;
206 // the upper 4 bits define the type of relocation
207 type
= *relInfo
>> 12;
208 // the lower 12 bits define the offset
209 offset
= *relInfo
& 0xfff;
212 case IMAGE_REL_BASED_ABSOLUTE
:
216 case IMAGE_REL_BASED_HIGHLOW
:
217 // change complete 32 bit address
218 patchAddrHL
= (DWORD
*)(dest
+ offset
);
219 *patchAddrHL
+= delta
;
223 case IMAGE_REL_BASED_DIR64
:
224 patchAddr64
= (ULONGLONG
*)(dest
+ offset
);
225 *patchAddr64
+= delta
;
230 // printf("Unknown relocation: %d\n", type);
235 // advance to next relocation block
236 relocation
= (PIMAGE_BASE_RELOCATION
)(((char*)relocation
) +
237 relocation
->SizeOfBlock
);
242 static int BuildImportTable(PMEMORYMODULE module
) {
244 unsigned char* codeBase
= module
->localCodeBase
;
246 PIMAGE_DATA_DIRECTORY directory
=
247 GET_HEADER_DICTIONARY(module
, IMAGE_DIRECTORY_ENTRY_IMPORT
);
248 if (directory
->Size
> 0) {
249 PIMAGE_IMPORT_DESCRIPTOR importDesc
=
250 (PIMAGE_IMPORT_DESCRIPTOR
)(codeBase
+ directory
->VirtualAddress
);
251 PIMAGE_IMPORT_DESCRIPTOR importEnd
=
252 (PIMAGE_IMPORT_DESCRIPTOR
)(codeBase
+ directory
->VirtualAddress
+
255 for (; importDesc
< importEnd
&& importDesc
->Name
; importDesc
++) {
256 POINTER_TYPE
* thunkRef
;
258 HMODULE handle
= GetModuleHandleA((LPCSTR
)(codeBase
+ importDesc
->Name
));
259 if (handle
== nullptr) {
261 OutputLastError("Can't load library");
267 module
->modules
= (HMODULE
*)realloc(
268 module
->modules
, (module
->numModules
+ 1) * (sizeof(HMODULE
)));
269 if (module
->modules
== nullptr) {
274 module
->modules
[module
->numModules
++] = handle
;
275 if (importDesc
->OriginalFirstThunk
) {
276 thunkRef
= (POINTER_TYPE
*)(codeBase
+ importDesc
->OriginalFirstThunk
);
277 funcRef
= (FARPROC
*)(codeBase
+ importDesc
->FirstThunk
);
280 thunkRef
= (POINTER_TYPE
*)(codeBase
+ importDesc
->FirstThunk
);
281 funcRef
= (FARPROC
*)(codeBase
+ importDesc
->FirstThunk
);
283 for (; *thunkRef
; thunkRef
++, funcRef
++) {
284 if (IMAGE_SNAP_BY_ORDINAL(*thunkRef
)) {
286 (FARPROC
)GetProcAddress(handle
, (LPCSTR
)IMAGE_ORDINAL(*thunkRef
));
288 PIMAGE_IMPORT_BY_NAME thunkData
=
289 (PIMAGE_IMPORT_BY_NAME
)(codeBase
+ (*thunkRef
));
290 *funcRef
= (FARPROC
)GetProcAddress(handle
, (LPCSTR
)&thunkData
->Name
);
307 static void* MemoryGetProcAddress(PMEMORYMODULE module
, const char* name
);
309 void* LoadRemoteLibraryAndGetAddress(HANDLE hRemoteProcess
,
310 const WCHAR
* library
, const char* symbol
) {
311 // Map the DLL into memory
312 nsAutoHandle
hLibrary(CreateFile(library
, GENERIC_READ
, FILE_SHARE_READ
,
313 nullptr, OPEN_EXISTING
,
314 FILE_ATTRIBUTE_NORMAL
, nullptr));
315 if (INVALID_HANDLE_VALUE
== hLibrary
) {
317 OutputLastError("Couldn't CreateFile the library.\n");
322 nsAutoHandle
hMapping(
323 CreateFileMapping(hLibrary
, nullptr, PAGE_READONLY
, 0, 0, nullptr));
326 OutputLastError("Couldn't CreateFileMapping.\n");
331 nsAutoRef
<FileView
> data(
332 (const unsigned char*)MapViewOfFile(hMapping
, FILE_MAP_READ
, 0, 0, 0));
335 OutputLastError("Couldn't MapViewOfFile.\n");
340 SIZE_T locationDelta
;
342 PIMAGE_DOS_HEADER dos_header
= (PIMAGE_DOS_HEADER
)data
.get();
343 if (dos_header
->e_magic
!= IMAGE_DOS_SIGNATURE
) {
345 OutputDebugStringA("Not a valid executable file.\n");
350 PIMAGE_NT_HEADERS old_header
=
351 (PIMAGE_NT_HEADERS
)(data
+ dos_header
->e_lfanew
);
352 if (old_header
->Signature
!= IMAGE_NT_SIGNATURE
) {
354 OutputDebugStringA("No PE header found.\n");
359 // reserve memory for image of library in this process and the target process
360 unsigned char* localCode
= (unsigned char*)VirtualAlloc(
361 nullptr, old_header
->OptionalHeader
.SizeOfImage
, MEM_RESERVE
| MEM_COMMIT
,
365 OutputLastError("Can't reserve local memory.");
369 unsigned char* remoteCode
= (unsigned char*)VirtualAllocEx(
370 hRemoteProcess
, nullptr, old_header
->OptionalHeader
.SizeOfImage
,
371 MEM_RESERVE
, PAGE_EXECUTE_READ
);
374 OutputLastError("Can't reserve remote memory.");
379 result
.localCodeBase
= localCode
;
380 result
.remoteCodeBase
= remoteCode
;
381 result
.numModules
= 0;
382 result
.modules
= nullptr;
384 // copy PE header to code
385 memcpy(localCode
, dos_header
,
386 dos_header
->e_lfanew
+ old_header
->OptionalHeader
.SizeOfHeaders
);
388 reinterpret_cast<PIMAGE_NT_HEADERS
>(localCode
+ dos_header
->e_lfanew
);
391 result
.headers
->OptionalHeader
.ImageBase
= (POINTER_TYPE
)remoteCode
;
393 // copy sections from DLL file block to new memory location
394 CopySections(data
, old_header
, &result
);
396 // adjust base address of imported data
397 locationDelta
= (SIZE_T
)(remoteCode
- old_header
->OptionalHeader
.ImageBase
);
398 if (locationDelta
!= 0) {
399 PerformBaseRelocation(&result
, locationDelta
);
402 // load required dlls and adjust function table of imports
403 if (!BuildImportTable(&result
)) {
407 // mark memory pages depending on section headers and release
408 // sections that are marked as "discardable"
409 if (!FinalizeSections(&result
, hRemoteProcess
)) {
413 return MemoryGetProcAddress(&result
, symbol
);
416 static void* MemoryGetProcAddress(PMEMORYMODULE module
, const char* name
) {
417 unsigned char* localCodeBase
= module
->localCodeBase
;
421 PIMAGE_EXPORT_DIRECTORY exports
;
422 PIMAGE_DATA_DIRECTORY directory
=
423 GET_HEADER_DICTIONARY(module
, IMAGE_DIRECTORY_ENTRY_EXPORT
);
424 if (directory
->Size
== 0) {
425 // no export table found
430 (PIMAGE_EXPORT_DIRECTORY
)(localCodeBase
+ directory
->VirtualAddress
);
431 if (exports
->NumberOfNames
== 0 || exports
->NumberOfFunctions
== 0) {
432 // DLL doesn't export anything
436 // search function name in list of exported names
437 nameRef
= (DWORD
*)(localCodeBase
+ exports
->AddressOfNames
);
438 ordinal
= (WORD
*)(localCodeBase
+ exports
->AddressOfNameOrdinals
);
439 for (i
= 0; i
< exports
->NumberOfNames
; i
++, nameRef
++, ordinal
++) {
440 if (stricmp(name
, (const char*)(localCodeBase
+ (*nameRef
))) == 0) {
447 // exported symbol not found
451 if ((DWORD
)idx
> exports
->NumberOfFunctions
) {
452 // name <-> ordinal number don't match
456 // AddressOfFunctions contains the RVAs to the "real" functions
457 return module
->remoteCodeBase
+
458 (*(DWORD
*)(localCodeBase
+ exports
->AddressOfFunctions
+ (idx
* 4)));