| OLD | NEW |
| (Empty) |
| 1 /*** | |
| 2 *pesect.c - PE image header routines | |
| 3 * | |
| 4 * Copyright (c) Microsoft Corporation. All rights reserved. | |
| 5 * | |
| 6 *Purpose: | |
| 7 * Defines routines that query info from a PE image header. Because | |
| 8 * one of these queries the current PE image, via the linker-defined | |
| 9 * variable __ImageBase, this object must be a static-link component | |
| 10 * of any C Runtime library. | |
| 11 * | |
| 12 *******************************************************************************/ | |
| 13 | |
| 14 #include <windows.h> | |
| 15 | |
| 16 #if defined (_WIN64) && defined (_M_IA64) | |
| 17 #pragma section(".base", long, read) | |
| 18 __declspec(allocate(".base")) | |
| 19 extern IMAGE_DOS_HEADER __ImageBase; | |
| 20 #else /* defined (_WIN64) && defined (_M_IA64) */ | |
| 21 extern IMAGE_DOS_HEADER __ImageBase; | |
| 22 #endif /* defined (_WIN64) && defined (_M_IA64) */ | |
| 23 | |
| 24 #pragma optimize("t", on) // optimize for speed, not space | |
| 25 | |
| 26 /*** | |
| 27 *BOOL _ValidateImageBase | |
| 28 * | |
| 29 *Purpose: | |
| 30 * Check if a PE image is located at a potential image base address. | |
| 31 * | |
| 32 *Entry: | |
| 33 * pImageBase - pointer to potential PE image in memory | |
| 34 * | |
| 35 *Return: | |
| 36 * TRUE PE image validated at pImageBase | |
| 37 * FALSE PE image not found | |
| 38 * | |
| 39 *******************************************************************************/ | |
| 40 | |
| 41 BOOL __cdecl _ValidateImageBase( | |
| 42 PBYTE pImageBase | |
| 43 ) | |
| 44 { | |
| 45 PIMAGE_DOS_HEADER pDOSHeader; | |
| 46 PIMAGE_NT_HEADERS pNTHeader; | |
| 47 PIMAGE_OPTIONAL_HEADER pOptHeader; | |
| 48 | |
| 49 pDOSHeader = (PIMAGE_DOS_HEADER)pImageBase; | |
| 50 if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) | |
| 51 { | |
| 52 return FALSE; | |
| 53 } | |
| 54 | |
| 55 pNTHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDOSHeader + pDOSHeader->e_lfanew); | |
| 56 if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) | |
| 57 { | |
| 58 return FALSE; | |
| 59 } | |
| 60 | |
| 61 pOptHeader = (PIMAGE_OPTIONAL_HEADER)&pNTHeader->OptionalHeader; | |
| 62 if (pOptHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) | |
| 63 { | |
| 64 return FALSE; | |
| 65 } | |
| 66 | |
| 67 return TRUE; | |
| 68 } | |
| 69 | |
| 70 /*** | |
| 71 *PIMAGE_SECTION_HEADER _FindPESection | |
| 72 * | |
| 73 *Purpose: | |
| 74 * Given an RVA (Relative Virtual Address, the offset from the Image Base | |
| 75 * for a PE image), determine which PE section, if any, includes that RVA. | |
| 76 * | |
| 77 *Entry: | |
| 78 * pImageBase - pointer to PE image in memory | |
| 79 * rva - RVA whose enclosing section is to be found | |
| 80 * | |
| 81 *Return: | |
| 82 * NULL RVA is not part by any section in the PE image | |
| 83 * non-NULL Pointer to IMAGE_SECTION_HEADER describing the section holding | |
| 84 * the RVA | |
| 85 * | |
| 86 *******************************************************************************/ | |
| 87 | |
| 88 PIMAGE_SECTION_HEADER __cdecl _FindPESection( | |
| 89 PBYTE pImageBase, | |
| 90 DWORD_PTR rva | |
| 91 ) | |
| 92 { | |
| 93 PIMAGE_NT_HEADERS pNTHeader; | |
| 94 PIMAGE_SECTION_HEADER pSection; | |
| 95 unsigned int iSection; | |
| 96 | |
| 97 pNTHeader = | |
| 98 (PIMAGE_NT_HEADERS) | |
| 99 (pImageBase + ((PIMAGE_DOS_HEADER)pImageBase)->e_lfanew); | |
| 100 | |
| 101 // | |
| 102 // Find the section holding the desired address. We make no assumptions | |
| 103 // here about the sort order of the section descriptors (though they | |
| 104 // always appear to be sorted by ascending section RVA). | |
| 105 // | |
| 106 for (iSection = 0, pSection = IMAGE_FIRST_SECTION(pNTHeader); | |
| 107 iSection < pNTHeader->FileHeader.NumberOfSections; | |
| 108 ++iSection, ++pSection) | |
| 109 { | |
| 110 if (rva >= pSection->VirtualAddress && | |
| 111 rva < pSection->VirtualAddress + pSection->Misc.VirtualSize) | |
| 112 { | |
| 113 // | |
| 114 // Section found | |
| 115 // | |
| 116 return pSection; | |
| 117 } | |
| 118 } | |
| 119 | |
| 120 // | |
| 121 // Section not found | |
| 122 // | |
| 123 return NULL; | |
| 124 } | |
| 125 | |
| 126 /*** | |
| 127 *BOOL _IsNonwritableInCurrentImage | |
| 128 * | |
| 129 *Purpose: | |
| 130 * Check if an address is located within the current PE image (the one | |
| 131 * starting at __ImageBase), that it is in a proper section of the image, | |
| 132 * and that section is not marked writable. This routine must be | |
| 133 * statically linked, not imported from the CRT DLL, so the correct | |
| 134 * __ImageBase is found. | |
| 135 * | |
| 136 *Entry: | |
| 137 * pTarget - address to check | |
| 138 * | |
| 139 *Return: | |
| 140 * 0 Address is either not in current image, not in a section, or | |
| 141 * in a writable section. | |
| 142 * non-0 Address is in a non-writable section of the current image. | |
| 143 * | |
| 144 *******************************************************************************/ | |
| 145 | |
| 146 BOOL __cdecl _IsNonwritableInCurrentImage( | |
| 147 PBYTE pTarget | |
| 148 ) | |
| 149 { | |
| 150 PBYTE pImageBase; | |
| 151 DWORD_PTR rvaTarget; | |
| 152 PIMAGE_SECTION_HEADER pSection; | |
| 153 | |
| 154 pImageBase = (PBYTE)&__ImageBase; | |
| 155 | |
| 156 __try { | |
| 157 // | |
| 158 // Make sure __ImageBase does address a PE image. This is likely an | |
| 159 // unnecessary check, since we should be running from a normal image, | |
| 160 // but it is fast, this routine is rarely called, and the normal call | |
| 161 // is for security purposes. If we don't have a PE image, return | |
| 162 // failure. | |
| 163 // | |
| 164 if (!_ValidateImageBase(pImageBase)) | |
| 165 { | |
| 166 return FALSE; | |
| 167 } | |
| 168 | |
| 169 // | |
| 170 // Convert the targetaddress to a Relative Virtual Address (RVA) within | |
| 171 // the image, and find the corresponding PE section. Return failure if | |
| 172 // the target address is not found within the current image. | |
| 173 // | |
| 174 rvaTarget = pTarget - pImageBase; | |
| 175 pSection = _FindPESection(pImageBase, rvaTarget); | |
| 176 if (pSection == NULL) | |
| 177 { | |
| 178 return FALSE; | |
| 179 } | |
| 180 | |
| 181 // | |
| 182 // Check the section characteristics to see if the target address is | |
| 183 // located within a writable section, returning a failure if yes. | |
| 184 // | |
| 185 return (pSection->Characteristics & IMAGE_SCN_MEM_WRITE) == 0; | |
| 186 } | |
| 187 __except (GetExceptionCode() == STATUS_ACCESS_VIOLATION) | |
| 188 { | |
| 189 // | |
| 190 // Just return failure if the PE image is corrupted in any way that | |
| 191 // triggers an AV. | |
| 192 // | |
| 193 return FALSE; | |
| 194 } | |
| 195 } | |
| OLD | NEW |