ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

image.c
Go to the documentation of this file.
00001 /* COPYRIGHT:       See COPYING in the top level directory
00002  * PROJECT:         ReactOS system libraries
00003  * FILE:            lib/rtl/image.c
00004  * PURPOSE:         Image handling functions
00005  *                  Relocate functions were previously located in
00006  *                  ntoskrnl/ldr/loader.c and
00007  *                  dll/ntdll/ldr/utils.c files
00008  * PROGRAMMER:      Eric Kohl + original authors from loader.c and utils.c file
00009  *                  Aleksey Bragin
00010  */
00011 
00012 /* INCLUDES *****************************************************************/
00013 
00014 #include <rtl.h>
00015 
00016 #define NDEBUG
00017 #include <debug.h>
00018 
00019 #define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m)))
00020 
00021 /* FUNCTIONS *****************************************************************/
00022 
00023 USHORT
00024 FORCEINLINE
00025 ChkSum(ULONG Sum, PUSHORT Src, ULONG Len)
00026 {
00027     ULONG i;
00028 
00029     for (i=0; i<Len; i++)
00030     {
00031         /* Sum up the current word */
00032         Sum += Src[i];
00033 
00034         /* Sum up everything above the low word as a carry */
00035         Sum = (Sum & 0xFFFF) + (Sum >> 16);
00036     }
00037 
00038     /* Apply carry one more time and clamp to the USHORT */
00039     return (Sum + (Sum >> 16)) & 0xFFFF;
00040 }
00041 
00042 BOOLEAN
00043 NTAPI
00044 LdrVerifyMappedImageMatchesChecksum(
00045     IN PVOID BaseAddress,
00046     IN SIZE_T ImageSize,
00047     IN ULONG FileLength)
00048 {
00049 #if 0
00050     PIMAGE_NT_HEADERS Header;
00051     PUSHORT Ptr;
00052     ULONG Sum;
00053     ULONG CalcSum;
00054     ULONG HeaderSum;
00055     ULONG i;
00056 
00057     // HACK: Ignore calls with ImageSize=0. Should be fixed by new MM.
00058     if (ImageSize == 0) return TRUE;
00059 
00060     /* Get NT header to check if it's an image at all */
00061     Header = RtlImageNtHeader(BaseAddress);
00062     if (!Header) return FALSE;
00063 
00064     /* Get checksum to match */
00065     HeaderSum = Header->OptionalHeader.CheckSum;
00066 
00067     /* Zero checksum seems to be accepted */
00068     if (HeaderSum == 0) return TRUE;
00069 
00070     /* Calculate the checksum */
00071     Sum = 0;
00072     Ptr = (PUSHORT) BaseAddress;
00073     for (i = 0; i < ImageSize / sizeof (USHORT); i++)
00074     {
00075         Sum += (ULONG)*Ptr;
00076         if (HIWORD(Sum) != 0)
00077         {
00078             Sum = LOWORD(Sum) + HIWORD(Sum);
00079         }
00080         Ptr++;
00081     }
00082 
00083     if (ImageSize & 1)
00084     {
00085         Sum += (ULONG)*((PUCHAR)Ptr);
00086         if (HIWORD(Sum) != 0)
00087         {
00088             Sum = LOWORD(Sum) + HIWORD(Sum);
00089         }
00090     }
00091 
00092     CalcSum = (USHORT)(LOWORD(Sum) + HIWORD(Sum));
00093 
00094     /* Subtract image checksum from calculated checksum. */
00095     /* fix low word of checksum */
00096     if (LOWORD(CalcSum) >= LOWORD(HeaderSum))
00097     {
00098         CalcSum -= LOWORD(HeaderSum);
00099     }
00100     else
00101     {
00102         CalcSum = ((LOWORD(CalcSum) - LOWORD(HeaderSum)) & 0xFFFF) - 1;
00103     }
00104 
00105     /* Fix high word of checksum */
00106     if (LOWORD(CalcSum) >= HIWORD(HeaderSum))
00107     {
00108         CalcSum -= HIWORD(HeaderSum);
00109     }
00110     else
00111     {
00112         CalcSum = ((LOWORD(CalcSum) - HIWORD(HeaderSum)) & 0xFFFF) - 1;
00113     }
00114 
00115     /* Add file length */
00116     CalcSum += ImageSize;
00117 
00118     if (CalcSum != HeaderSum)
00119         DPRINT1("Image %p checksum mismatches! 0x%x != 0x%x, ImageSize %x, FileLen %x\n", BaseAddress, CalcSum, HeaderSum, ImageSize, FileLength);
00120 
00121     return (BOOLEAN)(CalcSum == HeaderSum);
00122 #else
00123     /*
00124      * FIXME: Warning, this violates the PE standard and makes ReactOS drivers
00125      * and other system code when normally on Windows they would not, since
00126      * we do not write the checksum in them.
00127      * Our compilers should be made to write out the checksum and this function
00128      * should be enabled as to reject badly checksummed code.
00129      */
00130     return TRUE;
00131 #endif
00132 }
00133 
00134 /*
00135  * @implemented
00136  */
00137 NTSTATUS
00138 NTAPI
00139 RtlImageNtHeaderEx(IN ULONG Flags,
00140                    IN PVOID Base,
00141                    IN ULONG64 Size,
00142                    OUT PIMAGE_NT_HEADERS *OutHeaders)
00143 {
00144     PIMAGE_NT_HEADERS NtHeaders;
00145     PIMAGE_DOS_HEADER DosHeader;
00146     BOOLEAN WantsRangeCheck;
00147 
00148     /* You must want NT Headers, no? */
00149     if (!OutHeaders) return STATUS_INVALID_PARAMETER;
00150 
00151     /* Assume failure */
00152     *OutHeaders = NULL;
00153 
00154     /* Validate Flags */
00155     if (Flags &~ RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK)
00156     {
00157         DPRINT1("Invalid flag combination... check for new API flags?\n");
00158         return STATUS_INVALID_PARAMETER;
00159     }
00160 
00161     /* Validate base */
00162     if (!(Base) || (Base == (PVOID)-1)) return STATUS_INVALID_PARAMETER;
00163 
00164     /* Check if the caller wants validation */
00165     WantsRangeCheck = !(Flags & RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK);
00166     if (WantsRangeCheck)
00167     {
00168         /* Make sure the image size is at least big enough for the DOS header */
00169         if (Size < sizeof(IMAGE_DOS_HEADER))
00170         {
00171             DPRINT1("Size too small\n");
00172             return STATUS_INVALID_IMAGE_FORMAT;
00173         }
00174     }
00175 
00176     /* Check if the DOS Signature matches */
00177     DosHeader = Base;
00178     if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
00179     {
00180         /* Not a valid COFF */
00181         DPRINT1("Not an MZ file\n");
00182         return STATUS_INVALID_IMAGE_FORMAT;
00183     }
00184 
00185     /* Check if the caller wants validation */
00186     if (WantsRangeCheck)
00187     {
00188         /* The offset should fit in the passsed-in size */
00189         if (DosHeader->e_lfanew >= Size)
00190         {
00191             /* Fail */
00192             DPRINT1("e_lfanew is larger than PE file\n");
00193             return STATUS_INVALID_IMAGE_FORMAT;
00194         }
00195 
00196         /* It shouldn't be past 4GB either */
00197         if (DosHeader->e_lfanew >=
00198             (MAXULONG - sizeof(IMAGE_DOS_SIGNATURE) - sizeof(IMAGE_FILE_HEADER)))
00199         {
00200             /* Fail */
00201             DPRINT1("e_lfanew is larger than 4GB\n");
00202             return STATUS_INVALID_IMAGE_FORMAT;
00203         }
00204 
00205         /* And the whole file shouldn't overflow past 4GB */
00206         if ((DosHeader->e_lfanew +
00207             sizeof(IMAGE_DOS_SIGNATURE) - sizeof(IMAGE_FILE_HEADER)) >= Size)
00208         {
00209             /* Fail */
00210             DPRINT1("PE is larger than 4GB\n");
00211             return STATUS_INVALID_IMAGE_FORMAT;
00212         }
00213     }
00214 
00215     /* The offset also can't be larger than 256MB, as a hard-coded check */
00216     if (DosHeader->e_lfanew >= (256 * 1024 * 1024))
00217     {
00218         /* Fail */
00219         DPRINT1("PE offset is larger than 256MB\n");
00220         return STATUS_INVALID_IMAGE_FORMAT;
00221     }
00222 
00223     /* Now it's safe to get the NT Headers */
00224     NtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)Base + DosHeader->e_lfanew);
00225 
00226     /* Verify the PE Signature */
00227     if (NtHeaders->Signature != IMAGE_NT_SIGNATURE)
00228     {
00229         /* Fail */
00230         DPRINT1("PE signature missing\n");
00231         return STATUS_INVALID_IMAGE_FORMAT;
00232     }
00233 
00234     /* Now return success and the NT header */
00235     *OutHeaders = NtHeaders;
00236     return STATUS_SUCCESS;
00237 }
00238 
00239 /*
00240  * @implemented
00241  */
00242 PIMAGE_NT_HEADERS
00243 NTAPI
00244 RtlImageNtHeader(IN PVOID Base)
00245 {
00246     PIMAGE_NT_HEADERS NtHeader;
00247 
00248     /* Call the new API */
00249     RtlImageNtHeaderEx(RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK,
00250                        Base,
00251                        0,
00252                        &NtHeader);
00253     return NtHeader;
00254 }
00255 
00256 /*
00257  * @implemented
00258  */
00259 PVOID
00260 NTAPI
00261 RtlImageDirectoryEntryToData(
00262     PVOID BaseAddress,
00263     BOOLEAN MappedAsImage,
00264     USHORT Directory,
00265     PULONG Size)
00266 {
00267     PIMAGE_NT_HEADERS NtHeader;
00268     ULONG Va;
00269 
00270     /* Magic flag for non-mapped images. */
00271     if ((ULONG_PTR)BaseAddress & 1)
00272     {
00273         BaseAddress = (PVOID)((ULONG_PTR)BaseAddress & ~1);
00274         MappedAsImage = FALSE;
00275     }
00276 
00277 
00278     NtHeader = RtlImageNtHeader (BaseAddress);
00279     if (NtHeader == NULL)
00280         return NULL;
00281 
00282     if (Directory >= SWAPD(NtHeader->OptionalHeader.NumberOfRvaAndSizes))
00283         return NULL;
00284 
00285     Va = SWAPD(NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress);
00286     if (Va == 0)
00287         return NULL;
00288 
00289     *Size = SWAPD(NtHeader->OptionalHeader.DataDirectory[Directory].Size);
00290 
00291     if (MappedAsImage || Va < SWAPD(NtHeader->OptionalHeader.SizeOfHeaders))
00292         return (PVOID)((ULONG_PTR)BaseAddress + Va);
00293 
00294     /* image mapped as ordinary file, we must find raw pointer */
00295     return RtlImageRvaToVa (NtHeader, BaseAddress, Va, NULL);
00296 }
00297 
00298 
00299 /*
00300  * @implemented
00301  */
00302 PIMAGE_SECTION_HEADER
00303 NTAPI
00304 RtlImageRvaToSection(
00305     PIMAGE_NT_HEADERS NtHeader,
00306     PVOID BaseAddress,
00307     ULONG Rva)
00308 {
00309     PIMAGE_SECTION_HEADER Section;
00310     ULONG Va;
00311     ULONG Count;
00312 
00313     Count = SWAPW(NtHeader->FileHeader.NumberOfSections);
00314     Section = IMAGE_FIRST_SECTION(NtHeader);
00315 
00316     while (Count--)
00317     {
00318         Va = SWAPD(Section->VirtualAddress);
00319         if ((Va <= Rva) &&
00320                 (Rva < Va + SWAPD(Section->Misc.VirtualSize)))
00321             return Section;
00322         Section++;
00323     }
00324     return NULL;
00325 }
00326 
00327 
00328 /*
00329  * @implemented
00330  */
00331 PVOID
00332 NTAPI
00333 RtlImageRvaToVa(
00334     PIMAGE_NT_HEADERS NtHeader,
00335     PVOID BaseAddress,
00336     ULONG Rva,
00337     PIMAGE_SECTION_HEADER *SectionHeader)
00338 {
00339     PIMAGE_SECTION_HEADER Section = NULL;
00340 
00341     if (SectionHeader)
00342         Section = *SectionHeader;
00343 
00344     if (Section == NULL ||
00345             Rva < SWAPD(Section->VirtualAddress) ||
00346             Rva >= SWAPD(Section->VirtualAddress) + SWAPD(Section->Misc.VirtualSize))
00347     {
00348         Section = RtlImageRvaToSection (NtHeader, BaseAddress, Rva);
00349         if (Section == NULL)
00350             return 0;
00351 
00352         if (SectionHeader)
00353             *SectionHeader = Section;
00354     }
00355 
00356     return (PVOID)((ULONG_PTR)BaseAddress +
00357                    Rva +
00358                    SWAPD(Section->PointerToRawData) -
00359                    (ULONG_PTR)SWAPD(Section->VirtualAddress));
00360 }
00361 
00362 PIMAGE_BASE_RELOCATION
00363 NTAPI
00364 LdrProcessRelocationBlockLongLong(
00365     IN ULONG_PTR Address,
00366     IN ULONG Count,
00367     IN PUSHORT TypeOffset,
00368     IN LONGLONG Delta)
00369 {
00370     SHORT Offset;
00371     USHORT Type;
00372     ULONG i;
00373     PUSHORT ShortPtr;
00374     PULONG LongPtr;
00375     PULONGLONG LongLongPtr;
00376 
00377     for (i = 0; i < Count; i++)
00378     {
00379         Offset = SWAPW(*TypeOffset) & 0xFFF;
00380         Type = SWAPW(*TypeOffset) >> 12;
00381         ShortPtr = (PUSHORT)(RVA(Address, Offset));
00382         /*
00383         * Don't relocate within the relocation section itself.
00384         * GCC/LD generates sometimes relocation records for the relocation section.
00385         * This is a bug in GCC/LD.
00386         * Fix for it disabled, since it was only in ntoskrnl and not in ntdll
00387         */
00388         /*
00389         if ((ULONG_PTR)ShortPtr < (ULONG_PTR)RelocationDir ||
00390         (ULONG_PTR)ShortPtr >= (ULONG_PTR)RelocationEnd)
00391         {*/
00392         switch (Type)
00393         {
00394             /* case IMAGE_REL_BASED_SECTION : */
00395             /* case IMAGE_REL_BASED_REL32 : */
00396         case IMAGE_REL_BASED_ABSOLUTE:
00397             break;
00398 
00399         case IMAGE_REL_BASED_HIGH:
00400             *ShortPtr = HIWORD(MAKELONG(0, *ShortPtr) + (Delta & 0xFFFFFFFF));
00401             break;
00402 
00403         case IMAGE_REL_BASED_LOW:
00404             *ShortPtr = SWAPW(*ShortPtr) + LOWORD(Delta & 0xFFFF);
00405             break;
00406 
00407         case IMAGE_REL_BASED_HIGHLOW:
00408             LongPtr = (PULONG)RVA(Address, Offset);
00409             *LongPtr = SWAPD(*LongPtr) + (Delta & 0xFFFFFFFF);
00410             break;
00411 
00412         case IMAGE_REL_BASED_DIR64:
00413             LongLongPtr = (PUINT64)RVA(Address, Offset);
00414             *LongLongPtr = SWAPQ(*LongLongPtr) + Delta;
00415             break;
00416 
00417         case IMAGE_REL_BASED_HIGHADJ:
00418         case IMAGE_REL_BASED_MIPS_JMPADDR:
00419         default:
00420             DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
00421             DPRINT1("Address %x, Current %d, Count %d, *TypeOffset %x\n", Address, i, Count, SWAPW(*TypeOffset));
00422             return (PIMAGE_BASE_RELOCATION)NULL;
00423         }
00424 
00425         TypeOffset++;
00426     }
00427 
00428     return (PIMAGE_BASE_RELOCATION)TypeOffset;
00429 }
00430 
00431 ULONG
00432 NTAPI
00433 LdrRelocateImageWithBias(
00434     IN PVOID BaseAddress,
00435     IN LONGLONG AdditionalBias,
00436     IN PCCH  LoaderName,
00437     IN ULONG Success,
00438     IN ULONG Conflict,
00439     IN ULONG Invalid)
00440 {
00441     PIMAGE_NT_HEADERS NtHeaders;
00442     PIMAGE_DATA_DIRECTORY RelocationDDir;
00443     PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
00444     ULONG Count;
00445     ULONG_PTR Address;
00446     PUSHORT TypeOffset;
00447     LONGLONG Delta;
00448 
00449     NtHeaders = RtlImageNtHeader(BaseAddress);
00450 
00451     if (NtHeaders == NULL)
00452         return Invalid;
00453 
00454     if (SWAPW(NtHeaders->FileHeader.Characteristics) & IMAGE_FILE_RELOCS_STRIPPED)
00455     {
00456         return Conflict;
00457     }
00458 
00459     RelocationDDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
00460 
00461     if (SWAPD(RelocationDDir->VirtualAddress) == 0 || SWAPD(RelocationDDir->Size) == 0)
00462     {
00463         return Success;
00464     }
00465 
00466     Delta = (ULONG_PTR)BaseAddress - SWAPD(NtHeaders->OptionalHeader.ImageBase) + AdditionalBias;
00467     RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)BaseAddress + SWAPD(RelocationDDir->VirtualAddress));
00468     RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + SWAPD(RelocationDDir->Size));
00469 
00470     while (RelocationDir < RelocationEnd &&
00471             SWAPW(RelocationDir->SizeOfBlock) > 0)
00472     {
00473         Count = (SWAPW(RelocationDir->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
00474         Address = (ULONG_PTR)RVA(BaseAddress, SWAPD(RelocationDir->VirtualAddress));
00475         TypeOffset = (PUSHORT)(RelocationDir + 1);
00476 
00477         RelocationDir = LdrProcessRelocationBlockLongLong(Address,
00478                         Count,
00479                         TypeOffset,
00480                         Delta);
00481 
00482         if (RelocationDir == NULL)
00483         {
00484             DPRINT1("Error during call to LdrProcessRelocationBlockLongLong()!\n");
00485             return Invalid;
00486         }
00487     }
00488 
00489     return Success;
00490 }
00491 
00492 /* EOF */

Generated on Sat May 26 2012 04:19:06 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.