COFFI
1.2
               
Tutorial and examples

Presentation

These examples run on a Windows system.

They are using the COFFI library for the PE format (COFFI_ARCHITECTURE_PE).

The examples/tutorial/tutorial.cpp is covered by the COFF File Reader documentation.

The examples/writer/writer.cpp is covered by the COFF File Writer documentation.

The examples/write_obj/write_obj.cpp is another example covering the creation of relocatable object files.

Examples sources listings

examples/tutorial/tutorial.cpp

1 //! [ex_reader_include]
2 #include <iostream>
3 #include <coffi/coffi.hpp>
4 
5 using namespace COFFI;
6 
7 int main(int argc, char** argv)
8 {
9  //! [ex_reader_include]
10  if (argc != 2) {
11  std::cout << "Usage: tutorial <coff_file>" << std::endl;
12  return 1;
13  }
14 
15  //! [ex_reader_create]
16  // Create an coffi reader
17  coffi reader;
18 
19  // Load COFF data
20  if (!reader.load(argv[1])) {
21  std::cout << "Can't find or process COFF file " << argv[1] << std::endl;
22  return 2;
23  }
24  //! [ex_reader_create]
25 
26  //! [ex_reader_archi]
27  // Print COFF file properties
28  std::cout << "COFF file architecture: ";
29  switch (reader.get_architecture()) {
31  if (reader.get_optional_header()) {
32  if (reader.get_optional_header()->get_magic() ==
34  std::cout << "Portable Executable PE32+" << std::endl;
35  }
36  else {
37  std::cout << "Portable Executable PE32" << std::endl;
38  }
39  }
40  else {
41  std::cout << "Portable Executable" << std::endl;
42  }
43  break;
45  std::cout << "CEVA" << std::endl;
46  break;
48  std::cout << "Texas Instruments" << std::endl;
49  break;
50  }
51  //! [ex_reader_archi]
52 
53  //! [ex_reader_sections]
54  // Print the COFF file sections info
55  auto sec_num = reader.get_sections().size();
56  std::cout << "Number of sections: " << sec_num << std::endl;
57  for (auto sec : reader.get_sections()) {
58  std::cout << " [" << sec->get_index() << "] " << sec->get_name()
59  << "\t" << sec->get_data_size() << std::endl;
60  }
61  //! [ex_reader_sections]
62 
63  //! [ex_reader_symbols]
64  // Print COFF file symbols info
65  for (auto sym : *reader.get_symbols()) {
66  std::cout << sym.get_index() << " " << sym.get_name() << " "
67  << sym.get_value() << std::endl;
68  }
69  //! [ex_reader_symbols]
70 
71  return 0;
72 }
The COFFI library's main class.
Definition: coffi.hpp:73
bool load(const std::string &file_name)
Initializes the coffi object by loading data from COFF binary file.
Definition: coffi.hpp:97
optional_header * get_optional_header()
Returns the optional COFF header.
Definition: coffi.hpp:448
sections & get_sections()
Returns a list of the COFF sections.
Definition: coffi.hpp:475
coffi_architecture_t get_architecture() const
Returns the coffi object architecture.
Definition: coffi.hpp:572
The COFFI library include file.
#define OH_MAGIC_PE32PLUS
PE32+ format.
Definition: coffi_types.hpp:92
COFFI library namespace.
Definition: coffi.hpp:66
@ COFFI_ARCHITECTURE_PE
Windows portable executable (PE or PE+)
@ COFFI_ARCHITECTURE_CEVA
CEVA Inc.
@ COFFI_ARCHITECTURE_TI
Texas Instruments.

examples/writer/writer.cpp

