| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | #ifndef PEWriter_H |
| 5 | #define PEWriter_H |
| 6 | |
| 7 | #include <crtwrap.h> |
| 8 | |
| 9 | #include <windows.h> |
| 10 | |
| 11 | #include "ceegen.h" |
| 12 | |
| 13 | #include "pesectionman.h" |
| 14 | |
| 15 | class PEWriter; |
| 16 | class PEWriterSection; |
| 17 | class PEDecoder; |
| 18 | struct entry; |
| 19 | struct ; |
| 20 | |
| 21 | #define SUBSECTION_ALIGN 16 |
| 22 | |
| 23 | /***************************************************************/ |
| 24 | // PEWriter is derived from PESectionManager. While the base class just |
| 25 | // manages the sections, PEWriter can actually write them out. |
| 26 | |
| 27 | class PEWriter : public PESectionMan |
| 28 | { |
| 29 | public: |
| 30 | |
| 31 | // See ICeeFileGen.h for definition of createFlags |
| 32 | HRESULT Init(PESectionMan *pFrom, DWORD createFlags, LPCWSTR seedFileName = NULL); |
| 33 | HRESULT Cleanup(); |
| 34 | |
| 35 | // Finds section with given name. returns 0 if not found |
| 36 | virtual PESection* getSection(const char* name); |
| 37 | |
| 38 | // Create a new section |
| 39 | virtual HRESULT newSection(const char* name, PESection **section, |
| 40 | unsigned flags=sdNone, unsigned estSize=0x10000, |
| 41 | unsigned estRelocs=0x100); |
| 42 | |
| 43 | HRESULT link(); |
| 44 | HRESULT fixup(CeeGenTokenMapper *pMapper); |
| 45 | HRESULT write(__in LPCWSTR fileName); |
| 46 | HRESULT write(void **ppImage); |
| 47 | |
| 48 | // calling these functions is optional |
| 49 | DWORD getSectionAlignment(); |
| 50 | void setSectionAlignment(DWORD); |
| 51 | DWORD getFileAlignment(); |
| 52 | void setFileAlignment(DWORD); |
| 53 | DWORD getImageBase32(); |
| 54 | void setImageBase32(DWORD); |
| 55 | UINT64 getImageBase64(); |
| 56 | void setImageBase64(UINT64); |
| 57 | void stripRelocations(bool val); // default = false |
| 58 | |
| 59 | void (PIMAGE_NT_HEADERS *, PIMAGE_SECTION_HEADER *ppSections, ULONG *pNumSections); |
| 60 | |
| 61 | // these affect the charactertics in the NT file header |
| 62 | void setCharacteristics(unsigned mask); |
| 63 | void clearCharacteristics(unsigned mask); |
| 64 | |
| 65 | // these affect the charactertics in the NT optional header |
| 66 | void setDllCharacteristics(unsigned mask); |
| 67 | void clearDllCharacteristics(unsigned mask); |
| 68 | |
| 69 | // sets the SubSystem field in the optional header |
| 70 | void setSubsystem(unsigned subsystem, unsigned major, unsigned minor); |
| 71 | |
| 72 | // specify the entry point as an offset into the text section. The |
| 73 | // method will convert into an RVA from the base |
| 74 | void setEntryPointTextOffset(unsigned entryPoint); |
| 75 | |
| 76 | HRESULT setDirectoryEntry(PEWriterSection *section, ULONG entry, ULONG size, ULONG offset=0); |
| 77 | |
| 78 | |
| 79 | // get the RVA for the IL section |
| 80 | ULONG getIlRva(); |
| 81 | |
| 82 | // set the RVA for the IL section by supplying offset to the IL section |
| 83 | void setIlRva(DWORD offset); |
| 84 | |
| 85 | unsigned getSubsystem(); |
| 86 | |
| 87 | size_t getImageBase(); |
| 88 | |
| 89 | void setEnCRvaBase(ULONG dataBase, ULONG rdataBase); |
| 90 | |
| 91 | HRESULT getFileTimeStamp(DWORD *pTimeStamp); |
| 92 | |
| 93 | IMAGE_NT_HEADERS32* () { return (IMAGE_NT_HEADERS32*) m_ntHeaders; } |
| 94 | IMAGE_NT_HEADERS64* () { return (IMAGE_NT_HEADERS64*) m_ntHeaders; } |
| 95 | |
| 96 | bool isPE32() // true -> created a PE 32-bit PE file |
| 97 | // false -> created a PE+ 64-bit PE file |
| 98 | { return (m_ntHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC)); } |
| 99 | |
| 100 | bool isI386() // true -> target machine is i386 |
| 101 | { return (m_ntHeaders->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_I386)); } |
| 102 | |
| 103 | bool isIA64() // true -> target machine is ia64 |
| 104 | { return (m_ntHeaders->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_IA64)); } |
| 105 | |
| 106 | bool isAMD64() // true -> target machine is ia64 |
| 107 | { return (m_ntHeaders->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_AMD64)); } |
| 108 | |
| 109 | bool isARM() // true -> target machine is ARM |
| 110 | { return (m_ntHeaders->FileHeader.Machine == VAL16(IMAGE_FILE_MACHINE_ARMNT)); } |
| 111 | |
| 112 | bool createCorMainStub() // do we need the CorExeMain/CorDllMain stubs? |
| 113 | { return m_createCorMainStub; } |
| 114 | |
| 115 | private: |
| 116 | DWORD m_ilRVA; |
| 117 | BOOL m_encMode; |
| 118 | ULONG m_dataRvaBase; |
| 119 | ULONG m_rdataRvaBase; |
| 120 | ULONG m_codeRvaBase; |
| 121 | DWORD m_peFileTimeStamp; |
| 122 | |
| 123 | HANDLE m_file; |
| 124 | |
| 125 | // "Seed" file information. The new file data will be "appended" to the seed file |
| 126 | // These are valid only if m_hSeedFile is valid |
| 127 | |
| 128 | HANDLE m_hSeedFile; |
| 129 | HANDLE m_hSeedFileMap; |
| 130 | PEDecoder * m_pSeedFileDecoder; |
| 131 | IMAGE_NT_HEADERS * ; |
| 132 | unsigned m_iSeedSections; |
| 133 | IMAGE_SECTION_HEADER*m_pSeedSections; |
| 134 | IMAGE_SECTION_HEADER*m_pSeedSectionToAdd; // used only by newSection() |
| 135 | |
| 136 | PEWriterSection **getSectStart() { |
| 137 | return (PEWriterSection**)sectStart; |
| 138 | } |
| 139 | |
| 140 | PEWriterSection **getSectCur() { |
| 141 | return (PEWriterSection**)sectCur; |
| 142 | } |
| 143 | |
| 144 | COUNT_T getSectCount() { |
| 145 | return COUNT_T(sectCur - sectStart); |
| 146 | } |
| 147 | |
| 148 | |
| 149 | IMAGE_DOS_HEADER ; |
| 150 | IMAGE_NT_HEADERS * ; |
| 151 | DWORD ; // Size of IMAGE_NT_HEADERS (not including section headers) |
| 152 | |
| 153 | unsigned virtualPos; |
| 154 | unsigned filePos; |
| 155 | |
| 156 | PEWriterSection * reloc; |
| 157 | PEWriterSection * strtab; |
| 158 | |
| 159 | IMAGE_SECTION_HEADER *, *; |
| 160 | |
| 161 | struct directoryEntry { |
| 162 | PEWriterSection *section; |
| 163 | ULONG offset; |
| 164 | ULONG size; |
| 165 | }; |
| 166 | |
| 167 | // Directory entries in the file header |
| 168 | directoryEntry * pEntries; |
| 169 | USHORT cEntries; |
| 170 | |
| 171 | bool m_createCorMainStub; |
| 172 | |
| 173 | // Helpers for link() |
| 174 | HRESULT linkSortSections(entry * entries, |
| 175 | unsigned * piEntries, // OUT |
| 176 | unsigned * piUniqueSections); // OUT |
| 177 | HRESULT (entry * entries, unsigned iEntries, unsigned iUniqueSections); |
| 178 | HRESULT linkPlaceSections(entry * entries, unsigned iEntries); |
| 179 | void (IMAGE_SECTION_HEADER * h, unsigned sectionIndex); |
| 180 | |
| 181 | HRESULT Open(__in LPCWSTR fileName); |
| 182 | HRESULT Write(const void *data, int size); |
| 183 | HRESULT Seek(int offset); |
| 184 | HRESULT Pad(int align); |
| 185 | HRESULT Close(); |
| 186 | }; |
| 187 | |
| 188 | // This class encapsulates emitting the base relocs into the |
| 189 | // .reloc section of the PE file, for the case where the image |
| 190 | // does not get loaded at its preferred base address. |
| 191 | |
| 192 | class PERelocSection |
| 193 | { |
| 194 | private: |
| 195 | PEWriterSection * section; |
| 196 | unsigned relocPage; |
| 197 | unsigned relocSize; |
| 198 | DWORD * relocSizeAddr; |
| 199 | unsigned pages; |
| 200 | |
| 201 | #ifdef _DEBUG |
| 202 | unsigned lastRVA; |
| 203 | #endif |
| 204 | |
| 205 | public: |
| 206 | PERelocSection(PEWriterSection *pBaseReloc); |
| 207 | void AddBaseReloc(unsigned rva, int type, unsigned short highAdj=0); |
| 208 | void Finish(bool isPE32); |
| 209 | }; |
| 210 | |
| 211 | class PEWriterSection : public PESection { |
| 212 | |
| 213 | public: |
| 214 | |
| 215 | PEWriterSection(const char* name, unsigned flags, |
| 216 | unsigned estSize, unsigned estRelocs) |
| 217 | : PESection(name, flags, estSize, estRelocs) {} |
| 218 | |
| 219 | virtual HRESULT (IMAGE_NT_HEADERS * , |
| 220 | PERelocSection * relocSection, |
| 221 | CeeGenTokenMapper * pTokenMapper, |
| 222 | DWORD rdataRvaBase, |
| 223 | DWORD dataRvaBase, |
| 224 | DWORD textRvaBase); |
| 225 | |
| 226 | virtual HRESULT write (HANDLE file); |
| 227 | virtual unsigned writeMem (void ** pMem); |
| 228 | virtual bool isSeedSection() { return false; } |
| 229 | |
| 230 | }; |
| 231 | |
| 232 | // This is for sections from the seed file. Their order needs to be maintained and |
| 233 | // they need to be written to the output file. |
| 234 | |
| 235 | class PESeedSection : public PEWriterSection { |
| 236 | |
| 237 | public: |
| 238 | |
| 239 | (PEDecoder * peDecoder, IMAGE_SECTION_HEADER * seedSection); |
| 240 | |
| 241 | // PESection methods |
| 242 | |
| 243 | unsigned dataLen() { return m_pSeedSectionHeader->SizeOfRawData; } |
| 244 | HRESULT applyRelocs(CeeGenTokenMapper *pTokenMapper) { return S_OK; } |
| 245 | char* getBlock(unsigned len, unsigned align) { _ASSERTE(!"PESeedSection" ); return NULL; } |
| 246 | HRESULT truncate(unsigned newLen) { _ASSERTE(!"PESeedSection" ); return E_FAIL; } |
| 247 | void (unsigned val, CeeSection& relativeTo, |
| 248 | CeeSectionRelocType reloc, |
| 249 | CeeSectionRelocExtra *) { _ASSERTE(!"PESeedSection" ); return; } |
| 250 | HRESULT (unsigned offset, CeeSection& relativeTo, |
| 251 | CeeSectionRelocType reloc, |
| 252 | CeeSectionRelocExtra *) { _ASSERTE(!"PESeedSection" ); return E_FAIL; } |
| 253 | HRESULT (unsigned offset, PESection *relativeTo, |
| 254 | CeeSectionRelocType reloc, |
| 255 | CeeSectionRelocExtra *) { _ASSERTE(!"PESeedSection" ); return E_FAIL; } |
| 256 | HRESULT (unsigned offset, CeeSectionRelocType reloc, |
| 257 | CeeSectionRelocExtra *) { _ASSERTE(!"PESeedSection" ); return E_FAIL; } |
| 258 | // unsigned char *name(); |
| 259 | // unsigned flags(); |
| 260 | // unsigned getBaseRVA(); |
| 261 | int getDirEntry() { _ASSERTE(!"PESeedSection" ); return 0; } |
| 262 | HRESULT directoryEntry(unsigned num) { _ASSERTE(!"PESeedSection" ); return E_FAIL; } |
| 263 | char * computePointer(unsigned offset) const { _ASSERTE(!"PESeedSection" ); return NULL; } |
| 264 | BOOL containsPointer(__in char *ptr) const { _ASSERTE(!"PESeedSection" ); return FALSE; } |
| 265 | unsigned computeOffset(__in char *ptr) const { _ASSERTE(!"PESeedSection" ); return 0; } |
| 266 | HRESULT cloneInstance(PESection *destination) { _ASSERTE(!"PESeedSection" ); return E_FAIL; } |
| 267 | |
| 268 | // PEWriterSection |
| 269 | |
| 270 | HRESULT (IMAGE_NT_HEADERS * , |
| 271 | PERelocSection * relocSection, |
| 272 | CeeGenTokenMapper * pTokenMapper, |
| 273 | DWORD rdataRvaBase, |
| 274 | DWORD dataRvaBase, |
| 275 | DWORD textRvaBase) { return S_OK; } |
| 276 | |
| 277 | HRESULT write(HANDLE file); |
| 278 | unsigned writeMem(void ** pMem); |
| 279 | bool isSeedSection() { return true; } |
| 280 | |
| 281 | protected: |
| 282 | |
| 283 | PEDecoder * m_pSeedFileDecoder; |
| 284 | IMAGE_SECTION_HEADER * ; |
| 285 | |
| 286 | }; |
| 287 | |
| 288 | inline DWORD PEWriter::getSectionAlignment() { |
| 289 | return VAL32(m_ntHeaders->OptionalHeader.FileAlignment); |
| 290 | } |
| 291 | |
| 292 | inline void PEWriter::setSectionAlignment(DWORD SectionAlignment) { |
| 293 | |
| 294 | _ASSERTE(m_hSeedFile == INVALID_HANDLE_VALUE); |
| 295 | m_ntHeaders->OptionalHeader.SectionAlignment = VAL32(SectionAlignment); |
| 296 | } |
| 297 | |
| 298 | inline DWORD PEWriter::getFileAlignment() { |
| 299 | return m_ntHeaders->OptionalHeader.FileAlignment; |
| 300 | } |
| 301 | |
| 302 | inline void PEWriter::setFileAlignment(DWORD fileAlignment) { |
| 303 | _ASSERTE(m_hSeedFile == INVALID_HANDLE_VALUE); |
| 304 | m_ntHeaders->OptionalHeader.FileAlignment = VAL32(fileAlignment); |
| 305 | } |
| 306 | |
| 307 | inline unsigned PEWriter::getSubsystem() { |
| 308 | return VAL16(m_ntHeaders->OptionalHeader.Subsystem); |
| 309 | } |
| 310 | |
| 311 | inline void PEWriter::setSubsystem(unsigned subsystem, unsigned major, unsigned minor) { |
| 312 | m_ntHeaders->OptionalHeader.Subsystem = VAL16(subsystem); |
| 313 | m_ntHeaders->OptionalHeader.MajorSubsystemVersion = VAL16(major); |
| 314 | m_ntHeaders->OptionalHeader.MinorSubsystemVersion = VAL16(minor); |
| 315 | } |
| 316 | |
| 317 | inline void PEWriter::setCharacteristics(unsigned mask) { |
| 318 | m_ntHeaders->FileHeader.Characteristics |= VAL16(mask); |
| 319 | } |
| 320 | |
| 321 | inline void PEWriter::clearCharacteristics(unsigned mask) { |
| 322 | m_ntHeaders->FileHeader.Characteristics &= VAL16(~mask); |
| 323 | } |
| 324 | |
| 325 | inline void PEWriter::setDllCharacteristics(unsigned mask) { |
| 326 | m_ntHeaders->OptionalHeader.DllCharacteristics |= VAL16(mask); |
| 327 | } |
| 328 | |
| 329 | inline void PEWriter::clearDllCharacteristics(unsigned mask) { |
| 330 | m_ntHeaders->OptionalHeader.DllCharacteristics &= VAL16(~mask); |
| 331 | } |
| 332 | |
| 333 | inline void PEWriter::setEntryPointTextOffset(unsigned offset) { |
| 334 | m_ntHeaders->OptionalHeader.AddressOfEntryPoint = VAL32(offset); |
| 335 | } |
| 336 | |
| 337 | #endif |
| 338 | |