Initial Commit
[libctiny.git] / pesect.c
blobe331ea84fbd188e6d9734a3a2cf7b2bf81bba5a9
1 /***
2 *pesect.c - PE image header routines
4 * Copyright (c) Microsoft Corporation. All rights reserved.
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.
12 *******************************************************************************/
14 #include <windows.h>
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) */
24 #pragma optimize("t", on) // optimize for speed, not space
26 /***
27 *BOOL _ValidateImageBase
29 *Purpose:
30 * Check if a PE image is located at a potential image base address.
32 *Entry:
33 * pImageBase - pointer to potential PE image in memory
35 *Return:
36 * TRUE PE image validated at pImageBase
37 * FALSE PE image not found
39 *******************************************************************************/
41 BOOL __cdecl _ValidateImageBase(
42 PBYTE pImageBase
45 PIMAGE_DOS_HEADER pDOSHeader;
46 PIMAGE_NT_HEADERS pNTHeader;
47 PIMAGE_OPTIONAL_HEADER pOptHeader;
49 pDOSHeader = (PIMAGE_DOS_HEADER)pImageBase;
50 if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
52 return FALSE;
55 pNTHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDOSHeader + pDOSHeader->e_lfanew);
56 if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
58 return FALSE;
61 pOptHeader = (PIMAGE_OPTIONAL_HEADER)&pNTHeader->OptionalHeader;
62 if (pOptHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
64 return FALSE;
67 return TRUE;
70 /***
71 *PIMAGE_SECTION_HEADER _FindPESection
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.
77 *Entry:
78 * pImageBase - pointer to PE image in memory
79 * rva - RVA whose enclosing section is to be found
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
86 *******************************************************************************/
88 PIMAGE_SECTION_HEADER __cdecl _FindPESection(
89 PBYTE pImageBase,
90 DWORD_PTR rva
93 PIMAGE_NT_HEADERS pNTHeader;
94 PIMAGE_SECTION_HEADER pSection;
95 unsigned int iSection;
97 pNTHeader =
98 (PIMAGE_NT_HEADERS)
99 (pImageBase + ((PIMAGE_DOS_HEADER)pImageBase)->e_lfanew);
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).
106 for (iSection = 0, pSection = IMAGE_FIRST_SECTION(pNTHeader);
107 iSection < pNTHeader->FileHeader.NumberOfSections;
108 ++iSection, ++pSection)
110 if (rva >= pSection->VirtualAddress &&
111 rva < pSection->VirtualAddress + pSection->Misc.VirtualSize)
114 // Section found
116 return pSection;
121 // Section not found
123 return NULL;
126 /***
127 *BOOL _IsNonwritableInCurrentImage
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.
136 *Entry:
137 * pTarget - address to check
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.
144 *******************************************************************************/
146 BOOL __cdecl _IsNonwritableInCurrentImage(
147 PBYTE pTarget
150 PBYTE pImageBase;
151 DWORD_PTR rvaTarget;
152 PIMAGE_SECTION_HEADER pSection;
154 pImageBase = (PBYTE)&__ImageBase;
156 __try {
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.
164 if (!_ValidateImageBase(pImageBase))
166 return FALSE;
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.
174 rvaTarget = pTarget - pImageBase;
175 pSection = _FindPESection(pImageBase, rvaTarget);
176 if (pSection == NULL)
178 return FALSE;
182 // Check the section characteristics to see if the target address is
183 // located within a writable section, returning a failure if yes.
185 return (pSection->Characteristics & IMAGE_SCN_MEM_WRITE) == 0;
187 __except (GetExceptionCode() == STATUS_ACCESS_VIOLATION)
190 // Just return failure if the PE image is corrupted in any way that
191 // triggers an AV.
193 return FALSE;