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 |