COFFI
1.2
               
coffi_headers.hpp
Go to the documentation of this file.
1 /*
2 Copyright (C) 2014-2014 by Serge Lamikhov-Center
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22 
23 /*! @file coffi_headers.hpp
24  * @brief COFFI library classes for the COFF file headers.
25  *
26  * Do not include this file directly. This file is included by coffi.hpp.
27  */
28 
29 #ifndef COFFI_WIN_HEADER_HPP
30 #define COFFI_WIN_HEADER_HPP
31 
32 #include <string>
33 #include <iostream>
34 
35 #include <coffi/coffi_utils.hpp>
36 
37 #if defined(__has_include) && __has_include(<gsl/narrow>)
38 #include <gsl/narrow>
39 using gsl::narrow_cast;
40 #else
41 #ifndef narrow_cast
42 #define narrow_cast static_cast
43 #endif
44 #endif
45 
46 namespace COFFI {
47 
48 //------------------------------------------------------------------------------
49 //! Class for accessing the MS-DOS file header
51 {
52  public:
53  //------------------------------------------------------------------------------
54  dos_header()
55  {
56  std::fill_n(reinterpret_cast<char*>(&header), sizeof(header), '\0');
57  static const uint8_t default_stub[] = {
58  0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01,
59  0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F,
60  0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74,
61  0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20,
62  0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D,
63  0x0A, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64  };
65  stub_ = 0;
66  stub_size_ = 0;
67  std::fill_n(reinterpret_cast<char*>(&header), sizeof(header), '\0');
68  set_stub(reinterpret_cast<const char*>(default_stub),
69  sizeof(default_stub));
70  set_signature('M' + ('Z' << 8));
71  set_bytes_in_last_block(144);
72  set_blocks_in_file(3);
73  set_header_paragraphs(4);
74  set_max_extra_paragraphs(65535);
75  set_sp(184);
76  set_reloc_table_offset(64);
77  set_pe_sign_location(sizeof(msdos_header) + get_stub_size());
78  }
79  virtual ~dos_header() { clean(); }
80 
81  //------------------------------------------------------------------------------
82  //! @accessors{dos_header}
83  COFFI_GET_SET_ACCESS(uint16_t, signature);
84  COFFI_GET_SET_ACCESS(uint16_t, bytes_in_last_block);
85  COFFI_GET_SET_ACCESS(uint16_t, blocks_in_file);
86  COFFI_GET_SET_ACCESS(uint16_t, num_relocs);
87  COFFI_GET_SET_ACCESS(uint16_t, header_paragraphs);
88  COFFI_GET_SET_ACCESS(uint16_t, min_extra_paragraphs);
89  COFFI_GET_SET_ACCESS(uint16_t, max_extra_paragraphs);
90  COFFI_GET_SET_ACCESS(uint16_t, ss);
91  COFFI_GET_SET_ACCESS(uint16_t, sp);
92  COFFI_GET_SET_ACCESS(uint16_t, checksum);
93  COFFI_GET_SET_ACCESS(uint16_t, ip);
94  COFFI_GET_SET_ACCESS(uint16_t, cs);
95  COFFI_GET_SET_ACCESS(uint16_t, reloc_table_offset);
96  COFFI_GET_SET_ACCESS(uint16_t, overlay_number);
97  COFFI_GET_SET_ACCESS(uint16_t, oem_id);
98  COFFI_GET_SET_ACCESS(uint16_t, oem_info);
99  COFFI_GET_SET_ACCESS(int32_t, pe_sign_location);
100 
101  COFFI_GET_SIZEOF();
102  //! @endaccessors
103 
104  //------------------------------------------------------------------------------
105  bool load(std::istream& stream)
106  {
107  clean();
108 
109  // Read EXE file signature
110  char e_ident0[CI_NIDENT0];
111  stream.read(reinterpret_cast<char*>(&e_ident0), sizeof(e_ident0));
112  if (stream.gcount() != sizeof(e_ident0)) {
113  return false;
114  }
115 
116  // Is it EXE file?
117  if (e_ident0[CI_MAG0] != PEMAG0 || e_ident0[CI_MAG1] != PEMAG1) {
118  return false;
119  }
120 
121  stream.seekg(0);
122  stream.read(reinterpret_cast<char*>(&header), sizeof(header));
123  if (stream.gcount() != sizeof(header)) {
124  return false;
125  }
126 
127  if (get_pe_sign_location() > static_cast<int32_t>(sizeof(header))) {
128  stub_size_ = get_pe_sign_location() - sizeof(header);
129  char* read_stub = new char[stub_size_];
130  if (!read_stub) {
131  return false;
132  }
133  stream.read(read_stub, stub_size_);
134  stub_ = read_stub;
135  if (stream.gcount() != stub_size_) {
136  return false;
137  }
138  }
139  else {
140  stream.seekg(get_pe_sign_location());
141  }
142 
143  char e_ident1[CI_NIDENT1];
144  stream.read(e_ident1, CI_NIDENT1);
145  if (stream.gcount() != CI_NIDENT1 || e_ident1[CI_MAG2] != PEMAG2 ||
146  e_ident1[CI_MAG3] != PEMAG3 || e_ident1[CI_MAG4] != PEMAG4 ||
147  e_ident1[CI_MAG5] != PEMAG5) {
148  return false;
149  }
150 
151  return true;
152  }
153 
154  //------------------------------------------------------------------------------
155  void save(std::ostream& stream)
156  {
157  stream.write(reinterpret_cast<char*>(&header), sizeof(header));
158  stream.write(stub_, stub_size_);
159  stream.put(PEMAG2);
160  stream.put(PEMAG3);
161  stream.put(PEMAG4);
162  stream.put(PEMAG5);
163  }
164 
165  //------------------------------------------------------------------------------
166  virtual const char* get_stub() const { return stub_; }
167 
168  //------------------------------------------------------------------------------
169  virtual uint32_t get_stub_size() const { return stub_size_; }
170 
171  //------------------------------------------------------------------------------
172  void set_stub(const char* data, uint32_t size)
173  {
174  if (stub_) {
175  delete[] stub_;
176  }
177  stub_size_ = size;
178  char* new_stub = new char[stub_size_];
179  if (!new_stub) {
180  stub_size_ = 0;
181  }
182  else {
183  std::copy(data, data + size, new_stub);
184  }
185  stub_ = new_stub;
186  }
187 
188  //------------------------------------------------------------------------------
189  void set_stub(const std::string& data)
190  {
191  set_stub(data.c_str(), narrow_cast<uint32_t>(data.size()));
192  }
193 
194  //------------------------------------------------------------------------------
195  private:
196  //------------------------------------------------------------------------------
197  void clean()
198  {
199  if (stub_) {
200  delete[] stub_;
201  stub_ = 0;
202  }
203  stub_size_ = 0;
204  }
205 
206  //------------------------------------------------------------------------------
207  msdos_header header;
208  const char* stub_;
209  int stub_size_;
210 };
211 
212 //------------------------------------------------------------------------------
213 //! Interface class for accessing the COFF file header, for all the COFF architectures.
215 {
216  public:
217  virtual ~coff_header() {}
218 
219  //! @accessors{coff_header}
220  COFFI_GET_SET_ACCESS_DECL(uint16_t, version);
221  COFFI_GET_SET_ACCESS_DECL(uint16_t, machine);
222  COFFI_GET_SET_ACCESS_DECL(uint16_t, sections_count);
223  COFFI_GET_SET_ACCESS_DECL(uint32_t, time_data_stamp);
224  COFFI_GET_SET_ACCESS_DECL(uint32_t, symbol_table_offset);
225  COFFI_GET_SET_ACCESS_DECL(uint32_t, symbols_count);
226  COFFI_GET_SET_ACCESS_DECL(uint16_t, optional_header_size);
227  COFFI_GET_SET_ACCESS_DECL(uint16_t, flags);
228  COFFI_GET_SET_ACCESS_DECL(uint16_t, target_id);
229 
230  COFFI_GET_SIZEOF_DECL();
231  //! @endaccessors
232 
233  virtual bool load(std::istream& stream) = 0;
234  virtual void save(std::ostream& stream) = 0;
235 };
236 
237 //------------------------------------------------------------------------------
238 /*! @brief Template class for accessing a COFF file header, depends on the underlying COFF file header format.
239  *
240  * The template parameter **class T** is one of:
241  * - coff_file_header: @copybrief coff_file_header
242  * - coff_file_header_ti: @copybrief coff_file_header_ti
243  */
244 template <class T> class coff_header_impl_tmpl : public coff_header
245 {
246  public:
248  {
249  std::fill_n(reinterpret_cast<char*>(&header), sizeof(header), '\0');
250  }
251 
252  //------------------------------------------------------------------------------
253  //! @accessors{coff_header_impl_tmpl}
254  COFFI_GET_SET_ACCESS(uint16_t, sections_count);
255  COFFI_GET_SET_ACCESS(uint32_t, time_data_stamp);
256  COFFI_GET_SET_ACCESS(uint32_t, symbol_table_offset);
257  COFFI_GET_SET_ACCESS(uint32_t, symbols_count);
258  COFFI_GET_SET_ACCESS(uint16_t, optional_header_size);
259  COFFI_GET_SET_ACCESS(uint16_t, flags);
260 
261  COFFI_GET_SIZEOF();
262  //! @endaccessors
263 
264  //------------------------------------------------------------------------------
265  bool load(std::istream& stream)
266  {
267  stream.read(reinterpret_cast<char*>(&header), sizeof(header));
268  if (stream.gcount() != sizeof(header)) {
269  return false;
270  }
271 
272  return true;
273  }
274 
275  //------------------------------------------------------------------------------
276  void save(std::ostream& stream)
277  {
278  stream.write(reinterpret_cast<char*>(&header), sizeof(header));
279  }
280 
281  //------------------------------------------------------------------------------
282  protected:
283  T header;
284 };
285 
286 //------------------------------------------------------------------------------
287 //! Class for accessing a COFF file header, for the PE format.
288 class coff_header_impl : public coff_header_impl_tmpl<coff_file_header>
289 {
290  public:
291  //! @accessors{coff_header_impl}
292  COFFI_GET_SET_ACCESS(uint16_t, machine);
293  COFFI_GET_SET_ACCESS_NONE(uint16_t, version);
294  COFFI_GET_SET_ACCESS_NONE(uint16_t, target_id);
295  //! @endaccessors
296 };
297 
298 //------------------------------------------------------------------------------
299 //! Class for accessing a COFF file header, for the Texas Instruments format.
300 class coff_header_impl_ti : public coff_header_impl_tmpl<coff_file_header_ti>
301 {
302  public:
303  //! @accessors{coff_header_impl_ti}
304  COFFI_GET_SET_ACCESS(uint16_t, version);
305  COFFI_GET_SET_ACCESS(uint16_t, target_id);
306  COFFI_GET_SET_ACCESS_NONE(uint16_t, machine);
307  //! @endaccessors
308 };
309 
310 //------------------------------------------------------------------------------
311 //! Interface class for accessing the COFF file optional header, for all the COFF architectures.
313 {
314  public:
315  virtual ~optional_header(){};
316 
317  //! @accessors{optional_header}
318  COFFI_GET_SET_ACCESS_DECL(uint16_t, magic);
319  COFFI_GET_SET_ACCESS_DECL(uint8_t, major_linker_version);
320  COFFI_GET_SET_ACCESS_DECL(uint8_t, minor_linker_version);
321  COFFI_GET_SET_ACCESS_DECL(uint16_t, linker_version);
322  COFFI_GET_SET_ACCESS_DECL(uint32_t, code_size);
323  COFFI_GET_SET_ACCESS_DECL(uint32_t, initialized_data_size);
324  COFFI_GET_SET_ACCESS_DECL(uint32_t, uninitialized_data_size);
325  COFFI_GET_SET_ACCESS_DECL(uint32_t, entry_point_address);
326  COFFI_GET_SET_ACCESS_DECL(uint32_t, code_base);
327  COFFI_GET_SET_ACCESS_DECL(uint32_t, data_base);
328 
329  COFFI_GET_SIZEOF_DECL();
330  //! @endaccessors
331 
332  virtual bool load(std::istream& stream) = 0;
333  virtual void save(std::ostream& stream) = 0;
334 };
335 
336 //------------------------------------------------------------------------------
337 /*! @brief Template class for accessing a COFF file optional header, depends on the underlying COFF file optional header format.
338  *
339  * The template parameter **class T** is one of:
340  * - coff_optional_header_pe: @copybrief coff_optional_header_pe
341  * - coff_optional_header_pe_plus: @copybrief coff_optional_header_pe_plus
342  * - common_optional_header_ti: @copybrief common_optional_header_ti
343  */
344 template <class T> class optional_header_impl_tmpl : public optional_header
345 {
346  public:
348  {
349  std::fill_n(reinterpret_cast<char*>(&header), sizeof(header), '\0');
350  }
351 
352  //------------------------------------------------------------------------------
353 
354  //! @accessors{optional_header_impl_tmpl}
355  COFFI_GET_SET_ACCESS(uint16_t, magic);
356  COFFI_GET_SET_ACCESS(uint32_t, code_size);
357  COFFI_GET_SET_ACCESS(uint32_t, initialized_data_size);
358  COFFI_GET_SET_ACCESS(uint32_t, uninitialized_data_size);
359  COFFI_GET_SET_ACCESS(uint32_t, entry_point_address);
360  COFFI_GET_SET_ACCESS(uint32_t, code_base);
361 
362  COFFI_GET_SIZEOF();
363  //! @endaccessors
364 
365  //---------------------------------------------------------------------
366  bool load(std::istream& stream)
367  {
368  std::fill_n(reinterpret_cast<char*>(&header), sizeof(header), '\0');
369  stream.read(reinterpret_cast<char*>(&header), sizeof(header));
370  if (stream.gcount() != sizeof(header)) {
371  return false;
372  }
373  return true;
374  }
375 
376  //------------------------------------------------------------------------------
377  void save(std::ostream& stream)
378  {
379  stream.write(reinterpret_cast<char*>(&header), sizeof(header));
380  }
381 
382  //------------------------------------------------------------------------------
383  T header;
384 };
385 
386 //------------------------------------------------------------------------------
387 //! Class for accessing a COFF file optional header, for the PE32 format.
389  : public optional_header_impl_tmpl<coff_optional_header_pe>
390 {
391  public:
392  //! @accessors{optional_header_impl_pe}
393  COFFI_GET_SET_ACCESS(uint8_t, major_linker_version);
394  COFFI_GET_SET_ACCESS(uint8_t, minor_linker_version);
395  COFFI_GET_SET_ACCESS_NONE(uint16_t, linker_version);
396  COFFI_GET_SET_ACCESS(uint32_t, data_base);
397  //! @endaccessors
398 };
399 
400 //------------------------------------------------------------------------------
401 //! Class for accessing a COFF file optional header, for the PE32+ format.
403  : public optional_header_impl_tmpl<coff_optional_header_pe_plus>
404 {
405  public:
406  //! @accessors{optional_header_impl_pe_plus}
407  COFFI_GET_SET_ACCESS(uint8_t, major_linker_version);
408  COFFI_GET_SET_ACCESS(uint8_t, minor_linker_version);
409  COFFI_GET_SET_ACCESS_NONE(uint16_t, linker_version);
410  COFFI_GET_SET_ACCESS_NONE(uint32_t, data_base);
411  //! @endaccessors
412 };
413 
414 //------------------------------------------------------------------------------
415 //! Class for accessing a COFF file optional header, for the Texas Instruments format.
417  : public optional_header_impl_tmpl<common_optional_header_ti>
418 {
419  public:
420  //! @accessors{optional_header_impl_ti}
421  COFFI_GET_SET_ACCESS(uint16_t, linker_version);
422  COFFI_GET_SET_ACCESS_NONE(uint8_t, major_linker_version);
423  COFFI_GET_SET_ACCESS_NONE(uint8_t, minor_linker_version);
424  COFFI_GET_SET_ACCESS(uint32_t, data_base);
425  //! @endaccessors
426 };
427 
428 //------------------------------------------------------------------------------
429 //! Interface class for accessing the Windows NT file header, for both the PE32 and PE32+ formats.
431 {
432  public:
433  virtual ~win_header(){};
434 
435  //! @accessors{win_header}
436  COFFI_GET_SET_ACCESS_DECL(uint64_t, image_base);
437  COFFI_GET_SET_ACCESS_DECL(uint32_t, section_alignment);
438  COFFI_GET_SET_ACCESS_DECL(uint32_t, file_alignment);
439  COFFI_GET_SET_ACCESS_DECL(uint16_t, major_os_version);
440  COFFI_GET_SET_ACCESS_DECL(uint16_t, minor_os_version);
441  COFFI_GET_SET_ACCESS_DECL(uint16_t, major_image_version);
442  COFFI_GET_SET_ACCESS_DECL(uint16_t, minor_image_version);
443  COFFI_GET_SET_ACCESS_DECL(uint16_t, major_subsystem_version);
444  COFFI_GET_SET_ACCESS_DECL(uint16_t, minor_subsystem_version);
445  COFFI_GET_SET_ACCESS_DECL(uint32_t, win32_version_value);
446  COFFI_GET_SET_ACCESS_DECL(uint32_t, image_size);
447  COFFI_GET_SET_ACCESS_DECL(uint32_t, headers_size);
448  COFFI_GET_SET_ACCESS_DECL(uint32_t, checksum);
449  COFFI_GET_SET_ACCESS_DECL(uint16_t, subsystem);
450  COFFI_GET_SET_ACCESS_DECL(uint16_t, dll_flags);
451  COFFI_GET_SET_ACCESS_DECL(uint64_t, stack_reserve_size);
452  COFFI_GET_SET_ACCESS_DECL(uint64_t, stack_commit_size);
453  COFFI_GET_SET_ACCESS_DECL(uint64_t, heap_reserve_size);
454  COFFI_GET_SET_ACCESS_DECL(uint64_t, heap_commit_size);
455  COFFI_GET_SET_ACCESS_DECL(uint32_t, loader_flags);
456  COFFI_GET_SET_ACCESS_DECL(uint32_t, number_of_rva_and_sizes);
457 
458  COFFI_GET_SIZEOF_DECL();
459  //! @endaccessors
460 
461  virtual bool load(std::istream& f) = 0;
462  virtual void save(std::ostream& f) = 0;
463 };
464 
465 //------------------------------------------------------------------------------
466 /*! @brief Template class for accessing a Windows NT file header, depends on the format (PE32 or PE32+).
467  *
468  * The template parameter **class T** is one of:
469  * - win_header_pe: For the PE32 format
470  * - win_header_pe_plus: For the PE32+ format
471  */
472 template <class T> class win_header_impl : public win_header
473 {
474  public:
475  //------------------------------------------------------------------------------
477  {
478  std::fill_n(reinterpret_cast<char*>(&header), sizeof(header), '\0');
479  set_image_base(0x00400000);
480  set_file_alignment(512);
481  }
482 
483  //------------------------------------------------------------------------------
484  //! @accessors{win_header_impl}
485  COFFI_GET_SET_ACCESS(uint64_t, image_base);
486  COFFI_GET_SET_ACCESS(uint32_t, section_alignment);
487  COFFI_GET_SET_ACCESS(uint32_t, file_alignment);
488  COFFI_GET_SET_ACCESS(uint16_t, major_os_version);
489  COFFI_GET_SET_ACCESS(uint16_t, minor_os_version);
490  COFFI_GET_SET_ACCESS(uint16_t, major_image_version);
491  COFFI_GET_SET_ACCESS(uint16_t, minor_image_version);
492  COFFI_GET_SET_ACCESS(uint16_t, major_subsystem_version);
493  COFFI_GET_SET_ACCESS(uint16_t, minor_subsystem_version);
494  COFFI_GET_SET_ACCESS(uint32_t, win32_version_value);
495  COFFI_GET_SET_ACCESS(uint32_t, image_size);
496  COFFI_GET_SET_ACCESS(uint32_t, headers_size);
497  COFFI_GET_SET_ACCESS(uint32_t, checksum);
498  COFFI_GET_SET_ACCESS(uint16_t, subsystem);
499  COFFI_GET_SET_ACCESS(uint16_t, dll_flags);
500  COFFI_GET_SET_ACCESS(uint64_t, stack_reserve_size);
501  COFFI_GET_SET_ACCESS(uint64_t, stack_commit_size);
502  COFFI_GET_SET_ACCESS(uint64_t, heap_reserve_size);
503  COFFI_GET_SET_ACCESS(uint64_t, heap_commit_size);
504  COFFI_GET_SET_ACCESS(uint32_t, loader_flags);
505  COFFI_GET_SET_ACCESS(uint32_t, number_of_rva_and_sizes);
506 
507  COFFI_GET_SIZEOF();
508  //! @endaccessors
509 
510  //------------------------------------------------------------------------------
511  bool load(std::istream& stream) override
512  {
513  int read_size = sizeof(header);
514  std::fill_n(reinterpret_cast<char*>(&header), read_size, '\0');
515  stream.read(reinterpret_cast<char*>(&header), read_size);
516  if (stream.gcount() != read_size) {
517  return false;
518  }
519 
520  return true;
521  }
522 
523  //------------------------------------------------------------------------------
524  void save(std::ostream& stream)
525  {
526  stream.write(reinterpret_cast<char*>(&header), sizeof(header));
527  }
528 
529  //------------------------------------------------------------------------------
530  private:
531  T header;
532 };
533 
534 } // namespace COFFI
535 
536 #endif // COFFI_WIN_HEADER_HPP
Class for accessing a COFF file header, for the Texas Instruments format.
Template class for accessing a COFF file header, depends on the underlying COFF file header format.
Class for accessing a COFF file header, for the PE format.
Interface class for accessing the COFF file header, for all the COFF architectures.
Class for accessing the MS-DOS file header.
Class for accessing a COFF file optional header, for the PE32+ format.
Class for accessing a COFF file optional header, for the PE32 format.
Class for accessing a COFF file optional header, for the Texas Instruments format.
Template class for accessing a COFF file optional header, depends on the underlying COFF file optiona...
Interface class for accessing the COFF file optional header, for all the COFF architectures.
Template class for accessing a Windows NT file header, depends on the format (PE32 or PE32+).
Interface class for accessing the Windows NT file header, for both the PE32 and PE32+ formats.
COFFI library utilities.
COFFI library namespace.
Definition: coffi.hpp:66
MS-DOS file header.