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
>
31 typedef FileView RawRef
;
32 static FileView
Void()
37 static void Release(RawRef aView
)
40 UnmapViewOfFile(aView
);
44 #ifndef IMAGE_SIZEOF_BASE_RELOCATION
45 // Vista SDKs no longer define IMAGE_SIZEOF_BASE_RELOCATION!?
46 #define IMAGE_SIZEOF_BASE_RELOCATION (sizeof(IMAGE_BASE_RELOCATION))
49 #include "LoadLibraryRemote.h"
52 PIMAGE_NT_HEADERS headers
;
53 unsigned char *localCodeBase
;
54 unsigned char *remoteCodeBase
;
57 } MEMORYMODULE
, *PMEMORYMODULE
;
59 typedef BOOL (WINAPI
*DllEntryProc
)(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpReserved
);
61 #define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx]
65 OutputLastError(const char *msg
)
69 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
,
70 nullptr, GetLastError(),
71 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
72 (LPSTR
) &tmp
, 0, nullptr);
73 tmpmsg
= (char *)LocalAlloc(LPTR
, strlen(msg
) + strlen(tmp
) + 3);
74 sprintf(tmpmsg
, "%s: %s", msg
, tmp
);
75 OutputDebugStringA(tmpmsg
);
82 CopySections(const unsigned char *data
, PIMAGE_NT_HEADERS old_headers
, PMEMORYMODULE module
)
85 unsigned char *codeBase
= module
->localCodeBase
;
87 PIMAGE_SECTION_HEADER section
= IMAGE_FIRST_SECTION(module
->headers
);
88 for (i
=0; i
<module
->headers
->FileHeader
.NumberOfSections
; i
++, section
++) {
89 dest
= codeBase
+ section
->VirtualAddress
;
90 memset(dest
, 0, section
->Misc
.VirtualSize
);
91 if (section
->SizeOfRawData
) {
92 memcpy(dest
, data
+ section
->PointerToRawData
, section
->SizeOfRawData
);
94 // section->Misc.PhysicalAddress = (POINTER_TYPE) module->remoteCodeBase + section->VirtualAddress;
98 // Protection flags for memory pages (Executable, Readable, Writeable)
99 static int ProtectionFlags
[2][2][2] = {
102 {PAGE_NOACCESS
, PAGE_WRITECOPY
},
103 {PAGE_READONLY
, PAGE_READWRITE
},
106 {PAGE_EXECUTE
, PAGE_EXECUTE_WRITECOPY
},
107 {PAGE_EXECUTE_READ
, PAGE_EXECUTE_READWRITE
},
112 FinalizeSections(PMEMORYMODULE module
, HANDLE hRemoteProcess
)
115 fprintf(stderr
, "Finalizing sections: local base %p, remote base %p\n",
116 module
->localCodeBase
, module
->remoteCodeBase
);
120 PIMAGE_SECTION_HEADER section
= IMAGE_FIRST_SECTION(module
->headers
);
122 // loop through all sections and change access flags
123 for (i
=0; i
<module
->headers
->FileHeader
.NumberOfSections
; i
++, section
++) {
124 DWORD protect
, oldProtect
, size
;
125 int executable
= (section
->Characteristics
& IMAGE_SCN_MEM_EXECUTE
) != 0;
126 int readable
= (section
->Characteristics
& IMAGE_SCN_MEM_READ
) != 0;
127 int writeable
= (section
->Characteristics
& IMAGE_SCN_MEM_WRITE
) != 0;
129 // determine protection flags based on characteristics
130 protect
= ProtectionFlags
[executable
][readable
][writeable
];
131 if (section
->Characteristics
& IMAGE_SCN_MEM_NOT_CACHED
) {
132 protect
|= PAGE_NOCACHE
;
135 // determine size of region
136 size
= section
->Misc
.VirtualSize
;
138 void* remoteAddress
= module
->remoteCodeBase
+ section
->VirtualAddress
;
139 void* localAddress
= module
->localCodeBase
+ section
->VirtualAddress
;
142 fprintf(stderr
, "Copying section %s to %p, size %x, executable %i readable %i writeable %i\n",
143 section
->Name
, remoteAddress
, size
, executable
, readable
, writeable
);
146 // Copy the data from local->remote and set the memory protection
147 if (!VirtualAllocEx(hRemoteProcess
, remoteAddress
, size
, MEM_COMMIT
, PAGE_READWRITE
))
150 if (!WriteProcessMemory(hRemoteProcess
,
156 OutputLastError("Error writing remote memory.\n");
161 if (VirtualProtectEx(hRemoteProcess
, remoteAddress
, size
, protect
, &oldProtect
) == 0) {
163 OutputLastError("Error protecting memory page");
173 PerformBaseRelocation(PMEMORYMODULE module
, SIZE_T delta
)
176 unsigned char *codeBase
= module
->localCodeBase
;
178 PIMAGE_DATA_DIRECTORY directory
= GET_HEADER_DICTIONARY(module
, IMAGE_DIRECTORY_ENTRY_BASERELOC
);
179 if (directory
->Size
> 0) {
180 PIMAGE_BASE_RELOCATION relocation
= (PIMAGE_BASE_RELOCATION
) (codeBase
+ directory
->VirtualAddress
);
181 for (; relocation
->VirtualAddress
> 0; ) {
182 unsigned char *dest
= codeBase
+ relocation
->VirtualAddress
;
183 unsigned short *relInfo
= (unsigned short *)((unsigned char *)relocation
+ IMAGE_SIZEOF_BASE_RELOCATION
);
184 for (i
=0; i
<((relocation
->SizeOfBlock
-IMAGE_SIZEOF_BASE_RELOCATION
) / 2); i
++, relInfo
++) {
187 ULONGLONG
*patchAddr64
;
191 // the upper 4 bits define the type of relocation
192 type
= *relInfo
>> 12;
193 // the lower 12 bits define the offset
194 offset
= *relInfo
& 0xfff;
198 case IMAGE_REL_BASED_ABSOLUTE
:
202 case IMAGE_REL_BASED_HIGHLOW
:
203 // change complete 32 bit address
204 patchAddrHL
= (DWORD
*) (dest
+ offset
);
205 *patchAddrHL
+= delta
;
209 case IMAGE_REL_BASED_DIR64
:
210 patchAddr64
= (ULONGLONG
*) (dest
+ offset
);
211 *patchAddr64
+= delta
;
216 //printf("Unknown relocation: %d\n", type);
221 // advance to next relocation block
222 relocation
= (PIMAGE_BASE_RELOCATION
) (((char *) relocation
) + relocation
->SizeOfBlock
);
228 BuildImportTable(PMEMORYMODULE module
)
231 unsigned char *codeBase
= module
->localCodeBase
;
233 PIMAGE_DATA_DIRECTORY directory
= GET_HEADER_DICTIONARY(module
, IMAGE_DIRECTORY_ENTRY_IMPORT
);
234 if (directory
->Size
> 0) {
235 PIMAGE_IMPORT_DESCRIPTOR importDesc
= (PIMAGE_IMPORT_DESCRIPTOR
) (codeBase
+ directory
->VirtualAddress
);
236 PIMAGE_IMPORT_DESCRIPTOR importEnd
= (PIMAGE_IMPORT_DESCRIPTOR
) (codeBase
+ directory
->VirtualAddress
+ directory
->Size
);
238 for (; importDesc
< importEnd
&& importDesc
->Name
; importDesc
++) {
239 POINTER_TYPE
*thunkRef
;
241 HMODULE handle
= GetModuleHandleA((LPCSTR
) (codeBase
+ importDesc
->Name
));
242 if (handle
== nullptr) {
244 OutputLastError("Can't load library");
250 module
->modules
= (HMODULE
*)realloc(module
->modules
, (module
->numModules
+1)*(sizeof(HMODULE
)));
251 if (module
->modules
== nullptr) {
256 module
->modules
[module
->numModules
++] = handle
;
257 if (importDesc
->OriginalFirstThunk
) {
258 thunkRef
= (POINTER_TYPE
*) (codeBase
+ importDesc
->OriginalFirstThunk
);
259 funcRef
= (FARPROC
*) (codeBase
+ importDesc
->FirstThunk
);
262 thunkRef
= (POINTER_TYPE
*) (codeBase
+ importDesc
->FirstThunk
);
263 funcRef
= (FARPROC
*) (codeBase
+ importDesc
->FirstThunk
);
265 for (; *thunkRef
; thunkRef
++, funcRef
++) {
266 if (IMAGE_SNAP_BY_ORDINAL(*thunkRef
)) {
267 *funcRef
= (FARPROC
)GetProcAddress(handle
, (LPCSTR
)IMAGE_ORDINAL(*thunkRef
));
269 PIMAGE_IMPORT_BY_NAME thunkData
= (PIMAGE_IMPORT_BY_NAME
) (codeBase
+ (*thunkRef
));
270 *funcRef
= (FARPROC
)GetProcAddress(handle
, (LPCSTR
)&thunkData
->Name
);
287 static void* MemoryGetProcAddress(PMEMORYMODULE module
, const char *name
);
289 void* LoadRemoteLibraryAndGetAddress(HANDLE hRemoteProcess
,
290 const WCHAR
* library
,
293 // Map the DLL into memory
294 nsAutoHandle
hLibrary(
295 CreateFile(library
, GENERIC_READ
, FILE_SHARE_READ
, nullptr, OPEN_EXISTING
,
296 FILE_ATTRIBUTE_NORMAL
, nullptr));
297 if (INVALID_HANDLE_VALUE
== hLibrary
) {
299 OutputLastError("Couldn't CreateFile the library.\n");
304 nsAutoHandle
hMapping(
305 CreateFileMapping(hLibrary
, nullptr, PAGE_READONLY
, 0, 0, nullptr));
308 OutputLastError("Couldn't CreateFileMapping.\n");
313 nsAutoRef
<FileView
> data(
314 (const unsigned char*) MapViewOfFile(hMapping
, FILE_MAP_READ
, 0, 0, 0));
317 OutputLastError("Couldn't MapViewOfFile.\n");
322 SIZE_T locationDelta
;
324 PIMAGE_DOS_HEADER dos_header
= (PIMAGE_DOS_HEADER
)data
.get();
325 if (dos_header
->e_magic
!= IMAGE_DOS_SIGNATURE
) {
327 OutputDebugStringA("Not a valid executable file.\n");
332 PIMAGE_NT_HEADERS old_header
= (PIMAGE_NT_HEADERS
)(data
+ dos_header
->e_lfanew
);
333 if (old_header
->Signature
!= IMAGE_NT_SIGNATURE
) {
335 OutputDebugStringA("No PE header found.\n");
340 // reserve memory for image of library in this process and the target process
341 unsigned char* localCode
= (unsigned char*) VirtualAlloc(nullptr,
342 old_header
->OptionalHeader
.SizeOfImage
,
343 MEM_RESERVE
| MEM_COMMIT
,
347 OutputLastError("Can't reserve local memory.");
351 unsigned char* remoteCode
= (unsigned char*) VirtualAllocEx(hRemoteProcess
, nullptr,
352 old_header
->OptionalHeader
.SizeOfImage
,
357 OutputLastError("Can't reserve remote memory.");
362 result
.localCodeBase
= localCode
;
363 result
.remoteCodeBase
= remoteCode
;
364 result
.numModules
= 0;
365 result
.modules
= nullptr;
367 // copy PE header to code
368 memcpy(localCode
, dos_header
, dos_header
->e_lfanew
+ old_header
->OptionalHeader
.SizeOfHeaders
);
369 result
.headers
= reinterpret_cast<PIMAGE_NT_HEADERS
>(localCode
+ dos_header
->e_lfanew
);
372 result
.headers
->OptionalHeader
.ImageBase
= (POINTER_TYPE
)remoteCode
;
374 // copy sections from DLL file block to new memory location
375 CopySections(data
, old_header
, &result
);
377 // adjust base address of imported data
378 locationDelta
= (SIZE_T
)(remoteCode
- old_header
->OptionalHeader
.ImageBase
);
379 if (locationDelta
!= 0) {
380 PerformBaseRelocation(&result
, locationDelta
);
383 // load required dlls and adjust function table of imports
384 if (!BuildImportTable(&result
)) {
388 // mark memory pages depending on section headers and release
389 // sections that are marked as "discardable"
390 if (!FinalizeSections(&result
, hRemoteProcess
)) {
394 return MemoryGetProcAddress(&result
, symbol
);
397 static void* MemoryGetProcAddress(PMEMORYMODULE module
, const char *name
)
399 unsigned char *localCodeBase
= module
->localCodeBase
;
403 PIMAGE_EXPORT_DIRECTORY exports
;
404 PIMAGE_DATA_DIRECTORY directory
= GET_HEADER_DICTIONARY(module
, IMAGE_DIRECTORY_ENTRY_EXPORT
);
405 if (directory
->Size
== 0) {
406 // no export table found
410 exports
= (PIMAGE_EXPORT_DIRECTORY
) (localCodeBase
+ directory
->VirtualAddress
);
411 if (exports
->NumberOfNames
== 0 || exports
->NumberOfFunctions
== 0) {
412 // DLL doesn't export anything
416 // search function name in list of exported names
417 nameRef
= (DWORD
*) (localCodeBase
+ exports
->AddressOfNames
);
418 ordinal
= (WORD
*) (localCodeBase
+ exports
->AddressOfNameOrdinals
);
419 for (i
=0; i
<exports
->NumberOfNames
; i
++, nameRef
++, ordinal
++) {
420 if (stricmp(name
, (const char *) (localCodeBase
+ (*nameRef
))) == 0) {
427 // exported symbol not found
431 if ((DWORD
)idx
> exports
->NumberOfFunctions
) {
432 // name <-> ordinal number don't match
436 // AddressOfFunctions contains the RVAs to the "real" functions
437 return module
->remoteCodeBase
+ (*(DWORD
*) (localCodeBase
+ exports
->AddressOfFunctions
+ (idx
*4)));