Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenimage.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
1.7.6.1
|