1 /* This example shows how to create a PE program file for Windows
2  *
3  * Instructions:
4  * 1. Compile and link this file with the COFFI library
5  * g++ writer.cpp -o writer_obj.exe
6  * 2. Execute the result file writer.exe
7  * writer.exe
8  * It will produce hello.exe
9  * 3. Run the result file:
10  * hello.exe
11  * It should open a "Hello World!" message box
12  */
13 
14 //! [ex_writer_open]
15 #include <coffi/coffi.hpp>
16 
17 using namespace COFFI;
18 
19 // clang-format off
20 
21 void write_the_file( const std::string &filename )
22 {
23  coffi writer;
24 
25  // You can't proceed without this function call!
27  //! [ex_writer_open]
28 
29  //! [ex_writer_optional]
30  // Create the optional header (required for images *.exe, *.dll)
31  writer.create_optional_header();
32  //! [ex_writer_optional]
33 
34  //! [ex_writer_code]
35  // Create code section
36  section* text_sec = writer.add_section( ".text" );
37  char text[] = {
38  '\x6A', '\x00', // push 0
39  '\x68', '\x00', '\x20', '\x40', '\x00', // push offset 0x00402000 (string in the .rdata section)
40  '\x68', '\x00', '\x20', '\x40', '\x00', // push offset 0x00402000 (string in the .rdata section)
41  '\x6A', '\x00', // push 0
42  '\xE8', '\x0E', '\x00', '\x00', '\x00', // call 0x401021
43  '\x6A', '\x00', // push 0
44  '\xE8', '\x01', '\x00', '\x00', '\x00', // call 0x40101b
45  '\xF4', // hlt
46  '\xFF', '\x25', '\x4C', '\x30', '\x40', '\x00', // 0x40101b: jmp *0x40304C (ExitProcess)
47  '\xFF', '\x25', '\x54', '\x30', '\x40', '\x00' // 0x401021: jmp *0x403054 (MessageBoxA)
48  };
49  text_sec->set_data( text, sizeof( text ) );
50  text_sec->set_virtual_address(0x1000);
51  text_sec->set_virtual_size(sizeof(text));
53  //! [ex_writer_code]
54 
55  //! [ex_writer_rdata]
56  // Create a .rdata section, with the string
57  section* rdata_sec = writer.add_section( ".rdata" );
58  char rdata[] = "Hello World!\0";
59  rdata_sec->set_data( rdata, sizeof( rdata ) );
60  rdata_sec->set_virtual_address(0x2000);
61  rdata_sec->set_virtual_size(sizeof(rdata));
63  //! [ex_writer_rdata]
64 
65  //! [ex_writer_idata]
66  // Create a .idata section
67  section* idata_sec = writer.add_section( ".idata" );
68  uint8_t idata[] = {
69  // RVA = 0x3000
70 
71  // Import table (array of IMAGE_IMPORT_DESCRIPTOR structures)
72  0x3C, 0x30, 0x00, 0x00, // OriginalFirstThunk: offset of the import lookup table
73  0x00, 0x00, 0x00, 0x00, // TimeDateStamp
74  0x00, 0x00, 0x00, 0x00, // ForwarderChain
75  0x5C, 0x30, 0x00, 0x00, // Name: Offset of "KERNEL32.dll"
76  0x4C, 0x30, 0x00, 0x00, // FirstThunk: offset of import address table
77 
78  // Import table (array of IMAGE_IMPORT_DESCRIPTOR structures)
79  0x44, 0x30, 0x00, 0x00, // OriginalFirstThunk: offset of the import lookup table
80  0x00, 0x00, 0x00, 0x00, // TimeDateStamp
81  0x00, 0x00, 0x00, 0x00, // ForwarderChain
82  0x6C, 0x30, 0x00, 0x00, // Name: Offset of "USER32.dll"
83  0x54, 0x30, 0x00, 0x00, // FirstThunk: offset of import address table
84 
85  // Empty IMAGE_IMPORT_DESCRIPTOR structure (signaling the end of the IMAGE_IMPORT_DESCRIPTOR array)
86  0x00, 0x00, 0x00, 0x00, // OriginalFirstThunk
87  0x00, 0x00, 0x00, 0x00, // TimeDateStamp
88  0x00, 0x00, 0x00, 0x00, // ForwarderChain
89  0x00, 0x00, 0x00, 0x00, // Name
90  0x00, 0x00, 0x00, 0x00, // FirstThunk
91 
92  // Import lookup table (array of IMAGE_THUNK_DATA structures)
93  // RVA = 0x303C
94  0x7C, 0x30, 0x00, 0x00, // Import function by name
95  0x00, 0x00, 0x00, 0x00, //
96  // RVA = 0x3044
97  0x8C, 0x30, 0x00, 0x00, // Import function by name
98  0x00, 0x00, 0x00, 0x00, //
99 
100  // Import address table (array of IMAGE_THUNK_DATA structures)
101  // RVA = 0x304C
102  0x7C, 0x30, 0x00, 0x00, // Import function by name
103  0x00, 0x00, 0x00, 0x00, //
104  // RVA = 0x3054
105  0x8C, 0x30, 0x00, 0x00, // Import function by name
106  0x00, 0x00, 0x00, 0x00, //
107 
108  // Names
109  // RVA = 0x305C
110  'K', 'E', 'R', 'N', 'E', 'L', '3', '2', '.', 'd', 'l', 'l', 0, 0, 0, 0,
111  // RVA = 0x306C
112  'U', 'S', 'E', 'R', '3', '2', '.', 'd', 'l', 'l', 0, 0, 0, 0, 0, 0,
113 
114  // Hint/Name Table
115  // RVA = 0x307C
116  0x5E, 0x01, 'E', 'x', 'i', 't', 'P', 'r', 'o', 'c', 'e', 's', 's', 0, 0, 0,
117  // RVA = 0x308C
118  0x7F, 0x02, 'M', 'e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'A', 0, 0, 0,
119  };
120 
121  idata_sec->set_data( (char*)idata, sizeof( idata ) );
122  idata_sec->set_virtual_address(0x3000);
123  idata_sec->set_virtual_size(sizeof(idata));
125  //! [ex_writer_idata]
126 
127  //! [ex_writer_reloc]
128  // Create a .reloc section
129  section* reloc_sec = writer.add_section( ".reloc" );
130  uint16_t reloc[] = {
131  0x1000, 0x0000, // RVA of relocation block
132  0x0010, 0x0000, // Size of the relocation block
133  0x3003, // Relocation HIGHLOW at address 0x1003
134  0x3008, // Relocation HIGHLOW at address 0x1008
135  0x301D, // Relocation HIGHLOW at address 0x101D
136  0x3023, // Relocation HIGHLOW at address 0x1023
137  };
138  reloc_sec->set_data( (char*)reloc, sizeof( reloc ) );
139  reloc_sec->set_virtual_address(0x4000);
140  reloc_sec->set_virtual_size(sizeof(reloc));
142  //! [ex_writer_reloc]
143 
144  //! [ex_writer_header]
145  // Set headers properties
147  writer.get_optional_header()->set_code_size(0x200);
148  writer.get_optional_header()->set_initialized_data_size(0x400);
149  writer.get_optional_header()->set_entry_point_address(0x00001000);
150  writer.get_optional_header()->set_code_base(0x00001000);
151  writer.get_optional_header()->set_data_base(0x00002000);
152  writer.get_win_header()->set_image_base(0x00400000);
153  writer.get_win_header()->set_section_alignment(0x1000);
154  writer.get_win_header()->set_major_os_version(4);
155  writer.get_win_header()->set_major_image_version(1);
156  writer.get_win_header()->set_major_subsystem_version(4);
157  writer.get_win_header()->set_image_size(0x5000);
158  writer.get_win_header()->set_headers_size(0x200);
159  writer.get_win_header()->set_subsystem(3); // Windows CUI
160  writer.get_win_header()->set_stack_reserve_size(0x00100000);
161  writer.get_win_header()->set_stack_commit_size(0x1000);
162  writer.get_win_header()->set_heap_reserve_size(0x100000);
163  writer.get_win_header()->set_heap_commit_size(0x1000);
164  //! [ex_writer_header]
165 
166  //! [ex_writer_directories]
167  // Add directories (required for images *.exe, *.dll)
168  writer.add_directory(image_data_directory{0, 0}); // Export Directory [.edata (or where ever we found it)]
169  writer.add_directory(image_data_directory{idata_sec->get_virtual_address(), idata_sec->get_virtual_size()}); // Import Directory [parts of .idata]
170  writer.add_directory(image_data_directory{0, 0}); // Resource Directory [.rsrc]
171  writer.add_directory(image_data_directory{0, 0}); // Exception Directory [.pdata]
172  writer.add_directory(image_data_directory{0, 0}); // Security Directory
173  writer.add_directory(image_data_directory{reloc_sec->get_virtual_address(), reloc_sec->get_virtual_size()}); // Base Relocation Directory [.reloc]
174  writer.add_directory(image_data_directory{0, 0}); // Debug Directory
175  writer.add_directory(image_data_directory{0, 0}); // Description Directory
176  writer.add_directory(image_data_directory{0, 0}); // Special Directory
177  writer.add_directory(image_data_directory{0, 0}); // Thread Storage Directory [.tls]
178  writer.add_directory(image_data_directory{0, 0}); // Load Configuration Directory
179  writer.add_directory(image_data_directory{0, 0}); // Bound Import Directory
180  writer.add_directory(image_data_directory{0x304C, 0x10}); // Import Address Table Directory
181  writer.add_directory(image_data_directory{0, 0}); // Delay Import Directory
182  writer.add_directory(image_data_directory{0, 0}); // CLR Runtime Header
183  writer.add_directory(image_data_directory{0, 0}); // Reserved
184  //! [ex_writer_directories]
185 
186  //! [ex_writer_save]
187  // Recompute all the offsets in the file
188  writer.layout();
189 
190  // Create the PE file
191  writer.save( filename );
192  //! [ex_writer_save]
193 }
194 // clang-format on
195 
196 int main()
197 {
198  write_the_file("hello.exe");
199  return 0;
200 }
section * add_section(const std::string &name)
Add a COFF section.
Definition: coffi.hpp:488
win_header * get_win_header()
Returns the Windows NT header.
Definition: coffi.hpp:463
coff_header * get_header()
Returns the COFF header.
Definition: coffi.hpp:436
bool save(const std::string &file_name)
Creates a file in COFF binary format.
Definition: coffi.hpp:310
directory * add_directory(const image_data_directory &rva_and_size)
Add a PE data directory.
Definition: coffi.hpp:525
void create(coffi_architecture_t architecture)
Cleans and/or initializes the coffi object.
Definition: coffi.hpp:353
void create_optional_header(uint16_t magic=OH_MAGIC_PE32)
Initializes an optional header for the coffi object.
Definition: coffi.hpp:389
void layout()
Performs the layout of the file.
Definition: coffi.hpp:581
Interface class for accessing a COFF section, for all the COFF architectures.
#define IMAGE_FILE_EXECUTABLE_IMAGE
Image only. Indicates that the image file is valid and can be run. If this flag is not set,...
#define IMAGE_SCN_CNT_INITIALIZED_DATA
The section contains initialized data.
#define IMAGE_SCN_CNT_CODE
The section contains executable code.
#define IMAGE_SCN_MEM_EXECUTE
The section can be executed as code.
#define IMAGE_SCN_ALIGN_4BYTES
Align data on a 4 - byte boundary.Valid only for object files.
#define IMAGE_SCN_MEM_READ
The section can be read.
#define IMAGE_FILE_32BIT_MACHINE
Machine based on 32-bit-word architecture.

