toolkit/crashreporter/LoadLibraryRemote.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #ifndef __GNUC__
michael@0 6 // disable warnings about pointer <-> DWORD conversions
michael@0 7 #pragma warning( disable : 4311 4312 )
michael@0 8 #endif
michael@0 9
michael@0 10 #ifdef _WIN64
michael@0 11 #define POINTER_TYPE ULONGLONG
michael@0 12 #else
michael@0 13 #define POINTER_TYPE DWORD
michael@0 14 #endif
michael@0 15
michael@0 16 #include <windows.h>
michael@0 17 #include <winnt.h>
michael@0 18 #include <stdlib.h>
michael@0 19 #ifdef DEBUG_OUTPUT
michael@0 20 #include <stdio.h>
michael@0 21 #endif
michael@0 22
michael@0 23 #include "nsWindowsHelpers.h"
michael@0 24
michael@0 25 typedef const unsigned char* FileView;
michael@0 26
michael@0 27 template<>
michael@0 28 class nsAutoRefTraits<FileView>
michael@0 29 {
michael@0 30 public:
michael@0 31 typedef FileView RawRef;
michael@0 32 static FileView Void()
michael@0 33 {
michael@0 34 return nullptr;
michael@0 35 }
michael@0 36
michael@0 37 static void Release(RawRef aView)
michael@0 38 {
michael@0 39 if (nullptr != aView)
michael@0 40 UnmapViewOfFile(aView);
michael@0 41 }
michael@0 42 };
michael@0 43
michael@0 44 #ifndef IMAGE_SIZEOF_BASE_RELOCATION
michael@0 45 // Vista SDKs no longer define IMAGE_SIZEOF_BASE_RELOCATION!?
michael@0 46 #define IMAGE_SIZEOF_BASE_RELOCATION (sizeof(IMAGE_BASE_RELOCATION))
michael@0 47 #endif
michael@0 48
michael@0 49 #include "LoadLibraryRemote.h"
michael@0 50
michael@0 51 typedef struct {
michael@0 52 PIMAGE_NT_HEADERS headers;
michael@0 53 unsigned char *localCodeBase;
michael@0 54 unsigned char *remoteCodeBase;
michael@0 55 HMODULE *modules;
michael@0 56 int numModules;
michael@0 57 } MEMORYMODULE, *PMEMORYMODULE;
michael@0 58
michael@0 59 typedef BOOL (WINAPI *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
michael@0 60
michael@0 61 #define GET_HEADER_DICTIONARY(module, idx) &(module)->headers->OptionalHeader.DataDirectory[idx]
michael@0 62
michael@0 63 #ifdef DEBUG_OUTPUT
michael@0 64 static void
michael@0 65 OutputLastError(const char *msg)
michael@0 66 {
michael@0 67 char* tmp;
michael@0 68 char *tmpmsg;
michael@0 69 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
michael@0 70 nullptr, GetLastError(),
michael@0 71 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
michael@0 72 (LPSTR) &tmp, 0, nullptr);
michael@0 73 tmpmsg = (char *)LocalAlloc(LPTR, strlen(msg) + strlen(tmp) + 3);
michael@0 74 sprintf(tmpmsg, "%s: %s", msg, tmp);
michael@0 75 OutputDebugStringA(tmpmsg);
michael@0 76 LocalFree(tmpmsg);
michael@0 77 LocalFree(tmp);
michael@0 78 }
michael@0 79 #endif
michael@0 80
michael@0 81 static void
michael@0 82 CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module)
michael@0 83 {
michael@0 84 int i;
michael@0 85 unsigned char *codeBase = module->localCodeBase;
michael@0 86 unsigned char *dest;
michael@0 87 PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
michael@0 88 for (i=0; i<module->headers->FileHeader.NumberOfSections; i++, section++) {
michael@0 89 dest = codeBase + section->VirtualAddress;
michael@0 90 memset(dest, 0, section->Misc.VirtualSize);
michael@0 91 if (section->SizeOfRawData) {
michael@0 92 memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData);
michael@0 93 }
michael@0 94 // section->Misc.PhysicalAddress = (POINTER_TYPE) module->remoteCodeBase + section->VirtualAddress;
michael@0 95 }
michael@0 96 }
michael@0 97
michael@0 98 // Protection flags for memory pages (Executable, Readable, Writeable)
michael@0 99 static int ProtectionFlags[2][2][2] = {
michael@0 100 {
michael@0 101 // not executable
michael@0 102 {PAGE_NOACCESS, PAGE_WRITECOPY},
michael@0 103 {PAGE_READONLY, PAGE_READWRITE},
michael@0 104 }, {
michael@0 105 // executable
michael@0 106 {PAGE_EXECUTE, PAGE_EXECUTE_WRITECOPY},
michael@0 107 {PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE},
michael@0 108 },
michael@0 109 };
michael@0 110
michael@0 111 static bool
michael@0 112 FinalizeSections(PMEMORYMODULE module, HANDLE hRemoteProcess)
michael@0 113 {
michael@0 114 #ifdef DEBUG_OUTPUT
michael@0 115 fprintf(stderr, "Finalizing sections: local base %p, remote base %p\n",
michael@0 116 module->localCodeBase, module->remoteCodeBase);
michael@0 117 #endif
michael@0 118
michael@0 119 int i;
michael@0 120 PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
michael@0 121
michael@0 122 // loop through all sections and change access flags
michael@0 123 for (i=0; i<module->headers->FileHeader.NumberOfSections; i++, section++) {
michael@0 124 DWORD protect, oldProtect, size;
michael@0 125 int executable = (section->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0;
michael@0 126 int readable = (section->Characteristics & IMAGE_SCN_MEM_READ) != 0;
michael@0 127 int writeable = (section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0;
michael@0 128
michael@0 129 // determine protection flags based on characteristics
michael@0 130 protect = ProtectionFlags[executable][readable][writeable];
michael@0 131 if (section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) {
michael@0 132 protect |= PAGE_NOCACHE;
michael@0 133 }
michael@0 134
michael@0 135 // determine size of region
michael@0 136 size = section->Misc.VirtualSize;
michael@0 137 if (size > 0) {
michael@0 138 void* remoteAddress = module->remoteCodeBase + section->VirtualAddress;
michael@0 139 void* localAddress = module->localCodeBase + section->VirtualAddress;
michael@0 140
michael@0 141 #ifdef DEBUG_OUTPUT
michael@0 142 fprintf(stderr, "Copying section %s to %p, size %x, executable %i readable %i writeable %i\n",
michael@0 143 section->Name, remoteAddress, size, executable, readable, writeable);
michael@0 144 #endif
michael@0 145
michael@0 146 // Copy the data from local->remote and set the memory protection
michael@0 147 if (!VirtualAllocEx(hRemoteProcess, remoteAddress, size, MEM_COMMIT, PAGE_READWRITE))
michael@0 148 return false;
michael@0 149
michael@0 150 if (!WriteProcessMemory(hRemoteProcess,
michael@0 151 remoteAddress,
michael@0 152 localAddress,
michael@0 153 size,
michael@0 154 nullptr)) {
michael@0 155 #ifdef DEBUG_OUTPUT
michael@0 156 OutputLastError("Error writing remote memory.\n");
michael@0 157 #endif
michael@0 158 return false;
michael@0 159 }
michael@0 160
michael@0 161 if (VirtualProtectEx(hRemoteProcess, remoteAddress, size, protect, &oldProtect) == 0) {
michael@0 162 #ifdef DEBUG_OUTPUT
michael@0 163 OutputLastError("Error protecting memory page");
michael@0 164 #endif
michael@0 165 return false;
michael@0 166 }
michael@0 167 }
michael@0 168 }
michael@0 169 return true;
michael@0 170 }
michael@0 171
michael@0 172 static void
michael@0 173 PerformBaseRelocation(PMEMORYMODULE module, SIZE_T delta)
michael@0 174 {
michael@0 175 DWORD i;
michael@0 176 unsigned char *codeBase = module->localCodeBase;
michael@0 177
michael@0 178 PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_BASERELOC);
michael@0 179 if (directory->Size > 0) {
michael@0 180 PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION) (codeBase + directory->VirtualAddress);
michael@0 181 for (; relocation->VirtualAddress > 0; ) {
michael@0 182 unsigned char *dest = codeBase + relocation->VirtualAddress;
michael@0 183 unsigned short *relInfo = (unsigned short *)((unsigned char *)relocation + IMAGE_SIZEOF_BASE_RELOCATION);
michael@0 184 for (i=0; i<((relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2); i++, relInfo++) {
michael@0 185 DWORD *patchAddrHL;
michael@0 186 #ifdef _WIN64
michael@0 187 ULONGLONG *patchAddr64;
michael@0 188 #endif
michael@0 189 int type, offset;
michael@0 190
michael@0 191 // the upper 4 bits define the type of relocation
michael@0 192 type = *relInfo >> 12;
michael@0 193 // the lower 12 bits define the offset
michael@0 194 offset = *relInfo & 0xfff;
michael@0 195
michael@0 196 switch (type)
michael@0 197 {
michael@0 198 case IMAGE_REL_BASED_ABSOLUTE:
michael@0 199 // skip relocation
michael@0 200 break;
michael@0 201
michael@0 202 case IMAGE_REL_BASED_HIGHLOW:
michael@0 203 // change complete 32 bit address
michael@0 204 patchAddrHL = (DWORD *) (dest + offset);
michael@0 205 *patchAddrHL += delta;
michael@0 206 break;
michael@0 207
michael@0 208 #ifdef _WIN64
michael@0 209 case IMAGE_REL_BASED_DIR64:
michael@0 210 patchAddr64 = (ULONGLONG *) (dest + offset);
michael@0 211 *patchAddr64 += delta;
michael@0 212 break;
michael@0 213 #endif
michael@0 214
michael@0 215 default:
michael@0 216 //printf("Unknown relocation: %d\n", type);
michael@0 217 break;
michael@0 218 }
michael@0 219 }
michael@0 220
michael@0 221 // advance to next relocation block
michael@0 222 relocation = (PIMAGE_BASE_RELOCATION) (((char *) relocation) + relocation->SizeOfBlock);
michael@0 223 }
michael@0 224 }
michael@0 225 }
michael@0 226
michael@0 227 static int
michael@0 228 BuildImportTable(PMEMORYMODULE module)
michael@0 229 {
michael@0 230 int result=1;
michael@0 231 unsigned char *codeBase = module->localCodeBase;
michael@0 232
michael@0 233 PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_IMPORT);
michael@0 234 if (directory->Size > 0) {
michael@0 235 PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress);
michael@0 236 PIMAGE_IMPORT_DESCRIPTOR importEnd = (PIMAGE_IMPORT_DESCRIPTOR) (codeBase + directory->VirtualAddress + directory->Size);
michael@0 237
michael@0 238 for (; importDesc < importEnd && importDesc->Name; importDesc++) {
michael@0 239 POINTER_TYPE *thunkRef;
michael@0 240 FARPROC *funcRef;
michael@0 241 HMODULE handle = GetModuleHandleA((LPCSTR) (codeBase + importDesc->Name));
michael@0 242 if (handle == nullptr) {
michael@0 243 #if DEBUG_OUTPUT
michael@0 244 OutputLastError("Can't load library");
michael@0 245 #endif
michael@0 246 result = 0;
michael@0 247 break;
michael@0 248 }
michael@0 249
michael@0 250 module->modules = (HMODULE *)realloc(module->modules, (module->numModules+1)*(sizeof(HMODULE)));
michael@0 251 if (module->modules == nullptr) {
michael@0 252 result = 0;
michael@0 253 break;
michael@0 254 }
michael@0 255
michael@0 256 module->modules[module->numModules++] = handle;
michael@0 257 if (importDesc->OriginalFirstThunk) {
michael@0 258 thunkRef = (POINTER_TYPE *) (codeBase + importDesc->OriginalFirstThunk);
michael@0 259 funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk);
michael@0 260 } else {
michael@0 261 // no hint table
michael@0 262 thunkRef = (POINTER_TYPE *) (codeBase + importDesc->FirstThunk);
michael@0 263 funcRef = (FARPROC *) (codeBase + importDesc->FirstThunk);
michael@0 264 }
michael@0 265 for (; *thunkRef; thunkRef++, funcRef++) {
michael@0 266 if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) {
michael@0 267 *funcRef = (FARPROC)GetProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef));
michael@0 268 } else {
michael@0 269 PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME) (codeBase + (*thunkRef));
michael@0 270 *funcRef = (FARPROC)GetProcAddress(handle, (LPCSTR)&thunkData->Name);
michael@0 271 }
michael@0 272 if (*funcRef == 0) {
michael@0 273 result = 0;
michael@0 274 break;
michael@0 275 }
michael@0 276 }
michael@0 277
michael@0 278 if (!result) {
michael@0 279 break;
michael@0 280 }
michael@0 281 }
michael@0 282 }
michael@0 283
michael@0 284 return result;
michael@0 285 }
michael@0 286
michael@0 287 static void* MemoryGetProcAddress(PMEMORYMODULE module, const char *name);
michael@0 288
michael@0 289 void* LoadRemoteLibraryAndGetAddress(HANDLE hRemoteProcess,
michael@0 290 const WCHAR* library,
michael@0 291 const char* symbol)
michael@0 292 {
michael@0 293 // Map the DLL into memory
michael@0 294 nsAutoHandle hLibrary(
michael@0 295 CreateFile(library, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
michael@0 296 FILE_ATTRIBUTE_NORMAL, nullptr));
michael@0 297 if (INVALID_HANDLE_VALUE == hLibrary) {
michael@0 298 #if DEBUG_OUTPUT
michael@0 299 OutputLastError("Couldn't CreateFile the library.\n");
michael@0 300 #endif
michael@0 301 return nullptr;
michael@0 302 }
michael@0 303
michael@0 304 nsAutoHandle hMapping(
michael@0 305 CreateFileMapping(hLibrary, nullptr, PAGE_READONLY, 0, 0, nullptr));
michael@0 306 if (!hMapping) {
michael@0 307 #if DEBUG_OUTPUT
michael@0 308 OutputLastError("Couldn't CreateFileMapping.\n");
michael@0 309 #endif
michael@0 310 return nullptr;
michael@0 311 }
michael@0 312
michael@0 313 nsAutoRef<FileView> data(
michael@0 314 (const unsigned char*) MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
michael@0 315 if (!data) {
michael@0 316 #if DEBUG_OUTPUT
michael@0 317 OutputLastError("Couldn't MapViewOfFile.\n");
michael@0 318 #endif
michael@0 319 return nullptr;
michael@0 320 }
michael@0 321
michael@0 322 SIZE_T locationDelta;
michael@0 323
michael@0 324 PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)data.get();
michael@0 325 if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
michael@0 326 #if DEBUG_OUTPUT
michael@0 327 OutputDebugStringA("Not a valid executable file.\n");
michael@0 328 #endif
michael@0 329 return nullptr;
michael@0 330 }
michael@0 331
michael@0 332 PIMAGE_NT_HEADERS old_header = (PIMAGE_NT_HEADERS)(data + dos_header->e_lfanew);
michael@0 333 if (old_header->Signature != IMAGE_NT_SIGNATURE) {
michael@0 334 #if DEBUG_OUTPUT
michael@0 335 OutputDebugStringA("No PE header found.\n");
michael@0 336 #endif
michael@0 337 return nullptr;
michael@0 338 }
michael@0 339
michael@0 340 // reserve memory for image of library in this process and the target process
michael@0 341 unsigned char* localCode = (unsigned char*) VirtualAlloc(nullptr,
michael@0 342 old_header->OptionalHeader.SizeOfImage,
michael@0 343 MEM_RESERVE | MEM_COMMIT,
michael@0 344 PAGE_READWRITE);
michael@0 345 if (!localCode) {
michael@0 346 #if DEBUG_OUTPUT
michael@0 347 OutputLastError("Can't reserve local memory.");
michael@0 348 #endif
michael@0 349 }
michael@0 350
michael@0 351 unsigned char* remoteCode = (unsigned char*) VirtualAllocEx(hRemoteProcess, nullptr,
michael@0 352 old_header->OptionalHeader.SizeOfImage,
michael@0 353 MEM_RESERVE,
michael@0 354 PAGE_EXECUTE_READ);
michael@0 355 if (!remoteCode) {
michael@0 356 #if DEBUG_OUTPUT
michael@0 357 OutputLastError("Can't reserve remote memory.");
michael@0 358 #endif
michael@0 359 }
michael@0 360
michael@0 361 MEMORYMODULE result;
michael@0 362 result.localCodeBase = localCode;
michael@0 363 result.remoteCodeBase = remoteCode;
michael@0 364 result.numModules = 0;
michael@0 365 result.modules = nullptr;
michael@0 366
michael@0 367 // copy PE header to code
michael@0 368 memcpy(localCode, dos_header, dos_header->e_lfanew + old_header->OptionalHeader.SizeOfHeaders);
michael@0 369 result.headers = reinterpret_cast<PIMAGE_NT_HEADERS>(localCode + dos_header->e_lfanew);
michael@0 370
michael@0 371 // update position
michael@0 372 result.headers->OptionalHeader.ImageBase = (POINTER_TYPE)remoteCode;
michael@0 373
michael@0 374 // copy sections from DLL file block to new memory location
michael@0 375 CopySections(data, old_header, &result);
michael@0 376
michael@0 377 // adjust base address of imported data
michael@0 378 locationDelta = (SIZE_T)(remoteCode - old_header->OptionalHeader.ImageBase);
michael@0 379 if (locationDelta != 0) {
michael@0 380 PerformBaseRelocation(&result, locationDelta);
michael@0 381 }
michael@0 382
michael@0 383 // load required dlls and adjust function table of imports
michael@0 384 if (!BuildImportTable(&result)) {
michael@0 385 return nullptr;
michael@0 386 }
michael@0 387
michael@0 388 // mark memory pages depending on section headers and release
michael@0 389 // sections that are marked as "discardable"
michael@0 390 if (!FinalizeSections(&result, hRemoteProcess)) {
michael@0 391 return nullptr;
michael@0 392 }
michael@0 393
michael@0 394 return MemoryGetProcAddress(&result, symbol);
michael@0 395 }
michael@0 396
michael@0 397 static void* MemoryGetProcAddress(PMEMORYMODULE module, const char *name)
michael@0 398 {
michael@0 399 unsigned char *localCodeBase = module->localCodeBase;
michael@0 400 int idx=-1;
michael@0 401 DWORD i, *nameRef;
michael@0 402 WORD *ordinal;
michael@0 403 PIMAGE_EXPORT_DIRECTORY exports;
michael@0 404 PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY(module, IMAGE_DIRECTORY_ENTRY_EXPORT);
michael@0 405 if (directory->Size == 0) {
michael@0 406 // no export table found
michael@0 407 return nullptr;
michael@0 408 }
michael@0 409
michael@0 410 exports = (PIMAGE_EXPORT_DIRECTORY) (localCodeBase + directory->VirtualAddress);
michael@0 411 if (exports->NumberOfNames == 0 || exports->NumberOfFunctions == 0) {
michael@0 412 // DLL doesn't export anything
michael@0 413 return nullptr;
michael@0 414 }
michael@0 415
michael@0 416 // search function name in list of exported names
michael@0 417 nameRef = (DWORD *) (localCodeBase + exports->AddressOfNames);
michael@0 418 ordinal = (WORD *) (localCodeBase + exports->AddressOfNameOrdinals);
michael@0 419 for (i=0; i<exports->NumberOfNames; i++, nameRef++, ordinal++) {
michael@0 420 if (stricmp(name, (const char *) (localCodeBase + (*nameRef))) == 0) {
michael@0 421 idx = *ordinal;
michael@0 422 break;
michael@0 423 }
michael@0 424 }
michael@0 425
michael@0 426 if (idx == -1) {
michael@0 427 // exported symbol not found
michael@0 428 return nullptr;
michael@0 429 }
michael@0 430
michael@0 431 if ((DWORD)idx > exports->NumberOfFunctions) {
michael@0 432 // name <-> ordinal number don't match
michael@0 433 return nullptr;
michael@0 434 }
michael@0 435
michael@0 436 // AddressOfFunctions contains the RVAs to the "real" functions
michael@0 437 return module->remoteCodeBase + (*(DWORD *) (localCodeBase + exports->AddressOfFunctions + (idx*4)));
michael@0 438 }

mercurial