Changeset 2861 for trunk/kLdr/kLdrRdrFile.c
- Timestamp:
- Nov 10, 2006, 4:04:42 AM (19 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/kLdr/kLdrRdrFile.c
r2860 r2861 35 35 36 36 #elif defined(__WIN32__) || defined(__WIN64__) || defined(__WIN__) 37 # define WIN32_NO_STATUS 37 38 # include <Windows.h> 38 39 # ifndef __WIN__ 39 40 # define __WIN__ 40 41 # endif 42 # include <ntsecapi.h> 43 # include <ntstatus.h> 44 45 /// @todo find a non-conflicting header with NTSTATUS, NTAPI, ++ 46 typedef LONG NTSTATUS; 47 #define NT_SUCCESS(x) ((x)>=0) 48 49 typedef struct _OBJECT_ATTRIBUTES 50 { 51 ULONG Length; 52 HANDLE RootDirectory; 53 PUNICODE_STRING ObjectName; 54 ULONG Attributes; 55 PVOID SecurityDescriptor; 56 PVOID SecurityQualityOfService; 57 } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; 58 59 typedef enum _SECTION_INHERIT 60 { 61 ViewShare = 1, 62 ViewUnmap = 2 63 } SECTION_INHERIT; 64 65 # define NTOSAPI __declspec(dllimport) 66 # define NtCurrentProcess() GetCurrentProcess() 67 68 # ifndef MEM_DOS_LIM 69 # define MEM_DOS_LIM 0x40000000UL 70 # endif 71 72 NTOSAPI 73 NTSTATUS 74 NTAPI 75 NtCreateSection( 76 OUT PHANDLE SectionHandle, 77 IN ACCESS_MASK DesiredAccess, 78 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 79 IN PLARGE_INTEGER SectionSize OPTIONAL, 80 IN ULONG Protect, 81 IN ULONG Attributes, 82 IN HANDLE FileHandle OPTIONAL 83 ); 84 85 NTOSAPI 86 NTSTATUS 87 NTAPI 88 NtMapViewOfSection( 89 IN HANDLE SectionHandle, 90 IN HANDLE ProcessHandle, 91 IN OUT PVOID *BaseAddress, 92 IN ULONG ZeroBits, 93 IN ULONG CommitSize, 94 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, 95 IN OUT PSIZE_T ViewSize, 96 IN SECTION_INHERIT InheritDisposition, 97 IN ULONG AllocationType, 98 IN ULONG Protect 99 ); 100 101 NTOSAPI 102 NTSTATUS 103 NTAPI 104 NtUnmapViewOfSection( 105 IN HANDLE ProcessHandle, 106 IN PVOID BaseAddress 107 ); 108 109 NTOSAPI 110 NTSTATUS 111 NTAPI 112 NtClose( 113 IN HANDLE Handle 114 ); 115 116 NTOSAPI 117 NTSTATUS 118 NTAPI 119 ZwProtectVirtualMemory( 120 IN HANDLE ProcessHandle, 121 IN OUT PVOID *BaseAddress, 122 IN OUT PULONG ProtectSize, 123 IN ULONG NewProtect, 124 OUT PULONG OldProtect 125 ); 126 # define NtProtectVirtualMemory ZwProtectVirtualMemory 127 128 NTOSAPI 129 NTSTATUS 130 NTAPI 131 NtAllocateVirtualMemory( 132 IN HANDLE ProcessHandle, 133 IN OUT PVOID *BaseAddress, 134 IN ULONG ZeroBits, 135 IN OUT PULONG AllocationSize, 136 IN ULONG AllocationType, 137 IN ULONG Protect 138 ); 139 140 NTOSAPI 141 NTSTATUS 142 NTAPI 143 NtFreeVirtualMemory( 144 IN HANDLE ProcessHandle, 145 IN OUT PVOID *BaseAddress, 146 IN OUT PULONG FreeSize, 147 IN ULONG FreeType 148 ); 41 149 42 150 #else … … 46 154 #include <kLdr.h> 47 155 #include "kLdrHlp.h" 156 157 158 /******************************************************************************* 159 * Defined Constants And Macros * 160 *******************************************************************************/ 161 /** @def KLDRRDRFILE_STRICT 162 * Define KLDRRDRFILE_STRICT to enabled strict checks in KLDRRDRFILE. */ 163 #define KLDRRDRFILE_STRICT 1 164 165 /** @def KLDRRDRFILE_ASSERT 166 * Assert that an expression is true when KLDRRDRFILE_STRICT is defined. 167 */ 168 #ifdef KLDRRDRFILE_STRICT 169 # define KLDRRDRFILE_ASSERT(expr) kldrHlpAssert(expr) 170 #else 171 # define KLDRRDRFILE_ASSERT(expr) do {} while (0) 172 #endif 48 173 49 174 … … 102 227 *******************************************************************************/ 103 228 static void kldrRdrFileDone(PKLDRRDR pRdr); 104 static int kldrRdrFileUnprepare(PKLDRRDR pRdr, void *pv, size_t cb); 105 static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pv, size_t cb); 106 static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt); 107 static int kldrRdrFileRefreshMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile); 108 static int kldrRdrFileMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile); 109 static int kldrRdrFilePrepare(PKLDRRDR pRdr, void **ppv, size_t cb, unsigned fFixed); 229 static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments); 230 static int kldrRdrFileGenericUnmap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments); 231 static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect); 232 static int kldrRdrFileGenericProtect(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect); 233 static int kldrRdrFileRefresh(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments); 234 static int kldrRdrFileGenericRefresh(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments); 235 static int kldrRdrFileMap(PKLDRRDR pRdr, void *ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed); 236 static int kldrRdrFileGenericMap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed); 110 237 static size_t kldrRdrFilePageSize(PKLDRRDR pRdr); 111 238 static const char *kldrRdrFileName(PKLDRRDR pRdr); … … 136 263 kldrRdrFileName, 137 264 kldrRdrFilePageSize, 138 kldrRdrFilePrepare,139 265 kldrRdrFileMap, 140 kldrRdrFileRefresh Map,266 kldrRdrFileRefresh, 141 267 kldrRdrFileProtect, 142 268 kldrRdrFileUnmap, 143 kldrRdrFileUnprepare,144 269 kldrRdrFileDone, 145 270 42 146 271 }; 272 273 274 #if defined(__WIN__) || defined(__NT__) 275 /** 276 * Converts a kLdr segment protection to NT protection for a mapping. 277 * 278 * @returns Nt page protection. 279 * @param enmProt kLdr protection. 280 */ 281 static ULONG kldrRdrFileGetNtMapProt(KLDRPROT enmProt) 282 { 283 switch (enmProt) 284 { 285 case KLDRPROT_NOACCESS: return PAGE_NOACCESS; 286 case KLDRPROT_READONLY: return PAGE_READONLY; 287 case KLDRPROT_READWRITE: return PAGE_READWRITE; 288 case KLDRPROT_WRITECOPY: return PAGE_WRITECOPY; 289 case KLDRPROT_EXECUTE: return PAGE_EXECUTE; 290 case KLDRPROT_EXECUTE_READ: return PAGE_EXECUTE_READ; 291 case KLDRPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE; 292 case KLDRPROT_EXECUTE_WRITECOPY: return PAGE_EXECUTE_WRITECOPY; 293 default: return ~(ULONG)0; 294 } 295 } 296 297 298 /** 299 * Converts a kLdr segment protection to NT protection for a allocation. 300 * 301 * @returns Nt page protection. 302 * @param enmProt kLdr protection. 303 */ 304 static ULONG kldrRdrFileGetNtAllocProt(KLDRPROT enmProt) 305 { 306 switch (enmProt) 307 { 308 case KLDRPROT_NOACCESS: return PAGE_NOACCESS; 309 case KLDRPROT_READONLY: return PAGE_READONLY; 310 case KLDRPROT_WRITECOPY: 311 case KLDRPROT_READWRITE: return PAGE_READWRITE; 312 case KLDRPROT_EXECUTE: return PAGE_EXECUTE; 313 case KLDRPROT_EXECUTE_READ: return PAGE_EXECUTE_READ; 314 case KLDRPROT_EXECUTE_WRITECOPY: 315 case KLDRPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE; 316 default: return ~(ULONG)0; 317 } 318 } 319 #endif 147 320 148 321 … … 159 332 * @param pFile The instance data. 160 333 * @param pv The base of the region. 161 * @param cb The size of the region.162 334 */ 163 static PKLDRRDRFILEPREP kldrRdrFileFindPrepExact(PKLDRRDRFILE pFile, void *pv , size_t cb)335 static PKLDRRDRFILEPREP kldrRdrFileFindPrepExact(PKLDRRDRFILE pFile, void *pv) 164 336 { 165 337 int32_t i = pFile->cPreps; 166 338 while (i-- > 0) 167 if ( pFile->aPreps[i].pv == pv 168 || pFile->aPreps[i].cb == cb) 339 if (pFile->aPreps[i].pv == pv) 169 340 return &pFile->aPreps[i]; 170 341 return NULL; … … 172 343 173 344 174 /** 175 * Finds a prepared mapping region containing the specified region. 176 * 177 * @returns Pointer to the aPrep entry. 178 * @param pFile The instance data. 179 * @param pv The base of the sub region. 180 * @param cb The size of the sub region. 181 */ 182 static PKLDRRDRFILEPREP kldrRdrFileFindPrepWithin(PKLDRRDRFILE pFile, void *pv, size_t cb) 183 { 184 int32_t i = pFile->cPreps; 185 while (i-- > 0) 186 if ((uintptr_t)pv - (uintptr_t)pFile->aPreps[i].pv < pFile->aPreps[i].cb) 187 { 188 if ((uintptr_t)pv - (uintptr_t)pFile->aPreps[i].pv + cb <= pFile->aPreps[i].cb) 189 return &pFile->aPreps[i]; 190 return NULL; 191 } 192 return NULL; 193 } 194 195 196 /** @copydoc KLDRRDR::pfnUnprepare */ 197 static int kldrRdrFileUnprepare(PKLDRRDR pRdr, void *pv, size_t cb) 345 /** @copydoc KLDRRDR::pfnUnmap */ 346 static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments) 198 347 { 199 348 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; 200 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb); 349 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase); 350 int rc; 201 351 if (!pPrep) 202 352 return KLDR_ERR_INVALID_PARAMETER; 203 353 204 return -1; 205 } 206 207 208 /** @copydoc KLDRRDR::pfnUnmap */ 209 static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pv, size_t cb) 354 #if defined(__WIN__) || defined(__NT__) 355 if (pPrep->hSection != NULL) 356 { 357 /** @todo implement me. */ 358 return -1; 359 } 360 #endif 361 362 rc = kldrRdrFileGenericUnmap(pRdr, pPrep, cSegments, paSegments); 363 364 /* remove the mapping data on success. */ 365 if (!rc) 366 { 367 pRdrFile->cPreps--; 368 if (pPrep != &pRdrFile->aPreps[pRdrFile->cPreps]) 369 *pPrep = pRdrFile->aPreps[pRdrFile->cPreps]; 370 } 371 return rc; 372 } 373 374 375 /** Generic implementation of kldrRdrFileUnmap. */ 376 static int kldrRdrFileGenericUnmap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments) 377 { 378 kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */); 379 return kldrHlpPageFree(pPrep->pv, pPrep->cb); 380 } 381 382 383 /** @copydoc KLDRRDR::pfnProtect */ 384 static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect) 210 385 { 211 386 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; 212 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv , cb);387 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase); 213 388 if (!pPrep) 214 389 return KLDR_ERR_INVALID_PARAMETER; 215 390 216 return -1; 217 } 218 219 220 /** @copydoc KLDRRDR::pfnProtect */ 221 static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt) 391 #if defined(__WIN__) || defined(__NT__) 392 if (pPrep->hSection != NULL) 393 { 394 /** @todo implement me. */ 395 return -1; 396 } 397 #endif 398 399 return kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, fUnprotectOrProtect); 400 } 401 402 403 /** Generic implementation of kldrRdrFileProtect. */ 404 static int kldrRdrFileGenericProtect(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect) 405 { 406 uint32_t i; 407 408 /* 409 * Iterate the segments and apply memory protection changes. 410 */ 411 for (i = 0; i < cSegments; i++) 412 { 413 int rc; 414 void *pv; 415 KLDRPROT enmProt; 416 417 if (paSegments[i].RVA == NIL_KLDRADDR) 418 continue; 419 420 /* calc new protection. */ 421 enmProt = paSegments[i].enmProt; 422 if (fUnprotectOrProtect) 423 { 424 switch (enmProt) 425 { 426 case KLDRPROT_NOACCESS: 427 case KLDRPROT_READONLY: 428 case KLDRPROT_READWRITE: 429 case KLDRPROT_WRITECOPY: 430 enmProt = KLDRPROT_READWRITE; 431 break; 432 case KLDRPROT_EXECUTE: 433 case KLDRPROT_EXECUTE_READ: 434 case KLDRPROT_EXECUTE_READWRITE: 435 case KLDRPROT_EXECUTE_WRITECOPY: 436 enmProt = KLDRPROT_EXECUTE_READWRITE; 437 break; 438 default: 439 KLDRRDRFILE_ASSERT(!"bad enmProt"); 440 return -1; 441 } 442 } 443 else 444 { 445 /* copy on write -> normal write. */ 446 if (enmProt == KLDRPROT_EXECUTE_WRITECOPY) 447 enmProt = KLDRPROT_EXECUTE_READWRITE; 448 else if (enmProt == KLDRPROT_WRITECOPY) 449 enmProt = KLDRPROT_READWRITE; 450 } 451 452 pv = (uint8_t *)pPrep->pv + paSegments[i].RVA; 453 454 rc = kldrHlpPageProtect(pv, paSegments[i].cbMapped, enmProt); 455 if (rc) 456 break; 457 } 458 459 return 0; 460 } 461 462 463 /** @copydoc KLDRRDR::pfnRefresh */ 464 static int kldrRdrFileRefresh(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments) 222 465 { 223 466 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; 224 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv , cb);467 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase); 225 468 if (!pPrep) 226 469 return KLDR_ERR_INVALID_PARAMETER; 227 470 228 return -1; 229 } 230 231 232 /** @copydoc KLDRRDR::pfnRefreshMap */ 233 static int kldrRdrFileRefreshMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile) 471 #if defined(__WIN__) || defined(__NT__) 472 if (pPrep->hSection != NULL) 473 { 474 /** @todo implement me. */ 475 return -1; 476 } 477 #endif 478 479 return kldrRdrFileGenericRefresh(pRdr, pPrep, cSegments, paSegments); 480 } 481 482 483 /** Generic implementation of kldrRdrFileRefresh. */ 484 static int kldrRdrFileGenericRefresh(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments) 485 { 486 int rc; 487 int rc2; 488 uint32_t i; 489 490 /* 491 * Make everything writable again. 492 */ 493 rc = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */); 494 if (rc) 495 { 496 kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */); 497 return rc; 498 } 499 500 /* 501 * Clear everything. 502 */ 503 /** @todo only zero the areas not covered by raw file bits. */ 504 kLdrHlpMemSet(pPrep->pv, 0, pPrep->cb); 505 506 /* 507 * Reload all the segments. 508 * We could possibly skip some segments, but we currently have 509 * no generic way of figuring out which at the moment. 510 */ 511 for (i = 0; i < cSegments; i++) 512 { 513 void *pv; 514 515 if ( paSegments[i].RVA == NIL_KLDRADDR 516 || !paSegments[i].cbFile) 517 continue; 518 519 pv = (uint8_t *)pPrep->pv + paSegments[i].RVA; 520 rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile); 521 if (rc) 522 break; 523 } 524 525 /* 526 * Protect the bits again. 527 */ 528 rc2 = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */); 529 if (rc2 && rc) 530 rc = rc2; 531 532 return rc; 533 } 534 535 536 /** @copydoc KLDRRDR::pfnMap */ 537 static int kldrRdrFileMap(PKLDRRDR pRdr, void **ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed) 234 538 { 235 539 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; 236 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb); 237 if (!pPrep) 238 return KLDR_ERR_INVALID_PARAMETER; 239 240 return -1; 241 } 242 243 244 /** @copydoc KLDRRDR::pfnMap */ 245 static int kldrRdrFileMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile) 246 { 247 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; 248 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb); 249 if (!pPrep) 250 return KLDR_ERR_INVALID_PARAMETER; 251 252 return -1; 253 } 254 255 256 /** @copydoc KLDRRDR:pfnPrepare */ 257 static int kldrRdrFilePrepare(PKLDRRDR pRdr, void **ppv, size_t cb, unsigned fFixed) 258 { 259 #ifdef __OS2__ 260 261 262 #elif defined(__WIN__) 263 264 #else 265 # error "port me." 266 #endif 267 return -1; 540 PKLDRRDRFILEPREP pPrep = &pRdrFile->aPreps[pRdrFile->cPreps]; 541 KLDRSIZE cbTotal; 542 const size_t cbPage = pRdr->pOps->pfnPageSize(pRdr); 543 int rc; 544 uint32_t i; 545 546 if (pRdrFile->cPreps >= KLDR_ELEMENTS(pRdrFile->aPreps)) 547 return KLDR_ERR_TOO_MANY_MAPPINGS; 548 549 /* 550 * Calc the total mapping space needed. 551 */ 552 cbTotal = 0; 553 for (i = 0; i < cSegments; i++) 554 { 555 KLDRSIZE uRVASegmentEnd; 556 if (paSegments[i].RVA == NIL_KLDRADDR) 557 continue; 558 uRVASegmentEnd = paSegments[i].RVA + paSegments[i].cbMapped; 559 if (cbTotal < uRVASegmentEnd) 560 cbTotal = uRVASegmentEnd; 561 } 562 pPrep->cb = (size_t)cbTotal; 563 if (pPrep->cb != cbTotal) 564 return KLDR_ERR_ADDRESS_OVERFLOW; 565 pPrep->cb = (pPrep->cb + (cbPage - 1)) & ~(cbPage- 1); 566 567 #if defined(__WIN__) || defined(__NT__) 568 /* 569 * The NT memory mapped file API sucks in a lot of ways. Unless you're actually 570 * trying to map a PE image and the kernel can parse the file for it self, the 571 * API just isn't up to scratch. 572 * 573 * Problems: 574 * 1. Reserving memory for the views is risky because you can't reserve and 575 * map into the reserved space. So, other threads might grab the memory 576 * before we get to it. 577 * 2. The page aligning of file offsets makes it impossible to map most 578 * executable images since these are commonly sector aligned. 579 * 3. When mapping a read+execute file, its not possible to create section 580 * larger than the file since the section size is bound to the data file 581 * size. This wouldn't have been such a problem if it was possible to 582 * map views beyond the section restriction, i.e. have a file size and 583 * view size. 584 * 4. Only x86 can map views at page granularity it seems, and that only 585 * using an undocument flag. The default granularity is 64KB. 586 * 5. There is more crappyness here... 587 * 588 * So, first we'll have to check if we can the file using the crappy NT APIs. 589 * Chances are we can't. 590 */ 591 for (i = 0; i < cSegments; i++) 592 { 593 if (paSegments[i].RVA == NIL_KLDRADDR) 594 continue; 595 596 /* The file backing of the segments must be page aligned. */ 597 if ( paSegments[i].cbFile 598 && paSegments[i].offFile & (cbPage - 1)) 599 break; 600 601 /* Only page alignment gaps between the file size and the mapping size. */ 602 if ( paSegments[i].cbFile 603 && (paSegments[i].cbFile & ~(cbPage - 1)) != (paSegments[i].cbMapped & ~(cbPage - 1)) ) 604 break; 605 606 /* The mapping addresses of the segments must be page aligned. 607 * Non-x86 will probably require 64KB alignment here. */ 608 if (paSegments[i].RVA & (cbPage - 1)) 609 break; 610 611 /* If we do have to allocate the segment it's RVA must be 64KB aligned. */ 612 if ( !paSegments[i].cbFile 613 && (paSegments[i].RVA & 0xffff)) 614 break; 615 } 616 /** @todo if this is a PE image, we might just try a SEC_IMAGE mapping. It'll work if the host and image machines matches. */ 617 if (i == cSegments) 618 { 619 /* WOW! it may work out! Incredible! */ 620 SIZE_T ViewSize; 621 LARGE_INTEGER SectionOffset; 622 LARGE_INTEGER MaxiumSize; 623 NTSTATUS Status; 624 PVOID pv; 625 626 MaxiumSize.QuadPart = pRdr->pOps->pfnSize(pRdr); 627 if (MaxiumSize.QuadPart > (LONGLONG)cbTotal) 628 MaxiumSize.QuadPart = cbTotal; 629 630 Status = NtCreateSection(&pPrep->hSection, 631 SECTION_MAP_EXECUTE | SECTION_MAP_READ, /* desired access */ 632 NULL, /* object attributes */ 633 &MaxiumSize, 634 PAGE_EXECUTE_WRITECOPY, /* page attributes */ 635 SEC_COMMIT, /* section attributes */ 636 pRdrFile->File); 637 if (!NT_SUCCESS(Status)) 638 return (int)Status; 639 640 /* 641 * Determin the base address. 642 */ 643 if (fFixed) 644 pPrep->pv = *ppvBase; 645 else 646 { 647 pv = NULL; 648 ViewSize = (size_t)cbTotal; 649 650 Status = NtAllocateVirtualMemory(NtCurrentProcess(), 651 &pv, 652 0, /* ZeroBits */ 653 &ViewSize, 654 MEM_RESERVE, 655 PAGE_READONLY); 656 if (NT_SUCCESS(Status)) 657 { 658 pPrep->pv = *ppvBase = pv; 659 ViewSize = 0; 660 Status = NtFreeVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, MEM_RELEASE); 661 } 662 if (!NT_SUCCESS(Status)) 663 { 664 NtClose(pPrep->hSection); 665 return Status; 666 } 667 } 668 669 /* 670 * Map the segments. 671 */ 672 for (i = 0; i < cSegments; i++) 673 { 674 ULONG fPageProt; 675 676 if (paSegments[i].RVA == NIL_KLDRADDR) 677 continue; 678 679 pv = (uint8_t *)pPrep->pv + paSegments[i].RVA; 680 if (paSegments[i].cbFile) 681 { 682 SectionOffset.QuadPart = paSegments[i].offFile; 683 ViewSize = paSegments[i].cbFile; 684 fPageProt = kldrRdrFileGetNtMapProt(paSegments[i].enmProt); 685 // STATUS_MAPPED_ALIGNMENT 686 // STATUS_CONFLICTING_ADDRESSES 687 // STATUS_INVALID_VIEW_SIZE 688 Status = NtMapViewOfSection(pPrep->hSection, NtCurrentProcess(), 689 &pv, 690 0, /* ZeroBits */ 691 0, /* CommitSize */ 692 &SectionOffset, /* SectionOffset */ 693 &ViewSize, 694 ViewUnmap, 695 MEM_DOS_LIM, /* AllocationType */ 696 fPageProt); 697 /* do we have to zero anything? */ 698 if ( NT_SUCCESS(Status) 699 && 0/*later*/) 700 { 701 //ULONG OldPageProt = 0; 702 //NtProtectVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, , 703 } 704 } 705 else 706 { 707 ViewSize = paSegments[i].cbMapped; 708 fPageProt = kldrRdrFileGetNtAllocProt(paSegments[i].enmProt); 709 Status = NtAllocateVirtualMemory(NtCurrentProcess(), 710 &pv, 711 0, /* ZeroBits */ 712 &ViewSize, 713 MEM_COMMIT, 714 fPageProt); 715 } 716 if (!NT_SUCCESS(Status)) 717 break; 718 } 719 720 /* 721 * On success, commit the mapping and return. 722 */ 723 if (NT_SUCCESS(Status)) 724 { 725 pRdrFile->cPreps++; 726 return 0; 727 } 728 729 /* bail out and fall back on the generic code. */ 730 while (i-- > 0) 731 { 732 PVOID pv; 733 734 if (paSegments[i].RVA == NIL_KLDRADDR) 735 continue; 736 737 pv = (uint8_t *)pPrep->pv + paSegments[i].RVA; 738 if (paSegments[i].cbFile) 739 NtUnmapViewOfSection(NtCurrentProcess(), pv); 740 else 741 NtFreeVirtualMemory(NtCurrentProcess(), &pv, NULL, MEM_RELEASE); 742 } 743 NtClose(pPrep->hSection); 744 } 745 /* else: fall back to the generic code */ 746 pPrep->hSection = NULL; 747 #endif 748 749 /* 750 * Use the generic map emulation. 751 */ 752 pPrep->pv = fFixed ? *ppvBase : NULL; 753 rc = kldrRdrFileGenericMap(pRdr, pPrep, cSegments, paSegments, fFixed); 754 if (!rc) 755 { 756 *ppvBase = pPrep->pv; 757 pRdrFile->cPreps++; 758 } 759 760 return rc; 761 } 762 763 764 /** Generic implementation of kldrRdrFileMap. */ 765 static int kldrRdrFileGenericMap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed) 766 { 767 int rc; 768 uint32_t i; 769 770 /* 771 * Generic mapping code using kldrHlpPageAlloc(), kldrHlpPageFree() and kldrHlpPageProtect(). 772 */ 773 rc = kldrHlpPageAlloc(&pPrep->pv, pPrep->cb, KLDRPROT_EXECUTE_READWRITE, fFixed); 774 if (rc) 775 return rc; 776 777 /* 778 * Load the data. 779 */ 780 for (i = 0; i < cSegments; i++) 781 { 782 void *pv; 783 784 if ( paSegments[i].RVA == NIL_KLDRADDR 785 || !paSegments[i].cbFile) 786 continue; 787 788 pv = (uint8_t *)pPrep->pv + paSegments[i].RVA; 789 rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile); 790 if (rc) 791 break; 792 } 793 794 /* 795 * Set segment protection. 796 */ 797 if (!rc) 798 { 799 rc = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */); 800 if (!rc) 801 return 0; 802 kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */); 803 } 804 805 /* bailout */ 806 kldrHlpPageFree(pPrep->pv, pPrep->cb); 807 return rc; 268 808 } 269 809 … … 572 1112 SecAttr.lpSecurityDescriptor = NULL; 573 1113 SecAttr.nLength = 0; 574 File = CreateFile(pszFilename, GENERIC_READ , FILE_SHARE_READ, &SecAttr, OPEN_ALWAYS, 0, NULL);1114 File = CreateFile(pszFilename, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, &SecAttr, OPEN_ALWAYS, 0, NULL); 575 1115 if (File == INVALID_HANDLE_VALUE) 576 1116 return GetLastError();
Note:
See TracChangeset
for help on using the changeset viewer.