examples/write_obj/write_obj.cpp

1 /*
2  * This example shows how to create a PE object file for Windows
3  *
4  * Instructions:
5  * 1. Compile and link this file with the COFFI library
6  * g++ write_obj.cpp -o writer_obj.exe
7  * 2. Execute the result file write_obj.exe
8  * write_obj.exe
9  * It will produce answer.o
10  * 3. Link the output file answer.o, with a test program
11  * gcc answer.o answer_test.c -o answer.exe
12  * 4. Run the result file:
13  * answer.exe
14  * It should print "The answer is 42"
15  */
16 
17 #include <string>
18 #include <coffi/coffi.hpp>
19 
20 using namespace COFFI;
21 
22 void write_the_file(const std::string& filename)
23 {
24  coffi writer;
25 
26  // You can't proceed before this function call!
28 
29  writer.get_header()->set_flags(IMAGE_FILE_32BIT_MACHINE |
31 
32  // Create code section
33  section* text_sec = writer.add_section(".text");
34  // Code that returns 42
35  char text[] = {
36  '\x55', // push %ebp
37  '\x89', '\xE5', // mov %esp,%ebp
38  '\x83', '\xE4', '\xF0', // and $0xfffffff0,%esp
39  '\xE8', '\x00', '\x00', '\x00', '\x00', // call b <_main+0xb>
40  '\xB8', '\x2A', '\x00', '\x00', '\x00', // mov $0x2a,%eax
41  '\xC9', // leave
42  '\xC3', // ret
43  '\x90', // nop
44  '\x90', // nop
45  };
46  text_sec->set_data(text, sizeof(text));
47  //text_sec->set_virtual_address(0x1000);
48  //text_sec->set_virtual_size(sizeof(text));
49  text_sec->set_flags(IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ |
51 
52  // Create a .data section, empty
53  section* data_sec = writer.add_section(".data");
54  data_sec->set_flags(IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE |
57 
58  // Create a .bss section, empty
59  section* bss_sec = writer.add_section(".bss");
60  bss_sec->set_flags(IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE |
63 
64  // Create a section with arbitrary data
65  section* v_sec = writer.add_section(".rdata$zzz");
66  char v[] = "This is an arbitrary read-only string data\0";
67  v_sec->set_data(v, sizeof(v));
70 
71  symbol* sym1 = writer.add_symbol(".file");
72  sym1->set_section_number(IMAGE_SYM_DEBUG);
73  sym1->set_storage_class(IMAGE_SYM_CLASS_FILE);
74  sym1->set_aux_symbols_number(1);
75  auxiliary_symbol_record_4 a1{"answer.c"};
76  sym1->get_auxiliary_symbols().push_back(*(auxiliary_symbol_record*)&a1);
77 
78  symbol* sym2 = writer.add_symbol("_answer");
79  sym2->set_type(IMAGE_SYM_TYPE_FUNCTION);
80  sym2->set_storage_class(IMAGE_SYM_CLASS_EXTERNAL);
81  sym2->set_section_number(text_sec->get_index() + 1);
82  sym2->set_aux_symbols_number(1);
84  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
85  sym2->get_auxiliary_symbols().push_back(a2);
86 
87  symbol* sym3 = writer.add_symbol(".text");
88  sym3->set_type(IMAGE_SYM_TYPE_NOT_FUNCTION);
89  sym3->set_storage_class(IMAGE_SYM_CLASS_STATIC);
90  sym3->set_section_number(text_sec->get_index() + 1);
91  sym3->set_aux_symbols_number(1);
93  text_sec->get_data_size(), 1, 0, 0, 0, 0, {0, 0, 0}};
94  sym3->get_auxiliary_symbols().push_back(
95  *reinterpret_cast<auxiliary_symbol_record*>(&a3));
96 
97  symbol* sym4 = writer.add_symbol(".data");
98  sym4->set_type(IMAGE_SYM_TYPE_NOT_FUNCTION);
99  sym4->set_storage_class(IMAGE_SYM_CLASS_STATIC);
100  sym4->set_section_number(data_sec->get_index() + 1);
101  sym4->set_aux_symbols_number(1);
103  data_sec->get_data_size(), 0, 0, 0, 0, 0, {0, 0, 0}};
104  sym4->get_auxiliary_symbols().push_back(
105  *reinterpret_cast<auxiliary_symbol_record*>(&a4));
106 
107  symbol* sym5 = writer.add_symbol(".bss");
108  sym5->set_type(IMAGE_SYM_TYPE_NOT_FUNCTION);
109  sym5->set_storage_class(IMAGE_SYM_CLASS_STATIC);
110  sym5->set_section_number(bss_sec->get_index() + 1);
111  sym5->set_aux_symbols_number(1);
113  bss_sec->get_data_size(), 0, 0, 0, 0, 0, {0, 0, 0}};
114  sym5->get_auxiliary_symbols().push_back(
115  *reinterpret_cast<auxiliary_symbol_record*>(&a5));
116 
117  symbol* sym6 = writer.add_symbol(".rdata$zzz");
118  sym6->set_type(IMAGE_SYM_TYPE_NOT_FUNCTION);
119  sym6->set_storage_class(IMAGE_SYM_CLASS_STATIC);
120  sym6->set_section_number(v_sec->get_index() + 1);
121  sym6->set_aux_symbols_number(1);
123  v_sec->get_data_size(), 0, 0, 0, 0, 0, {0, 0, 0}};
124  sym6->get_auxiliary_symbols().push_back(
125  *reinterpret_cast<auxiliary_symbol_record*>(&a6));
126 
127  // Create the object file
128  writer.save(filename);
129 }
130 
131 int main()
132 {
133  write_the_file("answer.o");
134  return 0;
135 }
symbol * add_symbol(const std::string &name)
Adds a symbol in the table.
Class for accessing a COFF symbol.
#define IMAGE_SCN_MEM_WRITE
The section can be written to.
#define IMAGE_SYM_DEBUG
The symbol provides general type or debugging information but does not correspond to a section....
#define IMAGE_SYM_CLASS_EXTERNAL
Used by Microsoft tools for external symbols. The Value field indicates the size if the section numbe...
#define IMAGE_FILE_LINE_NUMS_STRIPPED
COFF line numbers have been removed.
#define IMAGE_SYM_CLASS_STATIC
The Value field specifies the offset of the symbol within the section. If the Value is 0,...
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA
The section contains uninitialized data.
#define IMAGE_SYM_CLASS_FILE
Used by Microsoft tools, as well as traditional COFF format, for the source-file symbol record....
PE auxiliary format 4: Files.
PE auxiliary format 5: Section definitions.
Generic auxiliary symbol record, covers any type of auxiliary symbol.