Sat, 03 Jan 2015 20:18:00 +0100
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 | } |